Skip to content

Commit

Permalink
Improve performances by not using Exceptions for code control flow wi…
Browse files Browse the repository at this point in the history
…thin BlockBreakListener (#615) (#621)

* Do not use Exceptions for code control flow for BlockBreakListener

* Implement nitpicks

* Formatting & refactor shouldCancel & add enums values computed once

---------

Co-authored-by: Geolykt <[email protected]>
  • Loading branch information
Rakambda and Geolykt authored Oct 28, 2023
1 parent 2d6190e commit 1bc8398
Show file tree
Hide file tree
Showing 16 changed files with 75 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public enum BreakMode{
FALL_ALL_BLOCK(true, true),
SHIFT_DOWN(false, false);

@Getter
private final static BreakMode[] values = values();

private final boolean checkLeavesAround;
private final boolean applySpeedMultiplier;
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ConfigurationPacket decodeConfigurationPacket(@NotNull IFriendlyByteBuf b
return ConfigurationPacket.builder()
.speedMultiplicand(buf.readDouble())
.forceToolUsage(buf.readBoolean())
.breakMode(BreakMode.values()[buf.readInteger()])
.breakMode(BreakMode.getValues()[buf.readInteger()])
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package fr.rakambda.fallingtree.common.tree;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public enum AbortedResult implements IBreakAttemptResult {
INVALID_PLAYER_STATE(false),
NOT_ENABLED(false),
NOT_SERVER(false),
NO_SUCH_TREE(false),
REQUIRED_TOOL_ABSENT(true),
TREE_TOO_BIG_BREAK(false),
TREE_TOO_BIG_SCAN(false);

private final boolean cancel;

@Override
public boolean shouldCancel() {
return cancel;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,22 @@
import fr.rakambda.fallingtree.common.config.enums.BreakMode;
import org.jetbrains.annotations.NotNull;

/**
* Record that denotes that an attempt to break a tree with the given mode has
* succeeded. Failures are instead denoted as {@link AbortedResult}.
*
* @param shouldCancel Whether the event which triggered the query should be cancelled as a result of this result.
* @param breakMode The mode with which the block was broken.
*/
public record BreakTreeResult(
boolean shouldCancel,
@NotNull BreakMode breakMode
){
) implements IBreakAttemptResult{
@Override
public boolean shouldCancel(){
return switch(breakMode()){
case INSTANTANEOUS, FALL_ITEM, FALL_BLOCK, FALL_ALL_BLOCK -> shouldCancel;
case SHIFT_DOWN -> true;
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package fr.rakambda.fallingtree.common.tree;

import fr.rakambda.fallingtree.common.wrapper.IBlockPos;
import fr.rakambda.fallingtree.common.wrapper.ILevel;
import fr.rakambda.fallingtree.common.wrapper.IPlayer;

/**
* The result of a {@link TreeHandler#breakTree(ILevel, IPlayer, IBlockPos)}, whether it succeeded or not.
* Failures are generally instances of {@link AbortedResult}, where are succeeded attempts are instances of
* {@link BreakTreeResult}.
*/
public sealed interface IBreakAttemptResult permits BreakTreeResult, AbortedResult{
boolean shouldCancel();
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void removePartsHigherThan(int y, @NotNull TreePartType partType){
}

public int getBreakableCount(){
return Arrays.stream(TreePartType.values())
return Arrays.stream(TreePartType.getValues())
.filter(TreePartType::isBreakable)
.mapToInt(this::getPartCount)
.sum();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@

import fr.rakambda.fallingtree.common.tree.breaking.*;
import fr.rakambda.fallingtree.common.tree.builder.TreeTooBigException;
import fr.rakambda.fallingtree.common.tree.exception.NoTreeFoundException;
import fr.rakambda.fallingtree.common.tree.exception.NotServerException;
import fr.rakambda.fallingtree.common.tree.exception.PlayerNotInRightState;
import fr.rakambda.fallingtree.common.FallingTreeCommon;
import fr.rakambda.fallingtree.common.config.enums.BreakMode;
import fr.rakambda.fallingtree.common.tree.exception.ToolUseForcedException;
import fr.rakambda.fallingtree.common.tree.exception.TreeBreakingException;
import fr.rakambda.fallingtree.common.tree.exception.TreeBreakingNotEnabledException;
import fr.rakambda.fallingtree.common.utils.CacheSpeed;
import fr.rakambda.fallingtree.common.wrapper.IBlockPos;
import fr.rakambda.fallingtree.common.wrapper.IEnchantment;
Expand All @@ -34,27 +28,27 @@ public class TreeHandler{
private final Map<UUID, CacheSpeed> speedCache = new ConcurrentHashMap<>();

@NotNull
public BreakTreeResult breakTree(@NotNull ILevel level, @NotNull IPlayer player, @NotNull IBlockPos blockPos) throws TreeBreakingNotEnabledException, PlayerNotInRightState, ToolUseForcedException, TreeBreakingException, NoTreeFoundException, NotServerException{
public IBreakAttemptResult breakTree(@NotNull ILevel level, @NotNull IPlayer player, @NotNull IBlockPos blockPos){
if(!level.isServer()){
throw new NotServerException();
return AbortedResult.NOT_SERVER;
}
if(!mod.getConfiguration().getTrees().isTreeBreaking()){
throw new TreeBreakingNotEnabledException();
return AbortedResult.NOT_ENABLED;
}

if(!mod.checkForceToolUsage(player, level, blockPos)){
mod.notifyPlayer(player, mod.translate("chat.fallingtree.force_tool_usage", mod.getConfiguration().getTrees().getMaxScanSize()));
throw new ToolUseForcedException();
return AbortedResult.REQUIRED_TOOL_ABSENT;
}

if(!mod.isPlayerInRightState(player)){
throw new PlayerNotInRightState();
return AbortedResult.INVALID_PLAYER_STATE;
}

try{
var treeOptional = mod.getTreeBuilder().getTree(player, level, blockPos);
if(treeOptional.isEmpty()){
throw new NoTreeFoundException();
return AbortedResult.NO_SUCH_TREE;
}

var tree = treeOptional.get();
Expand All @@ -64,11 +58,11 @@ public BreakTreeResult breakTree(@NotNull ILevel level, @NotNull IPlayer player,
}
catch(TreeTooBigException e){
mod.notifyPlayer(player, mod.translate("chat.fallingtree.tree_too_big", mod.getConfiguration().getTrees().getMaxScanSize()));
throw new TreeBreakingException(e);
return AbortedResult.TREE_TOO_BIG_SCAN;
}
catch(BreakTreeTooBigException e){
mod.notifyPlayer(player, mod.translate("chat.fallingtree.break_tree_too_big", mod.getConfiguration().getTrees().getMaxSize()));
throw new TreeBreakingException(e);
return AbortedResult.TREE_TOO_BIG_BREAK;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@ public enum TreePartType{
MANGROVE_ROOTS(true),
OTHER(false);

@Getter
private static final TreePartType[] values = values();

private final boolean breakable;
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
package fr.rakambda.fallingtree.fabric.event;

import fr.rakambda.fallingtree.common.FallingTreeCommon;
import fr.rakambda.fallingtree.common.tree.exception.NoTreeFoundException;
import fr.rakambda.fallingtree.common.tree.exception.NotServerException;
import fr.rakambda.fallingtree.common.tree.exception.PlayerNotInRightState;
import fr.rakambda.fallingtree.common.tree.exception.ToolUseForcedException;
import fr.rakambda.fallingtree.common.tree.exception.TreeBreakingException;
import fr.rakambda.fallingtree.common.tree.exception.TreeBreakingNotEnabledException;
import fr.rakambda.fallingtree.fabric.common.wrapper.BlockPosWrapper;
import fr.rakambda.fallingtree.fabric.common.wrapper.LevelWrapper;
import fr.rakambda.fallingtree.fabric.common.wrapper.PlayerWrapper;
Expand All @@ -26,24 +20,16 @@ public class BlockBreakListener implements PlayerBlockBreakEvents.Before{
@NotNull
private final FallingTreeCommon<?> mod;

/**
* @return true if event is handled successful (not cancelling it), false otherwise (cancelling event)
*/
@Override
public boolean beforeBlockBreak(Level level, Player player, BlockPos blockPos, BlockState blockState, BlockEntity blockEntity){
var wrappedPlayer = new PlayerWrapper(player);
var wrappedLevel = level instanceof ServerLevel serverLevel ? new ServerLevelWrapper(serverLevel) : new LevelWrapper(level);
var wrappedPos = new BlockPosWrapper(blockPos);

try{
var result = mod.getTreeHandler().breakTree(wrappedLevel, wrappedPlayer, wrappedPos);
return switch(result.breakMode()){
case INSTANTANEOUS, FALL_ITEM, FALL_BLOCK, FALL_ALL_BLOCK -> !result.shouldCancel();
case SHIFT_DOWN -> false;
};
}
catch(TreeBreakingNotEnabledException | PlayerNotInRightState | TreeBreakingException | NoTreeFoundException | NotServerException e){
return true;
}
catch(ToolUseForcedException e){
return false;
}
var result = mod.getTreeHandler().breakTree(wrappedLevel, wrappedPlayer, wrappedPos);
return !result.shouldCancel();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package fr.rakambda.fallingtree.forge.event;

import fr.rakambda.fallingtree.common.FallingTreeCommon;
import fr.rakambda.fallingtree.common.tree.exception.*;
import fr.rakambda.fallingtree.forge.common.wrapper.BlockPosWrapper;
import fr.rakambda.fallingtree.forge.common.wrapper.LevelWrapper;
import fr.rakambda.fallingtree.forge.common.wrapper.PlayerWrapper;
Expand Down Expand Up @@ -55,21 +54,9 @@ public void onBlockBreakEvent(@Nonnull BlockEvent.BreakEvent event){
var wrappedLevel = event.getLevel() instanceof ServerLevel serverLevel ? new ServerLevelWrapper(serverLevel) : new LevelWrapper(event.getLevel());
var wrappedPos = new BlockPosWrapper(event.getPos());

try{
var result = mod.getTreeHandler().breakTree(wrappedLevel, wrappedPlayer, wrappedPos);
if(event.isCancelable()){
switch(result.breakMode()){
case INSTANTANEOUS, FALL_ITEM, FALL_BLOCK, FALL_ALL_BLOCK -> event.setCanceled(result.shouldCancel());
case SHIFT_DOWN -> event.setCanceled(true);
}
}
}
catch(TreeBreakingNotEnabledException | PlayerNotInRightState | TreeBreakingException | NoTreeFoundException | NotServerException ignored){
}
catch(ToolUseForcedException e){
if(event.isCancelable()){
event.setCanceled(true);
}
var result = mod.getTreeHandler().breakTree(wrappedLevel, wrappedPlayer, wrappedPos);
if(result.shouldCancel() && event.isCancelable()){
event.setCanceled(true);
}
}
}

0 comments on commit 1bc8398

Please sign in to comment.