From 418420523ac0474a811a6a6fba0c4bfacbefd65b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 4 Oct 2019 16:53:48 +0100 Subject: [PATCH] Proxy the current turtle's inventory Previously we were just returning the current tile. However, if someone was holding a reference to this inventory (such as a GUI), then it'd be outdated and invalid once the turtle had moved. This caused a couple of issues: - turtle_inventory events would not be fired when moving items in the turtle GUI. - As of 75e2845c01532987026ed028e97bab74e274a9dd, turtles would no longer share their inventory state after moving. Thus, removing items from a GUI using an invalid inventory would move them from an old tile, duplicating the items. Fixes #298, fixes #300 --- .../media/inventory/ContainerHeldItem.java | 3 +- .../shared/turtle/blocks/TileTurtle.java | 4 +- .../shared/turtle/core/TurtleBrain.java | 13 +- .../shared/util/InventoryDelegate.java | 146 ++++++++++++++++++ .../shared/util/InventoryUtil.java | 6 - 5 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java diff --git a/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java index 4daa4fe34..cc059646b 100644 --- a/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.media.inventory; -import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; import net.minecraft.item.ItemStack; @@ -22,7 +21,7 @@ public class ContainerHeldItem extends Container public ContainerHeldItem( EntityPlayer player, EnumHand hand ) { m_hand = hand; - m_stack = InventoryUtil.copyItem( player.getHeldItem( hand ) ); + m_stack = player.getHeldItem( hand ).copy(); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index e70c7d333..e4b23311c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -224,7 +224,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default m_inventoryChanged = false; for( int n = 0; n < getSizeInventory(); n++ ) { - m_previousInventory.set( n, InventoryUtil.copyItem( getStackInSlot( n ) ) ); + m_previousInventory.set( n, getStackInSlot( n ).copy() ); } } } @@ -268,7 +268,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default if( slot < getSizeInventory() ) { m_inventory.set( slot, new ItemStack( tag ) ); - m_previousInventory.set( slot, InventoryUtil.copyItem( m_inventory.get( slot ) ) ); + m_previousInventory.set( slot, m_inventory.get( slot ).copy() ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 494b8750d..bf68e2b3f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -20,10 +20,7 @@ import dan200.computercraft.shared.computer.blocks.TileComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; -import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.ColourUtils; -import dan200.computercraft.shared.util.Holiday; -import dan200.computercraft.shared.util.HolidayUtil; +import dan200.computercraft.shared.util.*; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.MoverType; @@ -40,6 +37,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.wrapper.InvWrapper; import javax.annotation.Nonnull; import java.util.*; @@ -53,6 +51,9 @@ public class TurtleBrain implements ITurtleAccess private ComputerProxy m_proxy; private GameProfile m_owningPlayer; + private final IInventory m_inventory = (InventoryDelegate) () -> m_owner; + private final IItemHandlerModifiable m_inventoryWrapper = new InvWrapper( m_inventory ); + private Queue m_commandQueue = new ArrayDeque<>(); private int m_commandsIssued = 0; @@ -531,14 +532,14 @@ public class TurtleBrain implements ITurtleAccess @Override public IInventory getInventory() { - return m_owner; + return m_inventory; } @Nonnull @Override public IItemHandlerModifiable getItemHandler() { - return m_owner.getItemHandler(); + return m_inventoryWrapper; } @Override diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java new file mode 100644 index 000000000..7f94d0460 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java @@ -0,0 +1,146 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; + +import javax.annotation.Nonnull; + +/** + * Provides a delegate over inventories. + * + * This may be used both on {@link net.minecraft.tileentity.TileEntity}s to redirect the inventory to another tile, + * and by other interfaces to have inventories which change their backing store. + */ +@FunctionalInterface +public interface InventoryDelegate extends IInventory +{ + IInventory getInventory(); + + @Override + default int getSizeInventory() + { + return getInventory().getSizeInventory(); + } + + @Override + default boolean isEmpty() + { + return getInventory().isEmpty(); + } + + @Nonnull + @Override + default ItemStack getStackInSlot( int slot ) + { + return getInventory().getStackInSlot( slot ); + } + + @Nonnull + @Override + default ItemStack decrStackSize( int slot, int count ) + { + return getInventory().decrStackSize( slot, count ); + } + + @Nonnull + @Override + default ItemStack removeStackFromSlot( int slot ) + { + return getInventory().removeStackFromSlot( slot ); + } + + @Override + default void setInventorySlotContents( int slot, ItemStack stack ) + { + getInventory().setInventorySlotContents( slot, stack ); + } + + @Override + default int getInventoryStackLimit() + { + return getInventory().getInventoryStackLimit(); + } + + @Override + default void markDirty() + { + getInventory().markDirty(); + } + + @Override + default boolean isUsableByPlayer( @Nonnull EntityPlayer player ) + { + return getInventory().isUsableByPlayer( player ); + } + + @Override + default void openInventory( @Nonnull EntityPlayer player ) + { + getInventory().openInventory( player ); + } + + @Override + default void closeInventory( @Nonnull EntityPlayer player ) + { + getInventory().closeInventory( player ); + } + + @Override + default boolean isItemValidForSlot( int slot, @Nonnull ItemStack stack ) + { + return getInventory().isItemValidForSlot( slot, stack ); + } + + @Override + default int getField( int id ) + { + return getInventory().getField( id ); + } + + @Override + default void setField( int id, int val ) + { + getInventory().setField( id, val ); + + } + + @Override + default int getFieldCount() + { + return getInventory().getFieldCount(); + } + + @Override + default void clear() + { + getInventory().clear(); + } + + @Nonnull + @Override + default String getName() + { + return getInventory().getName(); + } + + @Override + default boolean hasCustomName() + { + return getInventory().hasCustomName(); + } + + @Nonnull + @Override + default ITextComponent getDisplayName() + { + return getInventory().getDisplayName(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 46a878f49..ae0434c9f 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -69,12 +69,6 @@ public final class InventoryUtil return shareTagA.equals( shareTagB ); } - @Nonnull - public static ItemStack copyItem( @Nonnull ItemStack a ) - { - return a.copy(); - } - // Methods for finding inventories: public static IItemHandler getInventory( World world, BlockPos pos, EnumFacing side )