441 lines
14 KiB
Java
441 lines
14 KiB
Java
package net.minecraft.tileentity;
|
|
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.block.Block;
|
|
import net.minecraft.block.BlockChest;
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.entity.player.InventoryPlayer;
|
|
import net.minecraft.init.SoundEvents;
|
|
import net.minecraft.inventory.Container;
|
|
import net.minecraft.inventory.ContainerChest;
|
|
import net.minecraft.inventory.IInventory;
|
|
import net.minecraft.inventory.InventoryLargeChest;
|
|
import net.minecraft.inventory.ItemStackHelper;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.util.EnumFacing;
|
|
import net.minecraft.util.ITickable;
|
|
import net.minecraft.util.NonNullList;
|
|
import net.minecraft.util.SoundCategory;
|
|
import net.minecraft.util.datafix.DataFixer;
|
|
import net.minecraft.util.datafix.FixTypes;
|
|
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
|
import net.minecraft.util.math.AxisAlignedBB;
|
|
import net.minecraft.util.math.BlockPos;
|
|
|
|
public class TileEntityChest extends TileEntityLockableLoot implements ITickable
|
|
{
|
|
private NonNullList<ItemStack> chestContents = NonNullList.<ItemStack>withSize(27, ItemStack.EMPTY);
|
|
/** Determines if the check for adjacent chests has taken place. */
|
|
public boolean adjacentChestChecked;
|
|
/** Contains the chest tile located adjacent to this one (if any) */
|
|
public TileEntityChest adjacentChestZNeg;
|
|
/** Contains the chest tile located adjacent to this one (if any) */
|
|
public TileEntityChest adjacentChestXPos;
|
|
/** Contains the chest tile located adjacent to this one (if any) */
|
|
public TileEntityChest adjacentChestXNeg;
|
|
/** Contains the chest tile located adjacent to this one (if any) */
|
|
public TileEntityChest adjacentChestZPos;
|
|
/** The current angle of the lid (between 0 and 1) */
|
|
public float lidAngle;
|
|
/** The angle of the lid last tick */
|
|
public float prevLidAngle;
|
|
/** The number of players currently using this chest */
|
|
public int numPlayersUsing;
|
|
/** Server sync counter (once per 20 ticks) */
|
|
private int ticksSinceSync;
|
|
private BlockChest.Type cachedChestType;
|
|
|
|
public TileEntityChest()
|
|
{
|
|
}
|
|
|
|
public TileEntityChest(BlockChest.Type typeIn)
|
|
{
|
|
this.cachedChestType = typeIn;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of slots in the inventory.
|
|
*/
|
|
public int getSizeInventory()
|
|
{
|
|
return 27;
|
|
}
|
|
|
|
public boolean isEmpty()
|
|
{
|
|
for (ItemStack itemstack : this.chestContents)
|
|
{
|
|
if (!itemstack.isEmpty())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the name of this object. For players this returns their username
|
|
*/
|
|
public String getName()
|
|
{
|
|
return this.hasCustomName() ? this.customName : "container.chest";
|
|
}
|
|
|
|
public static void registerFixesChest(DataFixer fixer)
|
|
{
|
|
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityChest.class, new String[] {"Items"}));
|
|
}
|
|
|
|
public void readFromNBT(NBTTagCompound compound)
|
|
{
|
|
super.readFromNBT(compound);
|
|
this.chestContents = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
|
|
|
|
if (!this.checkLootAndRead(compound))
|
|
{
|
|
ItemStackHelper.loadAllItems(compound, this.chestContents);
|
|
}
|
|
|
|
if (compound.hasKey("CustomName", 8))
|
|
{
|
|
this.customName = compound.getString("CustomName");
|
|
}
|
|
}
|
|
|
|
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
|
{
|
|
super.writeToNBT(compound);
|
|
|
|
if (!this.checkLootAndWrite(compound))
|
|
{
|
|
ItemStackHelper.saveAllItems(compound, this.chestContents);
|
|
}
|
|
|
|
if (this.hasCustomName())
|
|
{
|
|
compound.setString("CustomName", this.customName);
|
|
}
|
|
|
|
return compound;
|
|
}
|
|
|
|
/**
|
|
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
|
|
*/
|
|
public int getInventoryStackLimit()
|
|
{
|
|
return 64;
|
|
}
|
|
|
|
public void updateContainingBlockInfo()
|
|
{
|
|
super.updateContainingBlockInfo();
|
|
this.adjacentChestChecked = false;
|
|
doubleChestHandler = null;
|
|
}
|
|
|
|
@SuppressWarnings("incomplete-switch")
|
|
private void setNeighbor(TileEntityChest chestTe, EnumFacing side)
|
|
{
|
|
if (chestTe.isInvalid())
|
|
{
|
|
this.adjacentChestChecked = false;
|
|
}
|
|
else if (this.adjacentChestChecked)
|
|
{
|
|
switch (side)
|
|
{
|
|
case NORTH:
|
|
|
|
if (this.adjacentChestZNeg != chestTe)
|
|
{
|
|
this.adjacentChestChecked = false;
|
|
}
|
|
|
|
break;
|
|
case SOUTH:
|
|
|
|
if (this.adjacentChestZPos != chestTe)
|
|
{
|
|
this.adjacentChestChecked = false;
|
|
}
|
|
|
|
break;
|
|
case EAST:
|
|
|
|
if (this.adjacentChestXPos != chestTe)
|
|
{
|
|
this.adjacentChestChecked = false;
|
|
}
|
|
|
|
break;
|
|
case WEST:
|
|
|
|
if (this.adjacentChestXNeg != chestTe)
|
|
{
|
|
this.adjacentChestChecked = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Performs the check for adjacent chests to determine if this chest is double or not.
|
|
*/
|
|
public void checkForAdjacentChests()
|
|
{
|
|
if (!this.adjacentChestChecked)
|
|
{
|
|
if (this.world == null || !this.world.isAreaLoaded(this.pos, 1)) return; // Forge: prevent loading unloaded chunks when checking neighbors
|
|
this.adjacentChestChecked = true;
|
|
this.adjacentChestXNeg = this.getAdjacentChest(EnumFacing.WEST);
|
|
this.adjacentChestXPos = this.getAdjacentChest(EnumFacing.EAST);
|
|
this.adjacentChestZNeg = this.getAdjacentChest(EnumFacing.NORTH);
|
|
this.adjacentChestZPos = this.getAdjacentChest(EnumFacing.SOUTH);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
protected TileEntityChest getAdjacentChest(EnumFacing side)
|
|
{
|
|
BlockPos blockpos = this.pos.offset(side);
|
|
|
|
if (this.isChestAt(blockpos))
|
|
{
|
|
TileEntity tileentity = this.world.getTileEntity(blockpos);
|
|
|
|
if (tileentity instanceof TileEntityChest)
|
|
{
|
|
TileEntityChest tileentitychest = (TileEntityChest)tileentity;
|
|
tileentitychest.setNeighbor(this, side.getOpposite());
|
|
return tileentitychest;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private boolean isChestAt(BlockPos posIn)
|
|
{
|
|
if (this.world == null)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Block block = this.world.getBlockState(posIn).getBlock();
|
|
return block instanceof BlockChest && ((BlockChest)block).chestType == this.getChestType();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Like the old updateEntity(), except more generic.
|
|
*/
|
|
public void update()
|
|
{
|
|
this.checkForAdjacentChests();
|
|
int i = this.pos.getX();
|
|
int j = this.pos.getY();
|
|
int k = this.pos.getZ();
|
|
++this.ticksSinceSync;
|
|
|
|
if (!this.world.isRemote && this.numPlayersUsing != 0 && (this.ticksSinceSync + i + j + k) % 200 == 0)
|
|
{
|
|
this.numPlayersUsing = 0;
|
|
float f = 5.0F;
|
|
|
|
for (EntityPlayer entityplayer : this.world.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB((double)((float)i - 5.0F), (double)((float)j - 5.0F), (double)((float)k - 5.0F), (double)((float)(i + 1) + 5.0F), (double)((float)(j + 1) + 5.0F), (double)((float)(k + 1) + 5.0F))))
|
|
{
|
|
if (entityplayer.openContainer instanceof ContainerChest)
|
|
{
|
|
IInventory iinventory = ((ContainerChest)entityplayer.openContainer).getLowerChestInventory();
|
|
|
|
if (iinventory == this || iinventory instanceof InventoryLargeChest && ((InventoryLargeChest)iinventory).isPartOfLargeChest(this))
|
|
{
|
|
++this.numPlayersUsing;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.prevLidAngle = this.lidAngle;
|
|
float f1 = 0.1F;
|
|
|
|
if (this.numPlayersUsing > 0 && this.lidAngle == 0.0F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
|
|
{
|
|
double d1 = (double)i + 0.5D;
|
|
double d2 = (double)k + 0.5D;
|
|
|
|
if (this.adjacentChestZPos != null)
|
|
{
|
|
d2 += 0.5D;
|
|
}
|
|
|
|
if (this.adjacentChestXPos != null)
|
|
{
|
|
d1 += 0.5D;
|
|
}
|
|
|
|
this.world.playSound((EntityPlayer)null, d1, (double)j + 0.5D, d2, SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
|
|
}
|
|
|
|
if (this.numPlayersUsing == 0 && this.lidAngle > 0.0F || this.numPlayersUsing > 0 && this.lidAngle < 1.0F)
|
|
{
|
|
float f2 = this.lidAngle;
|
|
|
|
if (this.numPlayersUsing > 0)
|
|
{
|
|
this.lidAngle += 0.1F;
|
|
}
|
|
else
|
|
{
|
|
this.lidAngle -= 0.1F;
|
|
}
|
|
|
|
if (this.lidAngle > 1.0F)
|
|
{
|
|
this.lidAngle = 1.0F;
|
|
}
|
|
|
|
float f3 = 0.5F;
|
|
|
|
if (this.lidAngle < 0.5F && f2 >= 0.5F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
|
|
{
|
|
double d3 = (double)i + 0.5D;
|
|
double d0 = (double)k + 0.5D;
|
|
|
|
if (this.adjacentChestZPos != null)
|
|
{
|
|
d0 += 0.5D;
|
|
}
|
|
|
|
if (this.adjacentChestXPos != null)
|
|
{
|
|
d3 += 0.5D;
|
|
}
|
|
|
|
this.world.playSound((EntityPlayer)null, d3, (double)j + 0.5D, d0, SoundEvents.BLOCK_CHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
|
|
}
|
|
|
|
if (this.lidAngle < 0.0F)
|
|
{
|
|
this.lidAngle = 0.0F;
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean receiveClientEvent(int id, int type)
|
|
{
|
|
if (id == 1)
|
|
{
|
|
this.numPlayersUsing = type;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return super.receiveClientEvent(id, type);
|
|
}
|
|
}
|
|
|
|
public void openInventory(EntityPlayer player)
|
|
{
|
|
if (!player.isSpectator())
|
|
{
|
|
if (this.numPlayersUsing < 0)
|
|
{
|
|
this.numPlayersUsing = 0;
|
|
}
|
|
|
|
++this.numPlayersUsing;
|
|
this.world.addBlockEvent(this.pos, this.getBlockType(), 1, this.numPlayersUsing);
|
|
this.world.notifyNeighborsOfStateChange(this.pos, this.getBlockType(), false);
|
|
|
|
if (this.getChestType() == BlockChest.Type.TRAP)
|
|
{
|
|
this.world.notifyNeighborsOfStateChange(this.pos.down(), this.getBlockType(), false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void closeInventory(EntityPlayer player)
|
|
{
|
|
if (!player.isSpectator() && this.getBlockType() instanceof BlockChest)
|
|
{
|
|
--this.numPlayersUsing;
|
|
this.world.addBlockEvent(this.pos, this.getBlockType(), 1, this.numPlayersUsing);
|
|
this.world.notifyNeighborsOfStateChange(this.pos, this.getBlockType(), false);
|
|
|
|
if (this.getChestType() == BlockChest.Type.TRAP)
|
|
{
|
|
this.world.notifyNeighborsOfStateChange(this.pos.down(), this.getBlockType(), false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public net.minecraftforge.items.VanillaDoubleChestItemHandler doubleChestHandler;
|
|
|
|
@SuppressWarnings("unchecked")
|
|
@Override
|
|
@Nullable
|
|
public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable net.minecraft.util.EnumFacing facing)
|
|
{
|
|
if (capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
|
{
|
|
if(doubleChestHandler == null || doubleChestHandler.needsRefresh())
|
|
doubleChestHandler = net.minecraftforge.items.VanillaDoubleChestItemHandler.get(this);
|
|
if (doubleChestHandler != null && doubleChestHandler != net.minecraftforge.items.VanillaDoubleChestItemHandler.NO_ADJACENT_CHESTS_INSTANCE)
|
|
return (T) doubleChestHandler;
|
|
}
|
|
return super.getCapability(capability, facing);
|
|
}
|
|
|
|
public net.minecraftforge.items.IItemHandler getSingleChestHandler()
|
|
{
|
|
return super.getCapability(net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
|
|
}
|
|
|
|
|
|
/**
|
|
* invalidates a tile entity
|
|
*/
|
|
public void invalidate()
|
|
{
|
|
super.invalidate();
|
|
this.updateContainingBlockInfo();
|
|
this.checkForAdjacentChests();
|
|
}
|
|
|
|
public BlockChest.Type getChestType()
|
|
{
|
|
if (this.cachedChestType == null)
|
|
{
|
|
if (this.world == null || !(this.getBlockType() instanceof BlockChest))
|
|
{
|
|
return BlockChest.Type.BASIC;
|
|
}
|
|
|
|
this.cachedChestType = ((BlockChest)this.getBlockType()).chestType;
|
|
}
|
|
|
|
return this.cachedChestType;
|
|
}
|
|
|
|
public String getGuiID()
|
|
{
|
|
return "minecraft:chest";
|
|
}
|
|
|
|
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
|
{
|
|
this.fillWithLoot(playerIn);
|
|
return new ContainerChest(playerInventory, this, playerIn);
|
|
}
|
|
|
|
protected NonNullList<ItemStack> getItems()
|
|
{
|
|
return this.chestContents;
|
|
}
|
|
} |