From 5e322323dd191b03fd4da4f40622f8bb32d2c3d1 Mon Sep 17 00:00:00 2001 From: alpha Date: Thu, 25 Jul 2024 19:56:25 -0500 Subject: [PATCH] Partial implementation for BlockToolModificationEvent --- modules/base/build.gradle | 1 + .../porting_lib/event/common/BlockEvents.java | 111 ++++++++++++++++++ .../mixin/common/AxeItemMixin.java | 32 +++++ .../porting_lib/util/PortingHooks.java | 15 ++- .../resources/porting_lib_base.mixins.json | 1 + 5 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/AxeItemMixin.java diff --git a/modules/base/build.gradle b/modules/base/build.gradle index 4686053e2..4233226d9 100644 --- a/modules/base/build.gradle +++ b/modules/base/build.gradle @@ -1,5 +1,6 @@ portingLib.addModuleDependencies([ "lazy_registration", + "tool_actions", "extensions", "gui_utils", "transfer", diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/BlockEvents.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/BlockEvents.java index e7d73fba1..6ad292d9f 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/BlockEvents.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/BlockEvents.java @@ -2,6 +2,8 @@ import io.github.fabricators_of_create.porting_lib.block.CustomExpBlock; import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.tool.ToolAction; +import io.github.fabricators_of_create.porting_lib.tool.ToolActions; import io.github.fabricators_of_create.porting_lib.util.PortingHooks; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; @@ -10,6 +12,7 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.item.enchantment.EnchantmentHelper; @@ -18,6 +21,7 @@ import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.EnumSet; @@ -28,11 +32,17 @@ public abstract class BlockEvents extends BaseEvent { for (BlockBreak e : callbacks) e.onBlockBreak(event); }); + public static final Event NEIGHBORS_NOTIFY = EventFactory.createArrayBacked(NotifyNeighbors.class, callbacks -> event -> { for (NotifyNeighbors e : callbacks) e.onNotifyNeighbors(event); }); + public static final Event BLOCK_MODIFICATION = EventFactory.createArrayBacked(BlockModification.class, callbacks -> event -> { + for (BlockModification e : callbacks) + e.onBlockModification(event); + }); + @FunctionalInterface public interface BlockBreak { void onBlockBreak(BreakEvent event); @@ -43,6 +53,11 @@ public interface NotifyNeighbors { void onNotifyNeighbors(NeighborNotifyEvent event); } + @FunctionalInterface + public interface BlockModification { + void onBlockModification(BlockToolModificationEvent event); + } + /** * Invoked before a block is placed from the head of {@link BlockItem#useOn(UseOnContext)}. Called on both client and server. * Return null to fall back to further processing. Any non-null value will result in placement being cancelled. @@ -203,4 +218,100 @@ public void sendEvent() { NEIGHBORS_NOTIFY.invoker().onNotifyNeighbors(this); } } + + /** + * Note for this event isn't fully implemented on 1.20.1 + * 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 level-modifying events are only performed if {@link #isSimulated()} returns {@code false}. + *

+ * This event is cancelable. If canceled, this will prevent the tool + * from changing the block's state. + */ + public static class BlockToolModificationEvent extends BlockEvents { + private final UseOnContext context; + private final ToolAction toolAction; + private final boolean simulate; + private BlockState state; + + public BlockToolModificationEvent(BlockState originalState, @NotNull UseOnContext context, ToolAction toolAction, boolean simulate) { + super(context.getLevel(), context.getClickedPos(), originalState); + this.context = context; + this.state = originalState; + this.toolAction = toolAction; + this.simulate = simulate; + } + + /** + * @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 level. + * If {@code false}, then level-modifying actions can be performed. + * + * @return {@code true} if this event should not perform any actions that modify the level. + * If {@code false}, then level-modifying actions can be performed. + */ + public boolean isSimulated() { + return this.simulate; + } + + /** + * Returns the nonnull use on context that this event was performed in. + * + * @return the nonnull use on context that this event was performed in + */ + @NotNull + 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; + } + + /** + * 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; + } + + @Override + public void sendEvent() { + BLOCK_MODIFICATION.invoker().onBlockModification(this); + } + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/AxeItemMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/AxeItemMixin.java new file mode 100644 index 000000000..ba74be9fa --- /dev/null +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/AxeItemMixin.java @@ -0,0 +1,32 @@ +package io.github.fabricators_of_create.porting_lib.mixin.common; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +import io.github.fabricators_of_create.porting_lib.tool.ToolActions; +import io.github.fabricators_of_create.porting_lib.util.PortingHooks; +import net.minecraft.world.item.AxeItem; + +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.block.state.BlockState; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.Optional; + +// This really should be in the tool actions modules fix this TODO: fix this on 1.21 +@Mixin(AxeItem.class) +public class AxeItemMixin { + @WrapOperation(method = "useOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/AxeItem;getStripped(Lnet/minecraft/world/level/block/state/BlockState;)Ljava/util/Optional;")) + private Optional onStripToolAction(AxeItem instance, BlockState blockState, Operation> original, UseOnContext context) { + BlockState eventState = PortingHooks.onToolUse(blockState, context, ToolActions.AXE_STRIP, false); + return eventState != blockState ? Optional.ofNullable(eventState) : original.call(instance, blockState); + } + + @WrapOperation(method = "useOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/WeatheringCopper;getPrevious(Lnet/minecraft/world/level/block/state/BlockState;)Ljava/util/Optional;")) + private Optional onScrapeToolAction(BlockState blockState, Operation> original, UseOnContext context) { + BlockState eventState = PortingHooks.onToolUse(blockState, context, ToolActions.AXE_SCRAPE, false); + return eventState != blockState ? Optional.ofNullable(eventState) : original.call(blockState); + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PortingHooks.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PortingHooks.java index 45b018336..69c718602 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PortingHooks.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PortingHooks.java @@ -1,13 +1,14 @@ package io.github.fabricators_of_create.porting_lib.util; -import javax.annotation.Nullable; - import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import io.github.fabricators_of_create.porting_lib.tool.ToolAction; import net.fabricmc.api.EnvType; import net.minecraft.server.TickTask; import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.context.UseOnContext; + import org.jetbrains.annotations.NotNull; import io.github.fabricators_of_create.porting_lib.event.common.BlockEvents; @@ -34,6 +35,8 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.pattern.BlockInWorld; +import org.jetbrains.annotations.Nullable; + @SuppressWarnings({"removal", "UnstableApiUsage"}) public class PortingHooks { public static boolean isCorrectToolForDrops(@NotNull BlockState state, @NotNull Player player) { @@ -92,7 +95,7 @@ public static int onBlockBreakEvent(Level world, GameType gameType, ServerPlayer public static void init() { EntityEvents.ON_JOIN_WORLD.register((entity, world, loadedFromDisk) -> { if (entity.getClass().equals(ItemEntity.class)) { - ItemStack stack = ((ItemEntity)entity).getItem(); + ItemStack stack = ((ItemEntity) entity).getItem(); Item item = stack.getItem(); if (item.hasCustomEntity(stack)) { Entity newEntity = item.createEntity(world, entity, stack); @@ -127,4 +130,10 @@ public static int onGrindstoneChange(@NotNull ItemStack top, @NotNull ItemStack outputSlot.setItem(0, e.getOutput()); return e.getXp(); } + + @Nullable + public static BlockState onToolUse(BlockState originalState, UseOnContext context, ToolAction toolAction, boolean simulate) { + BlockEvents.BlockToolModificationEvent event = new BlockEvents.BlockToolModificationEvent(originalState, context, toolAction, simulate); + return event.post() ? null : event.getFinalState(); + } } diff --git a/modules/base/src/main/resources/porting_lib_base.mixins.json b/modules/base/src/main/resources/porting_lib_base.mixins.json index cacff8000..6a73a7bd5 100644 --- a/modules/base/src/main/resources/porting_lib_base.mixins.json +++ b/modules/base/src/main/resources/porting_lib_base.mixins.json @@ -10,6 +10,7 @@ "client.CreateWorldScreenMixin", "common.AbstractMinecartMixin", "common.AnvilMenuMixin", + "common.AxeItemMixin", "common.BambooStalkBlockMixin", "common.BaseRailBlockMixin", "common.BeaconBlockEntityMixin",