package com.minemaarten.advancedmod.tileentity;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import net.minecraft.entity.item.EntityItem;
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.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import com.minemaarten.advancedmod.init.ModBlocks;
import com.minemaarten.advancedmod.utility.Log;
public class TileEntityModularStorage extends TileEntityAdvancedMod implements IInventory{
private static final int SLOTS_PER_BLOCK = 1;
private ItemStack[] inventory = new ItemStack[SLOTS_PER_BLOCK];
private TileEntityModularStorage master;
private boolean isMaster;
private boolean firstRun = true;
public boolean isMaster(){
return isMaster;
}
public TileEntityModularStorage getMaster(){
initializeMultiblockIfNecessary();
return master;
}
private void setMaster(TileEntityModularStorage master, int storages){
this.master = master;
boolean wasMaster = isMaster;
isMaster = master == this;
if(isMaster) {
Log.info("Master set to " + storages + " blocks");
ItemStack[] newInventory = new ItemStack[SLOTS_PER_BLOCK * storages];
for(int i = 0; i < inventory.length; i++) {
if(i < newInventory.length) {
newInventory[i] = inventory[i];
} else if(inventory[i] != null) {
worldObj.spawnEntityInWorld(new EntityItem(worldObj, xCoord, yCoord, zCoord, inventory[i]));
}
}
inventory = newInventory;
} else if(!isMaster && wasMaster) {
for(ItemStack stack : inventory) {
if(stack != null) worldObj.spawnEntityInWorld(new EntityItem(worldObj, xCoord, yCoord, zCoord, stack));
}
}
}
@Override
public void updateEntity(){
super.updateEntity();
if(firstRun) {
initializeMultiblockIfNecessary();
firstRun = false;
}
}
@Override
public void invalidate(){
super.invalidate();
for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
TileEntity te = worldObj.getTileEntity(xCoord + d.offsetX, yCoord + d.offsetY, zCoord + d.offsetZ);
if(te instanceof TileEntityModularStorage) {
((TileEntityModularStorage)te).master = null;
((TileEntityModularStorage)te).initializeMultiblockIfNecessary();
}
}
for(ItemStack stack : inventory) {
if(stack != null) worldObj.spawnEntityInWorld(new EntityItem(worldObj, xCoord, yCoord, zCoord, stack));
}
}
private void initializeMultiblockIfNecessary(){
if(master == null || master.isInvalid()) {
List<TileEntityModularStorage> connectedStorages = new ArrayList<TileEntityModularStorage>();
Stack<TileEntityModularStorage> traversingStorages = new Stack<TileEntityModularStorage>();
TileEntityModularStorage master = this;
traversingStorages.add(this);
while(!traversingStorages.isEmpty()) {
TileEntityModularStorage storage = traversingStorages.pop();
if(storage.isMaster()) {
master = storage;
}
connectedStorages.add(storage);
for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
TileEntity te = worldObj.getTileEntity(storage.xCoord + d.offsetX, storage.yCoord + d.offsetY, storage.zCoord + d.offsetZ);
if(te instanceof TileEntityModularStorage && !connectedStorages.contains(te)) {
traversingStorages.add((TileEntityModularStorage)te);
}
}
}
Log.info("Setting master to " + master.xCoord + ", " + master.yCoord + ", " + master.zCoord + " for " + connectedStorages.size() + " blocks");
for(TileEntityModularStorage storage : connectedStorages) {
storage.setMaster(master, connectedStorages.size());
}
}
}
@Override
public void onGuiButtonPress(int id){
}
@Override
public void writeToPacket(ByteBuf buf){
}
@Override
public void readFromPacket(ByteBuf buf){
// worldObj.markBlockRangeForRenderUpdate(xCoord, yCoord, zCoord, xCoord, yCoord, zCoord);
}
@Override
public void readFromNBT(NBTTagCompound tag){
super.readFromNBT(tag);
isMaster = tag.getBoolean("isMaster");
inventory = new ItemStack[tag.getInteger("slots")];
NBTTagList camoStackTag = tag.getTagList("inventory", 10);
for(int i = 0; i < camoStackTag.tagCount(); i++) {
NBTTagCompound t = camoStackTag.getCompoundTagAt(i);
int index = t.getByte("index");
if(index >= 0 && index < inventory.length) {
inventory[index] = ItemStack.loadItemStackFromNBT(t);
}
}
}
@Override
public void writeToNBT(NBTTagCompound tag){
super.writeToNBT(tag);
tag.setBoolean("isMaster", isMaster);
tag.setInteger("slots", inventory.length);
NBTTagList camoStackTag = new NBTTagList();
for(int i = 0; i < inventory.length; i++) {
ItemStack stack = inventory[i];
if(stack != null) {
NBTTagCompound t = new NBTTagCompound();
stack.writeToNBT(t);
t.setByte("index", (byte)i);
camoStackTag.appendTag(t);
}
}
tag.setTag("inventory", camoStackTag);
}
/**
* Returns the number of slots in the inventory.
*/
@Override
public int getSizeInventory(){
return isMaster() ? inventory.length : getMaster().getSizeInventory();
}
/**
* Returns the stack in slot i
*/
@Override
public ItemStack getStackInSlot(int slot){
return isMaster ? inventory[slot] : getMaster().getStackInSlot(slot);
}
/**
* Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
* new stack.
*/
@Override
public ItemStack decrStackSize(int slot, int decreaseAmount){
if(isMaster()) {
if(inventory[slot] != null) {
ItemStack itemstack;
if(inventory[slot].stackSize <= decreaseAmount) {
itemstack = inventory[slot];
setInventorySlotContents(slot, null);
markDirty();
return itemstack;
} else {
itemstack = inventory[slot].splitStack(decreaseAmount);
if(inventory[slot].stackSize == 0) {
setInventorySlotContents(slot, null);
}
markDirty();
return itemstack;
}
} else {
return null;
}
} else {
return getMaster().decrStackSize(slot, decreaseAmount);
}
}
/**
* When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
* like when you close a workbench GUI.
*/
@Override
public ItemStack getStackInSlotOnClosing(int slot){
if(isMaster()) {
if(inventory[slot] != null) {
ItemStack itemstack = inventory[slot];
inventory[slot] = null;
return itemstack;
} else {
return null;
}
} else {
return getMaster().getStackInSlotOnClosing(slot);
}
}
/**
* Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
*/
@Override
public void setInventorySlotContents(int slot, ItemStack stack){
if(isMaster()) {
inventory[slot] = stack;
if(stack != null && stack.stackSize > getInventoryStackLimit()) {
stack.stackSize = getInventoryStackLimit();
}
markDirty();
} else {
getMaster().setInventorySlotContents(slot, stack);
}
}
/**
* Returns the name of the inventory
*/
@Override
public String getInventoryName(){
return ModBlocks.modularStorage.getUnlocalizedName() + ".name";
}
/**
* Returns if the inventory is named
*/
@Override
public boolean hasCustomInventoryName(){
return false;
}
/**
* Returns the maximum stack size for a inventory slot.
*/
@Override
public int getInventoryStackLimit(){
return 64;
}
/**
* Do not make give this method the name canInteractWith because it clashes with Container
*/
@Override
public boolean isUseableByPlayer(EntityPlayer player){
return worldObj.getTileEntity(xCoord, yCoord, zCoord) != this ? false : player.getDistanceSq(xCoord + 0.5D, yCoord + 0.5D, zCoord + 0.5D) <= 64.0D;
}
@Override
public void openInventory(){}
@Override
public void closeInventory(){}
/**
* Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot.
*/
@Override
public boolean isItemValidForSlot(int slot, ItemStack stack){
return true;
}
}