package mekanism.common.tile;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.EnumSet;
import mekanism.api.Coord4D;
import mekanism.api.IConfigCardAccess;
import mekanism.api.MekanismConfig.general;
import mekanism.api.Range4D;
import mekanism.api.transmitters.TransmissionType;
import mekanism.common.Mekanism;
import mekanism.common.Upgrade;
import mekanism.common.base.IElectricMachine;
import mekanism.common.base.IRedstoneControl;
import mekanism.common.base.ISideConfiguration;
import mekanism.common.base.IUpgradeTile;
import mekanism.common.capabilities.Capabilities;
import mekanism.common.integration.IComputerIntegration;
import mekanism.common.network.PacketTileEntity.TileEntityMessage;
import mekanism.common.recipe.inputs.MachineInput;
import mekanism.common.recipe.machines.MachineRecipe;
import mekanism.common.recipe.outputs.MachineOutput;
import mekanism.common.security.ISecurityTile;
import mekanism.common.tile.component.TileComponentConfig;
import mekanism.common.tile.component.TileComponentEjector;
import mekanism.common.tile.component.TileComponentSecurity;
import mekanism.common.tile.component.TileComponentUpgrade;
import mekanism.common.util.MekanismUtils;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fml.common.FMLCommonHandler;
public abstract class TileEntityBasicMachine<INPUT extends MachineInput<INPUT>, OUTPUT extends MachineOutput<OUTPUT>, RECIPE extends MachineRecipe<INPUT, OUTPUT, RECIPE>> extends TileEntityNoisyElectricBlock implements IElectricMachine<INPUT, OUTPUT, RECIPE>, IComputerIntegration, ISideConfiguration, IUpgradeTile, IRedstoneControl, IConfigCardAccess, ISecurityTile
{
/** How much energy this machine uses per tick, un-upgraded. */
public double BASE_ENERGY_PER_TICK;
/** How much energy this machine uses per tick including upgrades */
public double energyPerTick;
/** How many ticks this machine has operated for. */
public int operatingTicks = 0;
/** Un-upgraded ticks required to operate -- or smelt an item. */
public int BASE_TICKS_REQUIRED;
/** Ticks required including upgrades */
public int ticksRequired;
/** How many ticks must pass until this block's active state can sync with the client. */
public int updateDelay;
/** Whether or not this block is in it's active state. */
public boolean isActive;
/** The client's current active state. */
public boolean clientActive;
/** The GUI texture path for this machine. */
public ResourceLocation guiLocation;
/** This machine's current RedstoneControl type. */
public RedstoneControl controlType = RedstoneControl.DISABLED;
/** This machine's previous amount of energy. */
public double prevEnergy;
public RECIPE cachedRecipe = null;
public TileComponentUpgrade upgradeComponent;
public TileComponentEjector ejectorComponent;
public TileComponentConfig configComponent;
public TileComponentSecurity securityComponent;
/**
* The foundation of all machines - a simple tile entity with a facing, active state, initialized state, sound effect, and animated texture.
* @param soundPath - location of the sound effect
* @param name - full name of this machine
* @param location - GUI texture path of this machine
* @param perTick - the energy this machine consumes every tick in it's active state
* @param baseTicksRequired - how many ticks it takes to run a cycle
* @param maxEnergy - how much energy this machine can store
*/
public TileEntityBasicMachine(String soundPath, String name, ResourceLocation location, double perTick, int baseTicksRequired, double maxEnergy)
{
super("machine." + soundPath, name, maxEnergy);
BASE_ENERGY_PER_TICK = perTick;
energyPerTick = perTick;
BASE_TICKS_REQUIRED = baseTicksRequired;
ticksRequired = baseTicksRequired;
guiLocation = location;
isActive = false;
securityComponent = new TileComponentSecurity(this);
}
@Override
public void onUpdate()
{
super.onUpdate();
if(worldObj.isRemote && updateDelay > 0)
{
updateDelay--;
if(updateDelay == 0 && clientActive != isActive)
{
isActive = clientActive;
MekanismUtils.updateBlock(worldObj, getPos());
}
}
if(!worldObj.isRemote)
{
if(updateDelay > 0)
{
updateDelay--;
if(updateDelay == 0 && clientActive != isActive)
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList<Object>())), new Range4D(Coord4D.get(this)));
}
}
}
}
@Override
public EnumSet<EnumFacing> getConsumingSides()
{
return configComponent.getSidesForData(TransmissionType.ENERGY, facing, 1);
}
@Override
public void readFromNBT(NBTTagCompound nbtTags)
{
super.readFromNBT(nbtTags);
operatingTicks = nbtTags.getInteger("operatingTicks");
clientActive = isActive = nbtTags.getBoolean("isActive");
controlType = RedstoneControl.values()[nbtTags.getInteger("controlType")];
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbtTags)
{
super.writeToNBT(nbtTags);
nbtTags.setInteger("operatingTicks", operatingTicks);
nbtTags.setBoolean("isActive", isActive);
nbtTags.setInteger("controlType", controlType.ordinal());
return nbtTags;
}
@Override
public void handlePacketData(ByteBuf dataStream)
{
super.handlePacketData(dataStream);
if(FMLCommonHandler.instance().getEffectiveSide().isClient())
{
operatingTicks = dataStream.readInt();
clientActive = dataStream.readBoolean();
ticksRequired = dataStream.readInt();
controlType = RedstoneControl.values()[dataStream.readInt()];
if(updateDelay == 0 && clientActive != isActive)
{
updateDelay = general.UPDATE_DELAY;
isActive = clientActive;
MekanismUtils.updateBlock(worldObj, getPos());
}
}
}
@Override
public ArrayList<Object> getNetworkedData(ArrayList<Object> data)
{
super.getNetworkedData(data);
data.add(operatingTicks);
data.add(isActive);
data.add(ticksRequired);
data.add(controlType.ordinal());
return data;
}
/**
* Gets the scaled progress level for the GUI.
*/
public double getScaledProgress()
{
return ((double)operatingTicks) / ((double)ticksRequired);
}
@Override
public boolean getActive()
{
return isActive;
}
@Override
public void setActive(boolean active)
{
isActive = active;
if(clientActive != active && updateDelay == 0)
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList<Object>())), new Range4D(Coord4D.get(this)));
updateDelay = 10;
clientActive = active;
}
}
@Override
public void recalculateUpgradables(Upgrade upgrade)
{
super.recalculateUpgradables(upgrade);
switch(upgrade)
{
case SPEED:
ticksRequired = MekanismUtils.getTicks(this, BASE_TICKS_REQUIRED);
energyPerTick = MekanismUtils.getEnergyPerTick(this, BASE_ENERGY_PER_TICK);
break;
case ENERGY:
energyPerTick = MekanismUtils.getEnergyPerTick(this, BASE_ENERGY_PER_TICK);
maxEnergy = MekanismUtils.getMaxEnergy(this, BASE_MAX_ENERGY);
break;
default:
break;
}
}
@Override
public boolean canSetFacing(int facing)
{
return facing != 0 && facing != 1;
}
@Override
public int[] getSlotsForFace(EnumFacing side)
{
return configComponent.getOutput(TransmissionType.ITEM, side, facing).availableSlots;
}
@Override
public TileComponentConfig getConfig()
{
return configComponent;
}
@Override
public EnumFacing getOrientation()
{
return facing;
}
@Override
public boolean renderUpdate()
{
return true;
}
@Override
public boolean lightUpdate()
{
return true;
}
@Override
public RedstoneControl getControlType()
{
return controlType;
}
@Override
public void setControlType(RedstoneControl type)
{
controlType = type;
MekanismUtils.saveChunk(this);
}
@Override
public boolean canPulse()
{
return false;
}
@Override
public TileComponentUpgrade getComponent()
{
return upgradeComponent;
}
@Override
public TileComponentEjector getEjector()
{
return ejectorComponent;
}
@Override
public TileComponentSecurity getSecurity()
{
return securityComponent;
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing side)
{
return capability == Capabilities.CONFIG_CARD_CAPABILITY || super.hasCapability(capability, side);
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing side)
{
if(capability == Capabilities.CONFIG_CARD_CAPABILITY)
{
return (T)this;
}
return super.getCapability(capability, side);
}
}