package mekanism.common.tile;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import mekanism.api.Coord4D;
import mekanism.api.Range4D;
import mekanism.common.Mekanism;
import mekanism.common.PacketHandler;
import mekanism.common.multiblock.IMultiblock;
import mekanism.common.multiblock.MultiblockCache;
import mekanism.common.multiblock.MultiblockManager;
import mekanism.common.multiblock.SynchronizedData;
import mekanism.common.multiblock.UpdateProtocol;
import mekanism.common.network.PacketTileEntity.TileEntityMessage;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public abstract class TileEntityMultiblock<T extends SynchronizedData<T>> extends TileEntityContainerBlock implements IMultiblock<T>
{
/** The multiblock data for this structure. */
public T structure;
/** Whether or not to send this multiblock's structure in the next update packet. */
public boolean sendStructure;
/** This multiblock's previous "has structure" state. */
public boolean prevStructure;
/** Whether or not this multiblock has it's structure, for the client side mechanics. */
public boolean clientHasStructure;
/** Whether or not this multiblock segment is rendering the structure. */
public boolean isRendering;
/** This multiblock segment's cached data */
public MultiblockCache cachedData = getNewCache();
/** This multiblock segment's cached inventory ID */
public String cachedID = null;
public TileEntityMultiblock(String name)
{
super(name);
}
@Override
public void onUpdate()
{
if(worldObj.isRemote)
{
if(structure == null)
{
structure = getNewStructure();
}
if(structure != null && clientHasStructure && isRendering)
{
if(!prevStructure)
{
Mekanism.proxy.doMultiblockSparkle(this);
}
}
prevStructure = clientHasStructure;
}
if(playersUsing.size() > 0 && ((worldObj.isRemote && !clientHasStructure) || (!worldObj.isRemote && structure == null)))
{
for(EntityPlayer player : playersUsing)
{
System.out.println(worldObj.isRemote + " " + clientHasStructure + " " + structure);
//player.closeScreen();
}
}
if(!worldObj.isRemote)
{
//System.out.println(pos + " " + structure);
if(structure == null)
{
isRendering = false;
if(cachedID != null)
{
getManager().updateCache(this);
}
}
if(structure == null && ticker == 5)
{
doUpdate();
}
if(prevStructure == (structure == null))
{
if(structure != null && !getSynchronizedData().hasRenderer)
{
getSynchronizedData().hasRenderer = true;
isRendering = true;
sendStructure = true;
}
for(EnumFacing side : EnumFacing.VALUES)
{
Coord4D obj = Coord4D.get(this).offset(side);
TileEntity tile = obj.getTileEntity(worldObj);
if(!obj.isAirBlock(worldObj) && (tile == null || tile.getClass() != getClass()))
{
obj.getBlock(worldObj).onNeighborChange(worldObj, obj.getPos(), getPos());
}
}
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList<Object>())), new Range4D(Coord4D.get(this)));
}
prevStructure = structure != null;
if(structure != null)
{
//System.out.println("Whee " + structure + " " + isInvalid());
getSynchronizedData().didTick = false;
if(getSynchronizedData().inventoryID != null)
{
cachedData.sync(getSynchronizedData());
cachedID = getSynchronizedData().inventoryID;
getManager().updateCache(this);
}
}
}
}
@Override
public void doUpdate()
{
if(!worldObj.isRemote && (structure == null || !getSynchronizedData().didTick))
{
getProtocol().doUpdate();
if(structure != null)
{
getSynchronizedData().didTick = true;
}
}
}
public void sendPacketToRenderer()
{
if(structure != null)
{
for(Coord4D obj : getSynchronizedData().locations)
{
TileEntityMultiblock<T> tileEntity = (TileEntityMultiblock<T>)obj.getTileEntity(worldObj);
if(tileEntity != null && tileEntity.isRendering)
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(tileEntity), tileEntity.getNetworkedData(new ArrayList<Object>())), new Range4D(Coord4D.get(tileEntity)));
}
}
}
}
protected abstract T getNewStructure();
public abstract MultiblockCache<T> getNewCache();
protected abstract UpdateProtocol<T> getProtocol();
public abstract MultiblockManager<T> getManager();
@Override
public ArrayList<Object> getNetworkedData(ArrayList<Object> data)
{
super.getNetworkedData(data);
data.add(isRendering);
data.add(structure != null);
if(structure != null && isRendering)
{
if(sendStructure)
{
sendStructure = false;
data.add(true);
data.add(getSynchronizedData().volHeight);
data.add(getSynchronizedData().volWidth);
data.add(getSynchronizedData().volLength);
getSynchronizedData().renderLocation.write(data);
data.add(getSynchronizedData().inventoryID);
}
else {
data.add(false);
}
}
return data;
}
@Override
public void handlePacketData(ByteBuf dataStream)
{
super.handlePacketData(dataStream);
if(FMLCommonHandler.instance().getEffectiveSide().isClient())
{
if(structure == null)
{
structure = getNewStructure();
}
isRendering = dataStream.readBoolean();
clientHasStructure = dataStream.readBoolean();
if(clientHasStructure && isRendering)
{
if(dataStream.readBoolean())
{
getSynchronizedData().volHeight = dataStream.readInt();
getSynchronizedData().volWidth = dataStream.readInt();
getSynchronizedData().volLength = dataStream.readInt();
getSynchronizedData().renderLocation = Coord4D.read(dataStream);
getSynchronizedData().inventoryID = PacketHandler.readString(dataStream);
}
}
}
}
@Override
public void readFromNBT(NBTTagCompound nbtTags)
{
super.readFromNBT(nbtTags);
if(structure == null)
{
if(nbtTags.hasKey("cachedID"))
{
cachedID = nbtTags.getString("cachedID");
cachedData.load(nbtTags);
}
}
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbtTags)
{
super.writeToNBT(nbtTags);
if(cachedID != null)
{
nbtTags.setString("cachedID", cachedID);
cachedData.save(nbtTags);
}
return nbtTags;
}
@Override
public ItemStack getStackInSlot(int slotID)
{
return structure != null && getSynchronizedData().getInventory() != null ? getSynchronizedData().getInventory()[slotID] : null;
}
@Override
public void setInventorySlotContents(int slotID, ItemStack itemstack)
{
if(structure != null && getSynchronizedData().getInventory() != null)
{
getSynchronizedData().getInventory()[slotID] = itemstack;
if(itemstack != null && itemstack.stackSize > getInventoryStackLimit())
{
itemstack.stackSize = getInventoryStackLimit();
}
}
}
@Override
public boolean onActivate(EntityPlayer player, EnumHand hand, ItemStack stack)
{
return false;
}
@Override
@SideOnly(Side.CLIENT)
public AxisAlignedBB getRenderBoundingBox()
{
return INFINITE_EXTENT_AABB;
}
@Override
public boolean handleInventory()
{
return false;
}
@Override
public T getSynchronizedData()
{
return structure;
}
}