diff --git a/SpongeAPI b/SpongeAPI index 0f857e9e90a..75c79a3375e 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 0f857e9e90ace1d9d06aa75d12b59079855432e7 +Subproject commit 75c79a3375e78593194c4601675294c621ae7e9d diff --git a/src/main/java/org/spongepowered/common/command/brigadier/SpongeParameterTranslator.java b/src/main/java/org/spongepowered/common/command/brigadier/SpongeParameterTranslator.java index 5471afc9dec..f2871715863 100644 --- a/src/main/java/org/spongepowered/common/command/brigadier/SpongeParameterTranslator.java +++ b/src/main/java/org/spongepowered/common/command/brigadier/SpongeParameterTranslator.java @@ -35,6 +35,7 @@ import org.spongepowered.api.command.parameter.managed.Flag; import org.spongepowered.common.command.brigadier.argument.ArgumentParser; import org.spongepowered.common.command.brigadier.argument.CustomArgumentParser; +import org.spongepowered.common.command.brigadier.tree.SpongeArgumentCommandNode; import org.spongepowered.common.command.brigadier.tree.SpongeArgumentCommandNodeBuilder; import org.spongepowered.common.command.brigadier.tree.SpongeCommandExecutorWrapper; import org.spongepowered.common.command.brigadier.tree.SpongeFlagLiteralCommandNode; @@ -189,6 +190,7 @@ private Collection> createAndAttachNod final boolean shouldTerminate, final boolean allowSubcommands) { + final Set> tailNodes = new HashSet<>(parents); final Set> nodesToAttachTo = new HashSet<>(parents); final ListIterator parameterIterator = children.listIterator(); while (parameterIterator.hasNext()) { @@ -291,22 +293,35 @@ private Collection> createAndAttachNod parametersToAttachTo.add(builtNode); + // Filter out optional nodes that have a matching type, they are nearly impossible to "merge" correctly. + if (isOptional) { + final Set> conflictingNodes = nodesToAttachTo.stream() + .filter(n -> n instanceof final SpongeArgumentCommandNode argumentNodeToAttachTo + && argumentNodeToAttachTo.isOptional() && argumentNodeToAttachTo.key().type().equals(valueParameter.key().type())) + .collect(Collectors.toSet()); + if (!conflictingNodes.isEmpty()) { + nodesToAttachTo.removeIf(n -> n.getChildren().stream().anyMatch(conflictingNodes::contains)); + } + } + // Make sure the nodes we need to attach to have the nodes we need to nodesToAttachTo.forEach(x -> x.addChild(builtNode)); } // If this is not optional, then we clear the "toAttachTo" list because we do not want to skip the parameter. if (!isOptional) { + tailNodes.clear(); nodesToAttachTo.clear(); } + tailNodes.addAll(parametersToAttachTo); nodesToAttachTo.addAll(parametersToAttachTo); } } // If we should make any terminal parameters actually terminal, we do that now. if (shouldTerminate) { - for (final CommandNode node : nodesToAttachTo) { + for (final CommandNode node : tailNodes) { // These are therefore terminal. if (node instanceof SpongeNode) { // they should be, but just in case ((SpongeNode) node).forceExecutor(executorWrapper); @@ -314,7 +329,7 @@ private Collection> createAndAttachNod } } - return nodesToAttachTo; + return tailNodes; } @SuppressWarnings({"unchecked", "rawtypes"}) @@ -334,7 +349,8 @@ private Collection> createAndAttachNod parameter.completer(), parameter.modifier().orElse(null), parameter.valueUsage().orElse(null), - suffix + suffix, + parameter.isOptional() ); // CommandCause is mixed into CommandSource, so this is okay. argumentBuilder.requires((Predicate) parameter.requirement()); diff --git a/src/main/java/org/spongepowered/common/command/brigadier/tree/SpongeArgumentCommandNode.java b/src/main/java/org/spongepowered/common/command/brigadier/tree/SpongeArgumentCommandNode.java index 288c273275a..dcfb75114fc 100644 --- a/src/main/java/org/spongepowered/common/command/brigadier/tree/SpongeArgumentCommandNode.java +++ b/src/main/java/org/spongepowered/common/command/brigadier/tree/SpongeArgumentCommandNode.java @@ -98,6 +98,7 @@ public final class SpongeArgumentCommandNode extends ArgumentCommandNode modifier; private final ValueUsage usage; private final boolean isComplexSuggestions; + private final boolean isOptional; // used so we can have insertion order. private final UnsortedNodeHolder nodeHolder = new UnsortedNodeHolder(); @@ -117,7 +118,8 @@ public SpongeArgumentCommandNode( final RedirectModifier modifier, final boolean forks, final String keyName, - final @Nullable ValueParameterModifier parameterModifier) { + final @Nullable ValueParameterModifier parameterModifier, + final boolean isOptional) { super(keyName, (ArgumentType) Constants.Command.STANDARD_STRING_ARGUMENT_TYPE, // we can abuse generics, we're not actually going to use this. command, @@ -131,6 +133,11 @@ public SpongeArgumentCommandNode( this.isComplexSuggestions = this.parser instanceof ComplexSuggestionNodeProvider; this.key = key; this.usage = usage; + this.isOptional = isOptional; + } + + public Parameter.Key key() { + return this.key; } public final boolean isComplex() { @@ -300,6 +307,10 @@ private String getUsageTextForClient() { return this.getName(); } + public boolean isOptional() { + return this.isOptional; + } + @Override public final void parse(final StringReader reader, final CommandContextBuilder contextBuilder) throws CommandSyntaxException { final int start = reader.getCursor(); diff --git a/src/main/java/org/spongepowered/common/command/brigadier/tree/SpongeArgumentCommandNodeBuilder.java b/src/main/java/org/spongepowered/common/command/brigadier/tree/SpongeArgumentCommandNodeBuilder.java index 52af53a3edb..8fab3c3c019 100644 --- a/src/main/java/org/spongepowered/common/command/brigadier/tree/SpongeArgumentCommandNodeBuilder.java +++ b/src/main/java/org/spongepowered/common/command/brigadier/tree/SpongeArgumentCommandNodeBuilder.java @@ -43,6 +43,7 @@ public final class SpongeArgumentCommandNodeBuilder extends ArgumentBuilder modifier; + private final boolean isOptional; private static @Nullable ValueCompleter filterNativeCompleters(final ArgumentParser parser, final ValueCompleter completer) { if (parser == completer && parser.hasClientNativeCompletions()) { @@ -57,13 +58,15 @@ public SpongeArgumentCommandNodeBuilder( final ValueCompleter completer, final @Nullable ValueParameterModifier modifier, final @Nullable ValueUsage usage, - final @Nullable String suffix) { + final @Nullable String suffix, + final boolean isOptional) { this.key = key; this.type = type; this.completer = SpongeArgumentCommandNodeBuilder.filterNativeCompleters(type, completer); this.modifier = modifier; this.usage = usage; this.suffix = suffix; + this.isOptional = isOptional; } @Override @@ -84,7 +87,8 @@ public SpongeArgumentCommandNode build() { this.getRedirectModifier(), this.isFork(), this.suffix == null ? this.key.key() : this.key.key() + "_" + this.suffix, - this.modifier); + this.modifier, + this.isOptional); for (final CommandNode child : this.getArguments()) { node.addChild(child); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/PhaseContext.java b/src/main/java/org/spongepowered/common/event/tracking/PhaseContext.java index e655e457281..bfa5a3dc810 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/PhaseContext.java +++ b/src/main/java/org/spongepowered/common/event/tracking/PhaseContext.java @@ -368,6 +368,10 @@ public void printTrace(final PrettyPrinter printer) { return null; } + public boolean isClientSide() { + return false; + } + protected boolean isRunaway(final PhaseContext phaseContext) { return phaseContext.getClass() == this.getClass(); } 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..34a32d058a4 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 @@ -364,8 +364,8 @@ default EffectTransactor logOpenInventory(final Player player) { return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); } - default EffectTransactor logCloseInventory(final Player player, final boolean clientSource) { - final CloseMenuTransaction transaction = new CloseMenuTransaction(player, clientSource); + default EffectTransactor logCloseInventory(final PhaseContext<@NonNull ?> current, final Player player) { + final CloseMenuTransaction transaction = new CloseMenuTransaction(player, current.isClientSide()); this.logTransaction(transaction); return this.pushEffect(new ResultingTransactionBySideEffect(InventoryEffect.getInstance())); } diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/BasicPacketContext.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/BasicPacketContext.java index 38db83cc709..f808513bf1c 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/BasicPacketContext.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/BasicPacketContext.java @@ -35,10 +35,6 @@ public BasicPacketContext(final PacketState state, final Pha @SuppressWarnings("unchecked") @Override public boolean hasCaptures() { - if (this.state == PacketPhase.General.CLOSE_WINDOW) { - return true; - } - return super.hasCaptures(); } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/BasicPacketState.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/BasicPacketState.java index 0f939708d82..172e917fe1f 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/BasicPacketState.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/BasicPacketState.java @@ -24,9 +24,6 @@ */ package org.spongepowered.common.event.tracking.phase.packet; -import net.minecraft.server.level.ServerPlayer; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.common.bridge.server.TickTaskBridge; import org.spongepowered.common.event.tracking.PhaseTracker; public class BasicPacketState extends PacketState { @@ -35,14 +32,4 @@ public class BasicPacketState extends PacketState { public BasicPacketContext createNewContext(final PhaseTracker tracker) { return new BasicPacketContext(this, tracker); } - - @Override - public void foldContextForThread(final BasicPacketContext context, final TickTaskBridge returnValue) { - final @Nullable ServerPlayer source = context.getPacketPlayer(); - returnValue.bridge$contextShift((c, f) -> { - if (source != null) { - f.pushCause(source); - } - }); - } } diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhase.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhase.java index 74d5759cbef..e0883694a46 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhase.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketPhase.java @@ -62,6 +62,7 @@ import org.spongepowered.common.event.tracking.phase.packet.drag.PrimaryDragInventoryStopState; import org.spongepowered.common.event.tracking.phase.packet.drag.SecondaryDragInventoryStopState; import org.spongepowered.common.event.tracking.phase.packet.inventory.BasicInventoryPacketState; +import org.spongepowered.common.event.tracking.phase.packet.inventory.CloseWindowContext; import org.spongepowered.common.event.tracking.phase.packet.inventory.CloseWindowState; import org.spongepowered.common.event.tracking.phase.packet.inventory.CreativeInventoryPacketState; import org.spongepowered.common.event.tracking.phase.packet.inventory.DoubleClickInventoryState; @@ -127,7 +128,7 @@ public static final class General { static final IPhaseState STOP_SPRINTING = new BasicPacketState(); static final IPhaseState STOP_SLEEPING = new StopSleepingPacketState(); static final IPhaseState TAB_COMPLETE = new BasicPacketState(); - public static final IPhaseState CLOSE_WINDOW = new CloseWindowState(); + public static final IPhaseState CLOSE_WINDOW = new CloseWindowState(); public static final IPhaseState UPDATE_SIGN = new BasicPacketState(); static final IPhaseState STOP_RIDING_JUMP = new BasicPacketState(); static final IPhaseState HANDLED_EXTERNALLY = new UnknownPacketState(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketState.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketState.java index bca22bedb47..e6c2cf7122f 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketState.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/PacketState.java @@ -28,13 +28,16 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.chunk.LevelChunk; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.CauseStackManager; import org.spongepowered.api.event.cause.entity.SpawnType; import org.spongepowered.api.event.cause.entity.SpawnTypes; +import org.spongepowered.common.bridge.server.TickTaskBridge; import org.spongepowered.common.bridge.world.level.chunk.LevelChunkBridge; import org.spongepowered.common.entity.PlayerTracker; import org.spongepowered.common.event.tracking.IPhaseState; @@ -106,6 +109,16 @@ protected boolean alwaysUnwinds() { return false; } + @Override + public void foldContextForThread(final P context, final TickTaskBridge returnValue) { + final @Nullable ServerPlayer source = context.getPacketPlayer(); + returnValue.bridge$contextShift((c, f) -> { + if (source != null) { + f.pushCause(source); + } + }); + } + private final String desc = TrackingUtil.phaseStateToString("Packet", this); @Override diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/inventory/CloseWindowContext.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/inventory/CloseWindowContext.java new file mode 100644 index 00000000000..a1dc96d633f --- /dev/null +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/inventory/CloseWindowContext.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.phase.packet.inventory; + +import org.spongepowered.common.event.tracking.PhaseTracker; +import org.spongepowered.common.event.tracking.phase.packet.PacketContext; +import org.spongepowered.common.event.tracking.phase.packet.PacketState; + +public final class CloseWindowContext extends PacketContext { + + private boolean clientSide = true; + + public CloseWindowContext(final PacketState state, final PhaseTracker tracker) { + super(state, tracker); + } + + public CloseWindowContext isClientSide(final boolean clientSide) { + this.clientSide = clientSide; + return this; + } + + @Override + public boolean hasCaptures() { + return true; + } + + @Override + public boolean isClientSide() { + return this.clientSide; + } + + @Override + protected void reset() { + super.reset(); + this.clientSide = true; + } +} diff --git a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/inventory/CloseWindowState.java b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/inventory/CloseWindowState.java index 97c0709750f..d524a768472 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/phase/packet/inventory/CloseWindowState.java +++ b/src/main/java/org/spongepowered/common/event/tracking/phase/packet/inventory/CloseWindowState.java @@ -34,23 +34,28 @@ import org.spongepowered.api.event.cause.entity.SpawnTypes; import org.spongepowered.api.event.entity.SpawnEntityEvent; import org.spongepowered.api.util.Tuple; +import org.spongepowered.common.event.tracking.PhaseTracker; import org.spongepowered.common.event.tracking.context.transaction.GameTransaction; import org.spongepowered.common.event.tracking.context.transaction.world.SpawnEntityTransaction; -import org.spongepowered.common.event.tracking.phase.packet.BasicPacketContext; -import org.spongepowered.common.event.tracking.phase.packet.BasicPacketState; +import org.spongepowered.common.event.tracking.phase.packet.PacketState; import java.util.function.Supplier; import java.util.stream.Collectors; -public final class CloseWindowState extends BasicPacketState { +public final class CloseWindowState extends PacketState { @Override - public Supplier getSpawnTypeForTransaction(final BasicPacketContext context, final Entity entityToSpawn) { + protected CloseWindowContext createNewContext(final PhaseTracker tracker) { + return new CloseWindowContext(this, tracker); + } + + @Override + public Supplier getSpawnTypeForTransaction(final CloseWindowContext context, final Entity entityToSpawn) { return SpawnTypes.DROPPED_ITEM; } @Override - public SpawnEntityEvent createSpawnEvent(final BasicPacketContext context, final @Nullable GameTransaction<@NonNull ?> parent, + public SpawnEntityEvent createSpawnEvent(final CloseWindowContext context, final @Nullable GameTransaction<@NonNull ?> parent, final ImmutableList> collect, final Cause currentCause) { return SpongeEventFactory.createDropItemEventClose(currentCause, collect.stream() diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/server/level/ServerPlayerMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/server/level/ServerPlayerMixin_Inventory_API.java index 8bbb25f2918..dddc6404319 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/server/level/ServerPlayerMixin_Inventory_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/server/level/ServerPlayerMixin_Inventory_API.java @@ -30,12 +30,12 @@ import org.spongepowered.api.item.inventory.Container; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.bridge.world.inventory.container.ContainerBridge; 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.TrackingUtil; -import org.spongepowered.common.event.tracking.context.transaction.EffectTransactor; import org.spongepowered.common.event.tracking.phase.packet.PacketPhase; import org.spongepowered.common.mixin.inventory.api.world.entity.player.PlayerMixin_Inventory_API; @@ -44,6 +44,8 @@ @Mixin(net.minecraft.server.level.ServerPlayer.class) public abstract class ServerPlayerMixin_Inventory_API extends PlayerMixin_Inventory_API implements ServerPlayer { + @Shadow public abstract void shadow$doCloseContainer(); + @Override public Optional openInventory() { return Optional.ofNullable((Container) this.containerMenu); @@ -75,12 +77,10 @@ public boolean closeInventory() throws IllegalArgumentException { try (final PhaseContext<@NonNull ?> ctx = PacketPhase.General.CLOSE_WINDOW.createPhaseContext(PhaseTracker.getWorldInstance(player.serverLevel())) .source(this) .packetPlayer(player) + .isClientSide(false) ) { ctx.buildAndSwitch(); - try (final EffectTransactor ignored = ctx.getTransactor().logCloseInventory(player, false)) { - this.containerMenu.removed(player); // Drop & capture cursor item - this.containerMenu.broadcastChanges(); - } + this.shadow$doCloseContainer(); if (!TrackingUtil.processBlockCaptures(ctx)) { return false; diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/level/ServerPlayerMixin_Inventory.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/level/ServerPlayerMixin_Inventory.java index 9e01385102d..1c2f1014325 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/level/ServerPlayerMixin_Inventory.java +++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/event/server/level/ServerPlayerMixin_Inventory.java @@ -36,12 +36,10 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.HorseInventoryMenu; -import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.Sponge; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.Slot; import org.spongepowered.api.item.inventory.equipment.EquipmentType; @@ -60,7 +58,6 @@ 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.event.tracking.phase.packet.PacketPhase; import org.spongepowered.common.event.tracking.phase.packet.inventory.SwapHandItemsState; import org.spongepowered.common.inventory.adapter.InventoryAdapter; import org.spongepowered.common.inventory.fabric.Fabric; @@ -124,29 +121,6 @@ public abstract class ServerPlayerMixin_Inventory extends PlayerMixin_Inventory } } - @Override - protected void inventory$switchToCloseWindowState(final InventoryMenu container, final Player player) { - // Corner case where the server is shutting down on the client, the server player is also being killed off. - if (Sponge.isServerAvailable() && Sponge.isClientAvailable()) { - container.removed(player); - return; - } - final ServerPlayer serverPlayer = (ServerPlayer) player; - - try (final PhaseContext<@NonNull ?> ctx = PacketPhase.General.CLOSE_WINDOW.createPhaseContext(PhaseTracker.getWorldInstance(this.shadow$serverLevel())) - .source(serverPlayer) - .packetPlayer(serverPlayer) - ) { - ctx.buildAndSwitch(); - try (final EffectTransactor ignored = ctx.getTransactor().logCloseInventory(player, true)) { - container.removed(player); // Drop & capture cursor item - container.broadcastChanges(); - } - } - this.impl$onCloseMenu(); // Handle Viewers - } - - @Override protected void inventory$onTouch(final Entity entity, final Player player) { if (entity instanceof ItemEntity) { entity.playerTouch(player); // ItemEntityMixin_Inventory creates transactions for pickup event @@ -255,4 +229,15 @@ public abstract class ServerPlayerMixin_Inventory extends PlayerMixin_Inventory } throw new IllegalStateException("Unknown Lens for Player Inventory: " + lens.getClass().getName()); } + + @Redirect(method = "doCloseContainer", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/AbstractContainerMenu;removed(Lnet/minecraft/world/entity/player/Player;)V")) + private void impl$onHandleContainerClose(final AbstractContainerMenu instance, final Player player) { + final PhaseContext<@NonNull ?> context = PhaseTracker.getWorldInstance((ServerLevel)player.level()).getPhaseContext(); + final TransactionalCaptureSupplier transactor = context.getTransactor(); + try (final EffectTransactor ignored = transactor.logCloseInventory(context, player)) { + instance.removed(player); + instance.broadcastChanges(); + } + } } 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..2396528be0f 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 @@ -130,17 +130,6 @@ public class ServerGamePacketListenerImplMixin_Inventory { // TrackingUtil.processBlockCaptures called by UseItemPacketState } - @Redirect(method = "handleContainerClose", - at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;doCloseContainer()V")) - private void impl$onHandleContainerClose(final ServerPlayer player) { - final PhaseContext<@NonNull ?> context = PhaseTracker.getWorldInstance(this.player.serverLevel()).getPhaseContext(); - final TransactionalCaptureSupplier transactor = context.getTransactor(); - try (final EffectTransactor ignored = transactor.logCloseInventory(player, true)) { - this.player.containerMenu.removed(player); - this.player.containerMenu.broadcastChanges(); - } - } - @Redirect(method = "handleRenameItem(Lnet/minecraft/network/protocol/game/ServerboundRenameItemPacket;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/AnvilMenu;setItemName(Ljava/lang/String;)Z")) private boolean impl$onHandleRenameItem(final AnvilMenu menu, final String name) {