package ic2.api.energy.prefab; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import cpw.mods.fml.common.FMLCommonHandler; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.ForgeDirection; import ic2.api.energy.event.EnergyTileLoadEvent; import ic2.api.energy.event.EnergyTileUnloadEvent; import ic2.api.energy.tile.IEnergySink; import ic2.api.info.Info; import ic2.api.item.ElectricItem; /** * BasicSink is a simple adapter to provide an ic2 energy sink. * * It's designed to be attached to a tile entity as a delegate. Functionally BasicSink acts as a * one-time configurable input energy buffer, thus providing a common use case for machines. * * Sub-classing BasicSink instead of using it as a delegate works as well, but isn't recommended. * The delegate can be extended with additional functionality through a sub class though. * * The constraints set by BasicSink like the strict tank-like energy buffering should provide a * more easy to use and stable interface than using IEnergySink directly while aiming for * optimal performance. * * Using BasicSink involves the following steps: * - create a BasicSink instance in your TileEntity, typically in a field * - forward invalidate, onChunkUnload, readFromNBT, writeToNBT and updateEntity to the BasicSink * instance. * If you have other means of determining when the tile entity is fully loaded, notify onLoaded * that way instead of forwarding updateEntity. * - call useEnergy whenever appropriate. canUseEnergy determines if enough energy is available * without consuming the energy. * - optionally use getEnergyStored to display the output buffer charge level * - optionally use setEnergyStored to sync the stored energy to the client (e.g. in the Container) * * Example implementation code: * @code{.java} * public class SomeTileEntity extends TileEntity { * // new basic energy sink, 1000 EU buffer, tier 1 (32 EU/t, LV) * private BasicSink ic2EnergySink = new BasicSink(this, 1000, 1); * * @Override * public void invalidate() { * ic2EnergySink.invalidate(); // notify the energy sink * ... * super.invalidate(); // this is important for mc! * } * * @Override * public void onChunkUnload() { * ic2EnergySink.onChunkUnload(); // notify the energy sink * ... * } * * @Override * public void readFromNBT(NBTTagCompound tag) { * super.readFromNBT(tag); * * ic2EnergySink.readFromNBT(tag); * ... * } * * @Override * public void writeToNBT(NBTTagCompound tag) { * super.writeToNBT(tag); * * ic2EnergySink.writeToNBT(tag); * ... * } * * @Override * public void updateEntity() { * ic2EnergySink.updateEntity(); // notify the energy sink * ... * if (ic2EnergySink.useEnergy(5)) { // use 5 eu from the sink's buffer this tick * ... // do something with the energy * } * ... * } * * ... * } * @endcode */ public class BasicSink extends TileEntity implements IEnergySink { // ********************************** // *** Methods for use by the mod *** // ********************************** /** * Constructor for a new BasicSink delegate. * * @param parent1 TileEntity represented by this energy sink. * @param capacity1 Maximum amount of eu to store. * @param tier1 IC2 tier, 1 = LV, 2 = MV, ... */ public BasicSink(TileEntity parent1, int capacity1, int tier1) { this.parent = parent1; this.capacity = capacity1; this.tier = tier1; } // in-world te forwards >> /** * Forward for the base TileEntity's updateEntity(), used for creating the energy net link. * Either updateEntity or onLoaded have to be used. */ @Override public void updateEntity() { if (!addedToEnet) onLoaded(); } /** * Notification that the base TileEntity finished loaded, for advanced uses. * Either updateEntity or onLoaded have to be used. */ public void onLoaded() { if (!addedToEnet && !FMLCommonHandler.instance().getEffectiveSide().isClient() && Info.isIc2Available()) { worldObj = parent.getWorldObj(); xCoord = parent.xCoord; yCoord = parent.yCoord; zCoord = parent.zCoord; MinecraftForge.EVENT_BUS.post(new EnergyTileLoadEvent(this)); addedToEnet = true; } } /** * Forward for the base TileEntity's invalidate(), used for destroying the energy net link. * Both invalidate and onChunkUnload have to be used. */ @Override public void invalidate() { super.invalidate(); onChunkUnload(); } /** * Forward for the base TileEntity's onChunkUnload(), used for destroying the energy net link. * Both invalidate and onChunkUnload have to be used. */ @Override public void onChunkUnload() { if (addedToEnet && Info.isIc2Available()) { MinecraftForge.EVENT_BUS.post(new EnergyTileUnloadEvent(this)); addedToEnet = false; } } /** * Forward for the base TileEntity's readFromNBT(), used for loading the state. * * @param tag Compound tag as supplied by TileEntity.readFromNBT() */ @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); NBTTagCompound data = tag.getCompoundTag("IC2BasicSink"); energyStored = data.getDouble("energy"); } /** * Forward for the base TileEntity's writeToNBT(), used for saving the state. * * @param tag Compound tag as supplied by TileEntity.writeToNBT() */ @Override public void writeToNBT(NBTTagCompound tag) { try { super.writeToNBT(tag); } catch (RuntimeException e) { // happens if this is a delegate, ignore } NBTTagCompound data = new NBTTagCompound(); data.setDouble("energy", energyStored); tag.setTag("IC2BasicSink", data); } // << in-world te forwards // methods for using this adapter >> /** * Get the maximum amount of energy this sink can hold in its buffer. * * @return Capacity in EU. */ public int getCapacity() { return capacity; } /** * Set the maximum amount of energy this sink can hold in its buffer. * * @param capacity1 Capacity in EU. */ public void setCapacity(int capacity1) { this.capacity = capacity1; } /** * Get the IC2 energy tier for this sink. * * @return IC2 Tier. */ public int getTier() { return tier; } /** * Set the IC2 energy tier for this sink. * * @param tier1 IC2 Tier. */ public void setTier(int tier1) { this.tier = tier1; } /** * Determine the energy stored in the sink's input buffer. * * @return amount in EU, may be above capacity */ public double getEnergyStored() { return energyStored; } /** * Set the stored energy to the specified amount. * * This is intended for server -> client synchronization, e.g. to display the stored energy in * a GUI through getEnergyStored(). * * @param amount */ public void setEnergyStored(double amount) { energyStored = amount; } /** * Determine if the specified amount of energy is available. * * @param amount in EU * @return true if the amount is available */ public boolean canUseEnergy(double amount) { return energyStored >= amount; } /** * Use the specified amount of energy, if available. * * @param amount amount to use * @return true if the amount was available */ public boolean useEnergy(double amount) { if (canUseEnergy(amount) && !FMLCommonHandler.instance().getEffectiveSide().isClient()) { energyStored -= amount; return true; } return false; } /** * Discharge the supplied ItemStack into this sink's energy buffer. * * @param stack ItemStack to discharge (null is ignored) * @param limit Transfer limit, values <= 0 will use the battery's limit * @return true if energy was transferred */ public boolean discharge(ItemStack stack, int limit) { if (stack == null || !Info.isIc2Available()) return false; double amount = capacity - energyStored; if (amount <= 0) return false; if (limit > 0 && limit < amount) amount = limit; amount = ElectricItem.manager.discharge(stack, amount, tier, limit > 0, true, false); energyStored += amount; return amount > 0; } // << methods for using this adapter // backwards compatibility (ignore these) >> @Deprecated public void onUpdateEntity() { updateEntity(); } @Deprecated public void onInvalidate() { invalidate(); } @Deprecated public void onOnChunkUnload() { onChunkUnload(); } @Deprecated public void onReadFromNbt(NBTTagCompound tag) { readFromNBT(tag); } @Deprecated public void onWriteToNbt(NBTTagCompound tag) { writeToNBT(tag); } // << backwards compatibility // ****************************** // *** Methods for use by ic2 *** // ****************************** // energy net interface >> @Override public boolean acceptsEnergyFrom(TileEntity emitter, ForgeDirection direction) { return true; } @Override public double getDemandedEnergy() { return Math.max(0, capacity - energyStored); } @Override public double injectEnergy(ForgeDirection directionFrom, double amount, double voltage) { energyStored += amount; return 0; } @Override public int getSinkTier() { return tier; } // << energy net interface public final TileEntity parent; protected int capacity; protected int tier; protected double energyStored; protected boolean addedToEnet; }