From 7d79f0d581b6fff11acf7ed3d2f8b8de9751e3a9 Mon Sep 17 00:00:00 2001 From: SizableShrimp Date: Tue, 12 Apr 2022 11:43:20 -0500 Subject: [PATCH] Add use context and simulate flag to getToolModifiedState, enabled HOE_TILL action. (#8557) --- .../minecraft/world/item/AxeItem.java.patch | 6 +- .../minecraft/world/item/HoeItem.java.patch | 22 ++- .../world/item/ShovelItem.java.patch | 2 +- .../net/minecraftforge/common/ToolAction.java | 2 +- .../minecraftforge/common/ToolActions.java | 12 +- .../common/extensions/IForgeBlock.java | 58 +++++- .../common/extensions/IForgeBlockState.java | 29 ++- .../event/ForgeEventFactory.java | 20 +- .../event/entity/player/UseHoeEvent.java | 5 +- .../event/world/BlockEvent.java | 174 ++++++++++++++---- .../debug/block/ToolInteractTest.java | 10 +- .../debug/item/CustomShieldTest.java | 2 +- 12 files changed, 268 insertions(+), 74 deletions(-) diff --git a/patches/minecraft/net/minecraft/world/item/AxeItem.java.patch b/patches/minecraft/net/minecraft/world/item/AxeItem.java.patch index 564913c63f..46ee28fd61 100644 --- a/patches/minecraft/net/minecraft/world/item/AxeItem.java.patch +++ b/patches/minecraft/net/minecraft/world/item/AxeItem.java.patch @@ -9,9 +9,9 @@ - Optional optional2 = Optional.ofNullable(HoneycombItem.f_150864_.get().get(blockstate.m_60734_())).map((p_150694_) -> { - return p_150694_.m_152465_(blockstate); - }); -+ Optional optional = Optional.ofNullable(blockstate.getToolModifiedState(level, blockpos, player, p_40529_.m_43722_(), net.minecraftforge.common.ToolActions.AXE_STRIP)); -+ Optional optional1 = Optional.ofNullable(blockstate.getToolModifiedState(level, blockpos, player, p_40529_.m_43722_(), net.minecraftforge.common.ToolActions.AXE_SCRAPE)); -+ Optional optional2 = Optional.ofNullable(blockstate.getToolModifiedState(level, blockpos, player, p_40529_.m_43722_(), net.minecraftforge.common.ToolActions.AXE_WAX_OFF)); ++ Optional optional = Optional.ofNullable(blockstate.getToolModifiedState(p_40529_, net.minecraftforge.common.ToolActions.AXE_STRIP, false)); ++ Optional optional1 = optional.isPresent() ? Optional.empty() : Optional.ofNullable(blockstate.getToolModifiedState(p_40529_, net.minecraftforge.common.ToolActions.AXE_SCRAPE, false)); ++ Optional optional2 = optional.isPresent() || optional1.isPresent() ? Optional.empty() : Optional.ofNullable(blockstate.getToolModifiedState(p_40529_, net.minecraftforge.common.ToolActions.AXE_WAX_OFF, false)); ItemStack itemstack = p_40529_.m_43722_(); Optional optional3 = Optional.empty(); if (optional.isPresent()) { diff --git a/patches/minecraft/net/minecraft/world/item/HoeItem.java.patch b/patches/minecraft/net/minecraft/world/item/HoeItem.java.patch index 2181e6edb4..b245809ecf 100644 --- a/patches/minecraft/net/minecraft/world/item/HoeItem.java.patch +++ b/patches/minecraft/net/minecraft/world/item/HoeItem.java.patch @@ -1,6 +1,19 @@ --- a/net/minecraft/world/item/HoeItem.java +++ b/net/minecraft/world/item/HoeItem.java -@@ -30,6 +_,8 @@ +@@ -21,6 +_,12 @@ + import net.minecraft.world.level.block.state.BlockState; + + public class HoeItem extends DiggerItem { ++ /** ++ * @deprecated Forge: This map is patched out of vanilla code. ++ * Listen to {@link net.minecraftforge.event.world.BlockEvent.BlockToolModificationEvent} ++ * or override {@link net.minecraftforge.common.extensions.IForgeBlock#getToolModifiedState(BlockState, UseOnContext, net.minecraftforge.common.ToolAction, boolean)}. ++ */ ++ @Deprecated + protected static final Map, Consumer>> f_41332_ = Maps.newHashMap(ImmutableMap.of(Blocks.f_50440_, Pair.of(HoeItem::m_150856_, m_150858_(Blocks.f_50093_.m_49966_())), Blocks.f_152481_, Pair.of(HoeItem::m_150856_, m_150858_(Blocks.f_50093_.m_49966_())), Blocks.f_50493_, Pair.of(HoeItem::m_150856_, m_150858_(Blocks.f_50093_.m_49966_())), Blocks.f_50546_, Pair.of(HoeItem::m_150856_, m_150858_(Blocks.f_50493_.m_49966_())), Blocks.f_152549_, Pair.of((p_150861_) -> { + return true; + }, m_150849_(Blocks.f_50493_.m_49966_(), Items.f_151017_)))); +@@ -30,9 +_,12 @@ } public InteractionResult m_6225_(UseOnContext p_41341_) { @@ -8,7 +21,12 @@ + if (hook != 0) return hook > 0 ? InteractionResult.SUCCESS : InteractionResult.FAIL; Level level = p_41341_.m_43725_(); BlockPos blockpos = p_41341_.m_8083_(); - Pair, Consumer> pair = f_41332_.get(level.m_8055_(blockpos).m_60734_()); +- Pair, Consumer> pair = f_41332_.get(level.m_8055_(blockpos).m_60734_()); ++ BlockState toolModifiedState = level.m_8055_(blockpos).getToolModifiedState(p_41341_, net.minecraftforge.common.ToolActions.HOE_TILL, false); ++ Pair, Consumer> pair = toolModifiedState == null ? null : Pair.of(ctx -> true, m_150858_(toolModifiedState)); + if (pair == null) { + return InteractionResult.PASS; + } else { @@ -72,5 +_,10 @@ public static boolean m_150856_(UseOnContext p_150857_) { diff --git a/patches/minecraft/net/minecraft/world/item/ShovelItem.java.patch b/patches/minecraft/net/minecraft/world/item/ShovelItem.java.patch index 1ce4aea8ef..8c8620a70c 100644 --- a/patches/minecraft/net/minecraft/world/item/ShovelItem.java.patch +++ b/patches/minecraft/net/minecraft/world/item/ShovelItem.java.patch @@ -5,7 +5,7 @@ } else { Player player = p_43119_.m_43723_(); - BlockState blockstate1 = f_43110_.get(blockstate.m_60734_()); -+ BlockState blockstate1 = blockstate.getToolModifiedState(level, blockpos, player, p_43119_.m_43722_(), net.minecraftforge.common.ToolActions.SHOVEL_FLATTEN); ++ BlockState blockstate1 = blockstate.getToolModifiedState(p_43119_, net.minecraftforge.common.ToolActions.SHOVEL_FLATTEN, false); BlockState blockstate2 = null; - if (blockstate1 != null && level.m_8055_(blockpos.m_7494_()).m_60795_()) { + if (blockstate1 != null && level.m_46859_(blockpos.m_7494_())) { diff --git a/src/main/java/net/minecraftforge/common/ToolAction.java b/src/main/java/net/minecraftforge/common/ToolAction.java index 068679b5d5..6586901677 100644 --- a/src/main/java/net/minecraftforge/common/ToolAction.java +++ b/src/main/java/net/minecraftforge/common/ToolAction.java @@ -11,7 +11,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @SuppressWarnings("ClassCanBeRecord") -public class ToolAction +public final class ToolAction { private static final Map actions = new ConcurrentHashMap<>(); diff --git a/src/main/java/net/minecraftforge/common/ToolActions.java b/src/main/java/net/minecraftforge/common/ToolActions.java index 899b0210f5..38e21c5c61 100644 --- a/src/main/java/net/minecraftforge/common/ToolActions.java +++ b/src/main/java/net/minecraftforge/common/ToolActions.java @@ -31,7 +31,7 @@ public class ToolActions public static final ToolAction SHOVEL_DIG = ToolAction.get("shovel_dig"); /** - * Exposed by shovels to allow querying tool behaviours + * Exposed by hoes to allow querying tool behaviours */ public static final ToolAction HOE_DIG = ToolAction.get("hoe_dig"); @@ -90,10 +90,10 @@ public class ToolActions */ public static final ToolAction SHEARS_DISARM = ToolAction.get("shears_disarm"); - ///** - // * Passed onto {@link IForgeBlock#getToolModifiedState} when a hoe wants to turn dirt into soil - // */ - // TODO: public static final ToolAction HOE_TILL = ToolAction.get("till"); + /** + * Passed onto {@link IForgeBlock#getToolModifiedState} when a hoe wants to turn dirt into soil + */ + public static final ToolAction HOE_TILL = ToolAction.get("till"); /** * A tool action corresponding to the 'block' action of shields. @@ -102,7 +102,7 @@ public class ToolActions // Default actions supported by each tool type public static final Set DEFAULT_AXE_ACTIONS = of(AXE_DIG, AXE_STRIP, AXE_SCRAPE, AXE_WAX_OFF); - public static final Set DEFAULT_HOE_ACTIONS = of(HOE_DIG /* TODO: , HOE_TILL */); + public static final Set DEFAULT_HOE_ACTIONS = of(HOE_DIG, HOE_TILL); public static final Set DEFAULT_SHOVEL_ACTIONS = of(SHOVEL_DIG, SHOVEL_FLATTEN); public static final Set DEFAULT_PICKAXE_ACTIONS = of(PICKAXE_DIG); public static final Set DEFAULT_SWORD_ACTIONS = of(SWORD_DIG, SWORD_SWEEP); diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java index 0dd95ac4b2..cc75d07eef 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java @@ -22,6 +22,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.FishingHook; import net.minecraft.world.entity.projectile.WitherSkull; import net.minecraft.world.item.*; +import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.block.*; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.pathfinder.BlockPathTypes; @@ -662,9 +663,48 @@ public interface IForgeBlock } /** - * Returns the state that this block should transform into when right clicked by a tool. - * For example: Used to determine if an axe can strip, a shovel can path, or a hoe can till. - * Return null if vanilla behavior should be disabled. + * Returns the state that this block should transform into when right-clicked by a tool. + * For example: Used to determine if {@link ToolActions#AXE_STRIP an axe can strip}, + * {@link ToolActions#SHOVEL_FLATTEN a shovel can path}, or {@link ToolActions#HOE_TILL a hoe can till}. + * Returns {@code null} if nothing should happen. + * + * @param state The current state + * @param context The use on context that the action was performed in + * @param toolAction The action being performed by the tool + * @param simulate If {@code true}, no actions that modify the world in any way should be performed. If {@code false}, the world may be modified. + * @return The resulting state after the action has been performed + */ + @Nullable + default BlockState getToolModifiedState(BlockState state, UseOnContext context, ToolAction toolAction, boolean simulate) + { + BlockState toolModifiedState = getToolModifiedState(state, context.getLevel(), context.getClickedPos(), + context.getPlayer(), context.getItemInHand(), toolAction); + + if (toolModifiedState == null && ToolActions.HOE_TILL == toolAction && context.getItemInHand().canPerformAction(ToolActions.HOE_TILL)) + { + // Logic copied from HoeItem#TILLABLES; needs to be kept in sync during updating + Block block = state.getBlock(); + if (block == Blocks.ROOTED_DIRT) + { + if (!simulate && !context.getLevel().isClientSide) + { + Block.popResourceFromFace(context.getLevel(), context.getClickedPos(), context.getClickedFace(), new ItemStack(Items.HANGING_ROOTS)); + } + return Blocks.DIRT.defaultBlockState(); + } else if ((block == Blocks.GRASS_BLOCK || block == Blocks.DIRT_PATH || block == Blocks.DIRT || block == Blocks.COARSE_DIRT) && + context.getLevel().getBlockState(context.getClickedPos().above()).isAir()) + { + return block == Blocks.COARSE_DIRT ? Blocks.DIRT.defaultBlockState() : Blocks.FARMLAND.defaultBlockState(); + } + } + + return toolModifiedState; + } + + /** + * Returns the state that this block should transform into when right-clicked by a tool. + * For example: Used to determine if {@link ToolActions#AXE_STRIP an axe can strip} or {@link ToolActions#SHOVEL_FLATTEN a shovel can path}. + * Returns {@code null} if nothing should happen. * * @param state The current state * @param level The level @@ -673,18 +713,20 @@ public interface IForgeBlock * @param stack The stack being used by the player * @param toolAction The action being performed by the tool * @return The resulting state after the action has been performed + * @deprecated Override and use {@link #getToolModifiedState(BlockState, UseOnContext, ToolAction, boolean)} instead */ @Nullable + // TODO 1.19: Remove this and move the default impl to the newer method in 1.19. Has to stay here to preserve behavior of overrides on this method. + @Deprecated(forRemoval = true, since = "1.18.2") default BlockState getToolModifiedState(BlockState state, Level level, BlockPos pos, Player player, ItemStack stack, ToolAction toolAction) { if (!stack.canPerformAction(toolAction)) return null; - if (ToolActions.AXE_STRIP.equals(toolAction)) return AxeItem.getAxeStrippingState(state); - else if(ToolActions.AXE_SCRAPE.equals(toolAction)) return WeatheringCopper.getPrevious(state).orElse(null); - else if(ToolActions.AXE_WAX_OFF.equals(toolAction)) return Optional.ofNullable(HoneycombItem.WAX_OFF_BY_BLOCK.get().get(state.getBlock())).map((p_150694_) -> { + if (ToolActions.AXE_STRIP == toolAction) return AxeItem.getAxeStrippingState(state); + else if(ToolActions.AXE_SCRAPE == toolAction) return WeatheringCopper.getPrevious(state).orElse(null); + else if(ToolActions.AXE_WAX_OFF == toolAction) return Optional.ofNullable(HoneycombItem.WAX_OFF_BY_BLOCK.get().get(state.getBlock())).map((p_150694_) -> { return p_150694_.withPropertiesOf(state); }).orElse(null); - //else if(ToolActions.HOE_TILL.equals(toolAction)) return HoeItem.getHoeTillingState(state); //TODO HoeItem bork - else if (ToolActions.SHOVEL_FLATTEN.equals(toolAction)) return ShovelItem.getShovelPathingState(state); + else if (ToolActions.SHOVEL_FLATTEN == toolAction) return ShovelItem.getShovelPathingState(state); return null; } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java index 30b6627a82..b1857a5fea 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java @@ -17,6 +17,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.FishingHook; +import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.pathfinder.BlockPathTypes; @@ -37,6 +38,7 @@ import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.ToolAction; +import net.minecraftforge.common.ToolActions; public interface IForgeBlockState { @@ -603,9 +605,27 @@ public interface IForgeBlockState } /** - * Returns the state that this block should transform into when right clicked by a tool. - * For example: Used to determine if an axe can strip, a shovel can path, or a hoe can till. - * Return null if vanilla behavior should be disabled. + * Returns the state that this block should transform into when right-clicked by a tool. + * For example: Used to determine if {@link ToolActions#AXE_STRIP an axe can strip}, + * {@link ToolActions#SHOVEL_FLATTEN a shovel can path}, or {@link ToolActions#HOE_TILL a hoe can till}. + * Returns {@code null} if nothing should happen. + * + * @param context The use on context that the action was performed in + * @param toolAction The action being performed by the tool + * @param simulate If {@code true}, no actions that modify the world in any way should be performed. If {@code false}, the world may be modified. + * @return The resulting state after the action has been performed + */ + @Nullable + default BlockState getToolModifiedState(UseOnContext context, ToolAction toolAction, boolean simulate) + { + BlockState eventState = net.minecraftforge.event.ForgeEventFactory.onToolUse(self(), context, toolAction, simulate); + return eventState != self() ? eventState : self().getBlock().getToolModifiedState(self(), context, toolAction, simulate); + } + + /** + * Returns the state that this block should transform into when right-clicked by a tool. + * For example: Used to determine if {@link ToolActions#AXE_STRIP an axe can strip} or {@link ToolActions#SHOVEL_FLATTEN a shovel can path}. + * Returns {@code null} if nothing should happen. * * @param level The level * @param pos The block position in level @@ -613,8 +633,11 @@ public interface IForgeBlockState * @param stack The stack being used by the player * @param toolAction The tool type to be considered when performing the action * @return The resulting state after the action has been performed + * @deprecated Use {@link #getToolModifiedState(UseOnContext, ToolAction, boolean)} instead */ @Nullable + // TODO 1.19: Remove + @Deprecated(forRemoval = true, since = "1.18.2") default BlockState getToolModifiedState(Level level, BlockPos pos, Player player, ItemStack stack, ToolAction toolAction) { BlockState eventState = net.minecraftforge.event.ForgeEventFactory.onToolUse(self(), level, pos, player, stack, toolAction); diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index d1a8672838..f1493a932a 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -125,6 +125,7 @@ import net.minecraftforge.event.entity.player.UseHoeEvent; import net.minecraftforge.event.furnace.FurnaceFuelBurnTimeEvent; import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.world.BlockEvent.BlockToolInteractEvent; +import net.minecraftforge.event.world.BlockEvent.BlockToolModificationEvent; import net.minecraftforge.event.world.BlockEvent.CreateFluidSourceEvent; import net.minecraftforge.event.world.BlockEvent.EntityMultiPlaceEvent; import net.minecraftforge.event.world.BlockEvent.EntityPlaceEvent; @@ -345,8 +346,8 @@ public class ForgeEventFactory return MinecraftForge.EVENT_BUS.post(event) ? "" : event.getMessage(); } - //TODO: 1.17 Remove - @Deprecated + //TODO 1.19: Remove + @Deprecated(forRemoval = true, since = "1.18.2") public static int onHoeUse(UseOnContext context) { UseHoeEvent event = new UseHoeEvent(context); @@ -360,6 +361,21 @@ public class ForgeEventFactory } @Nullable + public static BlockState onToolUse(BlockState originalState, UseOnContext context, ToolAction toolAction, boolean simulate) + { + // TODO 1.19: Remove ternary and just use BlockToolModificationEvent constructor with simulate parameter passed in + BlockToolModificationEvent event = simulate + ? new BlockToolModificationEvent(originalState, context, toolAction, true) + : new BlockToolInteractEvent(originalState, context, toolAction); + return MinecraftForge.EVENT_BUS.post(event) ? null : event.getFinalState(); + } + + /** + * @deprecated Use {@link #onToolUse(BlockState, UseOnContext, ToolAction, boolean)} instead. + */ + @Nullable + // TODO 1.19: Remove + @Deprecated(forRemoval = true, since = "1.18.2") public static BlockState onToolUse(BlockState originalState, Level level, BlockPos pos, Player player, ItemStack stack, ToolAction toolAction) { BlockToolInteractEvent event = new BlockToolInteractEvent(level, pos, originalState, player, stack, toolAction); diff --git a/src/main/java/net/minecraftforge/event/entity/player/UseHoeEvent.java b/src/main/java/net/minecraftforge/event/entity/player/UseHoeEvent.java index b57c70e2cc..205ab204d9 100644 --- a/src/main/java/net/minecraftforge/event/entity/player/UseHoeEvent.java +++ b/src/main/java/net/minecraftforge/event/entity/player/UseHoeEvent.java @@ -19,12 +19,11 @@ import javax.annotation.Nonnull; * and damage the hoe. * * setResult(ALLOW) is the same as the old setHandled(); - * - * TODO: 1.17 Remove */ @Cancelable @HasResult -@Deprecated +// TODO 1.19: Remove +@Deprecated(forRemoval = true, since = "1.18.2") public class UseHoeEvent extends PlayerEvent { private final UseOnContext context;; diff --git a/src/main/java/net/minecraftforge/event/world/BlockEvent.java b/src/main/java/net/minecraftforge/event/world/BlockEvent.java index d0c0347f0d..1331918273 100644 --- a/src/main/java/net/minecraftforge/event/world/BlockEvent.java +++ b/src/main/java/net/minecraftforge/event/world/BlockEvent.java @@ -8,6 +8,7 @@ package net.minecraftforge.event.world; import java.util.EnumSet; import java.util.List; +import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.portal.PortalShape; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.item.enchantment.EnchantmentHelper; @@ -22,6 +23,7 @@ import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.Level; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.ToolAction; +import net.minecraftforge.common.ToolActions; import net.minecraftforge.common.util.BlockSnapshot; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; @@ -415,65 +417,159 @@ public class BlockEvent extends Event } /** - * Fired when when this block is right clicked by a tool to change its state. - * For example: Used to determine if an axe can strip or a shovel can path. - * For hoes, see {@code net.minecraft.world.item.HoeItem#TILLABLES} and - * {@link net.minecraftforge.event.entity.player.UseHoeEvent}. - * + * Fired when a block is right-clicked by a tool to change its state. + * For example: Used to determine if {@link ToolActions#AXE_STRIP an axe can strip}, + * {@link ToolActions#SHOVEL_FLATTEN a shovel can path}, or {@link ToolActions#HOE_TILL a hoe can till}. + *

+ * This deprecated subclass event is only fired when {@link #isSimulated()} is false. + * To receive simulated events, use {@link BlockToolModificationEvent}. + *

* This event is {@link Cancelable}. If canceled, this will prevent the tool * from changing the block's state. + * + * @deprecated Use {@link BlockToolModificationEvent} and put world-modifying actions behind if (!event.isSimulated()). */ @Cancelable - public static class BlockToolInteractEvent extends BlockEvent + @Deprecated(forRemoval = true, since = "1.18.2") + public static class BlockToolInteractEvent extends BlockToolModificationEvent { - private final Player player; private final ItemStack stack; - private final ToolAction toolAction; - private BlockState state; + + public BlockToolInteractEvent(BlockState originalState, @Nonnull UseOnContext context, ToolAction toolAction) + { + super(originalState, context, toolAction, false); + this.player = context.getPlayer(); + this.stack = context.getItemInHand(); + } public BlockToolInteractEvent(LevelAccessor world, BlockPos pos, BlockState originalState, Player player, ItemStack stack, ToolAction toolAction) { - super(world, pos, originalState); + super(world, pos, originalState, toolAction); this.player = player; this.stack = stack; - this.state = originalState; - this.toolAction = toolAction; - } - - /**Gets the player using the tool.*/ - public Player getPlayer() - { - return player; - } - - /**Gets the tool being used.*/ - public ItemStack getHeldItemStack() - { - return stack; - } - - /**Gets the action being performed.*/ - public ToolAction getToolAction() - { - return toolAction; } /** - * Sets the transformed state after tool use. - * If not set, will return the original state. - * This will be bypassed if canceled returning null instead. - * */ - public void setFinalState(BlockState finalState) + * @return the player using the tool, never null + */ + @Nonnull + public Player getPlayer() + { + return this.player; + } + + public ItemStack getHeldItemStack() + { + return this.stack; + } + } + + /** + * Fired when a block is right-clicked by a tool to change its state. + * For example: Used to determine if {@link ToolActions#AXE_STRIP an axe can strip}, + * {@link ToolActions#SHOVEL_FLATTEN a shovel can path}, or {@link ToolActions#HOE_TILL a hoe can till}. + *

+ * Care must be taken to ensure world-modifying events are only performed if {@link #isSimulated()} returns {@code true}. + *

+ * This event is {@link Cancelable}. If canceled, this will prevent the tool + * from changing the block's state. + */ + public static class BlockToolModificationEvent extends BlockEvent + { + private final UseOnContext context; + private final ToolAction toolAction; + private final boolean simulate; + private BlockState state; + + public BlockToolModificationEvent(BlockState originalState, @Nonnull UseOnContext context, ToolAction toolAction, boolean simulate) + { + super(context.getLevel(), context.getClickedPos(), originalState); + this.context = context; + this.state = originalState; + this.toolAction = toolAction; + this.simulate = simulate; + } + + // TODO 1.19: Remove + BlockToolModificationEvent(LevelAccessor level, BlockPos pos, BlockState originalState, ToolAction toolAction) + { + super(level, pos, originalState); + this.context = null; + this.state = originalState; + this.toolAction = toolAction; + this.simulate = false; + } + + /** + * @return the player using the tool. + * May be null based on what was provided by {@link #getContext() the use on context}. + */ + @Nullable + public Player getPlayer() + { + return this.context.getPlayer(); + } + + /** + * @return the tool being used + */ + public ItemStack getHeldItemStack() + { + return this.context.getItemInHand(); + } + + /** + * @return the action being performed + */ + public ToolAction getToolAction() + { + return this.toolAction; + } + + /** + * Returns {@code true} if this event should not perform any actions that modify the world. + * If {@code false}, then world-modifying actions can be performed. + * + * @return {@code true} if this event should not perform any actions that modify the world. + * If {@code false}, then world-modifying actions can be performed. + */ + public boolean isSimulated() + { + return this.simulate; + } + + /** + * Returns the nullable use on context that this event was performed in. + * Starting in 1.19, this will never be null. + * + * @return the nullable use on context that this event was performed in + */ + // TODO 1.19: Remove nullable annotation and add non-null annotation + @Nullable + public UseOnContext getContext() + { + return context; + } + + /** + * Sets the state to transform the block into after tool use. + * + * @param finalState the state to transform the block into after tool use + * @see #getFinalState() + */ + public void setFinalState(@Nullable BlockState finalState) { this.state = finalState; } /** - * Gets the transformed state after tool use. - * If setFinalState not called, will return the original state. - * This will be bypassed if canceled returning null instead. - * */ + * Returns the state to transform the block into after tool use. + * If {@link #setFinalState(BlockState)} is not called, this will return the original state. + * If {@link #isCanceled()} is {@code true}, this value will be ignored and the tool action will be canceled. + * + * @return the state to transform the block into after tool use + */ public BlockState getFinalState() { return state; diff --git a/src/test/java/net/minecraftforge/debug/block/ToolInteractTest.java b/src/test/java/net/minecraftforge/debug/block/ToolInteractTest.java index 67efbffc4c..5beb38d5cb 100644 --- a/src/test/java/net/minecraftforge/debug/block/ToolInteractTest.java +++ b/src/test/java/net/minecraftforge/debug/block/ToolInteractTest.java @@ -9,7 +9,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.world.BlockEvent.BlockToolInteractEvent; +import net.minecraftforge.event.world.BlockEvent.BlockToolModificationEvent; import net.minecraftforge.fml.common.Mod; @Mod("tool_interact_test") @@ -17,16 +17,16 @@ public class ToolInteractTest { private static final Logger LOGGER = LogManager.getLogger(); - + public ToolInteractTest() { MinecraftForge.EVENT_BUS.addListener(this::onToolInteraction); } - - private void onToolInteraction(final BlockToolInteractEvent event) + + private void onToolInteraction(final BlockToolModificationEvent event) { //Test 1: No Changes, just test if event is called. State and Final State should be the same - LOGGER.info("BlockState {} is modified to {} at position {} by {} with {}", event.getState(), event.getFinalState(), event.getPos(), event.getPlayer(), event.getHeldItemStack()); + LOGGER.info("BlockState {} is modified to {} at position {} by {} with {} simulated={}", event.getState(), event.getFinalState(), event.getPos(), event.getPlayer(), event.getHeldItemStack(), event.isSimulated()); //Test 2: Canceling, nothing in game should change /*event.setCanceled(true); diff --git a/src/test/java/net/minecraftforge/debug/item/CustomShieldTest.java b/src/test/java/net/minecraftforge/debug/item/CustomShieldTest.java index b45ff354c4..e182d7953b 100644 --- a/src/test/java/net/minecraftforge/debug/item/CustomShieldTest.java +++ b/src/test/java/net/minecraftforge/debug/item/CustomShieldTest.java @@ -64,7 +64,7 @@ public class CustomShieldTest @Override public boolean canPerformAction(ItemStack stack, ToolAction toolAction) { - return toolAction.equals(ToolActions.SHIELD_BLOCK); + return toolAction == ToolActions.SHIELD_BLOCK; } } }