package com.cricketcraft.chisel.block.tileentity; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import com.cricketcraft.chisel.init.ChiselBlocks; import com.cricketcraft.chisel.network.PacketHandler; import com.cricketcraft.chisel.network.message.MessagePresentConnect; public class TileEntityPresent extends TileEntity implements IInventory, IDoubleChest { private TileEntityPresent connection = null; // If cachedDir is non-null, but connection is null, this present must be // connected to an unloaded present. This is handled appropriately. private ForgeDirection cachedDir = null; private boolean isParent; private final ItemStack[] inventory = new ItemStack[27]; private int rotation; private boolean autoSearch = true; @Override public void updateEntity() { if (!isConnected() && autoSearch && worldObj != null /* ugh */) { if (cachedDir != null) { connectTo(cachedDir); } else if (!worldObj.isRemote){ findConnections(); } autoSearch = false; } } public boolean isConnected() { return connection != null; } private boolean connectTo(TileEntityPresent present, ForgeDirection dir) { if (present.getBlockMetadata() == getBlockMetadata() && !present.isConnected() && (present.cachedDir == null || present.cachedDir == dir.getOpposite()) && Math.abs(present.xCoord - xCoord + present.yCoord - yCoord + present.zCoord - zCoord) == 1) { connection = present; connection.connection = this; connection.cachedDir = dir.getOpposite(); connection.markDirty(); cachedDir = dir; isParent = !present.isParent; markDirty(); PacketHandler.INSTANCE.sendToDimension(new MessagePresentConnect(this, dir, true), worldObj.provider.dimensionId); return true; } return false; } public boolean connectTo(ForgeDirection dir) { int x = xCoord + dir.offsetX, y = yCoord + dir.offsetY, z = zCoord + dir.offsetZ; TileEntity te = getTileSafe(x, y, z); if (te instanceof TileEntityPresent) { return connectTo((TileEntityPresent) te, dir); } return !exists(x, y, z); } /** * @param preserveDir * If true, this is only a virtual disconnect, meaning the other * chest still exists, but is still loaded, so maintain a * cachedDir for reconnection upon chunk load. */ public void disconnect(boolean preserveDir) { if (isConnected()) { if (!preserveDir) { this.connection.cachedDir = null; this.cachedDir = null; } this.connection.connection = null; this.connection.markDirty(); this.connection = null; this.markDirty(); PacketHandler.INSTANCE.sendToDimension(new MessagePresentConnect(this, ForgeDirection.UNKNOWN, false, preserveDir), worldObj.provider.dimensionId); } } public TileEntityPresent getConnection() { return connection; } public ForgeDirection getConnectionDir() { return cachedDir == null ? ForgeDirection.UNKNOWN : cachedDir; } public boolean isParent() { return isParent || !isConnected(); } public int getRotation() { return rotation; } public void setRotation(int rot) { this.rotation = rot; } public void findConnections() { if (!isConnected()) { if (cachedDir != null) { if (connectTo(cachedDir)) { return; } } for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { if (dir != ForgeDirection.UP && dir != ForgeDirection.DOWN) { if (connectTo(dir)) { return; } } } } } public TileEntityPresent getParent() { return isParent || connection == null ? this : connection; } @Override public AxisAlignedBB getRenderBoundingBox() { return ChiselBlocks.present.getBoundingBox(this); } @Override public void writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); NBTTagList nbttaglist = new NBTTagList(); for (int i = 0; i < getTrueSizeInventory(); ++i) { if (inventory[i] != null) { NBTTagCompound nbttagcompound1 = new NBTTagCompound(); nbttagcompound1.setByte("Slot", (byte) i); inventory[i].writeToNBT(nbttagcompound1); nbttaglist.appendTag(nbttagcompound1); } } tag.setTag("Items", nbttaglist); tag.setBoolean("isParent", isParent); tag.setInteger("rotation", rotation); if (cachedDir != null) { tag.setInteger("conDir", cachedDir.ordinal()); } } @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); NBTTagList nbttaglist = tag.getTagList("Items", 10); for (int i = 0; i < nbttaglist.tagCount(); ++i) { NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); int j = nbttagcompound1.getByte("Slot") & 255; if (j >= 0 && j < getTrueSizeInventory()) { inventory[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1); } } this.isParent = tag.getBoolean("isParent"); this.rotation = tag.getInteger("rotation"); if (tag.hasKey("conDir")) { cachedDir = ForgeDirection.values()[tag.getInteger("conDir")]; } autoSearch = true; } @Override public Packet getDescriptionPacket() { NBTTagCompound tag = new NBTTagCompound(); writeToNBT(tag); return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 1, tag); } @Override public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity packet) { readFromNBT(packet.func_148857_g()); } @Override public boolean shouldRefresh(Block oldBlock, Block newBlock, int oldMeta, int newMeta, World world, int x, int y, int z) { // prevent losing TE data when in-world chiseling return oldBlock != newBlock; } @Override public void invalidate() { super.invalidate(); if (isConnected()) { disconnect(false); } } @Override public void onChunkUnload() { super.onChunkUnload(); if (isConnected()) { disconnect(true); } } private int getAdjustedSlot(int slot) { slot %= getSizeInventory(); if (isConnected() && !isParent) { slot = (slot + getTrueSizeInventory()) % getSizeInventory(); } return slot; } private TileEntity getTileSafe(int x, int y, int z) { if (exists(x, y, z)) { return worldObj.getTileEntity(x, y, z); } return null; } // private Block getBlockSafe(int x, int y, int z) { // if (exists(x, y, z)) { // return worldObj.getBlock(x, y, z); // } // return null; // } // // private int getMetaSafe(int x, int y, int z) { // if (exists(x, y, z)) { // return worldObj.getBlockMetadata(x, y, z); // } // return 0; // } // private boolean exists(int x, int y, int z) { return worldObj.blockExists(x, y, z); } /* IInventory */ @Override public int getSizeInventory() { return isConnected() ? getTrueSizeInventory() + connection.getTrueSizeInventory() : getTrueSizeInventory(); } @Override public ItemStack getStackInSlot(int slot) { slot = getAdjustedSlot(slot); if (slot >= getTrueSizeInventory()) { return isConnected() ? connection.inventory[slot % getTrueSizeInventory()] : null; } else { return inventory[slot]; } } @Override public ItemStack decrStackSize(int slot, int amount) { slot = getAdjustedSlot(slot); ItemStack[] inv = inventory; if (isConnected() && slot >= getTrueSizeInventory()) { inv = connection.inventory; slot %= getTrueSizeInventory(); connection.markDirty(); } if (inv[slot] != null) { ItemStack itemstack; if (inv[slot].stackSize <= amount) { itemstack = inv[slot]; inv[slot] = null; this.markDirty(); return itemstack; } else { itemstack = inv[slot].splitStack(amount); if (inv[slot].stackSize == 0) { inv[slot] = null; } this.markDirty(); return itemstack; } } else { return null; } } @Override public ItemStack getStackInSlotOnClosing(int slot) { return getStackInSlot(slot); } @Override public void setInventorySlotContents(int slot, ItemStack stack) { slot = getAdjustedSlot(slot); if (slot < getTrueSizeInventory()) { inventory[slot] = stack; } else if (isConnected()) { connection.inventory[slot % getTrueSizeInventory()] = stack; connection.markDirty(); } } @Override public String getInventoryName() { return "chisel.present"; } @Override public boolean hasCustomInventoryName() { return false; } @Override public int getInventoryStackLimit() { return 64; } @Override public boolean isUseableByPlayer(EntityPlayer p_70300_1_) { return true; } @Override public void openInventory() { ; } @Override public void closeInventory() { ; } @Override public boolean isItemValidForSlot(int p_94041_1_, ItemStack p_94041_2_) { return true; } /* IDoubleChest */ @Override public int getTrueSizeInventory() { return inventory.length; } @Override public ItemStack getTrueStackInSlot(int slot) { return inventory[slot % getTrueSizeInventory()]; } @Override public void putStackInTrueSlot(int slot, ItemStack stack) { inventory[slot % getTrueSizeInventory()] = stack; } }