Search in sources :

Example 6 with IMixinContainer

use of org.spongepowered.common.interfaces.IMixinContainer in project SpongeCommon by SpongePowered.

the class MixinEntityPlayerMP method onCloseContainer.

@Inject(method = "closeContainer", at = @At("RETURN"))
public void onCloseContainer(CallbackInfo ci) {
    IMixinContainer mixinContainer = (IMixinContainer) this.openContainer;
    // Safety measure to avoid memory leaks as mods may call this directly
    if (mixinContainer.capturingInventory()) {
        mixinContainer.setCaptureInventory(false);
        mixinContainer.getCapturedTransactions().clear();
    }
}
Also used : IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) Inject(org.spongepowered.asm.mixin.injection.Inject)

Example 7 with IMixinContainer

use of org.spongepowered.common.interfaces.IMixinContainer in project SpongeCommon by SpongePowered.

the class BasicInventoryPacketState method unwind.

@Override
public void unwind(InventoryPacketContext context) {
    final EntityPlayerMP player = context.getPacketPlayer();
    // The server will disable the player's crafting after receiving a
    // client packet
    // that did not pass validation (server click item != packet click item)
    // The server then sends a SPacketConfirmTransaction and waits for a
    // CPacketConfirmTransaction to re-enable crafting confirming that the
    // client
    // acknowledged the denied transaction.
    // To detect when this happens, we turn off capturing so we can avoid
    // firing
    // invalid events.
    // See MixinNetHandlerPlayServer processClickWindow redirect for rest of
    // fix.
    // --bloodmc
    final IMixinContainer mixinContainer = ContainerUtil.toMixin(player.openContainer);
    if (!mixinContainer.capturingInventory()) {
        mixinContainer.getCapturedTransactions().clear();
        return;
    }
    // TODO clear this shit out of the context
    final CPacketClickWindow packetIn = context.getPacket();
    final ItemStackSnapshot lastCursor = context.getCursor();
    final ItemStackSnapshot newCursor = ItemStackUtil.snapshotOf(player.inventory.getItemStack());
    final Transaction<ItemStackSnapshot> transaction = new Transaction<>(lastCursor, newCursor);
    final net.minecraft.inventory.Container openContainer = player.openContainer;
    final List<SlotTransaction> slotTransactions = mixinContainer.getCapturedTransactions();
    final int usedButton = packetIn.getUsedButton();
    final List<Entity> capturedItems = new ArrayList<>();
    for (EntityItem entityItem : context.getCapturedItems()) {
        capturedItems.add(EntityUtil.fromNative(entityItem));
    }
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(openContainer);
        Sponge.getCauseStackManager().pushCause(player);
        final ClickInventoryEvent inventoryEvent;
        inventoryEvent = this.createInventoryEvent(player, ContainerUtil.fromNative(openContainer), transaction, Lists.newArrayList(slotTransactions), capturedItems, usedButton);
        // If this happens and we captured no entities, avoid firing events
        if (mixinContainer.getCapturedTransactions().isEmpty() && capturedItems.isEmpty() && transaction.getOriginal().equals(transaction.getFinal())) {
            mixinContainer.setCaptureInventory(false);
            return;
        }
        if (inventoryEvent != null) {
            // Don't fire inventory drop events when there are no entities
            if (inventoryEvent instanceof AffectEntityEvent && ((AffectEntityEvent) inventoryEvent).getEntities().isEmpty()) {
                slotTransactions.clear();
                mixinContainer.setCaptureInventory(false);
                return;
            }
            // packet has everything we want.
            if (!(inventoryEvent instanceof ClickInventoryEvent.Drag)) {
                PacketPhaseUtil.validateCapturedTransactions(packetIn.getSlotId(), openContainer, inventoryEvent.getTransactions());
            }
            SpongeImpl.postEvent(inventoryEvent);
            if (inventoryEvent.isCancelled() || PacketPhaseUtil.allTransactionsInvalid(inventoryEvent.getTransactions())) {
                if (inventoryEvent instanceof ClickInventoryEvent.Drop) {
                    capturedItems.clear();
                }
                // Restore cursor
                if (inventoryEvent.isCancelled() || !inventoryEvent.getCursorTransaction().isValid()) {
                    PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getOriginal());
                } else if (inventoryEvent.getCursorTransaction().getCustom().isPresent()) {
                    PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getFinal());
                }
                // Restore target slots
                PacketPhaseUtil.handleSlotRestore(player, openContainer, inventoryEvent.getTransactions(), true);
            } else {
                PacketPhaseUtil.handleSlotRestore(player, openContainer, inventoryEvent.getTransactions(), false);
                // Handle cursor
                if (!inventoryEvent.getCursorTransaction().isValid()) {
                    PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getOriginal());
                } else if (inventoryEvent.getCursorTransaction().getCustom().isPresent()) {
                    PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getFinal());
                } else if (inventoryEvent instanceof ClickInventoryEvent.Drag) {
                    int increment;
                    increment = slotTransactions.stream().filter((t) -> !t.isValid()).mapToInt((t) -> t.getFinal().getQuantity()).sum();
                    final ItemStack cursor = inventoryEvent.getCursorTransaction().getFinal().createStack();
                    cursor.setQuantity(cursor.getQuantity() + increment);
                    PacketPhaseUtil.handleCustomCursor(player, cursor.createSnapshot());
                } else if (inventoryEvent instanceof ClickInventoryEvent.Double && !(inventoryEvent instanceof ClickInventoryEvent.Shift)) {
                    int decrement;
                    decrement = slotTransactions.stream().filter((t) -> !t.isValid()).mapToInt((t) -> t.getOriginal().getQuantity()).sum();
                    final ItemStack cursor = inventoryEvent.getCursorTransaction().getFinal().createStack();
                    cursor.setQuantity(cursor.getQuantity() - decrement);
                    PacketPhaseUtil.handleCustomCursor(player, cursor.createSnapshot());
                }
                if (inventoryEvent instanceof SpawnEntityEvent) {
                    processSpawnedEntities(player, (SpawnEntityEvent) inventoryEvent);
                } else if (!context.getCapturedEntitySupplier().isEmpty()) {
                    SpawnEntityEvent spawnEntityEvent = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), context.getCapturedEntities());
                    SpongeImpl.postEvent(spawnEntityEvent);
                    if (!spawnEntityEvent.isCancelled()) {
                        processSpawnedEntities(player, spawnEntityEvent);
                    }
                }
            }
        }
    }
    slotTransactions.clear();
    mixinContainer.setCaptureInventory(false);
}
Also used : SpongeImpl(org.spongepowered.common.SpongeImpl) CPacketClickWindow(net.minecraft.network.play.client.CPacketClickWindow) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) ItemStackUtil(org.spongepowered.common.item.inventory.util.ItemStackUtil) EntityPlayerMP(net.minecraft.entity.player.EntityPlayerMP) ArrayList(java.util.ArrayList) ContainerUtil(org.spongepowered.common.item.inventory.util.ContainerUtil) ItemStack(org.spongepowered.api.item.inventory.ItemStack) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Lists(com.google.common.collect.Lists) AffectEntityEvent(org.spongepowered.api.event.entity.AffectEntityEvent) IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) CauseStackManager(org.spongepowered.api.event.CauseStackManager) ClickInventoryEvent(org.spongepowered.api.event.item.inventory.ClickInventoryEvent) Transaction(org.spongepowered.api.data.Transaction) Nullable(javax.annotation.Nullable) EntityItem(net.minecraft.entity.item.EntityItem) Packet(net.minecraft.network.Packet) SpongeEventFactory(org.spongepowered.api.event.SpongeEventFactory) Sponge(org.spongepowered.api.Sponge) SpawnEntityEvent(org.spongepowered.api.event.entity.SpawnEntityEvent) Entity(org.spongepowered.api.entity.Entity) EntityUtil(org.spongepowered.common.entity.EntityUtil) List(java.util.List) Container(org.spongepowered.api.item.inventory.Container) Entity(org.spongepowered.api.entity.Entity) CPacketClickWindow(net.minecraft.network.play.client.CPacketClickWindow) ArrayList(java.util.ArrayList) CauseStackManager(org.spongepowered.api.event.CauseStackManager) EntityItem(net.minecraft.entity.item.EntityItem) ClickInventoryEvent(org.spongepowered.api.event.item.inventory.ClickInventoryEvent) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) SpawnEntityEvent(org.spongepowered.api.event.entity.SpawnEntityEvent) IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Transaction(org.spongepowered.api.data.Transaction) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) EntityPlayerMP(net.minecraft.entity.player.EntityPlayerMP) AffectEntityEvent(org.spongepowered.api.event.entity.AffectEntityEvent) ItemStack(org.spongepowered.api.item.inventory.ItemStack)

Example 8 with IMixinContainer

use of org.spongepowered.common.interfaces.IMixinContainer in project SpongeCommon by SpongePowered.

the class DropInventoryState method unwind.

@Override
public void unwind(InventoryPacketContext context) {
    final EntityPlayerMP player = context.getPacketPlayer();
    final ItemStack usedStack = context.getItemUsed();
    final ItemStackSnapshot usedSnapshot = ItemStackUtil.snapshotOf(usedStack);
    final Entity spongePlayer = EntityUtil.fromNative(player);
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(spongePlayer);
        Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
        context.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blocks -> TrackingUtil.processBlockCaptures(blocks, this, context));
        context.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(items -> {
            final ArrayList<Entity> entities = new ArrayList<>();
            for (EntityItem item : items) {
                entities.add(EntityUtil.fromNative(item));
            }
            final DropItemEvent.Dispense dropItemEvent = SpongeEventFactory.createDropItemEventDispense(Sponge.getCauseStackManager().getCurrentCause(), entities);
            SpongeImpl.postEvent(dropItemEvent);
            if (!dropItemEvent.isCancelled()) {
                processSpawnedEntities(player, dropItemEvent);
            }
        });
        final IMixinContainer mixinContainer = ContainerUtil.toMixin(player.openContainer);
        mixinContainer.setCaptureInventory(false);
        mixinContainer.getCapturedTransactions().clear();
    }
}
Also used : IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) Entity(org.spongepowered.api.entity.Entity) DropItemEvent(org.spongepowered.api.event.item.inventory.DropItemEvent) CauseStackManager(org.spongepowered.api.event.CauseStackManager) ArrayList(java.util.ArrayList) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) EntityPlayerMP(net.minecraft.entity.player.EntityPlayerMP) ItemStack(org.spongepowered.api.item.inventory.ItemStack) EntityItem(net.minecraft.entity.item.EntityItem)

Example 9 with IMixinContainer

use of org.spongepowered.common.interfaces.IMixinContainer in project SpongeCommon by SpongePowered.

the class DropItemWithHotkeyState method unwind.

@Override
public void unwind(InventoryPacketContext context) {
    final EntityPlayerMP player = context.getPacketPlayer();
    // final ItemStack usedStack = context.getItemUsed();
    // final ItemStackSnapshot usedSnapshot = ItemStackUtil.snapshotOf(usedStack);
    final Entity spongePlayer = EntityUtil.fromNative(player);
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(spongePlayer);
        Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
        context.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blocks -> TrackingUtil.processBlockCaptures(blocks, this, context));
        context.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(items -> {
            final ArrayList<Entity> entities = new ArrayList<>();
            for (EntityItem item : items) {
                entities.add(EntityUtil.fromNative(item));
            }
            int usedButton = 0;
            if (context.getPacket() instanceof CPacketPlayerDigging) {
                final CPacketPlayerDigging packetIn = context.getPacket();
                usedButton = packetIn.getAction() == CPacketPlayerDigging.Action.DROP_ITEM ? PacketPhase.PACKET_BUTTON_PRIMARY_ID : 1;
            } else {
                final CPacketClickWindow packetIn = context.getPacket();
                usedButton = packetIn.getUsedButton();
            }
            Transaction<ItemStackSnapshot> cursorTrans = new Transaction<>(ItemStackSnapshot.NONE, ItemStackSnapshot.NONE);
            final IMixinContainer mixinContainer = ContainerUtil.toMixin(player.openContainer);
            List<SlotTransaction> slotTrans = mixinContainer.getCapturedTransactions();
            ClickInventoryEvent.Drop dropItemEvent = ((DropItemWithHotkeyState) this).createInventoryEvent(player, ContainerUtil.fromNative(player.openContainer), cursorTrans, Lists.newArrayList(slotTrans), entities, usedButton);
            SpongeImpl.postEvent(dropItemEvent);
            if (dropItemEvent.isCancelled() || PacketPhaseUtil.allTransactionsInvalid(dropItemEvent.getTransactions())) {
                ((IMixinEntityPlayerMP) player).restorePacketItem(EnumHand.MAIN_HAND);
                PacketPhaseUtil.handleSlotRestore(player, player.openContainer, dropItemEvent.getTransactions(), true);
            } else {
                processSpawnedEntities(player, dropItemEvent);
            }
            slotTrans.clear();
            mixinContainer.setCaptureInventory(false);
        });
        context.getCapturedEntityDropSupplier().acceptIfNotEmpty(itemMapping -> {
        });
        final IMixinContainer mixinContainer = ContainerUtil.toMixin(player.openContainer);
        mixinContainer.setCaptureInventory(false);
        mixinContainer.getCapturedTransactions().clear();
    }
}
Also used : CPacketPlayerDigging(net.minecraft.network.play.client.CPacketPlayerDigging) Entity(org.spongepowered.api.entity.Entity) CPacketClickWindow(net.minecraft.network.play.client.CPacketClickWindow) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) ArrayList(java.util.ArrayList) ClickInventoryEvent(org.spongepowered.api.event.item.inventory.ClickInventoryEvent) IMixinEntityPlayerMP(org.spongepowered.common.interfaces.entity.player.IMixinEntityPlayerMP) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Transaction(org.spongepowered.api.data.Transaction) CauseStackManager(org.spongepowered.api.event.CauseStackManager) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) EntityPlayerMP(net.minecraft.entity.player.EntityPlayerMP) IMixinEntityPlayerMP(org.spongepowered.common.interfaces.entity.player.IMixinEntityPlayerMP) EntityItem(net.minecraft.entity.item.EntityItem)

Example 10 with IMixinContainer

use of org.spongepowered.common.interfaces.IMixinContainer in project SpongeCommon by SpongePowered.

the class SpongeCommonEventFactory method callInteractInventoryCloseEvent.

public static InteractInventoryEvent.Close callInteractInventoryCloseEvent(Container container, EntityPlayerMP player, ItemStackSnapshot lastCursor, ItemStackSnapshot newCursor, boolean clientSource) {
    Transaction<ItemStackSnapshot> cursorTransaction = new Transaction<>(lastCursor, newCursor);
    final InteractInventoryEvent.Close event = SpongeEventFactory.createInteractInventoryEventClose(Sponge.getCauseStackManager().getCurrentCause(), cursorTransaction, ContainerUtil.fromNative(container));
    SpongeImpl.postEvent(event);
    if (event.isCancelled()) {
        if (clientSource && container.getSlot(0) != null) {
            if (!(container instanceof ContainerPlayer)) {
                // Inventory closed by client, reopen window and send
                // container
                player.openContainer = container;
                final String guiId;
                final Slot slot = container.getSlot(0);
                final IInventory slotInventory = slot.inventory;
                if (slotInventory instanceof IInteractionObject) {
                    guiId = ((IInteractionObject) slotInventory).getGuiID();
                } else {
                    // expected fallback for unknown types
                    guiId = "minecraft:container";
                }
                slotInventory.openInventory(player);
                player.connection.sendPacket(new SPacketOpenWindow(container.windowId, guiId, slotInventory.getDisplayName(), slotInventory.getSizeInventory()));
                // resync data to client
                player.sendContainerToPlayer(container);
            } else {
            // TODO: Maybe print a warning or throw an exception here?
            // The player gui cannot be opened from the
            // server so allowing this event to be cancellable when the
            // GUI has been closed already would result
            // in opening the wrong GUI window.
            }
        }
        // Handle cursor
        if (!event.getCursorTransaction().isValid()) {
            handleCustomCursor(player, event.getCursorTransaction().getOriginal());
        }
    } else {
        IMixinContainer mixinContainer = (IMixinContainer) player.openContainer;
        mixinContainer.getCapturedTransactions().clear();
        mixinContainer.setCaptureInventory(false);
        // Handle cursor
        if (!event.getCursorTransaction().isValid()) {
            handleCustomCursor(player, event.getCursorTransaction().getOriginal());
        } else if (event.getCursorTransaction().getCustom().isPresent()) {
            handleCustomCursor(player, event.getCursorTransaction().getFinal());
        }
        if (!clientSource && player.openContainer != null && player.connection != null) {
            player.closeScreen();
        }
    }
    return event;
}
Also used : ContainerPlayer(net.minecraft.inventory.ContainerPlayer) IInventory(net.minecraft.inventory.IInventory) IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) IInteractionObject(net.minecraft.world.IInteractionObject) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Transaction(org.spongepowered.api.data.Transaction) InteractInventoryEvent(org.spongepowered.api.event.item.inventory.InteractInventoryEvent) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) SPacketSetSlot(net.minecraft.network.play.server.SPacketSetSlot) Slot(net.minecraft.inventory.Slot) SPacketOpenWindow(net.minecraft.network.play.server.SPacketOpenWindow)

Aggregations

IMixinContainer (org.spongepowered.common.interfaces.IMixinContainer)14 ItemStackSnapshot (org.spongepowered.api.item.inventory.ItemStackSnapshot)11 EntityPlayerMP (net.minecraft.entity.player.EntityPlayerMP)9 SlotTransaction (org.spongepowered.api.item.inventory.transaction.SlotTransaction)9 Transaction (org.spongepowered.api.data.Transaction)7 Entity (org.spongepowered.api.entity.Entity)7 CauseStackManager (org.spongepowered.api.event.CauseStackManager)7 ArrayList (java.util.ArrayList)5 EntityItem (net.minecraft.entity.item.EntityItem)5 ClickInventoryEvent (org.spongepowered.api.event.item.inventory.ClickInventoryEvent)5 ItemStack (org.spongepowered.api.item.inventory.ItemStack)5 SpawnEntityEvent (org.spongepowered.api.event.entity.SpawnEntityEvent)4 Nullable (javax.annotation.Nullable)3 Container (net.minecraft.inventory.Container)3 IInventory (net.minecraft.inventory.IInventory)3 SPacketSetSlot (net.minecraft.network.play.server.SPacketSetSlot)3 DropItemEvent (org.spongepowered.api.event.item.inventory.DropItemEvent)3 Inventory (org.spongepowered.api.item.inventory.Inventory)3 CraftingInventory (org.spongepowered.api.item.inventory.crafting.CraftingInventory)3 CraftingRecipe (org.spongepowered.api.item.recipe.crafting.CraftingRecipe)3