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); } }