From 729fb4d0f7aa5fc551e4aff132766ed6c62de916 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 20 Jan 2019 17:03:39 +0100 Subject: [PATCH] Added capability support for inventories Refactored inventory handling outside Commons and TileEntityAbstractBase --- src/main/java/cr0s/warpdrive/Commons.java | 30 -- .../block/TileEntityAbstractBase.java | 110 ------ .../collection/TileEntityAbstractMiner.java | 3 +- .../collection/TileEntityLaserTreeFarm.java | 96 ++--- .../TileEntityForceFieldProjector.java | 16 +- .../cr0s/warpdrive/command/CommandDump.java | 52 +-- .../cr0s/warpdrive/data/ForceFieldSetup.java | 5 +- .../cr0s/warpdrive/data/InventoryWrapper.java | 330 ++++++++++++++++++ .../warpdrive/world/WorldGenStructure.java | 22 +- 9 files changed, 414 insertions(+), 250 deletions(-) create mode 100644 src/main/java/cr0s/warpdrive/data/InventoryWrapper.java diff --git a/src/main/java/cr0s/warpdrive/Commons.java b/src/main/java/cr0s/warpdrive/Commons.java index 77fb7b53..e5cbc941 100644 --- a/src/main/java/cr0s/warpdrive/Commons.java +++ b/src/main/java/cr0s/warpdrive/Commons.java @@ -22,13 +22,11 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; -import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.EnumBlockRenderType; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; @@ -387,34 +385,6 @@ public class Commons { return ret; } - public static Collection getConnectedInventories(final TileEntity tileEntityConnection) { - final Collection result = new ArrayList<>(6); - - for(final EnumFacing side : EnumFacing.VALUES) { - final TileEntity tileEntity = tileEntityConnection.getWorld().getTileEntity( - tileEntityConnection.getPos().offset(side)); - if (tileEntity instanceof IInventory) { - result.add((IInventory) tileEntity); - - if (tileEntity instanceof TileEntityChest) { - final TileEntityChest tileEntityChest = (TileEntityChest) tileEntity; - tileEntityChest.checkForAdjacentChests(); - if (tileEntityChest.adjacentChestXNeg != null) { - result.add(tileEntityChest.adjacentChestXNeg); - } else if (tileEntityChest.adjacentChestXPos != null) { - result.add(tileEntityChest.adjacentChestXPos); - } else if (tileEntityChest.adjacentChestZNeg != null) { - result.add(tileEntityChest.adjacentChestZNeg); - } else if (tileEntityChest.adjacentChestZPos != null) { - result.add(tileEntityChest.adjacentChestZPos); - } - } - } - } - - return result; - } - // searching methods diff --git a/src/main/java/cr0s/warpdrive/block/TileEntityAbstractBase.java b/src/main/java/cr0s/warpdrive/block/TileEntityAbstractBase.java index 31fe0154..4aaeac6a 100644 --- a/src/main/java/cr0s/warpdrive/block/TileEntityAbstractBase.java +++ b/src/main/java/cr0s/warpdrive/block/TileEntityAbstractBase.java @@ -8,14 +8,10 @@ import cr0s.warpdrive.api.IBlockBase; import cr0s.warpdrive.api.IBlockUpdateDetector; import cr0s.warpdrive.api.IVideoChannel; import cr0s.warpdrive.api.WarpDriveText; -import cr0s.warpdrive.config.WarpDriveConfig; import cr0s.warpdrive.data.CameraRegistryItem; import cr0s.warpdrive.data.EnumTier; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -24,9 +20,7 @@ import java.util.UUID; import net.minecraft.block.Block; import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Items; -import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -177,110 +171,6 @@ public abstract class TileEntityAbstractBase extends TileEntity implements IBloc return blockStateOld.getBlock() != blockStateNew.getBlock(); } - // Inventory management methods - protected boolean addToConnectedInventories(final ItemStack itemStack) { - final List itemStacks = new ArrayList<>(1); - itemStacks.add(itemStack); - return addToInventories(itemStacks, Commons.getConnectedInventories(this)); - } - - protected boolean addToConnectedInventories(final List itemStacks) { - return addToInventories(itemStacks, Commons.getConnectedInventories(this)); - } - - protected boolean addToInventories(final List itemStacks, final Collection inventories) { - boolean overflow = false; - if (itemStacks != null) { - for (final ItemStack itemStack : itemStacks) { - if (itemStack.isEmpty()) { - WarpDrive.logger.error(String.format("%s Invalid empty itemStack...", - this)); - continue; - } - int qtyLeft = itemStack.getCount(); - final ItemStack itemStackLeft = itemStack.copy(); - for (final IInventory inventory : inventories) { - qtyLeft = addToInventory(itemStack, inventory); - if (qtyLeft > 0) { - itemStackLeft.setCount(qtyLeft); - } else { - break; - } - } - if (qtyLeft > 0) { - if (WarpDriveConfig.LOGGING_COLLECTION) { - WarpDrive.logger.info(String.format("%s Overflow detected", - this)); - } - overflow = true; - int transfer; - while (qtyLeft > 0) { - transfer = Math.min(qtyLeft, itemStackLeft.getMaxStackSize()); - final ItemStack itemStackDrop = Commons.copyWithSize(itemStackLeft, transfer); - final EntityItem entityItem = new EntityItem(world, pos.getX() + 0.5D, pos.getY() + 1.0D, pos.getZ() + 0.5D, itemStackDrop); - world.spawnEntity(entityItem); - qtyLeft -= transfer; - } - } - } - } - return overflow; - } - - private static int addToInventory(final ItemStack itemStackSource, final IInventory inventory) { - if (itemStackSource == null || itemStackSource.isEmpty()) { - return 0; - } - - int qtyLeft = itemStackSource.getCount(); - int transfer; - - if (inventory != null) { - // fill existing stacks first - for (int i = 0; i < inventory.getSizeInventory(); i++) { - if (!inventory.isItemValidForSlot(i, itemStackSource)) { - continue; - } - - final ItemStack itemStack = inventory.getStackInSlot(i); - if ( itemStack.isEmpty() - || !itemStack.isItemEqual(itemStackSource) ) { - continue; - } - - transfer = Math.min(qtyLeft, itemStack.getMaxStackSize() - itemStack.getCount()); - itemStack.grow(transfer); - qtyLeft -= transfer; - if (qtyLeft <= 0) { - return 0; - } - } - - // put remaining in empty slot - for (int i = 0; i < inventory.getSizeInventory(); i++) { - if (!inventory.isItemValidForSlot(i, itemStackSource)) { - continue; - } - - final ItemStack itemStack = inventory.getStackInSlot(i); - if (!itemStack.isEmpty()) { - continue; - } - - transfer = Math.min(qtyLeft, itemStackSource.getMaxStackSize()); - final ItemStack dest = Commons.copyWithSize(itemStackSource, transfer); - inventory.setInventorySlotContents(i, dest); - qtyLeft -= transfer; - - if (qtyLeft <= 0) { - return 0; - } - } - } - - return qtyLeft; - } - // area protection protected boolean isBlockBreakCanceled(final UUID uuidPlayer, final World world, final BlockPos blockPosEvent) { diff --git a/src/main/java/cr0s/warpdrive/block/collection/TileEntityAbstractMiner.java b/src/main/java/cr0s/warpdrive/block/collection/TileEntityAbstractMiner.java index b5c33452..0aca21e9 100644 --- a/src/main/java/cr0s/warpdrive/block/collection/TileEntityAbstractMiner.java +++ b/src/main/java/cr0s/warpdrive/block/collection/TileEntityAbstractMiner.java @@ -6,6 +6,7 @@ import cr0s.warpdrive.WarpDrive; import cr0s.warpdrive.block.TileEntityAbstractLaser; import cr0s.warpdrive.config.WarpDriveConfig; import cr0s.warpdrive.data.FluidWrapper; +import cr0s.warpdrive.data.InventoryWrapper; import cr0s.warpdrive.data.Vector3; import java.lang.reflect.InvocationTargetException; @@ -72,7 +73,7 @@ public abstract class TileEntityAbstractMiner extends TileEntityAbstractLaser { net.minecraftforge.event.ForgeEventFactory.fireBlockHarvesting(itemStackDrops, getWorld(), valuable, blockState, 0, 1.0f, true, entityPlayer); - if (addToConnectedInventories(itemStackDrops)) { + if (InventoryWrapper.addToConnectedInventories(world, pos, itemStackDrops)) { stop(); } // standard harvest block effect diff --git a/src/main/java/cr0s/warpdrive/block/collection/TileEntityLaserTreeFarm.java b/src/main/java/cr0s/warpdrive/block/collection/TileEntityLaserTreeFarm.java index c77243e1..8217b88c 100644 --- a/src/main/java/cr0s/warpdrive/block/collection/TileEntityLaserTreeFarm.java +++ b/src/main/java/cr0s/warpdrive/block/collection/TileEntityLaserTreeFarm.java @@ -5,9 +5,12 @@ import cr0s.warpdrive.WarpDrive; import cr0s.warpdrive.api.WarpDriveText; import cr0s.warpdrive.config.Dictionary; import cr0s.warpdrive.config.WarpDriveConfig; +import cr0s.warpdrive.data.EnumComponentType; import cr0s.warpdrive.data.EnumLaserTreeFarmMode; +import cr0s.warpdrive.data.InventoryWrapper; import cr0s.warpdrive.data.SoundEvents; import cr0s.warpdrive.data.Vector3; +import cr0s.warpdrive.item.ItemComponent; import cr0s.warpdrive.network.PacketHandler; import li.cil.oc.api.machine.Arguments; @@ -23,7 +26,7 @@ import java.util.LinkedList; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -import net.minecraft.inventory.IInventory; +import net.minecraft.init.Blocks; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -285,6 +288,7 @@ public class TileEntityLaserTreeFarm extends TileEntityAbstractMiner { // save the rubber producing blocks in tapping mode if (currentState == STATE_TAP) { + // IC2 rubber tree wet spot if (blockStateValuable.getBlock().isAssociatedBlock(WarpDriveConfig.IC2_rubberWood)) { final int metadata = blockStateValuable.getBlock().getMetaFromState(blockStateValuable); if (metadata >= 2 && metadata <= 5) { @@ -304,12 +308,12 @@ public class TileEntityLaserTreeFarm extends TileEntityAbstractMiner { updateBlockState(blockState, BlockLaserTreeFarm.MODE, EnumLaserTreeFarmMode.FARMING_POWERED); } - final ItemStack resin = WarpDriveConfig.IC2_Resin.copy(); - resin.setCount( (int) Math.round(Math.random() * 4) ); - if (addToConnectedInventories(resin)) { + final ItemStack itemStackResin = WarpDriveConfig.IC2_Resin.copy(); + itemStackResin.setCount( (int) Math.round(Math.random() * 4.0D) ); + if (InventoryWrapper.addToConnectedInventories(world, pos, itemStackResin)) { stop(); } - totalHarvested += resin.getCount(); + totalHarvested += itemStackResin.getCount(); final int age = Math.max(10, Math.round((4 + world.rand.nextFloat()) * TREE_FARM_HARVEST_LOG_DELAY_TICKS)); PacketHandler.sendBeamPacket(world, laserOutput, new Vector3(valuable).translate(0.5D), 0.8F, 0.8F, 0.2F, age, 0, 50); @@ -372,7 +376,7 @@ public class TileEntityLaserTreeFarm extends TileEntityAbstractMiner { final BlockPos blockPosPlant = soil.add(0, 1, 0); final IBlockState blockStateSoil = world.getBlockState(soil); soilIndex++; - final Collection inventories = Commons.getConnectedInventories(this); + final Collection inventories = InventoryWrapper.getConnectedInventories(world, pos); if (inventories.isEmpty()) { currentState = STATE_WARMUP; delayTargetTicks = TREE_FARM_WARMUP_DELAY_TICKS; @@ -380,62 +384,65 @@ public class TileEntityLaserTreeFarm extends TileEntityAbstractMiner { return; } - int slotIndex = 0; - int plantableCount = 0; - ItemStack itemStack = null; - IBlockState plant = null; - IInventory inventory = null; - for (final IInventory inventoryLoop : inventories) { - if (plant == null) { - slotIndex = 0; - } - while (slotIndex < inventoryLoop.getSizeInventory() && plant == null) { - itemStack = inventoryLoop.getStackInSlot(slotIndex); - if (itemStack.isEmpty()) { - slotIndex++; + int indexSlotPlant = 0; + int countPlantable = 0; + ItemStack itemStackPlant = null; + IBlockState blockStatePlant = null; + Object inventoryPlant = null; + for (final Object inventoryLoop : inventories) { + indexSlotPlant = 0; + while (indexSlotPlant < InventoryWrapper.getSize(inventoryLoop) && blockStatePlant == null) { + itemStackPlant = InventoryWrapper.getStackInSlot(inventoryLoop, indexSlotPlant); + if (itemStackPlant.isEmpty()) { + indexSlotPlant++; continue; } - final Block blockFromItem = Block.getBlockFromItem(itemStack.getItem()); - if ( !(itemStack.getItem() instanceof IPlantable) + final Block blockFromItem = Block.getBlockFromItem(itemStackPlant.getItem()); + if ( !(itemStackPlant.getItem() instanceof IPlantable) && !(blockFromItem instanceof IPlantable) ) { - slotIndex++; + indexSlotPlant++; continue; } - plantableCount++; - final IPlantable plantable = (IPlantable) ((itemStack.getItem() instanceof IPlantable) ? itemStack.getItem() : blockFromItem); - if (itemStack.getItem() instanceof ItemBlock) { - final ItemBlock itemBlock = (ItemBlock) itemStack.getItem(); - final int metadata = itemBlock.getMetadata(itemStack.getMetadata()); + countPlantable++; + final IPlantable plantable = (IPlantable) ((itemStackPlant.getItem() instanceof IPlantable) ? itemStackPlant.getItem() : blockFromItem); + if (itemStackPlant.getItem() instanceof ItemBlock) { + final ItemBlock itemBlock = (ItemBlock) itemStackPlant.getItem(); + final int metadata = itemBlock.getMetadata(itemStackPlant.getMetadata()); final Block block = itemBlock.getBlock(); - plant = block.getStateForPlacement(world, blockPosPlant, EnumFacing.UP, - 0.5F, 0.0F, 0.5F, metadata, - null, EnumHand.MAIN_HAND); // @TODO use fake player to place sapling + blockStatePlant = block.getStateForPlacement(world, blockPosPlant, EnumFacing.UP, + 0.5F, 0.0F, 0.5F, metadata, + null, EnumHand.MAIN_HAND); // @TODO use fake player to place sapling } else { - plant = plantable.getPlant(world, blockPosPlant); + blockStatePlant = plantable.getPlant(world, blockPosPlant); } if (WarpDriveConfig.LOGGING_COLLECTION) { WarpDrive.logger.info(String.format("Slot %d as %s which plantable %s as block %s", - slotIndex, itemStack, plantable, plant)); + indexSlotPlant, itemStackPlant, plantable, blockStatePlant)); } if (!blockStateSoil.getBlock().canSustainPlant(blockStateSoil, world, soil, EnumFacing.UP, plantable)) { - plant = null; - slotIndex++; + blockStatePlant = null; + indexSlotPlant++; continue; } - if (!plant.getBlock().canPlaceBlockAt(world, blockPosPlant)) { - plant = null; - slotIndex++; + if (!blockStatePlant.getBlock().canPlaceBlockAt(world, blockPosPlant)) { + blockStatePlant = null; + indexSlotPlant++; continue; } - inventory = inventoryLoop; + inventoryPlant = inventoryLoop; + } + + // exit the loop if we've found a valid plant + if (blockStatePlant != null) { + break; } } // no plantable found at all, back to scanning - if (plantableCount <= 0) { + if (countPlantable <= 0) { currentState = STATE_SCAN; delayTargetTicks = TREE_FARM_SCAN_DELAY_TICKS; updateBlockState(blockState, BlockLaserTreeFarm.MODE, EnumLaserTreeFarmMode.SCANNING_POWERED); @@ -443,7 +450,9 @@ public class TileEntityLaserTreeFarm extends TileEntityAbstractMiner { } // no sapling found for this soil, moving on... - if (inventory == null || plant == null || itemStack == null) { + if ( inventoryPlant == null + || blockStatePlant == null + || itemStackPlant == null ) { if (WarpDriveConfig.LOGGING_COLLECTION) { WarpDrive.logger.debug("No sapling found"); } @@ -451,7 +460,7 @@ public class TileEntityLaserTreeFarm extends TileEntityAbstractMiner { } // check area protection - if (isBlockPlaceCanceled(null, world, blockPosPlant, plant)) { + if (isBlockPlaceCanceled(null, world, blockPosPlant, blockStatePlant)) { if (WarpDriveConfig.LOGGING_COLLECTION) { WarpDrive.logger.info(String.format("%s Planting cancelled %s", this, Commons.format(world, blockPosPlant))); @@ -471,15 +480,14 @@ public class TileEntityLaserTreeFarm extends TileEntityAbstractMiner { updateBlockState(blockState, BlockLaserTreeFarm.MODE, EnumLaserTreeFarmMode.PLANTING_POWERED); } - itemStack.shrink(1); - inventory.setInventorySlotContents(slotIndex, itemStack); + InventoryWrapper.decrStackSize(inventoryPlant, indexSlotPlant, 1); // totalPlanted++; final int age = Math.max(10, Math.round((4 + world.rand.nextFloat()) * WarpDriveConfig.MINING_LASER_MINE_DELAY_TICKS)); PacketHandler.sendBeamPacket(world, laserOutput, new Vector3(blockPosPlant).translate(0.5D), 0.2F, 0.7F, 0.4F, age, 0, 50); world.playSound(null, pos, SoundEvents.LASER_LOW, SoundCategory.BLOCKS, 4F, 1F); - world.setBlockState(blockPosPlant, plant, 3); + world.setBlockState(blockPosPlant, blockStatePlant, 3); } } } diff --git a/src/main/java/cr0s/warpdrive/block/forcefield/TileEntityForceFieldProjector.java b/src/main/java/cr0s/warpdrive/block/forcefield/TileEntityForceFieldProjector.java index 8f57c545..7a17489a 100644 --- a/src/main/java/cr0s/warpdrive/block/forcefield/TileEntityForceFieldProjector.java +++ b/src/main/java/cr0s/warpdrive/block/forcefield/TileEntityForceFieldProjector.java @@ -13,6 +13,7 @@ import cr0s.warpdrive.data.EnumForceFieldState; import cr0s.warpdrive.data.EnumForceFieldUpgrade; import cr0s.warpdrive.data.FluidWrapper; import cr0s.warpdrive.data.ForceFieldSetup; +import cr0s.warpdrive.data.InventoryWrapper; import cr0s.warpdrive.data.SoundEvents; import cr0s.warpdrive.data.Vector3; import cr0s.warpdrive.data.VectorI; @@ -41,7 +42,6 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; -import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetworkManager; @@ -631,17 +631,16 @@ public class TileEntityForceFieldProjector extends TileEntityAbstractForceField int slotIndex = 0; boolean found = false; int countItemBlocks = 0; - ItemStack itemStack = null; Block blockToPlace = null; int metadataToPlace = -1; - IInventory inventory = null; + Object inventory = null; final BlockPos blockPos = vector.getBlockPos(); - for (final IInventory inventoryLoop : forceFieldSetup.inventories) { + for (final Object inventoryLoop : forceFieldSetup.inventories) { if (!found) { slotIndex = 0; } - while (slotIndex < inventoryLoop.getSizeInventory() && !found) { - itemStack = inventoryLoop.getStackInSlot(slotIndex); + while (slotIndex < InventoryWrapper.getSize(inventoryLoop) && !found) { + final ItemStack itemStack = InventoryWrapper.getStackInSlot(inventoryLoop, slotIndex); if (itemStack.isEmpty()) { slotIndex++; continue; @@ -699,8 +698,7 @@ public class TileEntityForceFieldProjector extends TileEntityAbstractForceField return true; } - itemStack.shrink(1); - inventory.setInventorySlotContents(slotIndex, itemStack); + InventoryWrapper.decrStackSize(inventory, slotIndex, 1); final int age = Math.max(10, Math.round((4 + world.rand.nextFloat()) * WarpDriveConfig.MINING_LASER_MINE_DELAY_TICKS)); PacketHandler.sendBeamPacket(world, new Vector3(this).translate(0.5D), new Vector3(vector.x, vector.y, vector.z).translate(0.5D), @@ -740,7 +738,7 @@ public class TileEntityForceFieldProjector extends TileEntityAbstractForceField if (itemStacks != null) { if (forceFieldSetup.hasCollection) { - if (addToInventories(itemStacks, forceFieldSetup.inventories)) { + if (InventoryWrapper.addToInventories(world, pos, forceFieldSetup.inventories, itemStacks)) { return true; } } else { diff --git a/src/main/java/cr0s/warpdrive/command/CommandDump.java b/src/main/java/cr0s/warpdrive/command/CommandDump.java index 56e75c06..9c249b20 100644 --- a/src/main/java/cr0s/warpdrive/command/CommandDump.java +++ b/src/main/java/cr0s/warpdrive/command/CommandDump.java @@ -2,15 +2,11 @@ package cr0s.warpdrive.command; import cr0s.warpdrive.Commons; import cr0s.warpdrive.WarpDrive; +import cr0s.warpdrive.data.InventoryWrapper; -import net.minecraft.block.ITileEntityProvider; -import net.minecraft.block.state.IBlockState; import net.minecraft.command.ICommandSender; -import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.server.MinecraftServer; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentString; @@ -18,7 +14,7 @@ import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import java.util.Collection; public class CommandDump extends AbstractCommand { @@ -36,16 +32,13 @@ public class CommandDump extends AbstractCommand { @Override public void execute(@Nonnull final MinecraftServer server, @Nonnull final ICommandSender commandSender, @Nonnull final String[] args) { final World world = commandSender.getEntityWorld(); - final BlockPos coordinates = commandSender.getPosition(); + final BlockPos blockPos = commandSender.getPosition(); //noinspection ConstantConditions - if (world == null || coordinates == null) { + if (world == null || blockPos == null) { Commons.addChatMessage(commandSender, getPrefix().appendSibling(new TextComponentTranslation("warpdrive.command.invalid_location").setStyle(Commons.styleWarning))); return; } - int x = coordinates.getX(); - int y = coordinates.getY(); - int z = coordinates.getZ(); // parse arguments if (args.length != 0) { @@ -54,26 +47,18 @@ public class CommandDump extends AbstractCommand { } // validate - IInventory inventory = null; - for (final EnumFacing direction : EnumFacing.values()) { - inventory = getInventory(world, x + direction.getXOffset(), y + direction.getYOffset(), z + direction.getZOffset()); - if (inventory != null) { - x += direction.getXOffset(); - y += direction.getYOffset(); - z += direction.getZOffset(); - break; - } - } - if (inventory == null) { + final Collection inventories = InventoryWrapper.getConnectedInventories(world, blockPos); + if (inventories.isEmpty()) { Commons.addChatMessage(commandSender, getPrefix().appendSibling(new TextComponentTranslation("warpdrive.command.no_container").setStyle(Commons.styleWarning))); return; } + final Object inventory = inventories.iterator().next(); // actually dump WarpDrive.logger.info(String.format("Dumping content from container %s:", - Commons.format(world, x, y, z))); - for (int indexSlot = 0; indexSlot < inventory.getSizeInventory(); indexSlot++) { - final ItemStack itemStack = inventory.getStackInSlot(indexSlot); + Commons.format(world, blockPos))); + for (int indexSlot = 0; indexSlot < InventoryWrapper.getSize(inventory); indexSlot++) { + final ItemStack itemStack = InventoryWrapper.getStackInSlot(inventory, indexSlot); if (itemStack != ItemStack.EMPTY && !itemStack.isEmpty()) { final ResourceLocation uniqueIdentifier = itemStack.getItem().getRegistryName(); assert uniqueIdentifier != null; @@ -95,21 +80,4 @@ public class CommandDump extends AbstractCommand { public String getUsage(@Nonnull final ICommandSender icommandsender) { return "/wdump: write loot table in console for item container below or next to player"; } - - @Nullable - private IInventory getInventory(@Nonnull final World world, final int x, final int y, final int z) { - final BlockPos blockPos = new BlockPos(x, y, z); - final IBlockState blockState = world.getBlockState(blockPos); - if (blockState.getBlock() instanceof ITileEntityProvider) { - if (blockState.getBlock().hasTileEntity(blockState)) { - final TileEntity tileEntity = world.getTileEntity(blockPos); - if (tileEntity instanceof IInventory) { - if (((IInventory) tileEntity).getSizeInventory() > 0) { - return (IInventory) tileEntity; - } - } - } - } - return null; - } } diff --git a/src/main/java/cr0s/warpdrive/data/ForceFieldSetup.java b/src/main/java/cr0s/warpdrive/data/ForceFieldSetup.java index 19104ec1..e9dc6c3c 100644 --- a/src/main/java/cr0s/warpdrive/data/ForceFieldSetup.java +++ b/src/main/java/cr0s/warpdrive/data/ForceFieldSetup.java @@ -20,7 +20,6 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; -import net.minecraft.inventory.IInventory; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumFacing; @@ -47,7 +46,7 @@ public class ForceFieldSetup extends GlobalPosition { private int colorMultiplierCamouflage; private int lightCamouflage; private final HashMap upgrades = new HashMap<>(EnumForceFieldUpgrade.length); - public final Collection inventories = new ArrayList<>(12); + public final Collection inventories = new ArrayList<>(12); public float scanSpeed; public float placeSpeed; @@ -202,7 +201,7 @@ public class ForceFieldSetup extends GlobalPosition { // container identification if (upgradeEffector == EnumForceFieldUpgrade.ITEM_PORT) { - inventories.addAll(Commons.getConnectedInventories(tileEntity)); + inventories.addAll(InventoryWrapper.getConnectedInventories(tileEntity.getWorld(), tileEntity.getPos())); } } } diff --git a/src/main/java/cr0s/warpdrive/data/InventoryWrapper.java b/src/main/java/cr0s/warpdrive/data/InventoryWrapper.java new file mode 100644 index 00000000..db62d2d1 --- /dev/null +++ b/src/main/java/cr0s/warpdrive/data/InventoryWrapper.java @@ -0,0 +1,330 @@ +package cr0s.warpdrive.data; + +import cr0s.warpdrive.Commons; +import cr0s.warpdrive.WarpDrive; +import cr0s.warpdrive.config.WarpDriveConfig; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockPos.MutableBlockPos; +import net.minecraft.world.World; + +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +// note: unlike Forge's InvWrapper this won't create ItemStack all around, saving us a bit of lag from GC and capabilities + +public class InventoryWrapper { + + // constants + // public static final String TAG_INVENTORY = "inventory"; + + // WarpDrive methods + public static boolean isInventory(final TileEntity tileEntity, final EnumFacing facing) { + boolean isInventory = false; + + if (tileEntity instanceof IInventory) { + isInventory = true; + } + + if ( !isInventory + && tileEntity.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing)) { + isInventory = true; + } + + return isInventory; + } + + public static Object getInventory(final TileEntity tileEntity, final EnumFacing facing) { + if (tileEntity instanceof IInventory) { + return tileEntity; + } + + if (tileEntity != null) { + return tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing); + } + + return null; + } + + public static @Nonnull Collection getConnectedInventories(final World world, final BlockPos blockPos) { + final Collection result = new ArrayList<>(6); + final Collection resultCapabilities = new ArrayList<>(6); + final MutableBlockPos mutableBlockPos = new MutableBlockPos(); + + for(final EnumFacing side : EnumFacing.VALUES) { + mutableBlockPos.setPos(blockPos.getX() + side.getXOffset(), + blockPos.getY() + side.getYOffset(), + blockPos.getZ() + side.getZOffset() ); + final TileEntity tileEntity = world.getTileEntity(mutableBlockPos); + + if (tileEntity instanceof IInventory) { + result.add(tileEntity); + + if (tileEntity instanceof TileEntityChest) { + final TileEntityChest tileEntityChest = (TileEntityChest) tileEntity; + tileEntityChest.checkForAdjacentChests(); + if (tileEntityChest.adjacentChestXNeg != null) { + result.add(tileEntityChest.adjacentChestXNeg); + } else if (tileEntityChest.adjacentChestXPos != null) { + result.add(tileEntityChest.adjacentChestXPos); + } else if (tileEntityChest.adjacentChestZNeg != null) { + result.add(tileEntityChest.adjacentChestZNeg); + } else if (tileEntityChest.adjacentChestZPos != null) { + result.add(tileEntityChest.adjacentChestZPos); + } + } + } else if (tileEntity != null) { + final IItemHandler itemHandler = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side); + if (itemHandler != null) { + resultCapabilities.add(itemHandler); + } + } + } + + // IItemHandler is causing more memory allocations, so we're prioritizing the interface approach + result.addAll(resultCapabilities); + return result; + } + + public static boolean addToConnectedInventories(final World world, final BlockPos blockPos, final ItemStack itemStack) { + final List itemStacks = new ArrayList<>(1); + itemStacks.add(itemStack); + final Collection inventories = getConnectedInventories(world, blockPos); + return addToInventories(world, blockPos, inventories, itemStacks); + } + + public static boolean addToConnectedInventories(final World world, final BlockPos blockPos, final List itemStacks) { + final Collection inventories = getConnectedInventories(world, blockPos); + return addToInventories(world, blockPos, inventories, itemStacks); + } + + public static boolean addToInventories(final World world, final BlockPos blockPos, + final Collection inventories, final List itemStacks) { + boolean overflow = false; + if (itemStacks != null) { + for (final ItemStack itemStack : itemStacks) { + if (itemStack.isEmpty()) { + WarpDrive.logger.error(String.format("Invalid empty itemStack %s", + Commons.format(world, blockPos) )); + continue; + } + int qtyLeft = itemStack.getCount(); + final ItemStack itemStackLeft = itemStack.copy(); + for (final Object inventory : inventories) { + if (inventory instanceof IInventory) { + qtyLeft = addToInventory(itemStack, (IInventory) inventory); + } else if (inventory instanceof IItemHandler) { + qtyLeft = addToInventory(itemStack, (IItemHandler) inventory); + } else { + WarpDrive.logger.error(String.format("Invalid inventory type %s, please report to mod author: %s", + Commons.format(world, blockPos), inventory )); + } + if (qtyLeft > 0) { + itemStackLeft.setCount(qtyLeft); + } else { + break; + } + } + if (qtyLeft > 0) { + if (WarpDriveConfig.LOGGING_COLLECTION) { + WarpDrive.logger.info(String.format("Overflow detected %s", + Commons.format(world, blockPos) )); + } + overflow = true; + int transfer; + while (qtyLeft > 0) { + transfer = Math.min(qtyLeft, itemStackLeft.getMaxStackSize()); + final ItemStack itemStackDrop = Commons.copyWithSize(itemStackLeft, transfer); + final EntityItem entityItem = new EntityItem(world, blockPos.getX() + 0.5D, blockPos.getY() + 1.0D, blockPos.getZ() + 0.5D, itemStackDrop); + world.spawnEntity(entityItem); + qtyLeft -= transfer; + } + } + } + } + return overflow; + } + + private static int addToInventory(final ItemStack itemStackSource, final IInventory inventory) { + if (itemStackSource == null || itemStackSource.isEmpty()) { + return 0; + } + + int qtyLeft = itemStackSource.getCount(); + if (inventory == null) { + return qtyLeft; + } + + // fill existing stacks first + for (int indexSlot = 0; indexSlot < inventory.getSizeInventory(); indexSlot++) { + if (!inventory.isItemValidForSlot(indexSlot, itemStackSource)) { + continue; + } + + final ItemStack itemStack = inventory.getStackInSlot(indexSlot); + if ( itemStack.isEmpty() + || !itemStack.isItemEqual(itemStackSource) ) { + continue; + } + + final int transfer = Math.min(Math.min(qtyLeft, itemStack.getMaxStackSize() - itemStack.getCount()), inventory.getInventoryStackLimit()); + itemStack.grow(transfer); + qtyLeft -= transfer; + if (qtyLeft <= 0) { + return 0; + } + } + + // put remaining in an empty slot + for (int indexSlot = 0; indexSlot < inventory.getSizeInventory(); indexSlot++) { + if (!inventory.isItemValidForSlot(indexSlot, itemStackSource)) { + continue; + } + + final ItemStack itemStack = inventory.getStackInSlot(indexSlot); + if (!itemStack.isEmpty()) { + continue; + } + + final int transfer = Math.min(Math.min(qtyLeft, itemStackSource.getMaxStackSize()), inventory.getInventoryStackLimit()); + final ItemStack dest = Commons.copyWithSize(itemStackSource, transfer); + inventory.setInventorySlotContents(indexSlot, dest); + qtyLeft -= transfer; + + if (qtyLeft <= 0) { + return 0; + } + } + + return qtyLeft; + } + + private static int addToInventory(final ItemStack itemStackSource, final IItemHandler itemHandler) { + if (itemStackSource == null || itemStackSource.isEmpty()) { + return 0; + } + + if (itemHandler == null) { + return itemStackSource.getCount(); + } + ItemStack itemStackLeft = itemStackSource; + + // fill existing stacks first + for (int indexSlot = 0; indexSlot < itemHandler.getSlots(); indexSlot++) { + if (!itemHandler.isItemValid(indexSlot, itemStackSource)) { + continue; + } + + final ItemStack itemStack = itemHandler.getStackInSlot(indexSlot); + if ( itemStack.isEmpty() + || !itemStack.isItemEqual(itemStackSource) ) { + continue; + } + + itemStackLeft = itemHandler.insertItem(indexSlot, itemStackLeft, false); + if (itemStackLeft.getCount() <= 0) { + return 0; + } + } + + // put remaining in an empty slot + for (int indexSlot = 0; indexSlot < itemHandler.getSlots(); indexSlot++) { + if (!itemHandler.isItemValid(indexSlot, itemStackSource)) { + continue; + } + + final ItemStack itemStack = itemHandler.getStackInSlot(indexSlot); + if (!itemStack.isEmpty()) { + continue; + } + + itemStackLeft = itemHandler.insertItem(indexSlot, itemStackSource, false); + if (itemStackLeft.getCount() <= 0) { + return 0; + } + } + + return itemStackLeft.getCount(); + } + + public static int getSize(final Object inventory) { + if (inventory instanceof IInventory) { + return ((IInventory) inventory).getSizeInventory(); + } else if (inventory instanceof IItemHandler) { + return ((IItemHandler) inventory).getSlots(); + } else { + WarpDrive.logger.error(String.format("Invalid inventory type, please report to mod author: %s", + inventory )); + return 0; + } + } + + public static ItemStack getStackInSlot(final Object inventory, final int indexSlot) { + if (inventory instanceof IInventory) { + return ((IInventory) inventory).getStackInSlot(indexSlot); + } else if (inventory instanceof IItemHandler) { + return ((IItemHandler) inventory).getStackInSlot(indexSlot); + } else { + WarpDrive.logger.error(String.format("Invalid inventory type, please report to mod author: %s", + inventory )); + return ItemStack.EMPTY; + } + } + + public static boolean isItemValid(final Object inventory, final int indexSlot, final ItemStack itemStack) { + if (inventory instanceof IInventory) { + return ((IInventory) inventory).isItemValidForSlot(indexSlot, itemStack); + } else if (inventory instanceof IItemHandler) { + return ((IItemHandler) inventory).isItemValid(indexSlot, itemStack); + } else { + WarpDrive.logger.error(String.format("Invalid inventory type, please report to mod author: %s", + inventory )); + return false; + } + } + + public static void insertItem(final Object inventory, final int indexSlot, final ItemStack itemStack) { + if (inventory instanceof IInventory) { + final ItemStack itemStackExisting = ((IInventory) inventory).getStackInSlot(indexSlot); + if (itemStackExisting.isEmpty()) { + ((IInventory) inventory).setInventorySlotContents(indexSlot, itemStack); + } else { + WarpDrive.logger.error(String.format("Invalid inventory slot %d for insertion of %s, inventory should be empty first, please report to mod author: %s", + indexSlot, itemStack, inventory)); + if (inventory instanceof TileEntity) { + final World world = ((TileEntity) inventory).getWorld(); + final BlockPos blockPos = ((TileEntity) inventory).getPos(); + final EntityItem entityItem = new EntityItem(world, blockPos.getX() + 0.5D, blockPos.getY() + 1.0D, blockPos.getZ() + 0.5D, itemStack); + world.spawnEntity(entityItem); + } + } + } else if (inventory instanceof IItemHandler) { + ((IItemHandler) inventory).insertItem(indexSlot, itemStack, false); + } else { + WarpDrive.logger.error(String.format("Invalid inventory type, please report to mod author: %s", + inventory )); + } + } + + public static void decrStackSize(final Object inventory, final int indexSlot, final int quantity) { + if (inventory instanceof IInventory) { + ((IInventory) inventory).decrStackSize(indexSlot, quantity); + } else if (inventory instanceof IItemHandler) { + ((IItemHandler) inventory).extractItem(indexSlot, quantity, false); + } else { + WarpDrive.logger.error(String.format("Invalid inventory type, please report to mod author: %s", + inventory )); + } + } +} diff --git a/src/main/java/cr0s/warpdrive/world/WorldGenStructure.java b/src/main/java/cr0s/warpdrive/world/WorldGenStructure.java index dd12b459..c0527184 100644 --- a/src/main/java/cr0s/warpdrive/world/WorldGenStructure.java +++ b/src/main/java/cr0s/warpdrive/world/WorldGenStructure.java @@ -8,6 +8,7 @@ import cr0s.warpdrive.config.Filler; import cr0s.warpdrive.config.GenericSet; import cr0s.warpdrive.config.Loot; import cr0s.warpdrive.config.WarpDriveConfig; +import cr0s.warpdrive.data.InventoryWrapper; import cr0s.warpdrive.data.JumpBlock; import cr0s.warpdrive.data.JumpShip; import cr0s.warpdrive.data.Transformation; @@ -19,7 +20,6 @@ import java.util.Random; import net.minecraft.block.Block; import net.minecraft.init.Blocks; -import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; @@ -202,8 +202,9 @@ public class WorldGenStructure { final int maxRetries) { // validate context final TileEntity tileEntity = world.getTileEntity(blockPos); + final Object inventory = InventoryWrapper.getInventory(tileEntity, null); - if (!(tileEntity instanceof IInventory)) { + if (inventory == null) { WarpDrive.logger.error(String.format("Unable to fill inventory with LootSet %s %s: %s has no inventory", group, Commons.format(world, blockPos), @@ -220,8 +221,7 @@ public class WorldGenStructure { } // evaluate parameters: quantity of loot, actual loot set - final IInventory inventory = (IInventory) tileEntity; - final int size = inventory.getSizeInventory(); + final int size = InventoryWrapper.getSize(inventory); final int countLoots = Math.min(quantityMin + rand.nextInt(quantityRandom1) + rand.nextInt(quantityRandom2), size); final GenericSet lootSet = WarpDriveConfig.LootManager.getRandomSetFromGroup(rand, group); @@ -236,7 +236,7 @@ public class WorldGenStructure { // shuffle slot indexes to reduce random calls and loops later on final ArrayList indexSlots = new ArrayList<>(size); for (int indexSlot = 0; indexSlot < size; indexSlot++) { - final ItemStack itemStack = inventory.getStackInSlot(indexSlot); + final ItemStack itemStack = InventoryWrapper.getStackInSlot(inventory, indexSlot); if (itemStack.isEmpty()) { indexSlots.add(indexSlot); } @@ -256,16 +256,16 @@ public class WorldGenStructure { // find a valid slot for it for (final Iterator iterator = indexSlots.iterator(); iterator.hasNext(); ) { final Integer indexSlot = iterator.next(); - if (!inventory.getStackInSlot(indexSlot).isEmpty()) { + if (!InventoryWrapper.getStackInSlot(inventory, indexSlot).isEmpty()) { assert false; // index used were already removed, so we shouldn't reach this continue; } - if (inventory.isItemValidForSlot(indexSlot, itemStackLoot)) { + if (InventoryWrapper.isItemValid(inventory, indexSlot, itemStackLoot)) { // remove that slot & item, even if insertion fail, to avoid a spam iterator.remove(); isAdded = true; try { - inventory.setInventorySlotContents(indexSlot, itemStackLoot); + InventoryWrapper.insertItem(inventory, indexSlot, itemStackLoot); if (WarpDriveConfig.LOGGING_WORLD_GENERATION) { WarpDrive.logger.debug(String.format("Filling inventory with LootSet %s %s: loot %s from %s in slot %d of inventory %s", group, @@ -273,7 +273,7 @@ public class WorldGenStructure { Commons.format(itemStackLoot), lootSet.getFullName(), indexSlot, - inventory.getName() == null ? "-null name-" : inventory.getName() )); + inventory )); } } catch (final Exception exception) { exception.printStackTrace(); @@ -283,7 +283,7 @@ public class WorldGenStructure { Commons.format(itemStackLoot), lootSet.getFullName(), indexSlot, - inventory.getName() == null ? "-null name-" : inventory.getName(), + inventory, exception.getMessage() )); } break; @@ -296,7 +296,7 @@ public class WorldGenStructure { if (!isAdded) { WarpDrive.logger.debug(String.format("Unable to find a valid loot from LootSet %s for inventory %s in %s: check your configuration", lootSet.getFullName(), - inventory.getName() == null ? "-null name-" : inventory.getName(), + inventory, Commons.format(world, blockPos) )); } }