From e7a39bd77298611f8200b327cfc1f07bbcaadbf1 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 21 Apr 2024 15:29:53 -0700 Subject: [PATCH 1/4] !feat: Refactor Interactions to use Transactions --- SpongeAPI | 2 +- .../bridge/world/TrackedWorldBridge.java | 13 +++ .../event/SpongeCommonEventFactory.java | 4 +- .../context/transaction/EffectTransactor.java | 10 +- .../context/transaction/GameTransaction.java | 31 +++--- .../ResultingTransactionBySideEffect.java | 6 +- .../context/transaction/TransactionSink.java | 38 ++++--- .../TransactionalCaptureSupplier.java | 5 +- .../effect/AddBlockLootDropsEffect.java | 12 ++- .../transaction/effect/BlockAddedEffect.java | 12 ++- .../transaction/effect/BlockChangeArgs.java | 36 +++++++ .../BroadcastInventoryChangesEffect.java | 12 +-- .../CheckBlockPostPlacementIsSameEffect.java | 13 +-- .../effect/ChunkChangeCompleteEffect.java | 12 +-- .../transaction/effect/EffectResult.java | 19 ++-- .../effect/EntityPerformingDropsEffect.java | 10 +- .../effect/ExplodeBlockEffect.java | 16 ++- .../transaction/effect/InteractionArgs.java | 42 ++++++++ .../effect/InteractionItemEffect.java | 58 ++++++++++ .../InteractionUseItemOnBlockEffect.java | 59 ++++++++++ .../transaction/effect/InventoryEffect.java | 10 +- .../effect/NotifyClientEffect.java | 11 +- .../effect/NotifyNeighborSideEffect.java | 12 ++- .../effect/OldBlockOnReplaceEffect.java | 13 +-- .../PerformBlockDropsFromDestruction.java | 10 +- .../effect/PlayerContainerRefreshEffect.java | 52 +++++++++ .../transaction/effect/PrepareBlockDrops.java | 10 +- .../effect/ProcessingSideEffect.java | 13 +-- .../RemoveTileEntityFromChunkEffect.java | 12 +-- ...SetAndRegisterBlockEntityToLevelChunk.java | 12 +-- .../effect/SetBlockToChunkSectionEffect.java | 12 +-- .../effect/SpawnDestructBlocksEffect.java | 12 +-- .../effect/UpdateChunkLightManagerEffect.java | 11 +- .../effect/UpdateConnectingBlocksEffect.java | 13 ++- .../effect/UpdateHeightMapEffect.java | 11 +- .../effect/UpdateLightSideEffect.java | 13 +-- ...reateNewTileEntityPostPlacementEffect.java | 10 +- .../effect/UpdateWorldRendererEffect.java | 11 +- .../transaction/effect/UseItemArgs.java | 41 +++++++ .../transaction/effect/UseItemEffect.java | 64 +++++++++++ .../WorldBlockChangeCompleteEffect.java | 10 +- .../effect/WorldDestroyBlockLevelEffect.java | 10 +- .../inventory/InteractItemTransaction.java | 101 ++++++++++++++++++ .../inventory/InventoryBasedTransaction.java | 5 + .../transaction/pipeline/ChunkPipeline.java | 8 +- .../pipeline/TileEntityPipeline.java | 21 ++-- .../pipeline/UseBlockPipeline.java | 101 ++++++++++++++++++ .../pipeline/UseItemOnBlockPipeline.java | 100 +++++++++++++++++ .../transaction/pipeline/UseItemPipeline.java | 100 +++++++++++++++++ .../transaction/pipeline/WorldPipeline.java | 20 ++-- .../transaction/type/TransactionTypes.java | 3 +- .../level/ServerLevelMixin_Tracker.java | 85 ++++++++++++++- .../ServerPlayerGameModeMixin_Tracker.java | 101 ++++++++---------- .../VolumeTransformationTest.java | 3 +- 54 files changed, 1153 insertions(+), 278 deletions(-) create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockChangeArgs.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java diff --git a/SpongeAPI b/SpongeAPI index 05573747a54..1645168a747 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 05573747a54dc967d4592e1244e6bde88651afe4 +Subproject commit 1645168a747b4316aa298331a1d35965301ca79f diff --git a/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java b/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java index 740a8eed68c..c5c48c5c380 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java @@ -26,11 +26,16 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.phys.BlockHitResult; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.world.BlockChangeFlag; @@ -39,6 +44,9 @@ import org.spongepowered.common.bridge.world.level.LevelBridge; import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.WorldPipeline; import java.util.Optional; @@ -105,4 +113,9 @@ public interface TrackedWorldBridge { */ SpongeBlockSnapshot bridge$createSnapshotWithEntity(BlockState state, BlockPos pos, BlockChangeFlag updateFlag, @Nullable BlockEntity tileEntity); + UseItemOnBlockPipeline bridge$startInteractionUseOnChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack); + + UseBlockPipeline bridge$startInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack); + + UseItemPipeline bridge$startItemInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative); } diff --git a/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java b/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java index 6ec6a447ce9..5a769dface4 100644 --- a/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java +++ b/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java @@ -339,10 +339,10 @@ public static InteractBlockEvent.Primary callInteractBlockEventPrimary(final Ser } } - public static InteractBlockEvent.Secondary callInteractBlockEventSecondary(final net.minecraft.world.entity.player.Player player, final ItemStack heldItem, final Vector3d hitVec, final BlockSnapshot targetBlock, final Direction targetSide, final InteractionHand hand) { + public static InteractBlockEvent.Secondary.Pre callInteractBlockEventSecondary(final net.minecraft.world.entity.player.Player player, final ItemStack heldItem, final Vector3d hitVec, final BlockSnapshot targetBlock, final Direction targetSide, final InteractionHand hand) { try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { SpongeCommonEventFactory.applyCommonInteractContext(player, heldItem, hand, targetBlock, null, frame); - final InteractBlockEvent.Secondary event = SpongeEventFactory.createInteractBlockEventSecondary(frame.currentCause(), + final InteractBlockEvent.Secondary.Pre event = SpongeEventFactory.createInteractBlockEventSecondaryPre(frame.currentCause(), Tristate.UNDEFINED, Tristate.UNDEFINED, Tristate.UNDEFINED, Tristate.UNDEFINED, targetBlock, hitVec, targetSide); SpongeCommon.post(event); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EffectTransactor.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EffectTransactor.java index cabf97ef8ca..b1e025c7e73 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EffectTransactor.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EffectTransactor.java @@ -30,13 +30,13 @@ import java.util.Deque; public class EffectTransactor implements AutoCloseable { - final @Nullable ResultingTransactionBySideEffect previousEffect; + final @Nullable ResultingTransactionBySideEffect previousEffect; public final @Nullable GameTransaction<@NonNull ?> parent; private final TransactionalCaptureSupplier supplier; - private final ResultingTransactionBySideEffect effect; + private final ResultingTransactionBySideEffect effect; - EffectTransactor(final ResultingTransactionBySideEffect effect, final @Nullable GameTransaction<@NonNull ?> parent, - final @Nullable ResultingTransactionBySideEffect previousEffect, final TransactionalCaptureSupplier transactor) { + EffectTransactor(final ResultingTransactionBySideEffect effect, final @Nullable GameTransaction<@NonNull ?> parent, + final @Nullable ResultingTransactionBySideEffect previousEffect, final TransactionalCaptureSupplier transactor) { /* | ChangeBlock(1) <- head will be RemoveTileEntity(1), tail is still RemoveTileentity(1) | |- RemoveTileEntity <- Head will be ChangeBlock(2) tail is still ChangeBlock(2) @@ -55,7 +55,7 @@ public void close() { && this.parent.sideEffects != null && this.parent.getEffects().peekLast() == this.effect ) { - final Deque effects = this.parent.getEffects(); + final Deque> effects = this.parent.getEffects(); effects.removeLast(); if (effects.isEmpty()) { this.parent.sideEffects = null; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java index cb50e5af272..391443f3f19 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java @@ -54,7 +54,7 @@ public abstract class GameTransaction implements protected boolean cancelled = false; // Children Definitions - @Nullable LinkedList sideEffects; + @Nullable LinkedList> sideEffects; // LinkedList node definitions @Nullable GameTransaction<@NonNull ?> previous; @@ -75,14 +75,14 @@ public final TransactionType getTransactionType() { return this.transactionType; } - final Deque getEffects() { + final Deque> getEffects() { if (this.sideEffects == null) { this.sideEffects = new LinkedList<>(); } return this.sideEffects; } - public final void addLast(final ResultingTransactionBySideEffect effect) { + public final void addLast(final ResultingTransactionBySideEffect effect) { if (this.sideEffects == null) { this.sideEffects = new LinkedList<>(); } @@ -97,7 +97,7 @@ public final boolean hasAnyPrimaryChildrenTransactions() { if (this.sideEffects == null) { return false; } - for (final ResultingTransactionBySideEffect sideEffect : this.sideEffects) { + for (final ResultingTransactionBySideEffect sideEffect : this.sideEffects) { @Nullable GameTransaction<@NonNull ?> transaction = sideEffect.head; while (transaction != null) { if (transaction.transactionType.isPrimary() || transaction.hasChildTransactions()) { @@ -131,10 +131,17 @@ public abstract Optional generateEvent( public final void markCancelled() { this.cancelled = true; this.childIterator().forEachRemaining(GameTransaction::markCancelled); + if (this.next != null && this.next.hasUnknownChainRequiringCancellation()) { + this.next.markCancelled(); + } } public abstract boolean markCancelledTransactions(E event, ImmutableList> transactions); + protected boolean hasUnknownChainRequiringCancellation() { + return false; + } + public void postProcessEvent(final PhaseContext<@NonNull ?> context, final E event) { } @@ -183,16 +190,16 @@ protected void captureState() { } private static class ChildIterator implements Iterator> { - private final Iterator effectIterator; + private final Iterator> effectIterator; private @Nullable GameTransaction<@NonNull ?> cachedNext; private @MonotonicNonNull GameTransaction<@NonNull ?> pointer; private boolean hasNoRemainingElements = false; - ChildIterator(final Iterator iterator) { + ChildIterator(final Iterator> iterator) { // We're going to search the iterator's effects until we find the first at least this.effectIterator = iterator; while (this.effectIterator.hasNext()) { - final ResultingTransactionBySideEffect next = this.effectIterator.next(); + final ResultingTransactionBySideEffect next = this.effectIterator.next(); if (next.head != null) { this.cachedNext = next.head; this.pointer = next.head; @@ -219,7 +226,7 @@ public boolean hasNext() { // start search for the next, sadly because effects don't make a clean chain, // there can be many effects with no transactions recorded while (this.effectIterator.hasNext()) { - final ResultingTransactionBySideEffect next = this.effectIterator.next(); + final ResultingTransactionBySideEffect next = this.effectIterator.next(); if (next.head != null) { this.cachedNext = next.head; return true; @@ -250,16 +257,16 @@ public boolean hasNext() { private static class ReverseChildIterator implements Iterator> { - private final Iterator effectIterator; + private final Iterator> effectIterator; private @Nullable GameTransaction<@NonNull ?> cachedPrevious; private @MonotonicNonNull GameTransaction<@NonNull ?> pointer; private boolean hasNoRemainingElements = false; - ReverseChildIterator(final Iterator iterator) { + ReverseChildIterator(final Iterator> iterator) { // We're going to search the iterator's effects until we find the first at least this.effectIterator = iterator; while (this.effectIterator.hasNext()) { - final ResultingTransactionBySideEffect next = this.effectIterator.next(); + final ResultingTransactionBySideEffect next = this.effectIterator.next(); if (next.tail != null) { this.pointer = next.tail; this.cachedPrevious = next.tail; @@ -287,7 +294,7 @@ public boolean hasNext() { // start search for the next, sadly because effects don't make a clean chain, // there can be many effects with no transactions recorded while (this.effectIterator.hasNext()) { - final ResultingTransactionBySideEffect next = this.effectIterator.next(); + final ResultingTransactionBySideEffect next = this.effectIterator.next(); if (next.tail != null) { this.cachedPrevious = next.tail; return true; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/ResultingTransactionBySideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/ResultingTransactionBySideEffect.java index c224628dbbc..3cae058b582 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/ResultingTransactionBySideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/ResultingTransactionBySideEffect.java @@ -33,12 +33,12 @@ import java.util.Iterator; import java.util.Optional; -public class ResultingTransactionBySideEffect { - public final ProcessingSideEffect effect; +public class ResultingTransactionBySideEffect { + public final ProcessingSideEffect effect; @Nullable GameTransaction<@NonNull ?> head; @Nullable GameTransaction<@NonNull ?> tail; - public ResultingTransactionBySideEffect(final ProcessingSideEffect effect) { + public ResultingTransactionBySideEffect(final ProcessingSideEffect effect) { this.effect = effect; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java index 0e62dddece7..73655b3996b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java @@ -27,6 +27,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -44,6 +45,7 @@ import net.minecraft.world.ticks.ScheduledTick; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.event.cause.entity.SpawnType; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStackSnapshot; @@ -51,6 +53,7 @@ import org.spongepowered.api.item.inventory.crafting.CraftingInventory; import org.spongepowered.api.item.inventory.transaction.SlotTransaction; import org.spongepowered.api.scheduler.ScheduledUpdate; +import org.spongepowered.api.util.Direction; import org.spongepowered.api.world.BlockChangeFlag; import org.spongepowered.api.world.BlockChangeFlags; import org.spongepowered.common.SpongeCommon; @@ -73,6 +76,7 @@ import org.spongepowered.common.event.tracking.context.transaction.effect.EntityPerformingDropsEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.InventoryEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.PrepareBlockDrops; +import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.event.tracking.context.transaction.inventory.ClickCreativeMenuTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.ClickMenuTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.CloseMenuTransaction; @@ -81,6 +85,7 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.CraftingTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.DropFromPlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.ExplicitInventoryOmittedTransaction; +import org.spongepowered.common.event.tracking.context.transaction.inventory.InteractItemTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.InventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.OpenMenuTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlaceRecipeTransaction; @@ -98,6 +103,7 @@ import org.spongepowered.common.world.BlockChange; import org.spongepowered.common.world.SpongeBlockChangeFlag; import org.spongepowered.common.world.volume.VolumeStreamUtils; +import org.spongepowered.math.vector.Vector3d; import java.lang.ref.WeakReference; import java.util.Objects; @@ -122,7 +128,7 @@ interface TransactionSink { @Deprecated void logTransaction(StatefulTransaction transaction); - EffectTransactor pushEffect(final ResultingTransactionBySideEffect effect); + EffectTransactor pushEffect(final ResultingTransactionBySideEffect effect); default ChangeBlock logBlockChange(final SpongeBlockSnapshot originalBlockSnapshot, final BlockState newState, final BlockChangeFlag flags @@ -175,7 +181,7 @@ default EffectTransactor logBlockDrops( original.blockChange = BlockChange.MODIFY; final PrepareBlockDropsTransaction transaction = new PrepareBlockDropsTransaction(pos, state, original); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(PrepareBlockDrops.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(PrepareBlockDrops.getInstance())); } @SuppressWarnings({"ConstantConditions", "unchecked"}) @@ -260,7 +266,7 @@ default boolean logTileRemoval(final @Nullable BlockEntity tileentity, final Sup final EntityPerformingDropsTransaction transaction = new EntityPerformingDropsTransaction(entity); this.logTransaction(transaction); if (transaction.recorded()) { - return this.pushEffect(new ResultingTransactionBySideEffect(EntityPerformingDropsEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(EntityPerformingDropsEffect.getInstance())); } return null; } @@ -336,44 +342,44 @@ default EffectTransactor logClickContainer( final ClickMenuTransaction transaction = new ClickMenuTransaction( player, menu, slotNum, buttonNum, clickType, slot, ItemStackUtil.snapshotOf(player.containerMenu.getCarried())); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logPlayerInventoryChangeWithEffect(final Player player, final PlayerInventoryTransaction.EventCreator eventCreator) { final PlayerInventoryTransaction transaction = new PlayerInventoryTransaction(player, eventCreator); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logCreativeClickContainer(final int slotNum, final ItemStackSnapshot creativeStack, final Player player) { final ClickCreativeMenuTransaction transaction = new ClickCreativeMenuTransaction(player, slotNum, creativeStack); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logDropFromPlayerInventory(final ServerPlayer player, final boolean dropAll) { final DropFromPlayerInventoryTransaction transaction = new DropFromPlayerInventoryTransaction(player, dropAll); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logOpenInventory(final Player player) { final OpenMenuTransaction transaction = new OpenMenuTransaction(player); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logCloseInventory(final Player player, final boolean clientSource) { final CloseMenuTransaction transaction = new CloseMenuTransaction(player, clientSource); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logPlaceRecipe(final boolean shift, final RecipeHolder recipe, final ServerPlayer player, final CraftingInventory craftInv) { final PlaceRecipeTransaction transaction = new PlaceRecipeTransaction(player, shift, recipe, craftInv); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default void logSelectTrade(final ServerPlayer player, final int item) { @@ -405,12 +411,20 @@ default void logCrafting(final Player player, @Nullable final ItemStack craftedS default EffectTransactor logIgnoredInventory(AbstractContainerMenu containerMenu) { final ExplicitInventoryOmittedTransaction transaction = new ExplicitInventoryOmittedTransaction(containerMenu); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } default EffectTransactor logInventoryTransaction(final AbstractContainerMenu containerMenu) { final InventoryTransaction transaction = new InventoryTransaction((Inventory) containerMenu); this.logTransaction(transaction); - return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InventoryEffect.getInstance())); } + + default void logSecondaryInteractionTransaction( + final ServerPlayer playerIn, final ItemStack stackIn, final Vector3d hitVec, + final BlockSnapshot snapshot, final Direction direction, final InteractionHand handIn) { + final InteractItemTransaction transaction = new InteractItemTransaction(playerIn, stackIn, hitVec, snapshot, direction, handIn); + this.logTransaction(transaction); + } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java index 2eaea7e33b9..36edd7e27c6 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java @@ -38,6 +38,7 @@ import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.ICaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.effect.PrepareBlockDrops; +import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.event.tracking.context.transaction.type.TransactionType; import java.util.Collections; @@ -94,9 +95,9 @@ public boolean isEmpty() { */ @Override - public EffectTransactor pushEffect(final ResultingTransactionBySideEffect effect) { + public EffectTransactor pushEffect(final ResultingTransactionBySideEffect effect) { final GameTransaction<@NonNull ?> parentTransaction = Optional.ofNullable(this.effect) - .map(child -> (GameTransaction) child.tail) + .map(child -> child.tail) .orElse(Objects.requireNonNull(this.tail, "Somehow pushing a new effect without an owning Transaction")); final EffectTransactor effectTransactor = new EffectTransactor(effect, parentTransaction, this.effect, this); this.effect = effect; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/AddBlockLootDropsEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/AddBlockLootDropsEffect.java index 05d963c3f60..5b431acffe9 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/AddBlockLootDropsEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/AddBlockLootDropsEffect.java @@ -40,7 +40,7 @@ import org.spongepowered.common.util.VecHelper; import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class AddBlockLootDropsEffect implements ProcessingSideEffect { +public final class AddBlockLootDropsEffect implements ProcessingSideEffect { private static final class Holder { static final AddBlockLootDropsEffect INSTANCE = new AddBlockLootDropsEffect(); @@ -53,10 +53,12 @@ public static AddBlockLootDropsEffect getInstance() { AddBlockLootDropsEffect() {} @Override - public EffectResult processSideEffect( - final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final BlockState newState = args.newState(); + final SpongeBlockChangeFlag flag = args.flag(); + final int limit = args.limit(); final PhaseContext<@NonNull ?> phaseContext = PhaseTracker.getInstance().getPhaseContext(); final ServerLevel world = pipeline.getServerWorld(); @@ -70,6 +72,6 @@ public EffectResult processSideEffect( phaseContext.populateLootContext(lootBuilder); - return new EffectResult(newState, oldState.state().getDrops(lootBuilder), false); + return new EffectResult<>(newState, oldState.state().getDrops(lootBuilder), false); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockAddedEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockAddedEffect.java index 50b2977f8b2..9c7daa20f57 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockAddedEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockAddedEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class BlockAddedEffect implements ProcessingSideEffect { +public final class BlockAddedEffect implements ProcessingSideEffect { private static final class Holder { static final BlockAddedEffect INSTANCE = new BlockAddedEffect(); @@ -42,9 +42,11 @@ public static BlockAddedEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var flag = args.flag(); + final var newState = args.newState(); // Vanilla will check if this is the server // if (!this.level.isClientSide) { // var2.onPlace(this.level, var1, var11, var3); @@ -55,6 +57,6 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli if (flag.performBlockPhysics()) { newState.onPlace(pipeline.getServerWorld(), oldState.pos(), oldState.state(), flag.movingBlocks()); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockChangeArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockChangeArgs.java new file mode 100644 index 00000000000..2a572a21dc3 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BlockChangeArgs.java @@ -0,0 +1,36 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.common.world.SpongeBlockChangeFlag; + +public record BlockChangeArgs( + BlockState newState, + SpongeBlockChangeFlag flag, + int limit +) implements ProcessingSideEffect.Args { + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BroadcastInventoryChangesEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BroadcastInventoryChangesEffect.java index 8664482ce9b..5d4300c3fb2 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BroadcastInventoryChangesEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/BroadcastInventoryChangesEffect.java @@ -25,14 +25,14 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class BroadcastInventoryChangesEffect implements ProcessingSideEffect { +public final class BroadcastInventoryChangesEffect implements ProcessingSideEffect { private static final class Holder { static final BroadcastInventoryChangesEffect INSTANCE = new BroadcastInventoryChangesEffect(); @@ -41,16 +41,16 @@ public static BroadcastInventoryChangesEffect getInstance() { return Holder.INSTANCE; } public static EffectTransactor transact(final TransactionalCaptureSupplier transactor) { - return transactor.pushEffect(new ResultingTransactionBySideEffect(BroadcastInventoryChangesEffect.getInstance())); + return transactor.pushEffect(new ResultingTransactionBySideEffect<>(BroadcastInventoryChangesEffect.getInstance())); } BroadcastInventoryChangesEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/CheckBlockPostPlacementIsSameEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/CheckBlockPostPlacementIsSameEffect.java index 951ba947beb..378827bf319 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/CheckBlockPostPlacementIsSameEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/CheckBlockPostPlacementIsSameEffect.java @@ -26,11 +26,11 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class CheckBlockPostPlacementIsSameEffect implements ProcessingSideEffect { +public final class CheckBlockPostPlacementIsSameEffect implements ProcessingSideEffect { private static final class Holder { static final CheckBlockPostPlacementIsSameEffect INSTANCE = new CheckBlockPostPlacementIsSameEffect(); } @@ -40,17 +40,18 @@ public static CheckBlockPostPlacementIsSameEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var newState = args.newState(); final LevelChunkSection chunkSection = pipeline.getAffectedSection(); final int x = oldState.pos().getX() & 15; final int y = oldState.pos().getY() & 15; final int z = oldState.pos().getZ() & 15; final BlockState currentState = chunkSection.getBlockState(x, y, z); if (!currentState.is(newState.getBlock())) { - return new EffectResult(newState, true); + return new EffectResult<>(newState, true); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ChunkChangeCompleteEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ChunkChangeCompleteEffect.java index 426a2637da3..4d705e43610 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ChunkChangeCompleteEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ChunkChangeCompleteEffect.java @@ -26,15 +26,16 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class ChunkChangeCompleteEffect implements ProcessingSideEffect { +public final class ChunkChangeCompleteEffect implements ProcessingSideEffect { private static final class Holder { static final ChunkChangeCompleteEffect INSTANCE = new ChunkChangeCompleteEffect(); } + ChunkChangeCompleteEffect() { } @@ -43,13 +44,12 @@ public static ChunkChangeCompleteEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - final LevelChunk chunk = pipeline.getAffectedChunk(); // this.unsaved = true; // Vanilla, we'll just call the accessor available chunk.markUnsaved(); - return new EffectResult(oldState.state(), true); + return new EffectResult<>(oldState.state(), true); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EffectResult.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EffectResult.java index 3ceacfb2e23..e6076ae2b0b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EffectResult.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EffectResult.java @@ -25,30 +25,35 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Collections; import java.util.List; -public final class EffectResult { +public final class EffectResult<@Nullable R> { - public static final EffectResult NULL_RETURN = new EffectResult(null, true); - public static final EffectResult NULL_PASS = new EffectResult(null, false); + public static <@Nullable T> EffectResult nullReturn() { + return new EffectResult<>(null, true); + } + + public static <@Nullable T> EffectResult nullPass() { + return new EffectResult<>(null, false); + } - public final @Nullable BlockState resultingState; + public final @Nullable R resultingState; public final List drops; public final boolean hasResult; - public EffectResult(final @Nullable BlockState resultingState, final boolean hasResult) { + public EffectResult(final @Nullable R resultingState, final boolean hasResult) { this.resultingState = resultingState; this.hasResult = hasResult; this.drops = Collections.emptyList(); } - public EffectResult(final @Nullable BlockState resultingState, final List drops, final boolean hasResult) { + public EffectResult(final @Nullable R resultingState, final List drops, final boolean hasResult) { this.resultingState = resultingState; this.drops = drops; this.hasResult = hasResult; } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EntityPerformingDropsEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EntityPerformingDropsEffect.java index eeb7ee4e4e5..4d9d4065a3d 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EntityPerformingDropsEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/EntityPerformingDropsEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class EntityPerformingDropsEffect implements ProcessingSideEffect { +public final class EntityPerformingDropsEffect implements ProcessingSideEffect { private static final class Holder { static final EntityPerformingDropsEffect INSTANCE = new EntityPerformingDropsEffect(); @@ -40,10 +40,10 @@ public static EntityPerformingDropsEffect getInstance() { EntityPerformingDropsEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ExplodeBlockEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ExplodeBlockEffect.java index f47669e56ea..af08550e265 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ExplodeBlockEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ExplodeBlockEffect.java @@ -28,14 +28,14 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.event.tracking.phase.general.ExplosionContext; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class ExplodeBlockEffect implements ProcessingSideEffect { +public final class ExplodeBlockEffect implements ProcessingSideEffect { private static final class Holder { static final ExplodeBlockEffect INSTANCE = new ExplodeBlockEffect(); @@ -47,20 +47,18 @@ public static ExplodeBlockEffect getInstance() { ExplodeBlockEffect() {} - @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public EffectResult processSideEffect( - final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final PhaseContext<@NonNull ?> phaseContext = PhaseTracker.getInstance().getPhaseContext(); final ServerLevel world = pipeline.getServerWorld(); final BlockPos pos = oldState.pos(); - if (phaseContext instanceof ExplosionContext) { - oldState.state().getBlock().wasExploded(world, pos, ((ExplosionContext) phaseContext).getExplosion()); + if (phaseContext instanceof ExplosionContext ec) { + oldState.state().getBlock().wasExploded(world, pos, ec.getExplosion()); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java new file mode 100644 index 00000000000..fac849e78d2 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java @@ -0,0 +1,42 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public record InteractionArgs( + Level world, + ServerPlayer player, + InteractionHand hand, + BlockHitResult blockRaytraceResult, + BlockState blockstate, + ItemStack copiedStack +) implements ProcessingSideEffect.Args { +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java new file mode 100644 index 00000000000..8ccfc3a0b4e --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java @@ -0,0 +1,58 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.InteractionResult; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; + +public final class InteractionItemEffect implements ProcessingSideEffect { + + private static final class Holder { + static final InteractionItemEffect INSTANCE = new InteractionItemEffect(); + } + + public static InteractionItemEffect getInstance() { + return Holder.INSTANCE; + } + + @Override + public EffectResult processSideEffect( + UseBlockPipeline pipeline, InteractionResult oldState, InteractionArgs args + ) { + final var player = args.player(); + final var world = args.world(); + final var blockstate = args.blockstate(); + final var blockHitResult = args.blockRaytraceResult(); + final InteractionResult result = blockstate.useWithoutItem(world, player, blockHitResult); + pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); + try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { + args.player().containerMenu.broadcastChanges(); + } + return new EffectResult<>(result, true); + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java new file mode 100644 index 00000000000..71d393a62fe --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java @@ -0,0 +1,59 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.ItemInteractionResult; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; + +public final class InteractionUseItemOnBlockEffect implements ProcessingSideEffect { + + private static final class Holder { + static final InteractionUseItemOnBlockEffect INSTANCE = new InteractionUseItemOnBlockEffect(); + } + + public static InteractionUseItemOnBlockEffect getInstance() { + return Holder.INSTANCE; + } + + @Override + public EffectResult processSideEffect( + UseItemOnBlockPipeline pipeline, ItemInteractionResult oldState, InteractionArgs args + ) { + final var player = args.player(); + final var hand = args.hand(); + final var world = args.world(); + final var blockRaytraceResult = args.blockRaytraceResult(); + final var blockstate = args.blockstate(); + final ItemInteractionResult result = blockstate.useItemOn(args.copiedStack(), world, player, hand, blockRaytraceResult); + pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); + try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { + args.player().containerMenu.broadcastChanges(); + } + return new EffectResult<>(result, true); + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InventoryEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InventoryEffect.java index 459b9c9c038..e58f1cb2849 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InventoryEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InventoryEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class InventoryEffect implements ProcessingSideEffect { +public final class InventoryEffect implements ProcessingSideEffect { private static final class Holder { static final InventoryEffect INSTANCE = new InventoryEffect(); @@ -40,10 +40,10 @@ public static InventoryEffect getInstance() { InventoryEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyClientEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyClientEffect.java index db70695e346..5ce7d8ec413 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyClientEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyClientEffect.java @@ -28,11 +28,12 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class NotifyClientEffect implements ProcessingSideEffect { +public final class NotifyClientEffect implements ProcessingSideEffect { private static final class Holder { static final NotifyClientEffect INSTANCE = new NotifyClientEffect(); @@ -45,9 +46,11 @@ public static NotifyClientEffect getInstance() { NotifyClientEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final BlockState newState = args.newState(); + final SpongeBlockChangeFlag flag = args.flag(); final LevelChunk chunk = pipeline.getAffectedChunk(); final ServerLevel world = pipeline.getServerWorld(); @@ -58,7 +61,7 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli // this.notifyBlockUpdate(pos, blockstate, newWorldState, flags); world.sendBlockUpdated(oldState.pos(), oldState.state(), newState, flag.getRawFlag()); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyNeighborSideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyNeighborSideEffect.java index f69722fdf70..94ff114d231 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyNeighborSideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/NotifyNeighborSideEffect.java @@ -26,11 +26,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class NotifyNeighborSideEffect implements ProcessingSideEffect { +public final class NotifyNeighborSideEffect implements ProcessingSideEffect { private static final class Holder { static final NotifyNeighborSideEffect INSTANCE = new NotifyNeighborSideEffect(); @@ -44,9 +44,11 @@ public static NotifyNeighborSideEffect getInstance() { @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var flag = args.flag(); + final var newState = args.newState(); final ServerLevel world = pipeline.getServerWorld(); // Vanilla isClientSide is redundant @@ -59,7 +61,7 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli world.updateNeighbourForOutputSignal(oldState.pos(), newState.getBlock()); } } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/OldBlockOnReplaceEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/OldBlockOnReplaceEffect.java index e635d85aa93..4050f8325c3 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/OldBlockOnReplaceEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/OldBlockOnReplaceEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class OldBlockOnReplaceEffect implements ProcessingSideEffect { +public final class OldBlockOnReplaceEffect implements ProcessingSideEffect { private static final class Holder { static final OldBlockOnReplaceEffect INSTANCE = new OldBlockOnReplaceEffect(); } @@ -42,9 +42,8 @@ public static OldBlockOnReplaceEffect getInstance() { } @Override - public EffectResult processSideEffect( - final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { // Normally, vanilla does this: // boolean var14 = var11.hasBlockEntity(); @@ -56,7 +55,9 @@ public EffectResult processSideEffect( // However, since we know we're not on the client (ChunkPipeline is not // used outside of server world context) // we can safely just do oldState.onRemove(this.level, var1, var2, var3). + final var flag = args.flag(); + final var newState = args.newState(); oldState.state().onRemove(pipeline.getServerWorld(), oldState.pos(), newState, flag.movingBlocks()); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PerformBlockDropsFromDestruction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PerformBlockDropsFromDestruction.java index c2f898c2c4a..94896c4e5af 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PerformBlockDropsFromDestruction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PerformBlockDropsFromDestruction.java @@ -27,11 +27,11 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class PerformBlockDropsFromDestruction implements ProcessingSideEffect { +public final class PerformBlockDropsFromDestruction implements ProcessingSideEffect { private static final class Holder { static final PerformBlockDropsFromDestruction INSTANCE = new PerformBlockDropsFromDestruction(); @@ -43,11 +43,11 @@ public static PerformBlockDropsFromDestruction getInstance() { PerformBlockDropsFromDestruction() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { Block.dropResources(oldState.state(), pipeline.getServerWorld(), oldState.pos(), oldState.tileEntity(), oldState.destroyer(), ItemStack.EMPTY); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java new file mode 100644 index 00000000000..a0f81ef9ad0 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java @@ -0,0 +1,52 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.InteractionResult; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; + +public final class PlayerContainerRefreshEffect implements ProcessingSideEffect { + + private static final class Holder { + static final PlayerContainerRefreshEffect INSTANCE = new PlayerContainerRefreshEffect(); + } + + public static PlayerContainerRefreshEffect getInstance() { + return Holder.INSTANCE; + } + + @Override + public EffectResult processSideEffect( + UseItemOnBlockPipeline pipeline, InteractionResult oldState, InteractionArgs args + ) { + pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); + try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { + args.player().containerMenu.broadcastChanges(); + } + return EffectResult.nullPass(); + } +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PrepareBlockDrops.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PrepareBlockDrops.java index 9c3c772729e..4ea2225adf3 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PrepareBlockDrops.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PrepareBlockDrops.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class PrepareBlockDrops implements ProcessingSideEffect { +public final class PrepareBlockDrops implements ProcessingSideEffect { private static final class Holder { static final PrepareBlockDrops INSTANCE = new PrepareBlockDrops(); @@ -41,10 +41,10 @@ public static PrepareBlockDrops getInstance() { PrepareBlockDrops() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java index 2d62b184f61..6c4a7d1ff09 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java @@ -24,16 +24,13 @@ */ package org.spongepowered.common.event.tracking.context.transaction.effect; -import net.minecraft.world.level.block.state.BlockState; -import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; -import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; +import org.checkerframework.checker.nullness.qual.Nullable; @FunctionalInterface -public interface ProcessingSideEffect { +public interface ProcessingSideEffect { - EffectResult processSideEffect(BlockPipeline pipeline, PipelineCursor oldState, BlockState newState, SpongeBlockChangeFlag flag, - int limit - ); + EffectResult processSideEffect(T pipeline, C oldState, A args); + + sealed interface Args permits BlockChangeArgs, InteractionArgs, UseItemArgs {} } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/RemoveTileEntityFromChunkEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/RemoveTileEntityFromChunkEffect.java index ff4588db8da..77cf679a028 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/RemoveTileEntityFromChunkEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/RemoveTileEntityFromChunkEffect.java @@ -26,11 +26,11 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class RemoveTileEntityFromChunkEffect implements ProcessingSideEffect { +public final class RemoveTileEntityFromChunkEffect implements ProcessingSideEffect { private static final class Holder { static final RemoveTileEntityFromChunkEffect INSTANCE = new RemoveTileEntityFromChunkEffect(); @@ -43,14 +43,14 @@ public static RemoveTileEntityFromChunkEffect getInstance() { RemoveTileEntityFromChunkEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final BlockEntity tileEntity = oldState.tileEntity(); if (tileEntity == null) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } pipeline.getAffectedChunk().removeBlockEntity(oldState.pos()); - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetAndRegisterBlockEntityToLevelChunk.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetAndRegisterBlockEntityToLevelChunk.java index 196a7c20bf2..4333e3e40d0 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetAndRegisterBlockEntityToLevelChunk.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetAndRegisterBlockEntityToLevelChunk.java @@ -31,9 +31,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class SetAndRegisterBlockEntityToLevelChunk implements ProcessingSideEffect { +public final class SetAndRegisterBlockEntityToLevelChunk implements ProcessingSideEffect { private static final class Holder { static final SetAndRegisterBlockEntityToLevelChunk INSTANCE = new SetAndRegisterBlockEntityToLevelChunk(); @@ -46,17 +45,16 @@ public static SetAndRegisterBlockEntityToLevelChunk getInstance() { SetAndRegisterBlockEntityToLevelChunk() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final ServerLevel serverWorld = pipeline.getServerWorld(); final @Nullable BlockEntity blockEntity = oldState.tileEntity(); final BlockPos pos = oldState.pos(); if (serverWorld.isOutsideBuildHeight(pos)) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } pipeline.getAffectedChunk().addAndRegisterBlockEntity(blockEntity); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetBlockToChunkSectionEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetBlockToChunkSectionEffect.java index 678aa48cff2..a680290bb94 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetBlockToChunkSectionEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SetBlockToChunkSectionEffect.java @@ -26,11 +26,11 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class SetBlockToChunkSectionEffect implements ProcessingSideEffect { +public final class SetBlockToChunkSectionEffect implements ProcessingSideEffect { private static final class Holder { private static final SetBlockToChunkSectionEffect INSTANCE = new SetBlockToChunkSectionEffect(); @@ -42,17 +42,17 @@ public static SetBlockToChunkSectionEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final BlockState newState = args.newState(); final LevelChunkSection chunkSection = pipeline.getAffectedSection(); final int x = oldState.pos().getX() & 15; final int y = oldState.pos().getY() & 15; final int z = oldState.pos().getZ() & 15; final BlockState oldStateReturned = chunkSection.setBlockState(x, y, z, newState); if (oldStateReturned == newState) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SpawnDestructBlocksEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SpawnDestructBlocksEffect.java index 3e144a2249d..ac4eeacd846 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SpawnDestructBlocksEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/SpawnDestructBlocksEffect.java @@ -29,13 +29,13 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; import java.util.List; -public final class SpawnDestructBlocksEffect implements ProcessingSideEffect { +public final class SpawnDestructBlocksEffect implements ProcessingSideEffect { private static final class Holder { static final SpawnDestructBlocksEffect INSTANCE = new SpawnDestructBlocksEffect(); @@ -47,11 +47,9 @@ public static SpawnDestructBlocksEffect getInstance() { SpawnDestructBlocksEffect() {} - @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public EffectResult processSideEffect( - final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final ServerLevel world = pipeline.getServerWorld(); final BlockPos pos = oldState.pos(); @@ -60,6 +58,6 @@ public EffectResult processSideEffect( drops.forEach(drop -> Block.popResource(world, pos, drop)); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateChunkLightManagerEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateChunkLightManagerEffect.java index 4cedc0c5810..32535c79b54 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateChunkLightManagerEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateChunkLightManagerEffect.java @@ -26,11 +26,11 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateChunkLightManagerEffect implements ProcessingSideEffect { +public final class UpdateChunkLightManagerEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateChunkLightManagerEffect INSTANCE = new UpdateChunkLightManagerEffect(); @@ -43,9 +43,8 @@ public static UpdateChunkLightManagerEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, - final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final LevelChunkSection chunkSection = pipeline.getAffectedSection(); final boolean wasEmpty = pipeline.wasEmpty(); @@ -53,6 +52,6 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli if (wasEmpty != isStillEmpty) { pipeline.getServerWorld().getChunkSource().getLightEngine().updateSectionStatus(oldState.pos(), isStillEmpty); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateConnectingBlocksEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateConnectingBlocksEffect.java index 28049195867..127b1ef7444 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateConnectingBlocksEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateConnectingBlocksEffect.java @@ -27,11 +27,11 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateConnectingBlocksEffect implements ProcessingSideEffect { +public final class UpdateConnectingBlocksEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateConnectingBlocksEffect INSTANCE = new UpdateConnectingBlocksEffect(); @@ -44,11 +44,14 @@ public static UpdateConnectingBlocksEffect getInstance() { UpdateConnectingBlocksEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { final ServerLevel world = pipeline.getServerWorld(); final BlockPos pos = oldState.pos(); + final var flag = args.flag(); + final var newState = args.newState(); + final var limit = args.limit(); if (flag.updateNeighboringShapes() && limit > 0) { // int i = p_241211_3_ & -34; // Vanilla negates 34 to flip neighbor notification and and "state drops" final int withoutNeighborDropsAndNestedNeighborUpdates = flag.asNestedNeighborUpdates().getRawFlag(); @@ -60,7 +63,7 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli newState.updateIndirectNeighbourShapes(world, pos, withoutNeighborDropsAndNestedNeighborUpdates, limit - 1); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateHeightMapEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateHeightMapEffect.java index de2b04b4949..a9ffa8d929a 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateHeightMapEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateHeightMapEffect.java @@ -26,14 +26,14 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.Heightmap; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.accessor.world.level.chunk.ChunkAccessAccessor; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; import java.util.Map; -public final class UpdateHeightMapEffect implements ProcessingSideEffect { +public final class UpdateHeightMapEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateHeightMapEffect INSTANCE = new UpdateHeightMapEffect(); @@ -46,9 +46,10 @@ public static UpdateHeightMapEffect getInstance() { } @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var newState = args.newState(); final Map heightMap = ((ChunkAccessAccessor) pipeline.getAffectedChunk()).accessor$heightmaps(); if (heightMap == null) { throw new IllegalStateException("Heightmap dereferenced!"); @@ -60,6 +61,6 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli heightMap.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(x, y, z, newState); heightMap.get(Heightmap.Types.OCEAN_FLOOR).update(x, y, z, newState); heightMap.get(Heightmap.Types.WORLD_SURFACE).update(x, y, z, newState); - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateLightSideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateLightSideEffect.java index b8962419f59..d3d168df41f 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateLightSideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateLightSideEffect.java @@ -29,11 +29,11 @@ import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.lighting.LightEngine; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateLightSideEffect implements ProcessingSideEffect { +public final class UpdateLightSideEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateLightSideEffect INSTANCE = new UpdateLightSideEffect(); @@ -47,12 +47,13 @@ public static UpdateLightSideEffect getInstance() { } @Override - public EffectResult processSideEffect( + public EffectResult<@Nullable BlockState> processSideEffect( final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + final BlockChangeArgs args ) { + final var flag = args.flag(); if (!flag.updateLighting()) { - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } final ServerLevel serverWorld = pipeline.getServerWorld(); final BlockState currentState = pipeline.getAffectedChunk().getBlockState(oldState.pos()); @@ -90,7 +91,7 @@ public EffectResult processSideEffect( // this.profiler.endSection(); filler.pop(); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateOrCreateNewTileEntityPostPlacementEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateOrCreateNewTileEntityPostPlacementEffect.java index aec887a346a..b6aa7aa1741 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateOrCreateNewTileEntityPostPlacementEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateOrCreateNewTileEntityPostPlacementEffect.java @@ -33,9 +33,8 @@ import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateOrCreateNewTileEntityPostPlacementEffect implements ProcessingSideEffect { +public final class UpdateOrCreateNewTileEntityPostPlacementEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateOrCreateNewTileEntityPostPlacementEffect INSTANCE = new UpdateOrCreateNewTileEntityPostPlacementEffect(); @@ -49,9 +48,10 @@ public static UpdateOrCreateNewTileEntityPostPlacementEffect getInstance() { @SuppressWarnings("deprecation") @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final var newState = args.newState(); final ServerLevel serverWorld = pipeline.getServerWorld(); final LevelChunk chunk = pipeline.getAffectedChunk(); if (((BlockStateBridge) newState).bridge$hasTileEntity()) { @@ -69,6 +69,6 @@ public EffectResult processSideEffect(final BlockPipeline pipeline, final Pipeli ((LevelChunkAccessor) chunk).accessor$updateBlockEntityTicker(maybeNewTileEntity); } } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateWorldRendererEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateWorldRendererEffect.java index 41a44be0d32..6c91e24d4d6 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateWorldRendererEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UpdateWorldRendererEffect.java @@ -25,11 +25,11 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class UpdateWorldRendererEffect implements ProcessingSideEffect { +public final class UpdateWorldRendererEffect implements ProcessingSideEffect { private static final class Holder { static final UpdateWorldRendererEffect INSTANCE = new UpdateWorldRendererEffect(); @@ -42,12 +42,13 @@ public static UpdateWorldRendererEffect getInstance() { UpdateWorldRendererEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, - final BlockState newState, final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, + final BlockChangeArgs args ) { + final var newState = args.newState(); if (oldState.state() != newState) { pipeline.getServerWorld().setBlocksDirty(oldState.pos(), oldState.state(), newState); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java new file mode 100644 index 00000000000..aebd7497bb2 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java @@ -0,0 +1,41 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; + +public record UseItemArgs( + Level world, + ServerPlayer player, + InteractionHand hand, + BlockHitResult result, + ItemStack copiedStack, + boolean creative +) implements ProcessingSideEffect.Args { +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java new file mode 100644 index 00000000000..130e414c734 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java @@ -0,0 +1,64 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.context.UseOnContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; + +public class UseItemEffect implements ProcessingSideEffect { + + private static final class Holder { + static final UseItemEffect INSTANCE = new UseItemEffect(); + } + + public static UseItemEffect getInstance() { + return UseItemEffect.Holder.INSTANCE; + } + + @Override + public EffectResult processSideEffect( + UseItemPipeline pipeline, InteractionResult oldState, UseItemArgs args + ) { + final var stack = args.copiedStack(); + final InteractionResult result; + final var context = new UseOnContext(args.player(), args.hand(), args.result()); + if (args.creative()) { + int $$14 = stack.getCount(); + result = stack.useOn(context); + stack.setCount($$14); + } else { + result = stack.useOn(context); + } + pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); + try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { + args.player().containerMenu.broadcastChanges(); + } + return new EffectResult<>(result, true); + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldBlockChangeCompleteEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldBlockChangeCompleteEffect.java index 58491086353..648300d5aac 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldBlockChangeCompleteEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldBlockChangeCompleteEffect.java @@ -25,11 +25,12 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class WorldBlockChangeCompleteEffect implements ProcessingSideEffect{ +public final class WorldBlockChangeCompleteEffect implements ProcessingSideEffect { private static final class Holder { static final WorldBlockChangeCompleteEffect INSTANCE = new WorldBlockChangeCompleteEffect(); @@ -42,12 +43,13 @@ public static WorldBlockChangeCompleteEffect getInstance() { WorldBlockChangeCompleteEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { + final BlockState newState = args.newState(); + final SpongeBlockChangeFlag flag = args.flag(); if (flag.notifyPathfinding()) { pipeline.getServerWorld().onBlockStateChange(oldState.pos(), oldState.state(), newState); } - return new EffectResult(oldState.state(), true); + return new EffectResult<>(oldState.state(), true); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldDestroyBlockLevelEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldDestroyBlockLevelEffect.java index 86e5e16119c..05a171680cd 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldDestroyBlockLevelEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/WorldDestroyBlockLevelEffect.java @@ -27,11 +27,11 @@ import net.minecraft.world.level.block.BaseFireBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.context.transaction.pipeline.BlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; -import org.spongepowered.common.world.SpongeBlockChangeFlag; -public final class WorldDestroyBlockLevelEffect implements ProcessingSideEffect { +public final class WorldDestroyBlockLevelEffect implements ProcessingSideEffect { private static final class Holder { static final WorldDestroyBlockLevelEffect INSTANCE = new WorldDestroyBlockLevelEffect(); @@ -44,12 +44,12 @@ public static WorldDestroyBlockLevelEffect getInstance() { WorldDestroyBlockLevelEffect() {} @Override - public EffectResult processSideEffect(final BlockPipeline pipeline, final PipelineCursor oldState, final BlockState newState, - final SpongeBlockChangeFlag flag, final int limit + public EffectResult<@Nullable BlockState> processSideEffect( + final BlockPipeline pipeline, final PipelineCursor oldState, final BlockChangeArgs args ) { if (!(oldState.state().getBlock() instanceof BaseFireBlock)) { pipeline.getServerWorld().levelEvent(2001, oldState.pos(), Block.getId(oldState.state())); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java new file mode 100644 index 00000000000..3302e01d076 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java @@ -0,0 +1,101 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.inventory; + +import com.google.common.collect.ImmutableList; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.block.InteractBlockEvent; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.api.util.Direction; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; +import org.spongepowered.common.event.tracking.context.transaction.type.TransactionTypes; +import org.spongepowered.common.item.util.ItemStackUtil; +import org.spongepowered.common.util.PrettyPrinter; +import org.spongepowered.math.vector.Vector3d; + +import java.util.Optional; +import java.util.function.BiConsumer; + +public class InteractItemTransaction extends GameTransaction { + + + private final Vector3d hitVec; + private final BlockSnapshot snapshot; + private final Direction direction; + private final InteractionHand hand; + private final ItemStackSnapshot stack; + + public InteractItemTransaction(ServerPlayer playerIn, ItemStack stackIn, Vector3d hitVec, BlockSnapshot snapshot, Direction direction, InteractionHand handIn) { + super(TransactionTypes.INTERACT_BLOCK_SECONDARY.get()); + this.stack = ItemStackUtil.snapshotOf(stackIn); + this.hitVec = hitVec; + this.snapshot = snapshot; + this.direction = direction; + this.hand = handIn; + } + + + @Override + public Optional, CauseStackManager.StackFrame>> getFrameMutator( + @Nullable GameTransaction<@NonNull ?> parent + ) { + return Optional.empty(); + } + + @Override + public void addToPrinter(PrettyPrinter printer) { + + } + + @Override + public Optional generateEvent( + final PhaseContext<@NonNull ?> context, + final @Nullable GameTransaction<@NonNull ?> parent, + final ImmutableList> gameTransactions, + final Cause currentCause + ) { + return Optional.empty(); + } + + @Override + public void restore(PhaseContext<@NonNull ?> context, InteractBlockEvent.Secondary.Composite event) { + + } + + @Override + public boolean markCancelledTransactions( + final InteractBlockEvent.Secondary.Composite event, + final ImmutableList> gameTransactions) { + return false; + } +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InventoryBasedTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InventoryBasedTransaction.java index 45672accf3a..be736521434 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InventoryBasedTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InventoryBasedTransaction.java @@ -67,6 +67,11 @@ protected InventoryBasedTransaction(final Inventory inventory) { this.inventory = inventory; } + @Override + protected boolean hasUnknownChainRequiringCancellation() { + return true; + } + @Override public Optional, CauseStackManager.StackFrame>> getFrameMutator( @Nullable final GameTransaction<@NonNull ?> parent diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/ChunkPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/ChunkPipeline.java index accd704f681..2c4d8c5ad9c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/ChunkPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/ChunkPipeline.java @@ -37,6 +37,7 @@ import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; import org.spongepowered.common.event.tracking.context.transaction.block.ChangeBlock; +import org.spongepowered.common.event.tracking.context.transaction.effect.BlockChangeArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.world.SpongeBlockChangeFlag; @@ -118,12 +119,11 @@ public LevelChunkSection getAffectedSection() { for (final ResultingTransactionBySideEffect effect : this.chunkEffects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final EffectResult result = effect.effect.processSideEffect( + final var args = new BlockChangeArgs(proposedState, flag, limit); + final EffectResult<@Nullable BlockState> result = effect.effect.processSideEffect( this, formerState, - proposedState, - flag, - limit + args ); if (result.hasResult) { return result.resultingState; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/TileEntityPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/TileEntityPipeline.java index 2a5dc819629..8f684044a29 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/TileEntityPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/TileEntityPipeline.java @@ -26,6 +26,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import org.checkerframework.checker.nullness.qual.Nullable; @@ -33,6 +34,7 @@ import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.effect.BlockChangeArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.world.SpongeBlockChangeFlag; @@ -49,7 +51,7 @@ public final class TileEntityPipeline implements BlockPipeline { private final @Nullable Supplier chunkSupplier; private final @Nullable Supplier serverWorld; private final @Nullable Supplier sectionSupplier; - private final List effects; + private final List> effects; private TileEntityPipeline(final Builder builder) { this.chunkSupplier = builder.chunkSupplier; @@ -98,15 +100,18 @@ public boolean wasEmpty() { public boolean processEffects(final PhaseContext context, final PipelineCursor initialCursor) { PipelineCursor currentCursor = initialCursor; - for (final ResultingTransactionBySideEffect effect : this.effects) { + for (final ResultingTransactionBySideEffect effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final EffectResult result = effect.effect.processSideEffect( - this, - currentCursor, + final BlockChangeArgs args = new BlockChangeArgs( currentCursor.state(), (SpongeBlockChangeFlag) BlockChangeFlags.NONE, currentCursor.limit() ); + final EffectResult<@Nullable BlockState> result = effect.effect.processSideEffect( + this, + currentCursor, + args + ); if (result.resultingState != currentCursor.state()) { currentCursor = new PipelineCursor( result.resultingState, @@ -129,13 +134,13 @@ public static final class Builder { @Nullable Supplier serverWorld; @Nullable Supplier chunkSupplier; @Nullable Supplier sectionSupplier; - List effects; + List> effects; - public Builder addEffect(final ProcessingSideEffect effect) { + public Builder addEffect(final ProcessingSideEffect effect) { if (this.effects == null) { this.effects = new LinkedList<>(); } - this.effects.add(new ResultingTransactionBySideEffect(Objects.requireNonNull(effect, "Effect is null"))); + this.effects.add(new ResultingTransactionBySideEffect<>(Objects.requireNonNull(effect, "Effect is null"))); return this; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java new file mode 100644 index 00000000000..4203d6474ad --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java @@ -0,0 +1,101 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.pipeline; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionItemEffect; + +import java.util.List; +import java.util.Objects; + +public class UseBlockPipeline { + + private final ServerLevel worldIn; + private final ServerPlayer player; + private final InteractionHand hand; + private final BlockHitResult blockRaytraceResult; + private final BlockState blockstate; + private final ItemStack copiedStack; + private final List> effects; + private final TransactionalCaptureSupplier transactor; + + + public UseBlockPipeline(ServerLevel worldIn, + ServerPlayer playerIn, + InteractionHand handIn, + BlockHitResult blockRaytraceResultIn, + BlockState blockstate, + ItemStack copiedStack, + final TransactionalCaptureSupplier transactor) { + + this.worldIn = worldIn; + this.player = playerIn; + this.hand = handIn; + this.blockRaytraceResult = blockRaytraceResultIn; + this.blockstate = blockstate; + this.copiedStack = copiedStack; + this.effects = List.of( + new ResultingTransactionBySideEffect<>(InteractionItemEffect.getInstance()) + ); + this.transactor = transactor; + } + + public InteractionResult processInteraction(PhaseContext context) { + var interaction = InteractionResult.PASS; + for (final var effect : this.effects) { + try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { + final InteractionArgs args = new InteractionArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); + final EffectResult result = effect.effect.processSideEffect( + this, + interaction, + args + ); + if (result.hasResult) { + final @Nullable InteractionResult resultingState = result.resultingState; + interaction = Objects.requireNonNullElse(resultingState, interaction); + } + } + } + return interaction; + } + + public TransactionalCaptureSupplier transactor() { + return this.transactor; + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java new file mode 100644 index 00000000000..82ba980892b --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java @@ -0,0 +1,100 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.pipeline; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionUseItemOnBlockEffect; + +import java.util.List; +import java.util.Objects; + +public final class UseItemOnBlockPipeline { + + private final ServerLevel worldIn; + private final ServerPlayer player; + private final InteractionHand hand; + private final BlockHitResult blockRaytraceResult; + private final BlockState blockstate; + private final ItemStack copiedStack; + private final List> effects; + private final TransactionalCaptureSupplier transactor; + + + public UseItemOnBlockPipeline(ServerLevel worldIn, + ServerPlayer playerIn, + InteractionHand handIn, + BlockHitResult blockRaytraceResultIn, + BlockState blockstate, + ItemStack copiedStack, + final TransactionalCaptureSupplier transactor) { + + this.worldIn = worldIn; + this.player = playerIn; + this.hand = handIn; + this.blockRaytraceResult = blockRaytraceResultIn; + this.blockstate = blockstate; + this.copiedStack = copiedStack; + this.effects = List.of( + new ResultingTransactionBySideEffect<>(InteractionUseItemOnBlockEffect.getInstance()) + ); + this.transactor = transactor; + } + + public ItemInteractionResult processInteraction(PhaseContext context) { + var interaction = ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + for (final var effect : this.effects) { + try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { + final InteractionArgs args = new InteractionArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); + final EffectResult result = effect.effect.processSideEffect( + this, + interaction, + args + ); + if (result.hasResult) { + final @Nullable ItemInteractionResult resultingState = result.resultingState; + interaction = Objects.requireNonNullElse(resultingState, interaction); + } + } + } + return interaction; + } + + public TransactionalCaptureSupplier transactor() { + return this.transactor; + } +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java new file mode 100644 index 00000000000..ce4fbd53238 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java @@ -0,0 +1,100 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.pipeline; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.BlockHitResult; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; +import org.spongepowered.common.event.tracking.context.transaction.effect.UseItemArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.UseItemEffect; + +import java.util.List; +import java.util.Objects; + +public class UseItemPipeline { + + private final ServerLevel worldIn; + private final ServerPlayer player; + private final InteractionHand hand; + private final ItemStack copiedStack; + private final BlockHitResult blockRaytraceResult; + private final boolean creative; + private final List> effects; + private final TransactionalCaptureSupplier transactor; + + + public UseItemPipeline(ServerLevel worldIn, + ServerPlayer playerIn, + InteractionHand handIn, + ItemStack copiedStack, + BlockHitResult blockRaytraceResult, + boolean creative, + final TransactionalCaptureSupplier transactor) { + + this.worldIn = worldIn; + this.player = playerIn; + this.hand = handIn; + this.copiedStack = copiedStack; + this.blockRaytraceResult = blockRaytraceResult; + this.creative = creative; + this.effects = List.of( + new ResultingTransactionBySideEffect<>(UseItemEffect.getInstance()) + ); + this.transactor = transactor; + } + + public InteractionResult processInteraction(PhaseContext context) { + var interaction = InteractionResult.PASS; + for (final var effect : this.effects) { + try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { + final var args = new UseItemArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.copiedStack, this.creative); + final EffectResult result = effect.effect.processSideEffect( + this, + interaction, + args + ); + if (result.hasResult) { + final @Nullable InteractionResult resultingState = result.resultingState; + interaction = Objects.requireNonNullElse(resultingState, interaction); + } + } + } + return interaction; + } + + public TransactionalCaptureSupplier transactor() { + return this.transactor; + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/WorldPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/WorldPipeline.java index fe5a8e9b355..3b6f49db7a9 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/WorldPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/WorldPipeline.java @@ -36,6 +36,7 @@ import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.effect.BlockChangeArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; import org.spongepowered.common.world.SpongeBlockChangeFlag; @@ -52,7 +53,7 @@ public final class WorldPipeline implements BlockPipeline { private final Supplier serverWorld; private final Supplier sectionSupplier; private final boolean wasEmpty; - private final List worldEffects; + private final List> worldEffects; private final ChunkPipeline chunkPipeline; WorldPipeline(final Builder builder) { @@ -101,14 +102,13 @@ public boolean processEffects(final PhaseContext context, final BlockState cu final int oldOpacity = oldState.getLightBlock(); PipelineCursor formerState = new PipelineCursor(oldState, pos, existing, destroyer, limit); - for (final ResultingTransactionBySideEffect effect : this.worldEffects) { + for (final ResultingTransactionBySideEffect effect : this.worldEffects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final EffectResult result = effect.effect.processSideEffect( + final var args = new BlockChangeArgs(newProposedState, flag, limit); + final EffectResult<@Nullable BlockState> result = effect.effect.processSideEffect( this, formerState, - newProposedState, - flag, - limit + args ); if (result.hasResult) { return result.resultingState != null; @@ -134,8 +134,8 @@ public static final class Builder { final Supplier serverWorld; final Supplier chunkSupplier; - final Supplier sectionSupplier; - @MonotonicNonNull List effects; + final Supplier<@Nullable LevelChunkSection> sectionSupplier; + @MonotonicNonNull List> effects; final ChunkPipeline chunkPipeline; Builder(final ChunkPipeline chunkPipeline) { @@ -145,11 +145,11 @@ public static final class Builder { this.chunkPipeline = chunkPipeline; } - public Builder addEffect(final ProcessingSideEffect effect) { + public Builder addEffect(final ProcessingSideEffect effect) { if (this.effects == null) { this.effects = new LinkedList<>(); } - this.effects.add(new ResultingTransactionBySideEffect(Objects.requireNonNull(effect, "Effect is null"))); + this.effects.add(new ResultingTransactionBySideEffect<>(Objects.requireNonNull(effect, "Effect is null"))); return this; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java index 2301cc5bfb0..188b314c4a3 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java @@ -29,6 +29,7 @@ import org.spongepowered.api.event.Cancellable; import org.spongepowered.api.event.Event; import org.spongepowered.api.event.block.ChangeBlockEvent; +import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.block.NotifyNeighborBlockEvent; import org.spongepowered.api.event.block.ScheduleBlockUpdateEvent; import org.spongepowered.api.event.entity.HarvestEntityEvent; @@ -67,7 +68,7 @@ public final class TransactionTypes { public static final DefaultedRegistryReference> SLOT_CHANGE = TransactionTypes.key(ResourceKey.sponge("slot_change")); - public static final DefaultedRegistryReference> SPAWN_ENTITY = TransactionTypes.key(ResourceKey.sponge("spawn_entity")); + public static final DefaultedRegistryReference> INTERACT_BLOCK_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); // SORTFIELDS:OFF diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java index 990a2389412..31844e0afc9 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java @@ -35,8 +35,10 @@ import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockEventData; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.ExplosionDamageCalculator; @@ -48,6 +50,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -105,6 +108,9 @@ import org.spongepowered.common.event.tracking.context.transaction.pipeline.ChunkPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.event.tracking.context.transaction.pipeline.TileEntityPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.WorldPipeline; import org.spongepowered.common.event.tracking.phase.general.GeneralPhase; import org.spongepowered.common.event.tracking.phase.tick.TickPhase; @@ -446,11 +452,11 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implem // Then build and use the BlockPipeline final ChunkPipeline chunkPipeline = mixinChunk.bridge$createChunkPipeline(pos, newState, currentState, spongeFlag, limit); final WorldPipeline.Builder worldPipelineBuilder = WorldPipeline.builder(chunkPipeline); - worldPipelineBuilder.addEffect((pipeline, oldState, newState1, flag1, cursorLimit) -> { + worldPipelineBuilder.addEffect((pipeline, oldState, args) -> { if (oldState == null) { - return EffectResult.NULL_RETURN; + return EffectResult.nullReturn(); } - return EffectResult.NULL_PASS; + return EffectResult.nullPass(); }) .addEffect(UpdateLightSideEffect.getInstance()) .addEffect(CheckBlockPostPlacementIsSameEffect.getInstance()) @@ -576,6 +582,79 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable return builder.build(); } + @Override + public UseItemOnBlockPipeline bridge$startInteractionUseOnChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack) { + if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + return null; + } + if (this.bridge$isFake()) { + return null; + } + + final var instance = PhaseTracker.getInstance(); + if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); + } + final var pipeline = new UseItemOnBlockPipeline( + (ServerLevel) worldIn, + playerIn, + handIn, + blockRaytraceResultIn, + blockstate, + copiedStack, + instance.getPhaseContext().getTransactor() + ); + return pipeline; + } + + @Override + public UseBlockPipeline bridge$startInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack) { + if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + return null; + } + if (this.bridge$isFake()) { + return null; + } + + final var instance = PhaseTracker.getInstance(); + if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); + } + final var pipeline = new UseBlockPipeline( + (ServerLevel) worldIn, + playerIn, + handIn, + blockRaytraceResultIn, + blockstate, + copiedStack, + instance.getPhaseContext().getTransactor() + ); + return pipeline; + } + @Override + public UseItemPipeline bridge$startItemInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative) { + if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + return null; + } + if (this.bridge$isFake()) { + return null; + } + + final var instance = PhaseTracker.getInstance(); + if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); + } + return new UseItemPipeline( + (ServerLevel) worldIn, + playerIn, + handIn, + copiedStack, + blockRaytraceResult, + creative, + instance.getPhaseContext().getTransactor() + ); + } + /** * Technically an overwrite, but because this is simply an override, we can * effectively do as we need to, which is determine if we are performing diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java index 1a01fd029a5..b06c7ac4d21 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java @@ -34,12 +34,10 @@ import net.minecraft.world.MenuProvider; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContextKeys; @@ -56,16 +54,12 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.common.bridge.server.level.ServerPlayerGameModeBridge; +import org.spongepowered.common.bridge.world.TrackedWorldBridge; import org.spongepowered.common.bridge.world.inventory.container.ContainerBridge; import org.spongepowered.common.event.SpongeCommonEventFactory; import org.spongepowered.common.event.inventory.InventoryEventFactory; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; -import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; -import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; -import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; -import org.spongepowered.common.event.tracking.context.transaction.effect.InventoryEffect; -import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.registry.provider.DirectionFacingProvider; import org.spongepowered.common.util.VecHelper; import org.spongepowered.math.vector.Vector3d; @@ -78,7 +72,7 @@ public abstract class ServerPlayerGameModeMixin_Tracker { @Shadow protected net.minecraft.server.level.ServerLevel level; @Shadow private GameType gameModeForPlayer; - @Shadow public abstract boolean isCreative(); + @Shadow public abstract boolean shadow$isCreative(); @Inject(method = "useItem", cancellable = true, at = @At(value = "INVOKE", @@ -105,7 +99,9 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl final BlockSnapshot snapshot = ((ServerWorld) (worldIn)).createSnapshot(VecHelper.toVector3i(blockpos)); final Vector3d hitVec = Vector3d.from(blockRaytraceResultIn.getBlockPos().getX(), blockRaytraceResultIn.getBlockPos().getY(), blockRaytraceResultIn.getBlockPos().getZ()); final org.spongepowered.api.util.Direction direction = DirectionFacingProvider.INSTANCE.getKey(blockRaytraceResultIn.getDirection()).get(); - final InteractBlockEvent.Secondary event = SpongeCommonEventFactory.callInteractBlockEventSecondary(playerIn, stackIn, hitVec, snapshot, direction, handIn); + final PhaseContext phaseContext = PhaseTracker.getInstance().getPhaseContext(); + phaseContext.getTransactor().logSecondaryInteractionTransaction(playerIn, stackIn, hitVec, snapshot, direction, handIn); + final InteractBlockEvent.Secondary.Pre event = SpongeCommonEventFactory.callInteractBlockEventSecondary(playerIn, stackIn, hitVec, snapshot, direction, handIn); final Tristate useItem = event.useItemResult(); final Tristate useBlock = event.useBlockResult(); ((ServerPlayerGameModeBridge) this).bridge$setInteractBlockRightClickCancelled(event.isCancelled()); @@ -113,49 +109,53 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl player.inventoryMenu.sendAllDataToRemote(); return InteractionResult.FAIL; } - final PhaseTracker phaseTracker = PhaseTracker.getWorldInstance((ServerLevel) worldIn); - // Sponge end - if (this.gameModeForPlayer == GameType.SPECTATOR) { - final MenuProvider inamedcontainerprovider = blockstate.getMenuProvider(worldIn, blockpos); - if (inamedcontainerprovider != null) { - playerIn.openMenu(inamedcontainerprovider); - final Vector3i pos = VecHelper.toVector3i(blockRaytraceResultIn.getBlockPos()); - final ServerLocation location = ServerLocation.of((ServerWorld) worldIn, pos); - try (final CauseStackManager.StackFrame frame = phaseTracker.pushCauseFrame()) { - frame.pushCause(playerIn); - frame.addContext(EventContextKeys.BLOCK_HIT, ((ServerWorld)(worldIn)).createSnapshot(pos)); - ((ContainerBridge) playerIn.containerMenu).bridge$setOpenLocation(location); - if (!InventoryEventFactory.callInteractContainerOpenEvent(playerIn)) { - return InteractionResult.SUCCESS; + try (final var frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + frame.pushCause(event); + // Sponge end + if (this.gameModeForPlayer == GameType.SPECTATOR) { + final MenuProvider inamedcontainerprovider = blockstate.getMenuProvider(worldIn, blockpos); + if (inamedcontainerprovider != null) { + playerIn.openMenu(inamedcontainerprovider); + final Vector3i pos = VecHelper.toVector3i(blockRaytraceResultIn.getBlockPos()); + final ServerLocation location = ServerLocation.of((ServerWorld) worldIn, pos); + try (final CauseStackManager.StackFrame blockHit = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + blockHit.pushCause(playerIn); + blockHit.addContext(EventContextKeys.BLOCK_HIT, ((ServerWorld) (worldIn)).createSnapshot(pos)); + ((ContainerBridge) playerIn.containerMenu).bridge$setOpenLocation(location); + if (!InventoryEventFactory.callInteractContainerOpenEvent(playerIn)) { + return InteractionResult.SUCCESS; + } } + return InteractionResult.SUCCESS; + } else { + return InteractionResult.PASS; } - return InteractionResult.SUCCESS; - } else { - return InteractionResult.PASS; } - } else { final boolean flag = !playerIn.getMainHandItem().isEmpty() || !playerIn.getOffhandItem().isEmpty(); final boolean flag1 = playerIn.isSecondaryUseActive() && flag; final ItemStack copiedStack = stackIn.copy(); if (useBlock != Tristate.FALSE && !flag1) { // Sponge check useBlock - final InteractionResult result = blockstate.useItemOn(playerIn.getItemInHand(handIn), worldIn, playerIn, handIn, blockRaytraceResultIn); - - if (result.consumesAction()) { + final var useInteraction = ((TrackedWorldBridge) level).bridge$startInteractionUseOnChange(worldIn, playerIn, handIn, blockRaytraceResultIn, blockstate, copiedStack); + if (useInteraction == null) { + return InteractionResult.FAIL; + } + final InteractionResult itemInteract = useInteraction.processInteraction(phaseContext); + if (itemInteract.consumesAction()) { CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(playerIn, blockpos, copiedStack); - return result; + return itemInteract; } - - if (result instanceof InteractionResult.TryEmptyHandInteraction && handIn == InteractionHand.MAIN_HAND) { + if (itemInteract instanceof InteractionResult.TryEmptyHandInteraction && handIn == InteractionHand.MAIN_HAND) { final AbstractContainerMenu lastOpenContainer = playerIn.containerMenu; // Sponge - final InteractionResult result2 = blockstate.useWithoutItem(worldIn, playerIn, blockRaytraceResultIn); + final var interaction = ((TrackedWorldBridge) level).bridge$startInteractionChange(worldIn, playerIn, handIn, blockRaytraceResultIn, blockstate, copiedStack); + final InteractionResult result2 = interaction.processInteraction(phaseContext); if (result2.consumesAction()) { // Sponge Start if (lastOpenContainer != playerIn.containerMenu) { final Vector3i pos = VecHelper.toVector3i(blockRaytraceResultIn.getBlockPos()); final ServerLocation location = ServerLocation.of((ServerWorld) worldIn, pos); - try (final CauseStackManager.StackFrame frame = phaseTracker.pushCauseFrame()) { - frame.pushCause(playerIn); - frame.addContext(EventContextKeys.BLOCK_HIT, ((ServerWorld) (worldIn)).createSnapshot(pos)); + try (final CauseStackManager.StackFrame blockUse = PhaseTracker.getCauseStackManager().pushCauseFrame()) { + blockUse.pushCause(playerIn); + blockUse.addContext(EventContextKeys.BLOCK_HIT, ((ServerWorld) (worldIn)).createSnapshot(pos)); ((ContainerBridge) playerIn.containerMenu).bridge$setOpenLocation(location); if (!InventoryEventFactory.callInteractContainerOpenEvent(playerIn)) { return InteractionResult.FAIL; @@ -167,6 +167,7 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl CriteriaTriggers.DEFAULT_BLOCK_USE.trigger(playerIn, blockpos); return result2; } + } } @@ -176,26 +177,9 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl ((ServerPlayerGameModeBridge) this).bridge$setInteractBlockRightClickCancelled(true); return InteractionResult.PASS; } - // Sponge end - final UseOnContext itemusecontext = new UseOnContext(playerIn, handIn, blockRaytraceResultIn); - final InteractionResult result; - if (this.isCreative()) { - final int i = stackIn.getCount(); - result = stackIn.useOn(itemusecontext); - stackIn.setCount(i); - } else { - result = stackIn.useOn(itemusecontext); - // Sponge start - log change in hand - final PhaseContext<@NonNull ?> context = phaseTracker.getPhaseContext(); - final TransactionalCaptureSupplier transactor = context.getTransactor(); - if (!transactor.isEmpty()) { //TODO: Add effect to attach the transaction to be the child of the parents - try (final EffectTransactor ignored = context.getTransactor().pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance()))) { - transactor.logPlayerInventoryChange(this.player, PlayerInventoryTransaction.EventCreator.STANDARD); - this.player.inventoryMenu.broadcastChanges(); - } - } - // Sponge end - } + final var interaction = ((TrackedWorldBridge) level).bridge$startItemInteractionChange(worldIn, playerIn, handIn, copiedStack, blockRaytraceResultIn, this.shadow$isCreative()); + final var result = interaction.processInteraction(phaseContext); + if (result.consumesAction()) { CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(playerIn, blockpos, copiedStack); @@ -204,7 +188,7 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl return result; } else { // Sponge start - if(useBlock == Tristate.FALSE && !flag1) { + if (useBlock == Tristate.FALSE && !flag1) { ((ServerPlayerGameModeBridge) this).bridge$setInteractBlockRightClickCancelled(true); } // Sponge end @@ -214,5 +198,4 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl } } - } diff --git a/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java b/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java index d0fec3da68f..b78ad302ca2 100644 --- a/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java +++ b/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java @@ -331,8 +331,7 @@ void testTransformationsOfPositions( .sub(VolumePositionTranslators.BLOCK_OFFSET); final Vector3i invertedBlockPos = invertedTransformedPos.toInt(); final Vector3i expectedPos; - Assertions.assertTrue( - type instanceof StubState, + Assertions.assertInstanceOf(StubState.class, type, () -> String.format("expected state to be a stub state for pos: [%f, %f, %f] but got %s", x, y, z, type ) From 96990e0bd281f3a7d520dfab6a3de75cb4c1a6b7 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Mon, 6 May 2024 01:06:26 -0700 Subject: [PATCH 2/4] feat: Add other interactions as pipeline transactions --- .editorconfig | 2 + .../bridge/world/TrackedWorldBridge.java | 5 +- .../event/SpongeCommonEventFactory.java | 4 +- .../transaction/EventByTransaction.java | 2 +- .../context/transaction/GameTransaction.java | 13 ++ .../context/transaction/TransactionSink.java | 26 +++- .../TransactionalCaptureSupplier.java | 7 +- ...actionArgs.java => InteractionAtArgs.java} | 2 +- .../effect/InteractionItemEffect.java | 4 +- .../InteractionUseItemOnBlockEffect.java | 4 +- .../effect/ProcessingSideEffect.java | 6 +- .../transaction/effect/UseItemArgs.java | 5 +- .../transaction/effect/UseItemAtArgs.java | 41 +++++++ ...efreshEffect.java => UseItemAtEffect.java} | 29 +++-- .../transaction/effect/UseItemEffect.java | 18 +-- .../transaction/effect/UseItemOnArgs.java | 39 ++++++ .../inventory/CompositeTransaction.java | 68 +++++++++++ .../inventory/InteractItemTransaction.java | 53 ++++----- .../InteractItemWithBlockTransaction.java | 112 ++++++++++++++++++ .../pipeline/UseBlockPipeline.java | 6 +- .../pipeline/UseItemAtPipeline.java | 100 ++++++++++++++++ .../pipeline/UseItemOnBlockPipeline.java | 6 +- .../transaction/pipeline/UseItemPipeline.java | 18 +-- .../transaction/type/TransactionTypes.java | 4 +- .../loader/SpongeCommonRegistryLoader.java | 2 +- .../core/world/entity/ai/goal/GoalMixin.java | 3 + ...GamePacketListenerImplMixin_Inventory.java | 10 +- .../level/ServerLevelMixin_Tracker.java | 69 +++++++---- .../ServerPlayerGameModeMixin_Tracker.java | 13 +- .../test/projectile/ProjectileTest.java | 2 +- .../test/volumestream/VolumeStreamTest.java | 2 +- 31 files changed, 550 insertions(+), 125 deletions(-) rename src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/{InteractionArgs.java => InteractionAtArgs.java} (98%) create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtArgs.java rename src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/{PlayerContainerRefreshEffect.java => UseItemAtEffect.java} (68%) create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemOnArgs.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemWithBlockTransaction.java create mode 100644 src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java diff --git a/.editorconfig b/.editorconfig index ea24aef8a80..14179785cef 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,8 @@ insert_final_newline = false max_line_length = 120 tab_width = 4 +[{*.json,*.jsonc,*.png.mcmeta,mcmod.info,pack.mcmeta}] +indent_size = 2 [*.yaml] indent_size = 2 \ No newline at end of file diff --git a/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java b/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java index c5c48c5c380..91d1e7d860a 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/TrackedWorldBridge.java @@ -45,6 +45,7 @@ import org.spongepowered.common.bridge.world.level.block.state.BlockStateBridge; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemAtPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.WorldPipeline; @@ -117,5 +118,7 @@ public interface TrackedWorldBridge { UseBlockPipeline bridge$startInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack); - UseItemPipeline bridge$startItemInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative); + UseItemAtPipeline bridge$startItemInteractionChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative); + + UseItemPipeline bridge$startItemInteractionUseChange(Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack); } diff --git a/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java b/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java index 5a769dface4..6a5eff8d157 100644 --- a/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java +++ b/src/main/java/org/spongepowered/common/event/SpongeCommonEventFactory.java @@ -297,10 +297,10 @@ public static InteractItemEvent.Primary callInteractItemEventPrimary(final net.m } } - public static InteractItemEvent.Secondary callInteractItemEventSecondary(final net.minecraft.world.entity.player.Player player, final ItemStack stack, final InteractionHand hand) { + public static InteractItemEvent.Secondary.Pre callInteractItemEventSecondary(final net.minecraft.world.entity.player.Player player, final ItemStack stack, final InteractionHand hand) { try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) { SpongeCommonEventFactory.applyCommonInteractContext(player, stack, hand, null, null, frame); - final InteractItemEvent.Secondary event = SpongeEventFactory.createInteractItemEventSecondary(frame.currentCause(), ItemStackUtil.snapshotOf(stack)); + final var event = SpongeEventFactory.createInteractItemEventSecondaryPre(frame.currentCause(), ItemStackUtil.snapshotOf(stack)); SpongeCommon.post(event); return event; } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EventByTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EventByTransaction.java index eed31f53d27..a2dc78e740c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EventByTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/EventByTransaction.java @@ -32,7 +32,7 @@ import org.spongepowered.api.event.Event; @DefaultQualifier(NonNull.class) -record EventByTransaction( +public record EventByTransaction( T event, ImmutableList> transactions, @Nullable GameTransaction<@NonNull ?> parent, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java index 391443f3f19..9f524c74b75 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/GameTransaction.java @@ -46,6 +46,7 @@ import java.util.Optional; import java.util.StringJoiner; import java.util.function.BiConsumer; +import java.util.stream.Stream; @DefaultQualifier(NonNull.class) public abstract class GameTransaction implements TransactionFlow, StatefulTransaction { @@ -189,6 +190,18 @@ protected void captureState() { } + public void associateSideEffectEvents(E e, Stream elements) { + + } + + public void pushCause(CauseStackManager.StackFrame frame, E e) { + frame.pushCause(e); + } + + public void finalizeSideEffects(E e) { + + } + private static class ChildIterator implements Iterator> { private final Iterator> effectIterator; private @Nullable GameTransaction<@NonNull ?> cachedNext; diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java index 73655b3996b..303ebf915a6 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionSink.java @@ -27,7 +27,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -46,6 +45,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.cause.entity.SpawnType; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStackSnapshot; @@ -74,6 +74,7 @@ import org.spongepowered.common.event.tracking.context.transaction.block.ScheduleUpdateTransaction; import org.spongepowered.common.event.tracking.context.transaction.effect.BlockAddedEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.EntityPerformingDropsEffect; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionItemEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.InventoryEffect; import org.spongepowered.common.event.tracking.context.transaction.effect.PrepareBlockDrops; import org.spongepowered.common.event.tracking.context.transaction.effect.ProcessingSideEffect; @@ -86,6 +87,7 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.DropFromPlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.ExplicitInventoryOmittedTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.InteractItemTransaction; +import org.spongepowered.common.event.tracking.context.transaction.inventory.InteractItemWithBlockTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.InventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.OpenMenuTransaction; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlaceRecipeTransaction; @@ -421,10 +423,26 @@ default EffectTransactor logInventoryTransaction(final AbstractContainerMenu con } default void logSecondaryInteractionTransaction( - final ServerPlayer playerIn, final ItemStack stackIn, final Vector3d hitVec, - final BlockSnapshot snapshot, final Direction direction, final InteractionHand handIn) { - final InteractItemTransaction transaction = new InteractItemTransaction(playerIn, stackIn, hitVec, snapshot, direction, handIn); + final ServerPlayer playerIn, final Vector3d hitVec, + final BlockSnapshot snapshot, final Direction direction, InteractBlockEvent.Secondary.Pre event) { + final InteractItemWithBlockTransaction transaction = new InteractItemWithBlockTransaction(playerIn, + hitVec, + snapshot, + direction, + event.originalUseBlockResult(), + event.useBlockResult(), + event.originalUseItemResult(), + event.useItemResult() + ); this.logTransaction(transaction); } + default EffectTransactor logSecondaryInteractItemTransaction( + final ServerPlayer playerIn, final ItemStack stackIn + ) { + final InteractItemTransaction transaction = new InteractItemTransaction(playerIn, stackIn); + this.logTransaction(transaction); + return this.pushEffect(new ResultingTransactionBySideEffect<>(InteractionItemEffect.getInstance())); + } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java index 36edd7e27c6..d5bb7c3cb0b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/TransactionalCaptureSupplier.java @@ -311,13 +311,16 @@ private static void generateEventForTransaction( if (transaction.sideEffects == null || transaction.sideEffects.isEmpty()) { continue; } - generatedEvent.ifPresent(frame::pushCause); + generatedEvent.ifPresent(e -> transaction.pushCause(frame, e)); for (final ResultingTransactionBySideEffect sideEffect : transaction.sideEffects) { if (sideEffect.head == null) { continue; } - builder.addAll(TransactionalCaptureSupplier.batchTransactions(sideEffect.head, pointer, context, transactionPostEventBuilder)); + final var elements = TransactionalCaptureSupplier.batchTransactions(sideEffect.head, pointer, context, transactionPostEventBuilder); + generatedEvent.ifPresent(e -> transaction.associateSideEffectEvents(e, elements.stream().map(EventByTransaction::event))); + builder.addAll(elements); } + generatedEvent.ifPresent(transaction::finalizeSideEffects); } } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionAtArgs.java similarity index 98% rename from src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java rename to src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionAtArgs.java index fac849e78d2..5cd9000fdc3 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionArgs.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionAtArgs.java @@ -31,7 +31,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -public record InteractionArgs( +public record InteractionAtArgs( Level world, ServerPlayer player, InteractionHand hand, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java index 8ccfc3a0b4e..57af8e795a9 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionItemEffect.java @@ -29,7 +29,7 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; -public final class InteractionItemEffect implements ProcessingSideEffect { +public final class InteractionItemEffect implements ProcessingSideEffect.Simple { private static final class Holder { static final InteractionItemEffect INSTANCE = new InteractionItemEffect(); @@ -41,7 +41,7 @@ public static InteractionItemEffect getInstance() { @Override public EffectResult processSideEffect( - UseBlockPipeline pipeline, InteractionResult oldState, InteractionArgs args + UseBlockPipeline pipeline, InteractionResult oldState, InteractionAtArgs args ) { final var player = args.player(); final var world = args.world(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java index 71d393a62fe..e0bcef3e8e8 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java @@ -29,7 +29,7 @@ import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; -public final class InteractionUseItemOnBlockEffect implements ProcessingSideEffect { +public final class InteractionUseItemOnBlockEffect implements ProcessingSideEffect { private static final class Holder { static final InteractionUseItemOnBlockEffect INSTANCE = new InteractionUseItemOnBlockEffect(); @@ -41,7 +41,7 @@ public static InteractionUseItemOnBlockEffect getInstance() { @Override public EffectResult processSideEffect( - UseItemOnBlockPipeline pipeline, ItemInteractionResult oldState, InteractionArgs args + UseItemOnBlockPipeline pipeline, ItemInteractionResult oldState, InteractionAtArgs args ) { final var player = args.player(); final var hand = args.hand(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java index 6c4a7d1ff09..be0e3f21018 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/ProcessingSideEffect.java @@ -29,8 +29,12 @@ @FunctionalInterface public interface ProcessingSideEffect { + interface Simple extends ProcessingSideEffect { + + } + EffectResult processSideEffect(T pipeline, C oldState, A args); - sealed interface Args permits BlockChangeArgs, InteractionArgs, UseItemArgs {} + sealed interface Args permits BlockChangeArgs, InteractionAtArgs, UseItemOnArgs, UseItemAtArgs, UseItemArgs {} } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java index aebd7497bb2..eeb1c6c3f2f 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemArgs.java @@ -25,17 +25,16 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.phys.BlockHitResult; public record UseItemArgs( Level world, ServerPlayer player, InteractionHand hand, - BlockHitResult result, ItemStack copiedStack, - boolean creative + ServerPlayerGameMode gameMode ) implements ProcessingSideEffect.Args { } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtArgs.java new file mode 100644 index 00000000000..ab8616303c3 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtArgs.java @@ -0,0 +1,41 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; + +public record UseItemAtArgs( + Level world, + ServerPlayer player, + InteractionHand hand, + BlockHitResult result, + ItemStack copiedStack, + boolean creative +) implements ProcessingSideEffect.Args { +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtEffect.java similarity index 68% rename from src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java rename to src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtEffect.java index a0f81ef9ad0..2f7dc7ea299 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/PlayerContainerRefreshEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemAtEffect.java @@ -25,28 +25,43 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.context.UseOnContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; -import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemAtPipeline; -public final class PlayerContainerRefreshEffect implements ProcessingSideEffect { +public class UseItemAtEffect implements ProcessingSideEffect.Simple { private static final class Holder { - static final PlayerContainerRefreshEffect INSTANCE = new PlayerContainerRefreshEffect(); + static final UseItemAtEffect INSTANCE = new UseItemAtEffect(); } - public static PlayerContainerRefreshEffect getInstance() { - return Holder.INSTANCE; + private UseItemAtEffect() { + } + + public static UseItemAtEffect getInstance() { + return UseItemAtEffect.Holder.INSTANCE; } @Override public EffectResult processSideEffect( - UseItemOnBlockPipeline pipeline, InteractionResult oldState, InteractionArgs args + UseItemAtPipeline pipeline, InteractionResult oldState, UseItemAtArgs args ) { + final var stack = args.copiedStack(); + final InteractionResult result; + final var context = new UseOnContext(args.player(), args.hand(), args.result()); + if (args.creative()) { + int count = stack.getCount(); + result = stack.useOn(context); + stack.setCount(count); + } else { + result = stack.useOn(context); + } pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { args.player().containerMenu.broadcastChanges(); } - return EffectResult.nullPass(); + return new EffectResult<>(result, true); } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java index 130e414c734..9a102746cc4 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemEffect.java @@ -25,17 +25,19 @@ package org.spongepowered.common.event.tracking.context.transaction.effect; import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.context.UseOnContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; -public class UseItemEffect implements ProcessingSideEffect { +public class UseItemEffect implements ProcessingSideEffect.Simple { private static final class Holder { static final UseItemEffect INSTANCE = new UseItemEffect(); } + private UseItemEffect() { + } + public static UseItemEffect getInstance() { return UseItemEffect.Holder.INSTANCE; } @@ -44,16 +46,8 @@ public static UseItemEffect getInstance() { public EffectResult processSideEffect( UseItemPipeline pipeline, InteractionResult oldState, UseItemArgs args ) { - final var stack = args.copiedStack(); - final InteractionResult result; - final var context = new UseOnContext(args.player(), args.hand(), args.result()); - if (args.creative()) { - int $$14 = stack.getCount(); - result = stack.useOn(context); - stack.setCount($$14); - } else { - result = stack.useOn(context); - } + final var gameMode = args.gameMode(); + final InteractionResult result = gameMode.useItem(args.player(), args.world(), args.copiedStack(), args.hand()); pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { args.player().containerMenu.broadcastChanges(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemOnArgs.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemOnArgs.java new file mode 100644 index 00000000000..72029fd5deb --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/UseItemOnArgs.java @@ -0,0 +1,39 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.effect; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; + +public record UseItemOnArgs( + UseOnContext context, + ItemStack itemStack, + ItemStackSnapshot itemStackSnapshot, + ServerPlayer player, + boolean isCreative +) implements ProcessingSideEffect.Args { +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java new file mode 100644 index 00000000000..ab730bdad7c --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java @@ -0,0 +1,68 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.inventory; + +import com.google.common.collect.ImmutableList; +import org.spongepowered.api.event.Cancellable; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.CompositeEvent; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.event.impl.AbstractCompositeEvent; +import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; +import org.spongepowered.common.event.tracking.context.transaction.type.TransactionType; + +import java.util.stream.Stream; + +public abstract class CompositeTransaction extends GameTransaction { + protected CompositeTransaction(TransactionType transactionType) { + super(transactionType); + } + + @Override + public void associateSideEffectEvents(E event, Stream elements) { + elements.forEach(event.children()::add); + } + + @Override + public void finalizeSideEffects(E post) { + // This finalizes the list to be immutable + ((AbstractCompositeEvent) post).postInit(); + } + + public void pushCause(CauseStackManager.StackFrame frame, E e) { + frame.pushCause(e.baseEvent()); + } + + @Override + public boolean markCancelledTransactions( + final E event, + final ImmutableList> gameTransactions) { + event.children().stream().filter(e -> e instanceof Cancellable) + .map(e -> (Cancellable) e) + .forEach(e -> e.setCancelled(event.isCancelled())); + return false; + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java index 3302e01d076..c2a8fc0399c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemTransaction.java @@ -26,50 +26,46 @@ import com.google.common.collect.ImmutableList; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.CauseStackManager; -import org.spongepowered.api.event.block.InteractBlockEvent; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.item.inventory.InteractItemEvent; import org.spongepowered.api.item.inventory.ItemStackSnapshot; -import org.spongepowered.api.util.Direction; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; import org.spongepowered.common.event.tracking.context.transaction.type.TransactionTypes; import org.spongepowered.common.item.util.ItemStackUtil; import org.spongepowered.common.util.PrettyPrinter; -import org.spongepowered.math.vector.Vector3d; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; -public class InteractItemTransaction extends GameTransaction { +public class InteractItemTransaction extends CompositeTransaction { - - private final Vector3d hitVec; - private final BlockSnapshot snapshot; - private final Direction direction; - private final InteractionHand hand; + private final ServerPlayer player; private final ItemStackSnapshot stack; - public InteractItemTransaction(ServerPlayer playerIn, ItemStack stackIn, Vector3d hitVec, BlockSnapshot snapshot, Direction direction, InteractionHand handIn) { - super(TransactionTypes.INTERACT_BLOCK_SECONDARY.get()); + public InteractItemTransaction( + final ServerPlayer playerIn, final ItemStack stackIn) { + super(TransactionTypes.INTERACT_ITEM_SECONDARY.get()); + this.player = playerIn; this.stack = ItemStackUtil.snapshotOf(stackIn); - this.hitVec = hitVec; - this.snapshot = snapshot; - this.direction = direction; - this.hand = handIn; - } + } @Override public Optional, CauseStackManager.StackFrame>> getFrameMutator( @Nullable GameTransaction<@NonNull ?> parent ) { - return Optional.empty(); + return Optional.of((context, frame) -> { + frame.pushCause(this.player); + }); } @Override @@ -78,24 +74,23 @@ public void addToPrinter(PrettyPrinter printer) { } @Override - public Optional generateEvent( + public Optional generateEvent( final PhaseContext<@NonNull ?> context, final @Nullable GameTransaction<@NonNull ?> parent, - final ImmutableList> gameTransactions, + final ImmutableList> gameTransactions, final Cause currentCause ) { - return Optional.empty(); + final var root = SpongeEventFactory.createInteractItemEventSecondary(currentCause, this.stack); + final List list = new ArrayList<>(); + final var composite = SpongeEventFactory.createInteractItemEventSecondaryPost(currentCause, root, list); + return Optional.of(composite); } - @Override - public void restore(PhaseContext<@NonNull ?> context, InteractBlockEvent.Secondary.Composite event) { - } @Override - public boolean markCancelledTransactions( - final InteractBlockEvent.Secondary.Composite event, - final ImmutableList> gameTransactions) { - return false; + public void restore(PhaseContext<@NonNull ?> context, InteractItemEvent.Secondary.Post event) { + } + } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemWithBlockTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemWithBlockTransaction.java new file mode 100644 index 00000000000..d49727d6adb --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/InteractItemWithBlockTransaction.java @@ -0,0 +1,112 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.inventory; + +import com.google.common.collect.ImmutableList; +import net.minecraft.server.level.ServerPlayer; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.CauseStackManager; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.block.InteractBlockEvent; +import org.spongepowered.api.util.Direction; +import org.spongepowered.api.util.Tristate; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; +import org.spongepowered.common.event.tracking.context.transaction.type.TransactionTypes; +import org.spongepowered.common.util.PrettyPrinter; +import org.spongepowered.math.vector.Vector3d; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.BiConsumer; + +public class InteractItemWithBlockTransaction extends CompositeTransaction { + + private final Vector3d hitVec; + private final BlockSnapshot snapshot; + private final Direction direction; + private final ServerPlayer player; + private final Tristate originalBlockResult, blockResult, originalItemResult, itemResult; + + public InteractItemWithBlockTransaction( + final ServerPlayer playerIn, final Vector3d hitVec, final BlockSnapshot snapshot, + final Direction direction, + final Tristate originalBlockResult, final Tristate useBlockResult, + final Tristate originalUseItemResult, final Tristate useItemResult) { + super(TransactionTypes.INTERACT_BLOCK_SECONDARY.get()); + this.player = playerIn; + this.hitVec = hitVec; + this.snapshot = snapshot; + this.direction = direction; + this.originalBlockResult = originalBlockResult; + this.blockResult = useBlockResult; + this.originalItemResult = originalUseItemResult; + this.itemResult = useItemResult; + } + + + @Override + public Optional, CauseStackManager.StackFrame>> getFrameMutator( + @Nullable GameTransaction<@NonNull ?> parent + ) { + return Optional.of((context, frame) -> { + frame.pushCause(this.player); + }); + } + + @Override + public void addToPrinter(PrettyPrinter printer) { + + } + + @Override + public Optional generateEvent( + final PhaseContext<@NonNull ?> context, + final @Nullable GameTransaction<@NonNull ?> parent, + final ImmutableList> gameTransactions, + final Cause currentCause + ) { + final var root = SpongeEventFactory.createInteractBlockEventSecondary(currentCause, + this.originalBlockResult, this.blockResult, + this.originalItemResult, this.itemResult, + this.snapshot, this.hitVec, + this.direction + ); + final List list = new ArrayList<>(); + final InteractBlockEvent.Secondary.Post composite = SpongeEventFactory.createInteractBlockEventSecondaryPost(currentCause, root, list); + return Optional.of(composite); + } + + @Override + public void restore(PhaseContext<@NonNull ?> context, InteractBlockEvent.Secondary.Post event) { + + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java index 4203d6474ad..f543af72bd6 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java @@ -37,7 +37,7 @@ import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; -import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionAtArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionItemEffect; import java.util.List; @@ -51,7 +51,7 @@ public class UseBlockPipeline { private final BlockHitResult blockRaytraceResult; private final BlockState blockstate; private final ItemStack copiedStack; - private final List> effects; + private final List> effects; private final TransactionalCaptureSupplier transactor; @@ -79,7 +79,7 @@ public InteractionResult processInteraction(PhaseContext context) { var interaction = InteractionResult.PASS; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final InteractionArgs args = new InteractionArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); + final InteractionAtArgs args = new InteractionAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); final EffectResult result = effect.effect.processSideEffect( this, interaction, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java new file mode 100644 index 00000000000..2f2c5f16b17 --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java @@ -0,0 +1,100 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.event.tracking.context.transaction.pipeline; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.BlockHitResult; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.common.event.tracking.PhaseContext; +import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; +import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; +import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; +import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; +import org.spongepowered.common.event.tracking.context.transaction.effect.UseItemAtArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.UseItemAtEffect; + +import java.util.List; +import java.util.Objects; + +public class UseItemAtPipeline { + + private final ServerLevel worldIn; + private final ServerPlayer player; + private final InteractionHand hand; + private final ItemStack copiedStack; + private final BlockHitResult blockRaytraceResult; + private final boolean creative; + private final List> effects; + private final TransactionalCaptureSupplier transactor; + + + public UseItemAtPipeline(ServerLevel worldIn, + ServerPlayer playerIn, + InteractionHand handIn, + ItemStack copiedStack, + BlockHitResult blockRaytraceResult, + boolean creative, + final TransactionalCaptureSupplier transactor) { + + this.worldIn = worldIn; + this.player = playerIn; + this.hand = handIn; + this.copiedStack = copiedStack; + this.blockRaytraceResult = blockRaytraceResult; + this.creative = creative; + this.effects = List.of( + new ResultingTransactionBySideEffect<>(UseItemAtEffect.getInstance()) + ); + this.transactor = transactor; + } + + public InteractionResult processInteraction(PhaseContext context) { + var interaction = InteractionResult.PASS; + for (final var effect : this.effects) { + try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { + final var args = new UseItemAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.copiedStack, this.creative); + final EffectResult result = effect.effect.processSideEffect( + this, + interaction, + args + ); + if (result.hasResult) { + final @Nullable InteractionResult resultingState = result.resultingState; + interaction = Objects.requireNonNullElse(resultingState, interaction); + } + } + } + return interaction; + } + + public TransactionalCaptureSupplier transactor() { + return this.transactor; + } + +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java index 82ba980892b..c24001d5719 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java @@ -37,7 +37,7 @@ import org.spongepowered.common.event.tracking.context.transaction.ResultingTransactionBySideEffect; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; import org.spongepowered.common.event.tracking.context.transaction.effect.EffectResult; -import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionArgs; +import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionAtArgs; import org.spongepowered.common.event.tracking.context.transaction.effect.InteractionUseItemOnBlockEffect; import java.util.List; @@ -51,7 +51,7 @@ public final class UseItemOnBlockPipeline { private final BlockHitResult blockRaytraceResult; private final BlockState blockstate; private final ItemStack copiedStack; - private final List> effects; + private final List> effects; private final TransactionalCaptureSupplier transactor; @@ -79,7 +79,7 @@ public ItemInteractionResult processInteraction(PhaseContext context) { var interaction = ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final InteractionArgs args = new InteractionArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); + final InteractionAtArgs args = new InteractionAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); final EffectResult result = effect.effect.processSideEffect( this, interaction, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java index ce4fbd53238..f2f315e91a7 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java @@ -29,7 +29,6 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.BlockHitResult; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; @@ -48,26 +47,19 @@ public class UseItemPipeline { private final ServerPlayer player; private final InteractionHand hand; private final ItemStack copiedStack; - private final BlockHitResult blockRaytraceResult; - private final boolean creative; private final List> effects; private final TransactionalCaptureSupplier transactor; - public UseItemPipeline(ServerLevel worldIn, - ServerPlayer playerIn, - InteractionHand handIn, - ItemStack copiedStack, - BlockHitResult blockRaytraceResult, - boolean creative, - final TransactionalCaptureSupplier transactor) { + ServerPlayer playerIn, + InteractionHand handIn, + ItemStack copiedStack, + final TransactionalCaptureSupplier transactor) { this.worldIn = worldIn; this.player = playerIn; this.hand = handIn; this.copiedStack = copiedStack; - this.blockRaytraceResult = blockRaytraceResult; - this.creative = creative; this.effects = List.of( new ResultingTransactionBySideEffect<>(UseItemEffect.getInstance()) ); @@ -78,7 +70,7 @@ public InteractionResult processInteraction(PhaseContext context) { var interaction = InteractionResult.PASS; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { - final var args = new UseItemArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.copiedStack, this.creative); + final var args = new UseItemArgs(this.worldIn, this.player, this.hand,this.copiedStack, this.player.gameMode); final EffectResult result = effect.effect.processSideEffect( this, interaction, diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java index 188b314c4a3..fcab599e3d6 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java @@ -36,6 +36,7 @@ import org.spongepowered.api.event.entity.SpawnEntityEvent; import org.spongepowered.api.event.item.inventory.AffectSlotEvent; import org.spongepowered.api.event.item.inventory.ChangeInventoryEvent; +import org.spongepowered.api.event.item.inventory.InteractItemEvent; import org.spongepowered.api.event.item.inventory.container.ClickContainerEvent; import org.spongepowered.api.event.item.inventory.container.InteractContainerEvent; import org.spongepowered.api.registry.DefaultedRegistryReference; @@ -68,7 +69,8 @@ public final class TransactionTypes { public static final DefaultedRegistryReference> SLOT_CHANGE = TransactionTypes.key(ResourceKey.sponge("slot_change")); - public static final DefaultedRegistryReference> INTERACT_BLOCK_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); + public static final DefaultedRegistryReference> INTERACT_BLOCK_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); + public static final DefaultedRegistryReference> INTERACT_ITEM_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); // SORTFIELDS:OFF diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java index eb6b5a2ff83..7d7570ff6b5 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java @@ -48,7 +48,7 @@ public class SpongeCommonRegistryLoader { l.add(TransactionTypes.NEIGHBOR_NOTIFICATION, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); l.add(TransactionTypes.SCHEDULE_BLOCK_UPDATE, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); l.add(TransactionTypes.SLOT_CHANGE, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); - l.add(TransactionTypes.SPAWN_ENTITY, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); + l.add(TransactionTypes.INTERACT_BLOCK_SECONDARY, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); }); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/GoalMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/GoalMixin.java index ab09ccf8e03..48052fae4f1 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/GoalMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/entity/ai/goal/GoalMixin.java @@ -29,6 +29,7 @@ import org.spongepowered.api.entity.ai.goal.GoalExecutor; import org.spongepowered.api.entity.ai.goal.GoalType; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -42,6 +43,8 @@ @Mixin(Goal.class) public abstract class GoalMixin implements GoalBridge { + @Shadow protected abstract int shadow$adjustedTickDelay(int $$0); + private Supplier impl$type; private GoalExecutor impl$owner; diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/network/ServerGamePacketListenerImplMixin_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/network/ServerGamePacketListenerImplMixin_Inventory.java index 6866a22f93b..fa0e5eab5b3 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/network/ServerGamePacketListenerImplMixin_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/network/ServerGamePacketListenerImplMixin_Inventory.java @@ -49,12 +49,12 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.common.bridge.world.TrackedWorldBridge; import org.spongepowered.common.bridge.world.inventory.container.MenuBridge; import org.spongepowered.common.event.tracking.PhaseContext; import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier; -import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.inventory.custom.SpongeInventoryMenu; import org.spongepowered.common.item.util.ItemStackUtil; @@ -122,12 +122,10 @@ public class ServerGamePacketListenerImplMixin_Inventory { final Level param1, final ItemStack param2, final InteractionHand param3) { final PhaseContext<@NonNull ?> context = PhaseTracker.getWorldInstance(this.player.serverLevel()).getPhaseContext(); final TransactionalCaptureSupplier transactor = context.getTransactor(); - try (final EffectTransactor ignored = transactor.logPlayerInventoryChangeWithEffect(this.player, PlayerInventoryTransaction.EventCreator.STANDARD)) { - final InteractionResult result = serverPlayerGameMode.useItem(param0, param1, param2, param3); - this.player.inventoryMenu.broadcastChanges(); // capture - return result; + try (final EffectTransactor ignored = transactor.logSecondaryInteractItemTransaction(param0, param2)) { + final var pipeline = ((TrackedWorldBridge) param1).bridge$startItemInteractionUseChange(param1, param0, param3, param2); + return pipeline.processInteraction(context); } - // TrackingUtil.processBlockCaptures called by UseItemPacketState } @Redirect(method = "handleContainerClose", diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java index 31844e0afc9..ece610b5871 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java @@ -109,6 +109,7 @@ import org.spongepowered.common.event.tracking.context.transaction.pipeline.PipelineCursor; import org.spongepowered.common.event.tracking.context.transaction.pipeline.TileEntityPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseBlockPipeline; +import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemAtPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemPipeline; import org.spongepowered.common.event.tracking.context.transaction.pipeline.WorldPipeline; @@ -131,15 +132,15 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implem @Redirect( - // This normally would target this.entityTickList.forEach((var2x) -> - // but we don't have lambda syntax support yet. - method = "lambda$tick$2", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/server/level/ServerLevel;guardEntityTick(Ljava/util/function/Consumer;Lnet/minecraft/world/entity/Entity;)V") + // This normally would target this.entityTickList.forEach((var2x) -> + // but we don't have lambda syntax support yet. + method = "lambda$tick$2", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/server/level/ServerLevel;guardEntityTick(Ljava/util/function/Consumer;Lnet/minecraft/world/entity/Entity;)V") ) private void tracker$wrapNormalEntityTick(final ServerLevel level, final Consumer entityUpdateConsumer, - final Entity entity + final Entity entity ) { final PhaseContext<@NonNull ?> currentState = PhaseTracker.getWorldInstance((ServerLevel) (Object) this).getPhaseContext(); TrackingUtil.tickEntity(entityUpdateConsumer, entity); @@ -158,9 +159,9 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implem * or we wrap in this method here. * * @param blockState The block state being ticked - * @param worldIn The world (this world) - * @param posIn The position of the block - * @param randomIn The world random + * @param worldIn The world (this world) + * @param posIn The position of the block + * @param randomIn The world random * @author gabizou - January 11th, 2020 - Minecraft 1.14.3 */ @Redirect(method = "tickBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/Block;)V", @@ -453,11 +454,11 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implem final ChunkPipeline chunkPipeline = mixinChunk.bridge$createChunkPipeline(pos, newState, currentState, spongeFlag, limit); final WorldPipeline.Builder worldPipelineBuilder = WorldPipeline.builder(chunkPipeline); worldPipelineBuilder.addEffect((pipeline, oldState, args) -> { - if (oldState == null) { - return EffectResult.nullReturn(); - } - return EffectResult.nullPass(); - }) + if (oldState == null) { + return EffectResult.nullReturn(); + } + return EffectResult.nullPass(); + }) .addEffect(UpdateLightSideEffect.getInstance()) .addEffect(CheckBlockPostPlacementIsSameEffect.getInstance()) .addEffect(UpdateWorldRendererEffect.getInstance()) @@ -547,7 +548,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable @Override public SpongeBlockSnapshot bridge$createSnapshot(final net.minecraft.world.level.block.state.BlockState state, final BlockPos pos, - final BlockChangeFlag updateFlag + final BlockChangeFlag updateFlag ) { final SpongeBlockSnapshot.BuilderImpl builder = SpongeBlockSnapshot.BuilderImpl.pooled(); builder.reset(); @@ -595,7 +596,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); } - final var pipeline = new UseItemOnBlockPipeline( + return new UseItemOnBlockPipeline( (ServerLevel) worldIn, playerIn, handIn, @@ -604,9 +605,9 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable copiedStack, instance.getPhaseContext().getTransactor() ); - return pipeline; } + @Override public UseBlockPipeline bridge$startInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack) { if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer @@ -620,7 +621,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); } - final var pipeline = new UseBlockPipeline( + return new UseBlockPipeline( (ServerLevel) worldIn, playerIn, handIn, @@ -629,10 +630,9 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable copiedStack, instance.getPhaseContext().getTransactor() ); - return pipeline; } @Override - public UseItemPipeline bridge$startItemInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative) { + public UseItemAtPipeline bridge$startItemInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative) { if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer return null; } @@ -644,7 +644,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); } - return new UseItemPipeline( + return new UseItemAtPipeline( (ServerLevel) worldIn, playerIn, handIn, @@ -655,6 +655,27 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable ); } + public UseItemPipeline bridge$startItemInteractionUseChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack) { + if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + return null; + } + if (this.bridge$isFake()) { + return null; + } + + final var instance = PhaseTracker.getInstance(); + if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); + } + return new UseItemPipeline( + (ServerLevel) worldIn, + playerIn, + handIn, + copiedStack, + instance.getPhaseContext().getTransactor() + ); + } + /** * Technically an overwrite, but because this is simply an override, we can * effectively do as we need to, which is determine if we are performing @@ -699,7 +720,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable final TileEntityPipeline pipeline = TileEntityPipeline.kickOff((ServerLevel) (Object) this, immutable) .addEffect(RemoveTileEntityFromChunkEffect.getInstance()) .build(); - pipeline.processEffects(current, new PipelineCursor(tileentity.getBlockState(), immutable, tileentity, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); + pipeline.processEffects(current, new PipelineCursor(tileentity.getBlockState(), immutable, tileentity, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); return; } super.shadow$removeBlockEntity(immutable); @@ -731,7 +752,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable final TileEntityPipeline pipeline = TileEntityPipeline.kickOff((ServerLevel) (Object) this, immutable) .addEffect(SetAndRegisterBlockEntityToLevelChunk.getInstance()) .build(); - pipeline.processEffects(current, new PipelineCursor(proposed.getBlockState(), immutable, proposed, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); + pipeline.processEffects(current, new PipelineCursor(proposed.getBlockState(), immutable, proposed, (Entity) null, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); return; } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java index b06c7ac4d21..15b021aee54 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java @@ -41,7 +41,6 @@ import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.EventContextKeys; -import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.item.inventory.InteractItemEvent; import org.spongepowered.api.util.Tristate; import org.spongepowered.api.world.server.ServerLocation; @@ -80,7 +79,7 @@ public abstract class ServerPlayerGameModeMixin_Tracker { public void impl$callInteractItemSecondary(final ServerPlayer player, final Level level, final ItemStack stack, final InteractionHand hand, final CallbackInfoReturnable cir ) { - final InteractItemEvent.Secondary event = SpongeCommonEventFactory.callInteractItemEventSecondary(player, stack, hand); + final InteractItemEvent.Secondary.Pre event = SpongeCommonEventFactory.callInteractItemEventSecondary(player, stack, hand); if (event.isCancelled()) { player.inventoryMenu.sendAllDataToRemote(); cir.setReturnValue(InteractionResult.FAIL); @@ -98,12 +97,16 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl // Sponge start final BlockSnapshot snapshot = ((ServerWorld) (worldIn)).createSnapshot(VecHelper.toVector3i(blockpos)); final Vector3d hitVec = Vector3d.from(blockRaytraceResultIn.getBlockPos().getX(), blockRaytraceResultIn.getBlockPos().getY(), blockRaytraceResultIn.getBlockPos().getZ()); - final org.spongepowered.api.util.Direction direction = DirectionFacingProvider.INSTANCE.getKey(blockRaytraceResultIn.getDirection()).get(); + final var direction = DirectionFacingProvider.INSTANCE.getKey(blockRaytraceResultIn.getDirection()).get(); final PhaseContext phaseContext = PhaseTracker.getInstance().getPhaseContext(); - phaseContext.getTransactor().logSecondaryInteractionTransaction(playerIn, stackIn, hitVec, snapshot, direction, handIn); - final InteractBlockEvent.Secondary.Pre event = SpongeCommonEventFactory.callInteractBlockEventSecondary(playerIn, stackIn, hitVec, snapshot, direction, handIn); + final var event = SpongeCommonEventFactory.callInteractBlockEventSecondary(playerIn, stackIn, hitVec, snapshot, direction, handIn); final Tristate useItem = event.useItemResult(); final Tristate useBlock = event.useBlockResult(); + phaseContext.getTransactor().logSecondaryInteractionTransaction(playerIn, + hitVec, + snapshot, + direction, + event); ((ServerPlayerGameModeBridge) this).bridge$setInteractBlockRightClickCancelled(event.isCancelled()); if (event.isCancelled()) { player.inventoryMenu.sendAllDataToRemote(); diff --git a/testplugins/src/main/java/org/spongepowered/test/projectile/ProjectileTest.java b/testplugins/src/main/java/org/spongepowered/test/projectile/ProjectileTest.java index 9d9743c1ce3..1f70e0e6626 100644 --- a/testplugins/src/main/java/org/spongepowered/test/projectile/ProjectileTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/projectile/ProjectileTest.java @@ -208,7 +208,7 @@ public ProjectileTestListener() { } @Listener - private void onClickBlock(final InteractBlockEvent.Secondary event, @First final ServerPlayer player) { + private void onClickBlock(final InteractBlockEvent.Secondary.Pre event, @First final ServerPlayer player) { final Vector3d interactionPoint = event.interactionPoint(); final ServerWorld world = player.world(); final EntityType nextType = this.projectileTypes.poll(); diff --git a/testplugins/src/main/java/org/spongepowered/test/volumestream/VolumeStreamTest.java b/testplugins/src/main/java/org/spongepowered/test/volumestream/VolumeStreamTest.java index 1de067274ed..67e0a85ccb0 100644 --- a/testplugins/src/main/java/org/spongepowered/test/volumestream/VolumeStreamTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/volumestream/VolumeStreamTest.java @@ -407,7 +407,7 @@ private void onInteract(final InteractBlockEvent.Primary event, @Root final Play } @Listener - public void onInteract(final InteractBlockEvent.Secondary event, @Root final Player player) { + public void onInteract(final InteractBlockEvent.Secondary.Pre event, @Root final Player player) { event.context().get(EventContextKeys.USED_ITEM).ifPresent(snapshot -> { final BlockSnapshot block = event.block(); if (snapshot.type().equals(ItemTypes.WOODEN_AXE.get()) && block != BlockSnapshot.empty()) { From d83145f496b2c860a4ba247ed1f8ed1aaff20a4d Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 29 Sep 2024 20:46:39 -0700 Subject: [PATCH 3/4] wip: update to the new event generator --- gradle/verification-metadata.xml | 15 +++++++++++++++ .../inventory/CompositeTransaction.java | 5 ++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index c84a8ad3482..234e29b5b32 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -20,6 +20,8 @@ + + @@ -702,6 +704,11 @@ + + + + + @@ -722,6 +729,14 @@ + + + + + + + + diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java index ab730bdad7c..c72a64f677d 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java @@ -59,9 +59,8 @@ public void pushCause(CauseStackManager.StackFrame frame, E e) { public boolean markCancelledTransactions( final E event, final ImmutableList> gameTransactions) { - event.children().stream().filter(e -> e instanceof Cancellable) - .map(e -> (Cancellable) e) - .forEach(e -> e.setCancelled(event.isCancelled())); + event.setCancelled(true); + gameTransactions.forEach(GameTransaction::markCancelled); return false; } From 5e670a96cb035a979049494a7cf0a7805bf3e77e Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 5 Jan 2025 00:43:30 -0800 Subject: [PATCH 4/4] feat: update to event-impl-gen 8 release --- SpongeAPI | 2 +- gradle/verification-metadata.xml | 61 ++++++++++++++++-- .../data/provider/block/state/BlockData.java | 2 +- .../InteractionUseItemOnBlockEffect.java | 10 +-- .../inventory/CompositeTransaction.java | 4 +- .../pipeline/UseBlockPipeline.java | 2 +- .../pipeline/UseItemAtPipeline.java | 2 +- .../pipeline/UseItemOnBlockPipeline.java | 12 ++-- .../transaction/pipeline/UseItemPipeline.java | 2 +- .../transaction/type/TransactionTypes.java | 1 + .../loader/SpongeCommonRegistryLoader.java | 1 + .../level/ServerLevelMixin_Tracker.java | 64 ++++++++----------- .../ServerPlayerGameModeMixin_Tracker.java | 6 +- 13 files changed, 104 insertions(+), 65 deletions(-) diff --git a/SpongeAPI b/SpongeAPI index 1645168a747..a9b2770ff0a 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 1645168a747b4316aa298331a1d35965301ca79f +Subproject commit a9b2770ff0a2a7e023334a3ca271c1771c1d1357 diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 234e29b5b32..68e8994380f 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -20,8 +20,6 @@ - - @@ -704,11 +702,6 @@ - - - - - @@ -737,6 +730,14 @@ + + + + + + + + @@ -1564,6 +1565,14 @@ + + + + + + + + @@ -2363,6 +2372,14 @@ + + + + + + + + @@ -5875,6 +5892,9 @@ + + + @@ -5944,6 +5964,9 @@ + + + @@ -6601,6 +6624,14 @@ + + + + + + + + @@ -7913,6 +7944,22 @@ + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/spongepowered/common/data/provider/block/state/BlockData.java b/src/main/java/org/spongepowered/common/data/provider/block/state/BlockData.java index 9d7066fdf5a..d173833d882 100644 --- a/src/main/java/org/spongepowered/common/data/provider/block/state/BlockData.java +++ b/src/main/java/org/spongepowered/common/data/provider/block/state/BlockData.java @@ -54,7 +54,7 @@ private BlockData() { } // @formatter:off - public static void register(final DataProviderRegistrator registrator) { + @SuppressWarnings("deprecation") public static void register(final DataProviderRegistrator registrator) { registrator .asImmutable(Block.class) .create(Keys.BLAST_RESISTANCE) diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java index e0bcef3e8e8..0400b726f92 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/effect/InteractionUseItemOnBlockEffect.java @@ -24,12 +24,12 @@ */ package org.spongepowered.common.event.tracking.context.transaction.effect; -import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.InteractionResult; import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.context.transaction.inventory.PlayerInventoryTransaction; import org.spongepowered.common.event.tracking.context.transaction.pipeline.UseItemOnBlockPipeline; -public final class InteractionUseItemOnBlockEffect implements ProcessingSideEffect { +public final class InteractionUseItemOnBlockEffect implements ProcessingSideEffect { private static final class Holder { static final InteractionUseItemOnBlockEffect INSTANCE = new InteractionUseItemOnBlockEffect(); @@ -40,15 +40,15 @@ public static InteractionUseItemOnBlockEffect getInstance() { } @Override - public EffectResult processSideEffect( - UseItemOnBlockPipeline pipeline, ItemInteractionResult oldState, InteractionAtArgs args + public EffectResult processSideEffect( + UseItemOnBlockPipeline pipeline, InteractionResult oldState, InteractionAtArgs args ) { final var player = args.player(); final var hand = args.hand(); final var world = args.world(); final var blockRaytraceResult = args.blockRaytraceResult(); final var blockstate = args.blockstate(); - final ItemInteractionResult result = blockstate.useItemOn(args.copiedStack(), world, player, hand, blockRaytraceResult); + final InteractionResult result = blockstate.useItemOn(args.copiedStack(), world, player, hand, blockRaytraceResult); pipeline.transactor().logPlayerInventoryChange(args.player(), PlayerInventoryTransaction.EventCreator.STANDARD); try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(pipeline.transactor())) { args.player().containerMenu.broadcastChanges(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java index c72a64f677d..6bb8c06583c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/inventory/CompositeTransaction.java @@ -35,8 +35,8 @@ import java.util.stream.Stream; -public abstract class CompositeTransaction extends GameTransaction { - protected CompositeTransaction(TransactionType transactionType) { +public abstract class CompositeTransaction> extends GameTransaction { + protected CompositeTransaction(TransactionType transactionType) { super(transactionType); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java index f543af72bd6..ac84e89cf0b 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseBlockPipeline.java @@ -76,7 +76,7 @@ public UseBlockPipeline(ServerLevel worldIn, } public InteractionResult processInteraction(PhaseContext context) { - var interaction = InteractionResult.PASS; + InteractionResult interaction = InteractionResult.PASS; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { final InteractionAtArgs args = new InteractionAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java index 2f2c5f16b17..a9606f31c03 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemAtPipeline.java @@ -75,7 +75,7 @@ public UseItemAtPipeline(ServerLevel worldIn, } public InteractionResult processInteraction(PhaseContext context) { - var interaction = InteractionResult.PASS; + InteractionResult interaction = InteractionResult.PASS; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { final var args = new UseItemAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.copiedStack, this.creative); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java index c24001d5719..c48d9e1865e 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemOnBlockPipeline.java @@ -27,7 +27,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; -import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; @@ -51,7 +51,7 @@ public final class UseItemOnBlockPipeline { private final BlockHitResult blockRaytraceResult; private final BlockState blockstate; private final ItemStack copiedStack; - private final List> effects; + private final List> effects; private final TransactionalCaptureSupplier transactor; @@ -75,18 +75,18 @@ public UseItemOnBlockPipeline(ServerLevel worldIn, this.transactor = transactor; } - public ItemInteractionResult processInteraction(PhaseContext context) { - var interaction = ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + public InteractionResult processInteraction(PhaseContext context) { + InteractionResult interaction = InteractionResult.TRY_WITH_EMPTY_HAND; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { final InteractionAtArgs args = new InteractionAtArgs(this.worldIn, this.player, this.hand, this.blockRaytraceResult, this.blockstate, this.copiedStack); - final EffectResult result = effect.effect.processSideEffect( + final EffectResult result = effect.effect.processSideEffect( this, interaction, args ); if (result.hasResult) { - final @Nullable ItemInteractionResult resultingState = result.resultingState; + final @Nullable InteractionResult resultingState = result.resultingState; interaction = Objects.requireNonNullElse(resultingState, interaction); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java index f2f315e91a7..67e57baa368 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/pipeline/UseItemPipeline.java @@ -67,7 +67,7 @@ public UseItemPipeline(ServerLevel worldIn, } public InteractionResult processInteraction(PhaseContext context) { - var interaction = InteractionResult.PASS; + InteractionResult interaction = InteractionResult.PASS; for (final var effect : this.effects) { try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) { final var args = new UseItemArgs(this.worldIn, this.player, this.hand,this.copiedStack, this.player.gameMode); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java index fcab599e3d6..8569612f2dc 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/TransactionTypes.java @@ -71,6 +71,7 @@ public final class TransactionTypes { public static final DefaultedRegistryReference> INTERACT_BLOCK_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); public static final DefaultedRegistryReference> INTERACT_ITEM_SECONDARY = TransactionTypes.key(ResourceKey.sponge("interact_block_secondary")); + public static final DefaultedRegistryReference> SPAWN_ENTITY = TransactionTypes.key(ResourceKey.sponge("spawn_entity")); // SORTFIELDS:OFF diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java index 7d7570ff6b5..475053f0f5a 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeCommonRegistryLoader.java @@ -49,6 +49,7 @@ public class SpongeCommonRegistryLoader { l.add(TransactionTypes.SCHEDULE_BLOCK_UPDATE, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); l.add(TransactionTypes.SLOT_CHANGE, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); l.add(TransactionTypes.INTERACT_BLOCK_SECONDARY, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); + l.add(TransactionTypes.SPAWN_ENTITY, k -> new NoOpTransactionType<>(false, k.value().toUpperCase(Locale.ROOT))); }); } diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java index ece610b5871..5abcff4bb6e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java @@ -32,6 +32,7 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundExplodePacket; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.RandomSource; @@ -66,6 +67,7 @@ import org.spongepowered.api.world.LocatableBlock; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; @@ -406,6 +408,7 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implem this.tracker$apiExplosion = null; } + @Unique private void tracker$cancelExplosionEffects(final Entity entity) { // TODO cancel effects if (entity instanceof ExplosiveBridge explosiveBridge) { @@ -440,6 +443,7 @@ public abstract class ServerLevelMixin_Tracker extends LevelMixin_Tracker implem return Optional.of(this.bridge$makePipeline(pos, currentState, newState, chunk, spongeFlag, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT)); } + @Unique private WorldPipeline.Builder bridge$makePipeline( final BlockPos pos, final BlockState currentState, @@ -516,13 +520,10 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable return false; } else { // Sponge Start - Sanity check against the PhaseTracker for instances - if (this.bridge$isFake()) { + final var instance = this.tracker$validateServerThread(); + if (instance == null) { return super.destroyBlock(pos, doDrops, p_241212_3_, limit); } - final PhaseTracker instance = PhaseTracker.getWorldInstance((ServerLevel) (Object) this); - if (!instance.onSidedThread()) { - throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); - } final FluidState fluidstate = this.shadow$getFluidState(pos); final BlockState emptyBlock = fluidstate.createLegacyBlock(); final SpongeBlockChangeFlag spongeFlag = BlockChangeFlagManager.fromNativeInt(3); @@ -585,17 +586,10 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable @Override public UseItemOnBlockPipeline bridge$startInteractionUseOnChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack) { - if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer - return null; - } - if (this.bridge$isFake()) { + final var instance = this.tracker$validateServerThread(); + if (instance == null) { return null; } - - final var instance = PhaseTracker.getInstance(); - if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { - throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); - } return new UseItemOnBlockPipeline( (ServerLevel) worldIn, playerIn, @@ -610,17 +604,10 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable @Override public UseBlockPipeline bridge$startInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, BlockHitResult blockRaytraceResultIn, BlockState blockstate, ItemStack copiedStack) { - if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer + final var instance = this.tracker$validateServerThread(); + if (instance == null) { return null; } - if (this.bridge$isFake()) { - return null; - } - - final var instance = PhaseTracker.getInstance(); - if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { - throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); - } return new UseBlockPipeline( (ServerLevel) worldIn, playerIn, @@ -631,19 +618,28 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable instance.getPhaseContext().getTransactor() ); } - @Override - public UseItemAtPipeline bridge$startItemInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative) { + + @Unique + private PhaseTracker tracker$validateServerThread() { if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer return null; } if (this.bridge$isFake()) { return null; } - final var instance = PhaseTracker.getInstance(); - if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { + if (instance.getSidedThread() != PhaseTracker.getServerInstanceExplicitly().getSidedThread() && instance != PhaseTracker.getServerInstanceExplicitly()) { throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); } + return instance; + } + + @Override + public UseItemAtPipeline bridge$startItemInteractionChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack, BlockHitResult blockRaytraceResult, boolean creative) { + final var instance = this.tracker$validateServerThread(); + if (instance == null) { + return null; + } return new UseItemAtPipeline( (ServerLevel) worldIn, playerIn, @@ -655,18 +651,12 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable ); } + @Override public UseItemPipeline bridge$startItemInteractionUseChange(net.minecraft.world.level.Level worldIn, ServerPlayer playerIn, InteractionHand handIn, ItemStack copiedStack) { - if (this.shadow$isDebug()) { // isClientSide is always false since this is WorldServer - return null; - } - if (this.bridge$isFake()) { + final var instance = this.tracker$validateServerThread(); + if (instance == null) { return null; } - - final var instance = PhaseTracker.getInstance(); - if (instance.getSidedThread() != PhaseTracker.SERVER.getSidedThread() && instance != PhaseTracker.SERVER) { - throw new UnsupportedOperationException("Cannot perform a tracked Block Change on a ServerWorld while not on the main thread!"); - } return new UseItemPipeline( (ServerLevel) worldIn, playerIn, @@ -685,7 +675,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean doDrops, @Nullable *
    *
  • This world instance is managed and verified by Sponge
  • *
  • This world must {@link LevelBridge#bridge$isFake()} return {@code false}
  • - *
  • The {@link PhaseTracker#SERVER}'s {@link PhaseTracker#getSidedThread()} must be {@code ==} {@link Thread#currentThread()}
  • The {@link PhaseTracker#getServerInstanceExplicitly}'s {@link PhaseTracker#getSidedThread()} must be {@code ==} {@link Thread#currentThread()}The current {@link IPhaseState} must be allowing to record transactions with an applicable {@link org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier} *
* After which, we may be able to appropriately associate the {@link net.minecraft.world.level.block.entity.BlockEntity} diff --git a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java index 15b021aee54..523170ece67 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java +++ b/src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerPlayerGameModeMixin_Tracker.java @@ -150,8 +150,8 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl if (itemInteract instanceof InteractionResult.TryEmptyHandInteraction && handIn == InteractionHand.MAIN_HAND) { final AbstractContainerMenu lastOpenContainer = playerIn.containerMenu; // Sponge final var interaction = ((TrackedWorldBridge) level).bridge$startInteractionChange(worldIn, playerIn, handIn, blockRaytraceResultIn, blockstate, copiedStack); - final InteractionResult result2 = interaction.processInteraction(phaseContext); - if (result2.consumesAction()) { + final var result = interaction.processInteraction(phaseContext); + if (result.consumesAction()) { // Sponge Start if (lastOpenContainer != playerIn.containerMenu) { final Vector3i pos = VecHelper.toVector3i(blockRaytraceResultIn.getBlockPos()); @@ -168,7 +168,7 @@ public InteractionResult useItemOn(final ServerPlayer playerIn, final Level worl // Sponge End CriteriaTriggers.DEFAULT_BLOCK_USE.trigger(playerIn, blockpos); - return result2; + return result; } }