Add use context and simulate flag to getToolModifiedState, enabled HOE_TILL action. (#8557)

This commit is contained in:
SizableShrimp authored and GitHub committed 2022-04-12 09:43:20 -07:00
1 parent 94ce098056
commit 7d79f0d581
12 files changed
+268 -74

No files matched your search

@@ -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<String, ToolAction> actions = new ConcurrentHashMap<>();
@@ -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<ToolAction> DEFAULT_AXE_ACTIONS = of(AXE_DIG, AXE_STRIP, AXE_SCRAPE, AXE_WAX_OFF);
public static final Set<ToolAction> DEFAULT_HOE_ACTIONS = of(HOE_DIG /* TODO: , HOE_TILL */);
public static final Set<ToolAction> DEFAULT_HOE_ACTIONS = of(HOE_DIG, HOE_TILL);
public static final Set<ToolAction> DEFAULT_SHOVEL_ACTIONS = of(SHOVEL_DIG, SHOVEL_FLATTEN);
public static final Set<ToolAction> DEFAULT_PICKAXE_ACTIONS = of(PICKAXE_DIG);
public static final Set<ToolAction> DEFAULT_SWORD_ACTIONS = of(SWORD_DIG, SWORD_SWEEP);
@@ -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;
}
@@ -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);
@@ -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);
@@ -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;;
@@ -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}.
* <p>
* This deprecated subclass event is <i>only</i> fired when {@link #isSimulated()} is false.
* To receive simulated events, use {@link BlockToolModificationEvent}.
* <p>
* 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 <code>if (!event.isSimulated())</code>.
*/
@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}.
* <p>
* Care must be taken to ensure world-modifying events are only performed if {@link #isSimulated()} returns {@code true}.
* <p>
* 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;