Search in sources :

Example 26 with SlotTransaction

use of org.spongepowered.api.item.inventory.transaction.SlotTransaction in project SpongeCommon by SpongePowered.

the class MixinEntityPlayer method onSetItemStackToSlot.

@Inject(method = "setItemStackToSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/NonNullList;set(ILjava/lang/Object;)Ljava/lang/Object;"))
private void onSetItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack, CallbackInfo ci) {
    if (((IMixinInventoryPlayer) this.inventory).capturesTransactions()) {
        if (slotIn == EntityEquipmentSlot.MAINHAND) {
            ItemStack orig = this.inventory.mainInventory.get(this.inventory.currentItem);
            Slot slot = ((PlayerInventory) this.inventory).getMain().getHotbar().getSlot(SlotIndex.of(this.inventory.currentItem)).get();
            ((IMixinInventoryPlayer) this.inventory).getCapturedTransactions().add(new SlotTransaction(slot, ItemStackUtil.snapshotOf(orig), ItemStackUtil.snapshotOf(stack)));
        } else if (slotIn == EntityEquipmentSlot.OFFHAND) {
            ItemStack orig = this.inventory.offHandInventory.get(0);
            Slot slot = ((PlayerInventory) this.inventory).getOffhand();
            ((IMixinInventoryPlayer) this.inventory).getCapturedTransactions().add(new SlotTransaction(slot, ItemStackUtil.snapshotOf(orig), ItemStackUtil.snapshotOf(stack)));
        } else if (slotIn.getSlotType() == EntityEquipmentSlot.Type.ARMOR) {
            ItemStack orig = this.inventory.armorInventory.get(slotIn.getIndex());
            Slot slot = ((PlayerInventory) this.inventory).getEquipment().getSlot(SlotIndex.of(slotIn.getIndex())).get();
            ((IMixinInventoryPlayer) this.inventory).getCapturedTransactions().add(new SlotTransaction(slot, ItemStackUtil.snapshotOf(orig), ItemStackUtil.snapshotOf(stack)));
        }
    }
}
Also used : IMixinInventoryPlayer(org.spongepowered.common.interfaces.entity.player.IMixinInventoryPlayer) EntityEquipmentSlot(net.minecraft.inventory.EntityEquipmentSlot) Slot(org.spongepowered.api.item.inventory.Slot) PlayerInventory(org.spongepowered.api.item.inventory.entity.PlayerInventory) ItemStack(net.minecraft.item.ItemStack) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Inject(org.spongepowered.asm.mixin.injection.Inject)

Example 27 with SlotTransaction

use of org.spongepowered.api.item.inventory.transaction.SlotTransaction in project SpongeCommon by SpongePowered.

the class MixinInventoryPlayer method onAdd.

@Redirect(method = "storePartialItemStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/InventoryPlayer;addResource(ILnet/minecraft/item/ItemStack;)I"))
public int onAdd(InventoryPlayer inv, int index, ItemStack stack) {
    if (this.doCapture) {
        // Capture items getting picked up
        Slot slot = index == 40 ? this.getOffhand() : getSpongeSlot(index);
        ItemStackSnapshot original = ItemStackUtil.snapshotOf(this.getStackInSlot(index));
        int result = this.addResource(index, stack);
        ItemStackSnapshot replacement = ItemStackUtil.snapshotOf(this.getStackInSlot(index));
        this.capturedTransactions.add(new SlotTransaction(slot, original, replacement));
        return result;
    }
    return this.addResource(index, stack);
}
Also used : Slot(org.spongepowered.api.item.inventory.Slot) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Redirect(org.spongepowered.asm.mixin.injection.Redirect)

Example 28 with SlotTransaction

use of org.spongepowered.api.item.inventory.transaction.SlotTransaction in project SpongeCommon by SpongePowered.

the class MixinContainer method detectAndSendChanges.

@Override
public void detectAndSendChanges(boolean captureOnly) {
    this.spongeInit();
    for (int i = 0; i < this.inventorySlots.size(); ++i) {
        final Slot slot = this.inventorySlots.get(i);
        final ItemStack itemstack = slot.getStack();
        ItemStack itemstack1 = this.inventoryItemStacks.get(i);
        if (!ItemStack.areItemStacksEqual(itemstack1, itemstack)) {
            // Sponge start
            if (this.captureInventory) {
                final ItemStackSnapshot originalItem = itemstack1.isEmpty() ? ItemStackSnapshot.NONE : ((org.spongepowered.api.item.inventory.ItemStack) itemstack1).createSnapshot();
                final ItemStackSnapshot newItem = itemstack.isEmpty() ? ItemStackSnapshot.NONE : ((org.spongepowered.api.item.inventory.ItemStack) itemstack).createSnapshot();
                org.spongepowered.api.item.inventory.Slot adapter = null;
                try {
                    adapter = this.getContainerSlot(i);
                    if (this.shiftCraft) {
                        this.capturedCraftShiftTransactions.add(new SlotTransaction(adapter, originalItem, newItem));
                    } else {
                        this.capturedSlotTransactions.add(new SlotTransaction(adapter, originalItem, newItem));
                    }
                } catch (IndexOutOfBoundsException e) {
                    SpongeImpl.getLogger().error("SlotIndex out of LensBounds! Did the Container change after creation?", e);
                }
                // We simply capture in order to send the proper changes back to client.
                if (captureOnly) {
                    continue;
                }
            }
            // Sponge end
            itemstack1 = itemstack.copy();
            this.inventoryItemStacks.set(i, itemstack1);
            for (IContainerListener listener : this.listeners) {
                listener.sendSlotContents((Container) (Object) this, i, itemstack1);
            }
        }
    }
}
Also used : SPacketSetSlot(net.minecraft.network.play.server.SPacketSetSlot) Slot(net.minecraft.inventory.Slot) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) IContainerListener(net.minecraft.inventory.IContainerListener) ItemStack(net.minecraft.item.ItemStack) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction)

Example 29 with SlotTransaction

use of org.spongepowered.api.item.inventory.transaction.SlotTransaction in project SpongeCommon by SpongePowered.

the class CommandState method unwind.

@Override
public void unwind(CommandPhaseContext phaseContext) {
    Optional<EntityPlayer> playerSource = phaseContext.getSource(EntityPlayer.class);
    if (playerSource.isPresent()) {
        // Post event for inventory changes
        ((IMixinInventoryPlayer) playerSource.get().inventory).setCapture(false);
        List<SlotTransaction> list = ((IMixinInventoryPlayer) playerSource.get().inventory).getCapturedTransactions();
        if (!list.isEmpty()) {
            ChangeInventoryEvent event = SpongeEventFactory.createChangeInventoryEvent(Sponge.getCauseStackManager().getCurrentCause(), ((Inventory) playerSource.get().inventory), list);
            SpongeImpl.postEvent(event);
            PacketPhaseUtil.handleSlotRestore(playerSource.get(), null, list, event.isCancelled());
            list.clear();
        }
    }
    final CommandSource sender = phaseContext.getSource(CommandSource.class).orElseThrow(TrackingUtil.throwWithContext("Expected to be capturing a Command Sender, but none found!", phaseContext));
    phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(list -> TrackingUtil.processBlockCaptures(list, this, phaseContext));
    try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(sender);
        Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.PLACEMENT);
        phaseContext.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
            // TODO the entity spawn causes are not likely valid,
            // need to investigate further.
            final SpawnEntityEvent spawnEntityEvent = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), entities);
            SpongeImpl.postEvent(spawnEntityEvent);
            if (!spawnEntityEvent.isCancelled()) {
                final boolean isPlayer = sender instanceof Player;
                final Player player = isPlayer ? (Player) sender : null;
                for (Entity entity : spawnEntityEvent.getEntities()) {
                    if (isPlayer) {
                        EntityUtil.toMixin(entity).setCreator(player.getUniqueId());
                    }
                    EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
                }
            }
        });
    }
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(sender);
        Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
        phaseContext.getCapturedEntityDropSupplier().acceptIfNotEmpty(uuidItemStackMultimap -> {
            for (Map.Entry<UUID, Collection<ItemDropData>> entry : uuidItemStackMultimap.asMap().entrySet()) {
                final UUID key = entry.getKey();
                @Nullable net.minecraft.entity.Entity foundEntity = null;
                for (WorldServer worldServer : WorldManager.getWorlds()) {
                    final net.minecraft.entity.Entity entityFromUuid = worldServer.getEntityFromUuid(key);
                    if (entityFromUuid != null) {
                        foundEntity = entityFromUuid;
                        break;
                    }
                }
                final Optional<Entity> affectedEntity = Optional.ofNullable((Entity) foundEntity);
                if (!affectedEntity.isPresent()) {
                    continue;
                }
                final Collection<ItemDropData> itemStacks = entry.getValue();
                if (itemStacks.isEmpty()) {
                    return;
                }
                final List<ItemDropData> items = new ArrayList<>();
                items.addAll(itemStacks);
                itemStacks.clear();
                final WorldServer minecraftWorld = EntityUtil.getMinecraftWorld(affectedEntity.get());
                if (!items.isEmpty()) {
                    final List<Entity> itemEntities = items.stream().map(data -> data.create(minecraftWorld)).map(EntityUtil::fromNative).collect(Collectors.toList());
                    Sponge.getCauseStackManager().pushCause(affectedEntity.get());
                    final DropItemEvent.Destruct destruct = SpongeEventFactory.createDropItemEventDestruct(Sponge.getCauseStackManager().getCurrentCause(), itemEntities);
                    SpongeImpl.postEvent(destruct);
                    Sponge.getCauseStackManager().popCause();
                    if (!destruct.isCancelled()) {
                        final boolean isPlayer = sender instanceof Player;
                        final Player player = isPlayer ? (Player) sender : null;
                        for (Entity entity : destruct.getEntities()) {
                            if (isPlayer) {
                                EntityUtil.toMixin(entity).setCreator(player.getUniqueId());
                            }
                            EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
                        }
                    }
                }
            }
        });
    }
}
Also used : Entity(org.spongepowered.api.entity.Entity) ArrayList(java.util.ArrayList) WorldServer(net.minecraft.world.WorldServer) CauseStackManager(org.spongepowered.api.event.CauseStackManager) UUID(java.util.UUID) DropItemEvent(org.spongepowered.api.event.item.inventory.DropItemEvent) IMixinInventoryPlayer(org.spongepowered.common.interfaces.entity.player.IMixinInventoryPlayer) EntityPlayer(net.minecraft.entity.player.EntityPlayer) Player(org.spongepowered.api.entity.living.player.Player) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) CommandSource(org.spongepowered.api.command.CommandSource) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) SpawnEntityEvent(org.spongepowered.api.event.entity.SpawnEntityEvent) IMixinInventoryPlayer(org.spongepowered.common.interfaces.entity.player.IMixinInventoryPlayer) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) EntityPlayer(net.minecraft.entity.player.EntityPlayer) ChangeInventoryEvent(org.spongepowered.api.event.item.inventory.ChangeInventoryEvent) Collection(java.util.Collection) ItemDropData(org.spongepowered.common.event.tracking.context.ItemDropData) Map(java.util.Map) Inventory(org.spongepowered.api.item.inventory.Inventory) Nullable(javax.annotation.Nullable)

Example 30 with SlotTransaction

use of org.spongepowered.api.item.inventory.transaction.SlotTransaction 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)

Aggregations

SlotTransaction (org.spongepowered.api.item.inventory.transaction.SlotTransaction)50 ItemStackSnapshot (org.spongepowered.api.item.inventory.ItemStackSnapshot)30 ArrayList (java.util.ArrayList)20 ItemStack (org.spongepowered.api.item.inventory.ItemStack)16 Inventory (org.spongepowered.api.item.inventory.Inventory)14 CraftingInventory (org.spongepowered.api.item.inventory.crafting.CraftingInventory)14 Entity (org.spongepowered.api.entity.Entity)13 Transaction (org.spongepowered.api.data.Transaction)11 ChangeInventoryEvent (org.spongepowered.api.event.item.inventory.ChangeInventoryEvent)11 ClickInventoryEvent (org.spongepowered.api.event.item.inventory.ClickInventoryEvent)11 Slot (org.spongepowered.api.item.inventory.Slot)11 Slot (net.minecraft.inventory.Slot)9 SPacketSetSlot (net.minecraft.network.play.server.SPacketSetSlot)9 AbstractSlot (org.lanternpowered.server.inventory.AbstractSlot)9 SpawnEntityEvent (org.spongepowered.api.event.entity.SpawnEntityEvent)9 IMixinContainer (org.spongepowered.common.interfaces.IMixinContainer)9 Nullable (javax.annotation.Nullable)8 ItemStack (net.minecraft.item.ItemStack)8 CauseStack (org.lanternpowered.server.event.CauseStack)8 List (java.util.List)7