diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java
index 2a8f1dd15..b18ba839e 100644
--- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java
+++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java
@@ -15,6 +15,7 @@ import net.minecraft.util.EnumFacing;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.Vec3d;
 import net.minecraft.world.World;
+import net.minecraftforge.items.IItemHandlerModifiable;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -138,10 +139,22 @@ public interface ITurtleAccess
      * Get the inventory of this turtle
      *
      * @return This turtle's inventory
+     * @see #getItemHandler()
      */
     @Nonnull
     IInventory getInventory();
 
+    /**
+     * Get the inventory of this turtle as an {@link IItemHandlerModifiable}.
+     *
+     * @return This turtle's inventory
+     * @see #getInventory() 
+     * @see IItemHandlerModifiable
+     * @see net.minecraftforge.items.CapabilityItemHandler#ITEM_HANDLER_CAPABILITY
+     */
+    @Nonnull
+    IItemHandlerModifiable getItemHandler();
+
     /**
      * Determine whether this turtle will require fuel when performing actions.
      *
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
index fbcf140d1..68d51853c 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
@@ -22,16 +22,27 @@ import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.inventory.IInventory;
 import net.minecraft.item.ItemStack;
 import net.minecraft.nbt.NBTTagCompound;
-import net.minecraft.util.*;
-import net.minecraft.util.math.*;
-import net.minecraft.util.text.*;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.EnumHand;
+import net.minecraft.util.ITickable;
+import net.minecraft.util.SoundEvent;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraft.util.text.TextComponentTranslation;
 import net.minecraft.world.World;
+import net.minecraftforge.common.capabilities.Capability;
+import net.minecraftforge.items.IItemHandlerModifiable;
+import net.minecraftforge.items.wrapper.InvWrapper;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
+import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
+
 public class TileDiskDrive extends TilePeripheralBase
     implements IInventory, ITickable
 {
@@ -50,6 +61,7 @@ public class TileDiskDrive extends TilePeripheralBase
     private final Map<IComputerAccess, MountInfo> m_computers;
 
     private ItemStack m_diskStack;
+    private final IItemHandlerModifiable m_itemHandler = new InvWrapper( this );
     private IMount m_diskMount;
     
     private boolean m_recordQueued;
@@ -681,4 +693,21 @@ public class TileDiskDrive extends TilePeripheralBase
     {
         ComputerCraft.playRecord( null, null, worldObj, getPos() );
     }
+
+    @Override
+    public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )
+    {
+        return capability == ITEM_HANDLER_CAPABILITY ||  super.hasCapability( capability, facing );
+    }
+
+    @Nonnull
+    @Override
+    public <T> T getCapability( @Nonnull Capability<T> capability, @Nullable EnumFacing facing )
+    {
+        if( capability == ITEM_HANDLER_CAPABILITY )
+        {
+            return ITEM_HANDLER_CAPABILITY.cast( m_itemHandler );
+        }
+        return super.getCapability( capability, facing );
+    }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
index 82ffeff4e..15c8277f3 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
@@ -23,13 +23,22 @@ import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import net.minecraft.nbt.NBTTagCompound;
 import net.minecraft.nbt.NBTTagList;
-import net.minecraft.util.*;
-import net.minecraft.util.math.*;
-import net.minecraft.util.text.*;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraft.util.text.TextComponentTranslation;
 import net.minecraft.world.World;
+import net.minecraftforge.common.capabilities.Capability;
 import net.minecraftforge.common.util.Constants;
+import net.minecraftforge.items.IItemHandlerModifiable;
+import net.minecraftforge.items.wrapper.InvWrapper;
+import net.minecraftforge.items.wrapper.SidedInvWrapper;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
 
 public class TilePrinter extends TilePeripheralBase
     implements IInventory, ISidedInventory
@@ -43,6 +52,9 @@ public class TilePrinter extends TilePeripheralBase
     // Members
 
     private final ItemStack[] m_inventory;
+    private final IItemHandlerModifiable m_itemHandlerAll = new InvWrapper( this );
+    private IItemHandlerModifiable[] m_itemHandlerSides;
+    
     private final Terminal m_page;
     private String m_pageTitle;
     private boolean m_printing;
@@ -532,7 +544,7 @@ public class TilePrinter extends TilePeripheralBase
             ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours );
             synchronized( m_inventory )
             {
-                ItemStack remainder = InventoryUtil.storeItems( stack, this, 7, 6, 7 );
+                ItemStack remainder = InventoryUtil.storeItems( stack, m_itemHandlerAll, 7, 6, 7 );
                 if( remainder == null )
                 {
                     m_printing = false;
@@ -596,4 +608,35 @@ public class TilePrinter extends TilePeripheralBase
             setAnim( anim );
         }
     }
+
+    @Override
+    public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )
+    {
+        return capability == ITEM_HANDLER_CAPABILITY || super.hasCapability( capability, facing );
+    }
+
+    @Nonnull
+    @Override
+    public <T> T getCapability( @Nonnull Capability<T> capability, @Nullable EnumFacing facing )
+    {
+        if( capability == ITEM_HANDLER_CAPABILITY )
+        {
+            if( facing == null )
+            {
+                return ITEM_HANDLER_CAPABILITY.cast( m_itemHandlerAll );
+            }
+            else
+            {
+                IItemHandlerModifiable[] handlers = m_itemHandlerSides;
+                if( handlers == null ) handlers = m_itemHandlerSides = new IItemHandlerModifiable[ 6 ];
+
+                int i = facing.ordinal();
+                IItemHandlerModifiable handler = handlers[ i ];
+                if( handler == null ) handler = handlers[ i ] = new SidedInvWrapper( this, facing );
+
+                return ITEM_HANDLER_CAPABILITY.cast( handler );
+            }
+        }
+        return super.getCapability( capability, facing );
+    }
 }
diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
index eda64b20e..efb3cf7e4 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
@@ -18,6 +18,7 @@ import dan200.computercraft.shared.util.WorldUtil;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.entity.player.InventoryPlayer;
 import net.minecraft.item.ItemStack;
+import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
 
 import javax.annotation.Nonnull;
 
@@ -100,7 +101,7 @@ public class PocketAPI implements ILuaAPI
                             ItemStack stack = previousUpgrade.getCraftingItem();
                             if( stack != null )
                             {
-                                stack = InventoryUtil.storeItems( stack, inventory, 0, 36, inventory.currentItem );
+                                stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem );
                                 if( stack != null )
                                 {
                                     WorldUtil.dropItemStack( stack, player.worldObj, player.posX, player.posY, player.posZ );
@@ -139,7 +140,7 @@ public class PocketAPI implements ILuaAPI
                         ItemStack stack = previousUpgrade.getCraftingItem();
                         if( stack != null )
                         {
-                            stack = InventoryUtil.storeItems( stack, inventory, 0, 36, inventory.currentItem );
+                            stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem );
                             if( stack != null )
                             {
                                 WorldUtil.dropItemStack( stack, player.worldObj, player.posX, player.posY, player.posZ );
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 6dfe23503..77b98d32e 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java
@@ -40,11 +40,17 @@ import net.minecraft.util.math.Vec3d;
 import net.minecraft.util.text.ITextComponent;
 import net.minecraft.util.text.TextComponentString;
 import net.minecraft.util.text.TextComponentTranslation;
+import net.minecraftforge.common.capabilities.Capability;
 import net.minecraftforge.common.util.Constants;
+import net.minecraftforge.items.IItemHandlerModifiable;
+import net.minecraftforge.items.wrapper.InvWrapper;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.util.List;
 
+import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
+
 public class TileTurtle extends TileComputerBase
     implements ITurtleTile, IInventory, ITickable
 {
@@ -65,6 +71,7 @@ public class TileTurtle extends TileComputerBase
 
     private ItemStack[] m_inventory;
     private ItemStack[] m_previousInventory;
+    private final IItemHandlerModifiable m_itemHandler = new InvWrapper( this );
     private boolean m_inventoryChanged;
     private TurtleBrain m_brain;
     private MoveState m_moveState;
@@ -714,4 +721,26 @@ public class TileTurtle extends TileComputerBase
         m_brain.setOwner( this );
         copy.m_moveState = MoveState.MOVED;
     }
+
+    public IItemHandlerModifiable getItemHandler()
+    {
+        return m_itemHandler;
+    }
+
+    @Override
+    public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )
+    {
+        return capability == ITEM_HANDLER_CAPABILITY ||  super.hasCapability( capability, facing );
+    }
+
+    @Nonnull
+    @Override
+    public <T> T getCapability( @Nonnull Capability<T> capability, @Nullable EnumFacing facing )
+    {
+        if( capability == ITEM_HANDLER_CAPABILITY )
+        {
+            return ITEM_HANDLER_CAPABILITY.cast( m_itemHandler );
+        }
+        return super.getCapability( capability, facing );
+    }
 }
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 7b859fa7c..b82b8f7de 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java
@@ -34,6 +34,7 @@ import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.Vec3d;
 import net.minecraft.world.World;
 import net.minecraftforge.common.util.Constants;
+import net.minecraftforge.items.IItemHandlerModifiable;
 
 import javax.annotation.Nonnull;
 import java.lang.ref.WeakReference;
@@ -649,6 +650,13 @@ public class TurtleBrain implements ITurtleAccess
         return m_owner;
     }
 
+    @Nonnull
+    @Override
+    public IItemHandlerModifiable getItemHandler()
+    {
+        return m_owner.getItemHandler();
+    }
+
     @Override
     public boolean isFuelNeeded()
     {
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java
index fabfa509e..dd2aef445 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java
@@ -40,7 +40,7 @@ public class TurtleCraftCommand implements ITurtleCommand
             // Store the results
             for( ItemStack stack : results )
             {
-                ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
                 if( remainder != null )
                 {
                     // Drop the remainder
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java
index 8d730f5cf..2ce5c6b5b 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java
@@ -17,6 +17,7 @@ import net.minecraft.item.ItemStack;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.EnumFacing;
 import net.minecraft.world.World;
+import net.minecraftforge.items.IItemHandler;
 
 import javax.annotation.Nonnull;
 
@@ -46,7 +47,7 @@ public class TurtleDropCommand implements ITurtleCommand
         EnumFacing direction = m_direction.toWorldDir( turtle );
 
         // Get things to drop
-        ItemStack stack = InventoryUtil.takeItems( m_quantity, turtle.getInventory(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
+        ItemStack stack = InventoryUtil.takeItems( m_quantity, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
         if( stack == null )
         {
             return TurtleCommandResult.failure( "No items to drop" );
@@ -58,15 +59,15 @@ public class TurtleDropCommand implements ITurtleCommand
         BlockPos newPosition = oldPosition.offset( direction );
         EnumFacing side = direction.getOpposite();
 
-        IInventory inventory = InventoryUtil.getInventory( world, newPosition, side );
+        IItemHandler inventory = InventoryUtil.getInventory( world, newPosition, side );
         if( inventory != null )
         {
             // Drop the item into the inventory
-            ItemStack remainder = InventoryUtil.storeItems( stack, inventory, side );
+            ItemStack remainder = InventoryUtil.storeItems( stack, inventory );
             if( remainder != null )
             {
                 // Put the remainder back in the turtle
-                InventoryUtil.storeItems( remainder, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                InventoryUtil.storeItems( remainder, turtle.getItemHandler(), turtle.getSelectedSlot() );
             }
 
             // Return true if we stored anything
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java
index 4f0a8884b..a77589c45 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java
@@ -14,6 +14,7 @@ import dan200.computercraft.shared.util.WorldUtil;
 import net.minecraft.inventory.IInventory;
 import net.minecraft.item.ItemStack;
 import net.minecraft.util.math.BlockPos;
+import net.minecraftforge.items.IItemHandler;
 
 import javax.annotation.Nonnull;
 
@@ -33,7 +34,7 @@ public class TurtleEquipCommand implements ITurtleCommand
         // Determine the upgrade to equipLeft
         ITurtleUpgrade newUpgrade;
         ItemStack newUpgradeStack;
-        IInventory inventory = turtle.getInventory();
+        IItemHandler inventory = turtle.getItemHandler();
         ItemStack selectedStack = inventory.getStackInSlot( turtle.getSelectedSlot() );
         if( selectedStack != null )
         {
@@ -68,19 +69,17 @@ public class TurtleEquipCommand implements ITurtleCommand
         {
             // Consume new upgrades item
             InventoryUtil.takeItems( 1, inventory, turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
-            inventory.markDirty();
         }
         if( oldUpgradeStack != null )
         {
             // Store old upgrades item
-            ItemStack remainder = InventoryUtil.storeItems( oldUpgradeStack, inventory, 0, inventory.getSizeInventory(), turtle.getSelectedSlot() );
+            ItemStack remainder = InventoryUtil.storeItems( oldUpgradeStack, inventory, turtle.getSelectedSlot() );
             if( remainder != null )
             {
                 // If there's no room for the items, drop them
                 BlockPos position = turtle.getPosition();
                 WorldUtil.dropItemStack( remainder, turtle.getWorld(), position, turtle.getDirection() );
             }
-            inventory.markDirty();
         }
         turtle.setUpgrade( m_side, newUpgrade );
 
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
index 3e6070770..82cd7a561 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
@@ -227,7 +227,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
             @Override
             public void consumeDrop( Entity entity, ItemStack drop )
             {
-                ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
                 if( remainder != null )
                 {
                     WorldUtil.dropItemStack( remainder, world, position, turtle.getDirection().getOpposite() );
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java
index 85f019f3b..13eacc159 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java
@@ -54,7 +54,7 @@ public class TurtlePlayer extends FakePlayer
             ItemStack stack = inventory.getStackInSlot( i );
             if( stack != null )
             {
-                ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
                 if( remainder != null )
                 {
                     WorldUtil.dropItemStack( remainder, turtle.getWorld(), dropPosition, dropDirection );
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java
index 9e4a19c14..de004d17a 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java
@@ -42,14 +42,14 @@ public class TurtleRefuelCommand implements ITurtleCommand
         {
             // Otherwise, refuel for real
             // Remove items from inventory
-            ItemStack stack = InventoryUtil.takeItems( m_limit, turtle.getInventory(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
+            ItemStack stack = InventoryUtil.takeItems( m_limit, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
             if( stack != null )
             {
                 TurtleCommandResult result = refuel( turtle, stack, false );
                 if( !result.isSuccess() )
                 {
                     // If the items weren't burnt, put them back
-                    InventoryUtil.storeItems( stack, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                    InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
                 }
                 return result;
             }
@@ -83,7 +83,7 @@ public class TurtleRefuelCommand implements ITurtleCommand
             // Store the replacement item in the inventory
             if( replacementStack != null )
             {
-                InventoryUtil.storeItems( replacementStack, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                InventoryUtil.storeItems( replacementStack, turtle.getItemHandler(), turtle.getSelectedSlot() );
             }
 
             // Animate
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java
index 6a3c37d07..569bd4887 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java
@@ -20,6 +20,7 @@ import net.minecraft.util.math.AxisAlignedBB;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.EnumFacing;
 import net.minecraft.world.World;
+import net.minecraftforge.items.IItemHandler;
 
 import javax.annotation.Nonnull;
 import java.util.List;
@@ -55,19 +56,19 @@ public class TurtleSuckCommand implements ITurtleCommand
         BlockPos newPosition = WorldUtil.moveCoords( oldPosition, direction );
         EnumFacing side = direction.getOpposite();
 
-        IInventory inventory = InventoryUtil.getInventory( world, newPosition, side );
+        IItemHandler inventory = InventoryUtil.getInventory( world, newPosition, side );
         if( inventory != null )
         {
             // Take from inventory of thing in front
-            ItemStack stack = InventoryUtil.takeItems( m_quantity, inventory, side );
+            ItemStack stack = InventoryUtil.takeItems( m_quantity, inventory );
             if( stack != null )
             {
                 // Try to place into the turtle
-                ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
                 if( remainder != null )
                 {
                     // Put the remainder back in the inventory
-                    InventoryUtil.storeItems( remainder, inventory, side );
+                    InventoryUtil.storeItems( remainder, inventory );
                 }
 
                 // Return true if we consumed anything
@@ -115,7 +116,7 @@ public class TurtleSuckCommand implements ITurtleCommand
                             storeStack = stack;
                             leaveStack = null;
                         }
-                        ItemStack remainder = InventoryUtil.storeItems( storeStack, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                        ItemStack remainder = InventoryUtil.storeItems( storeStack, turtle.getItemHandler(), turtle.getSelectedSlot() );
                         if( remainder != storeStack )
                         {
                             storedItems = true;
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java
index 464fc6bc9..ae11ee336 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java
@@ -31,7 +31,7 @@ public class TurtleTransferToCommand implements ITurtleCommand
     public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
     {
         // Take stack
-        ItemStack stack = InventoryUtil.takeItems( m_quantity, turtle.getInventory(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
+        ItemStack stack = InventoryUtil.takeItems( m_quantity, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
         if( stack == null )
         {
             turtle.playAnimation( TurtleAnimation.Wait );
@@ -39,11 +39,11 @@ public class TurtleTransferToCommand implements ITurtleCommand
         }
 
         // Store stack
-        ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getInventory(), m_slot, 1, m_slot );
+        ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), m_slot, 1, m_slot );
         if( remainder != null )
         {
             // Put the remainder back
-            InventoryUtil.storeItems( remainder, turtle.getInventory(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
+            InventoryUtil.storeItems( remainder, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() );
         }
 
         // Return true if we moved anything
diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
index e448b04d0..c3aac1a37 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
@@ -36,6 +36,7 @@ import org.apache.commons.lang3.tuple.Pair;
 
 import javax.annotation.Nonnull;
 import javax.vecmath.Matrix4f;
+import java.util.List;
 
 public class TurtleTool implements ITurtleUpgrade
 {
@@ -180,7 +181,7 @@ public class TurtleTool implements ITurtleUpgrade
                 @Override
                 public void consumeDrop( Entity entity, ItemStack drop )
                 {
-                    ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                    ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
                     if( remainder != null )
                     {
                         WorldUtil.dropItemStack( remainder, world, position, turtle.getDirection().getOpposite() );
@@ -261,12 +262,12 @@ public class TurtleTool implements ITurtleUpgrade
             // Consume the items the block drops
             if( canHarvestBlock( world, newPosition ) )
             {
-                java.util.List<ItemStack> items = getBlockDropped( world, newPosition );
+                List<ItemStack> items = getBlockDropped( world, newPosition );
                 if( items != null && items.size() > 0 )
                 {
                     for( ItemStack stack : items )
                     {
-                        ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getInventory(), 0, turtle.getInventory().getSizeInventory(), turtle.getSelectedSlot() );
+                        ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
                         if( remainder != null )
                         {
                             // If there's no room for the items, drop them
diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java
index 4c6f1915e..00cf71cc5 100644
--- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java
+++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java
@@ -6,19 +6,20 @@
 
 package dan200.computercraft.shared.util;
 
-import net.minecraft.block.Block;
 import net.minecraft.entity.Entity;
-import net.minecraft.init.Blocks;
 import net.minecraft.inventory.IInventory;
 import net.minecraft.inventory.ISidedInventory;
-import net.minecraft.inventory.InventoryLargeChest;
 import net.minecraft.item.ItemStack;
 import net.minecraft.tileentity.TileEntity;
-import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.EnumFacing;
+import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.Vec3d;
-import net.minecraft.world.ILockableContainer;
 import net.minecraft.world.World;
+import net.minecraftforge.items.CapabilityItemHandler;
+import net.minecraftforge.items.IItemHandler;
+import net.minecraftforge.items.ItemHandlerHelper;
+import net.minecraftforge.items.wrapper.InvWrapper;
+import net.minecraftforge.items.wrapper.SidedInvWrapper;
 import org.apache.commons.lang3.tuple.Pair;
 
 public class InventoryUtil
@@ -27,35 +28,12 @@ public class InventoryUtil
 
     public static boolean areItemsEqual( ItemStack a, ItemStack b )
     {
-        if( areItemsStackable( a, b ) )
-        {
-            if( a == null || a.stackSize == b.stackSize )
-            {
-                return true;
-            }
-        }
-        return false;
+        return a == b || ItemStack.areItemStacksEqual( a, b );
     }
 
     public static boolean areItemsStackable( ItemStack a, ItemStack b )
     {
-        if( a == b )
-        {
-            return true;
-        }
-        
-        if( a != null && b != null && a.getItem() == b.getItem() )
-        {
-            if( a.getItemDamage() == b.getItemDamage() )
-            {
-                if( (a.getTagCompound() == null && b.getTagCompound() == null) ||
-                    (a.getTagCompound() != null && b.getTagCompound() != null && a.getTagCompound().equals( b.getTagCompound() ) ) )
-                {
-                    return true;
-                }
-            }
-        }
-        return false;
+        return a == b || ItemHandlerHelper.canItemStacksStack( a, b );
     }
 
     public static ItemStack copyItem( ItemStack a )
@@ -69,40 +47,28 @@ public class InventoryUtil
 
     // Methods for finding inventories:
 
-    public static IInventory getInventory( World world, BlockPos pos, EnumFacing side )
+    public static IItemHandler getInventory( World world, BlockPos pos, EnumFacing side )
     {
         // Look for tile with inventory
         int y = pos.getY();
         if( y >= 0 && y < world.getHeight() )
         {
             TileEntity tileEntity = world.getTileEntity( pos );
-            if( tileEntity != null && tileEntity instanceof IInventory )
+            if( tileEntity != null )
             {
-                // Special case code for double chests
-                Block block = world.getBlockState( pos ).getBlock();
-                if( block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST )
+                IItemHandler itemHandler = tileEntity.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side );
+                if( itemHandler != null )
                 {
-                    // Check if it's a double chest, and return a combined inventory if so
-                    if( world.getBlockState( pos.west() ).getBlock() == block )
-                    {
-                        return new InventoryLargeChest( "Large chest", (ILockableContainer)world.getTileEntity( pos.west() ), (ILockableContainer)tileEntity );
-                    }
-                    if( world.getBlockState( pos.east() ).getBlock() == block )
-                    {
-                        return new InventoryLargeChest( "Large chest", (ILockableContainer)tileEntity, (ILockableContainer)world.getTileEntity( pos.east() ) );
-                    }
-                    if( world.getBlockState( pos.north() ).getBlock() == block )
-                    {
-                        return new InventoryLargeChest( "Large chest", (ILockableContainer)world.getTileEntity( pos.north() ), (ILockableContainer)tileEntity );
-                    }
-                    if( world.getBlockState( pos.south() ).getBlock() == block )
-                    {
-                        return new InventoryLargeChest( "Large chest", (ILockableContainer)tileEntity, (ILockableContainer)world.getTileEntity( pos.south() ) );
-                    }
+                    return itemHandler;
+                }
+                else if( side != null && tileEntity instanceof ISidedInventory )
+                {
+                    return new SidedInvWrapper( (ISidedInventory) tileEntity, side );
+                }
+                else if( tileEntity instanceof IInventory )
+                {
+                    return new InvWrapper( (IInventory) tileEntity );
                 }
-
-                // Otherwise, get tile inventory
-                return (IInventory)tileEntity;
             }
         }
 
@@ -122,60 +88,52 @@ public class InventoryUtil
             Entity entity = hit.getKey();
             if( entity instanceof IInventory )
             {
-                return (IInventory) entity;
+                return new InvWrapper( (IInventory) entity );
             }
         }
         return null;
     }
-    
+
     // Methods for placing into inventories:
-    
-    public static ItemStack storeItems( ItemStack itemstack, IInventory inventory, int start, int range, int begin )
+
+    public static ItemStack storeItems( ItemStack itemstack, IItemHandler inventory, int start, int range, int begin )
     {
         int[] slots = makeSlotList( start, range, begin );
-        return storeItems( itemstack, inventory, slots, null );
+        return storeItems( itemstack, inventory, slots );
     }
 
-    public static ItemStack storeItems( ItemStack itemstack, IInventory inventory, EnumFacing side )
+    public static ItemStack storeItems( ItemStack itemstack, IItemHandler inventory, int begin )
     {
-        // Try ISidedInventory
-        if( inventory instanceof ISidedInventory )
-        {
-            // Place into ISidedInventory
-            ISidedInventory sidedInventory = (ISidedInventory)inventory;
-            int[] slots = sidedInventory.getSlotsForFace( side );
-            return storeItems( itemstack, inventory, slots, side );
-        }
-
-        // No ISidedInventory, store into any slot
-        int[] slots = makeSlotList( 0, inventory.getSizeInventory(), 0 ); // TODO: optimise this out?
-        return storeItems( itemstack, inventory, slots, side );
+        int[] slots = makeSlotList( 0, inventory.getSlots(), begin );
+        return storeItems( itemstack, inventory, slots );
     }
-    
+
+    public static ItemStack storeItems( ItemStack itemstack, IItemHandler inventory )
+    {
+        int[] slots = makeSlotList( 0, inventory.getSlots(), 0 ); // TODO: optimise this out?
+        return storeItems( itemstack, inventory, slots );
+    }
+
     // Methods for taking out of inventories
-    
-    public static ItemStack takeItems( int count, IInventory inventory, int start, int range, int begin )
+
+    public static ItemStack takeItems( int count, IItemHandler inventory, int start, int range, int begin )
     {
         int[] slots = makeSlotList( start, range, begin );
-        return takeItems( count, inventory, slots, null );
+        return takeItems( count, inventory, slots );
     }
-        
-    public static ItemStack takeItems( int count, IInventory inventory, EnumFacing side )
-    {
-        // Try ISidedInventory
-        if( inventory instanceof ISidedInventory )
-        {
-            // Place into ISidedInventory
-            ISidedInventory sidedInventory = (ISidedInventory)inventory;
-            int[] slots = sidedInventory.getSlotsForFace( side );
-            return takeItems( count, inventory, slots, side );
-        }
 
-        // No ISidedInventory, store into any slot
-        int[] slots = makeSlotList( 0, inventory.getSizeInventory(), 0 );
-        return takeItems( count, inventory, slots, side );
+    public static ItemStack takeItems( int count, IItemHandler inventory, int begin )
+    {
+        int[] slots = makeSlotList( 0, inventory.getSlots(), begin );
+        return takeItems( count, inventory, slots );
     }
-    
+
+    public static ItemStack takeItems( int count, IItemHandler inventory )
+    {
+        int[] slots = makeSlotList( 0, inventory.getSlots(), 0 );
+        return takeItems( count, inventory, slots );
+    }
+
     // Private methods
 
     private static int[] makeSlotList( int start, int range, int begin )
@@ -184,16 +142,16 @@ public class InventoryUtil
         {
             return null;
         }
-        
-        int[] slots = new int[range];
-        for( int n=0; n<slots.length; ++n )
+
+        int[] slots = new int[ range ];
+        for( int n = 0; n < slots.length; ++n )
         {
-            slots[n] = start + ( (n + (begin - start)) % range );
+            slots[ n ] = start + ((n + (begin - start)) % range);
         }
         return slots;
     }
-        
-    private static ItemStack storeItems( ItemStack stack, IInventory inventory, int[] slots, EnumFacing face )
+
+    private static ItemStack storeItems( ItemStack stack, IItemHandler inventory, int[] slots )
     {
         if( slots == null || slots.length == 0 )
         {
@@ -208,74 +166,13 @@ public class InventoryUtil
         ItemStack remainder = stack;
         for( int slot : slots )
         {
-            if( canPlaceItemThroughFace( inventory, slot, remainder, face ) )
-            {
-                ItemStack slotContents = inventory.getStackInSlot( slot );
-                if( slotContents == null )
-                {
-                    // Slot is empty
-                    int space = inventory.getInventoryStackLimit();
-                    if( space >= remainder.stackSize )
-                    {
-                        // Items fit completely in slot
-                        inventory.setInventorySlotContents( slot, remainder );
-                        inventory.markDirty();
-                        return null;
-                    }
-                    else
-                    {
-                        // Items fit partially in slot
-                        remainder = remainder.copy();
-                        inventory.setInventorySlotContents( slot, remainder.splitStack( space ) );
-                    }
-                }
-                else if( areItemsStackable( slotContents, remainder ) )
-                {
-                    // Slot is occupied, but matching
-                    int space = Math.min( slotContents.getMaxStackSize(), inventory.getInventoryStackLimit() ) - slotContents.stackSize;
-                    if( space >= remainder.stackSize )
-                    {
-                        // Items fit completely in slot
-                        slotContents.stackSize += remainder.stackSize;
-                        inventory.setInventorySlotContents( slot, slotContents );
-                        inventory.markDirty();
-                        return null;
-                    }
-                    else if( space > 0 )
-                    {
-                        // Items fit partially in slot
-                        remainder = remainder.copy();
-                        remainder.stackSize -= space;
-                        slotContents.stackSize += space;
-                        inventory.setInventorySlotContents( slot, slotContents );
-                    }
-                }
-            }
-        }
-
-        // If the output isn't the input, inform the change
-        if( remainder != stack )
-        {
-            inventory.markDirty();
+            if( remainder == null ) break;
+            remainder = inventory.insertItem( slot, remainder, false );
         }
         return remainder;
     }
 
-    private static boolean canPlaceItemThroughFace( IInventory inventory, int slot, ItemStack itemstack, EnumFacing face )
-    {
-        if( inventory.isItemValidForSlot( slot, itemstack ) )
-        {
-            if( face != null && inventory instanceof ISidedInventory )
-            {
-                ISidedInventory sided = (ISidedInventory)inventory;
-                return sided.canInsertItem( slot, itemstack, face );
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private static ItemStack takeItems( int count, IInventory inventory, int[] slots, EnumFacing face )
+    private static ItemStack takeItems( int count, IItemHandler inventory, int[] slots )
     {
         if( slots == null )
         {
@@ -287,65 +184,30 @@ public class InventoryUtil
         int countRemaining = count;
         for( int slot : slots )
         {
-            if( countRemaining > 0 )
+            if( countRemaining <= 0 ) break;
+
+            ItemStack stack = inventory.getStackInSlot( slot );
+            if( stack != null )
             {
-                ItemStack stack = inventory.getStackInSlot( slot );
-                if( stack != null && canTakeItemThroughFace( inventory, slot, stack, face ) )
+                if( partialStack == null || areItemsStackable( stack, partialStack ) )
                 {
-                    if( partialStack == null || areItemsStackable( stack, partialStack ) )
+                    ItemStack extracted = inventory.extractItem( slot, countRemaining, false );
+                    if( extracted != null )
                     {
-                        // Found a matching thing
-                        if( countRemaining >= stack.stackSize )
+                        countRemaining -= extracted.stackSize;
+                        if( partialStack == null )
                         {
-                            // Eat the thing whole
-                            inventory.setInventorySlotContents( slot, null );
-                            if( partialStack == null )
-                            {
-                                partialStack = stack;
-                                countRemaining = Math.min( countRemaining, partialStack.getItem().getItemStackLimit( partialStack ) ) - stack.stackSize;
-                            }
-                            else
-                            {
-                                partialStack.stackSize += stack.stackSize;
-                                countRemaining -= stack.stackSize;
-                            }
+                            partialStack = extracted;
                         }
                         else
                         {
-                            // Eat part of the thing
-                            ItemStack splitStack = stack.splitStack( countRemaining );
-                            if( partialStack == null )
-                            {
-                                partialStack = splitStack;
-                                countRemaining = Math.min( countRemaining, partialStack.getItem().getItemStackLimit( partialStack ) ) - splitStack.stackSize;
-                            }
-                            else
-                            {
-                                partialStack.stackSize += splitStack.stackSize;
-                                countRemaining -= splitStack.stackSize;
-                            }
+                            partialStack.stackSize += extracted.stackSize;
                         }
                     }
                 }
             }
         }
 
-        // Return the final stack
-        if( partialStack != null )
-        {
-            inventory.markDirty();
-            return partialStack;
-        }
-        return null;
-    }
-
-    private static boolean canTakeItemThroughFace( IInventory inventory, int slot, ItemStack itemstack, EnumFacing face )
-    {
-        if( face != null && inventory instanceof ISidedInventory )
-        {
-            ISidedInventory sided = (ISidedInventory)inventory;
-            return sided.canExtractItem( slot, itemstack, face );
-        }
-        return true;
+        return partialStack;
     }
 }