Added capability support for inventories

Refactored inventory handling outside Commons and TileEntityAbstractBase
This commit is contained in:
Unknown 2019-01-20 17:03:39 +01:00 committed by unknown
parent 9ee49914ec
commit 729fb4d0f7
9 changed files with 414 additions and 250 deletions

View file

@ -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<IInventory> getConnectedInventories(final TileEntity tileEntityConnection) {
final Collection<IInventory> 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

View file

@ -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<ItemStack> itemStacks = new ArrayList<>(1);
itemStacks.add(itemStack);
return addToInventories(itemStacks, Commons.getConnectedInventories(this));
}
protected boolean addToConnectedInventories(final List<ItemStack> itemStacks) {
return addToInventories(itemStacks, Commons.getConnectedInventories(this));
}
protected boolean addToInventories(final List<ItemStack> itemStacks, final Collection<IInventory> 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) {

View file

@ -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

View file

@ -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<IInventory> inventories = Commons.getConnectedInventories(this);
final Collection<Object> 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);
}
}
}

View file

@ -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 {

View file

@ -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<Object> 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;
}
}

View file

@ -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<IForceFieldUpgradeEffector, Float> upgrades = new HashMap<>(EnumForceFieldUpgrade.length);
public final Collection<IInventory> inventories = new ArrayList<>(12);
public final Collection<Object> 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()));
}
}
}

View file

@ -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<Object> getConnectedInventories(final World world, final BlockPos blockPos) {
final Collection<Object> result = new ArrayList<>(6);
final Collection<IItemHandler> 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<ItemStack> itemStacks = new ArrayList<>(1);
itemStacks.add(itemStack);
final Collection<Object> inventories = getConnectedInventories(world, blockPos);
return addToInventories(world, blockPos, inventories, itemStacks);
}
public static boolean addToConnectedInventories(final World world, final BlockPos blockPos, final List<ItemStack> itemStacks) {
final Collection<Object> inventories = getConnectedInventories(world, blockPos);
return addToInventories(world, blockPos, inventories, itemStacks);
}
public static boolean addToInventories(final World world, final BlockPos blockPos,
final Collection<Object> inventories, final List<ItemStack> 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 ));
}
}
}

View file

@ -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<Loot> 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<Integer> 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<Integer> 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) ));
}
}