| /** |
| * Copyright (c) SpaceToad, 2011 http://www.mod-buildcraft.com |
| * |
| * BuildCraft is distributed under the terms of the Minecraft Mod Public License |
| * 1.0, or MMPL. Please check the contents of the license located in |
| * http://www.mod-buildcraft.com/MMPL-1.0.txt |
| */ |
| package buildcraft.api.power; |
| |
| import net.minecraft.nbt.NBTTagCompound; |
| import net.minecraftforge.common.ForgeDirection; |
| import buildcraft.api.core.SafeTimeTracker; |
| |
| public final class PowerHandler |
| { |
| |
| public static enum Type |
| { |
| |
| ENGINE, GATE, MACHINE, PIPE, STORAGE; |
| |
| public boolean canReceiveFromPipes() |
| { |
| switch (this) |
| { |
| case MACHINE: |
| case STORAGE: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| public boolean eatsEngineExcess() |
| { |
| switch (this) |
| { |
| case MACHINE: |
| case STORAGE: |
| return true; |
| default: |
| return false; |
| } |
| } |
| } |
| |
| public static class PerditionCalculator |
| { |
| |
| public static final float DEFAULT_POWERLOSS = 1F; |
| public static final float MIN_POWERLOSS = 0.01F; |
| private final float powerLoss; |
| |
| public PerditionCalculator() |
| { |
| powerLoss = DEFAULT_POWERLOSS; |
| } |
| |
| public PerditionCalculator(float powerLoss) |
| { |
| if (powerLoss < MIN_POWERLOSS) |
| { |
| powerLoss = MIN_POWERLOSS; |
| } |
| this.powerLoss = powerLoss; |
| } |
| |
| /** |
| * Apply the perdition algorithm to the current stored energy. This function can only be |
| * called once per tick, but it might not be called every tick. It is triggered by any |
| * manipulation of the stored energy. |
| * |
| * @param powerHandler the PowerHandler requesting the perdition update |
| * @param current the current stored energy |
| * @param ticksPassed ticks since the last time this function was called |
| * @return |
| */ |
| public float applyPerdition(PowerHandler powerHandler, float current, long ticksPassed) |
| { |
| current -= powerLoss * ticksPassed; |
| if (current < 0) |
| { |
| current = 0; |
| } |
| return current; |
| } |
| } |
| |
| public static final PerditionCalculator DEFAULT_PERDITION = new PerditionCalculator(); |
| private float minEnergyReceived; |
| private float maxEnergyReceived; |
| private float maxEnergyStored; |
| private float activationEnergy; |
| private float energyStored = 0; |
| private final SafeTimeTracker doWorkTracker = new SafeTimeTracker(); |
| private final SafeTimeTracker sourcesTracker = new SafeTimeTracker(); |
| private final SafeTimeTracker perditionTracker = new SafeTimeTracker(); |
| public final int[] powerSources = new int[6]; |
| public final IPowerReceptor receptor; |
| private PerditionCalculator perdition; |
| private final PowerReceiver receiver; |
| private final Type type; |
| |
| public PowerHandler(IPowerReceptor receptor, Type type) |
| { |
| this.receptor = receptor; |
| this.type = type; |
| this.receiver = new PowerReceiver(); |
| this.perdition = DEFAULT_PERDITION; |
| } |
| |
| public PowerReceiver getPowerReceiver() |
| { |
| return receiver; |
| } |
| |
| public float getMinEnergyReceived() |
| { |
| return minEnergyReceived; |
| } |
| |
| public float getMaxEnergyReceived() |
| { |
| return maxEnergyReceived; |
| } |
| |
| public float getMaxEnergyStored() |
| { |
| return maxEnergyStored; |
| } |
| |
| public float getActivationEnergy() |
| { |
| return activationEnergy; |
| } |
| |
| public float getEnergyStored() |
| { |
| return energyStored; |
| } |
| |
| /** |
| * Setup your PowerHandler's settings. |
| * |
| * @param minEnergyReceived This is the minimum about of power that will be accepted by the |
| * PowerHandler. This should generally be greater than the activationEnergy if you plan to use |
| * the doWork() callback. Anything greater than 1 will prevent Redstone Engines from powering |
| * this Provider. |
| * @param maxEnergyReceived The maximum amount of power accepted by the PowerHandler. This |
| * should generally be less than 500. Too low and larger engines will overheat while trying to |
| * power the machine. Too high, and the engines will never warm up. Greater values also place |
| * greater strain on the power net. |
| * @param activationEnergy If the stored energy is greater than this value, the doWork() |
| * callback is called (once per tick). |
| * @param maxStoredEnergy The maximum amount of power this PowerHandler can store. Values tend |
| * to range between 100 and 5000. With 1000 and 1500 being common. |
| */ |
| public void configure(float minEnergyReceived, float maxEnergyReceived, float activationEnergy, float maxStoredEnergy) |
| { |
| if (minEnergyReceived > maxEnergyReceived) |
| { |
| maxEnergyReceived = minEnergyReceived; |
| } |
| this.minEnergyReceived = minEnergyReceived; |
| this.maxEnergyReceived = maxEnergyReceived; |
| this.maxEnergyStored = maxStoredEnergy; |
| this.activationEnergy = activationEnergy; |
| } |
| |
| public void configurePowerPerdition(int powerLoss, int powerLossRegularity) |
| { |
| if (powerLoss == 0 || powerLossRegularity == 0) |
| { |
| perdition = new PerditionCalculator(0); |
| return; |
| } |
| perdition = new PerditionCalculator((float) powerLoss / (float) powerLossRegularity); |
| } |
| |
| /** |
| * Allows you to define a new PerditionCalculator class to handler perdition calculations. |
| * |
| * For example if you want exponentially increasing loss based on amount stored. |
| * |
| * @param perdition |
| */ |
| public void setPerdition(PerditionCalculator perdition) |
| { |
| if (perdition == null) |
| perdition = DEFAULT_PERDITION; |
| this.perdition = perdition; |
| } |
| |
| public PerditionCalculator getPerdition() |
| { |
| if (perdition == null) |
| return DEFAULT_PERDITION; |
| return perdition; |
| } |
| |
| /** |
| * Ticks the power handler. You should call this if you can, but its not required. |
| * |
| * If you don't call it, the possibility exists for some weirdness with the perdition algorithm |
| * and work callback as its possible they will not be called on every tick they otherwise would |
| * be. You should be able to design around this though if you are aware of the limitations. |
| */ |
| public void update() |
| { |
| applyPerdition(); |
| applyWork(); |
| validateEnergy(); |
| } |
| |
| private void applyPerdition() |
| { |
| if (perditionTracker.markTimeIfDelay(receptor.getWorld(), 1) && energyStored > 0) |
| { |
| float newEnergy = getPerdition().applyPerdition(this, energyStored, perditionTracker.durationOfLastDelay()); |
| if (newEnergy == 0 || newEnergy < energyStored) |
| energyStored = newEnergy; |
| else |
| energyStored = DEFAULT_PERDITION.applyPerdition(this, energyStored, perditionTracker.durationOfLastDelay()); |
| validateEnergy(); |
| } |
| } |
| |
| private void applyWork() |
| { |
| if (energyStored >= activationEnergy) |
| { |
| if (doWorkTracker.markTimeIfDelay(receptor.getWorld(), 1)) |
| { |
| receptor.doWork(this); |
| } |
| } |
| } |
| |
| private void updateSources(ForgeDirection source) |
| { |
| if (sourcesTracker.markTimeIfDelay(receptor.getWorld(), 1)) |
| { |
| for (int i = 0; i < 6; ++i) |
| { |
| powerSources[i] -= sourcesTracker.durationOfLastDelay(); |
| if (powerSources[i] < 0) |
| { |
| powerSources[i] = 0; |
| } |
| } |
| } |
| |
| if (source != null) |
| powerSources[source.ordinal()] = 10; |
| } |
| |
| /** |
| * Extract energy from the PowerHandler. You must call this even if doWork() triggers. |
| * |
| * @param min |
| * @param max |
| * @param doUse |
| * @return amount used |
| */ |
| public float useEnergy(float min, float max, boolean doUse) |
| { |
| applyPerdition(); |
| |
| float result = 0; |
| |
| if (energyStored >= min) |
| { |
| if (energyStored <= max) |
| { |
| result = energyStored; |
| if (doUse) |
| { |
| energyStored = 0; |
| } |
| } |
| else |
| { |
| result = max; |
| if (doUse) |
| { |
| energyStored -= max; |
| } |
| } |
| } |
| |
| validateEnergy(); |
| |
| return result; |
| } |
| |
| public void readFromNBT(NBTTagCompound data) |
| { |
| readFromNBT(data, "powerProvider"); |
| } |
| |
| public void readFromNBT(NBTTagCompound data, String tag) |
| { |
| NBTTagCompound nbt = data.getCompoundTag(tag); |
| energyStored = nbt.getFloat("storedEnergy"); |
| } |
| |
| public void writeToNBT(NBTTagCompound data) |
| { |
| writeToNBT(data, "powerProvider"); |
| } |
| |
| public void writeToNBT(NBTTagCompound data, String tag) |
| { |
| NBTTagCompound nbt = new NBTTagCompound(); |
| nbt.setFloat("storedEnergy", energyStored); |
| data.setCompoundTag(tag, nbt); |
| } |
| |
| public final class PowerReceiver |
| { |
| |
| private PowerReceiver() |
| { |
| } |
| |
| public float getMinEnergyReceived() |
| { |
| return minEnergyReceived; |
| } |
| |
| public float getMaxEnergyReceived() |
| { |
| return maxEnergyReceived; |
| } |
| |
| public float getMaxEnergyStored() |
| { |
| return maxEnergyStored; |
| } |
| |
| public float getActivationEnergy() |
| { |
| return activationEnergy; |
| } |
| |
| public float getEnergyStored() |
| { |
| return energyStored; |
| } |
| |
| public Type getType() |
| { |
| return type; |
| } |
| |
| public void update() |
| { |
| PowerHandler.this.update(); |
| } |
| |
| /** |
| * The amount of power that this PowerHandler currently needs. |
| * |
| * @return |
| */ |
| public float powerRequest() |
| { |
| update(); |
| return Math.min(maxEnergyReceived, maxEnergyStored - energyStored); |
| } |
| |
| /** |
| * Add power to the PowerReceiver from an external source. |
| * |
| * @param quantity |
| * @param from |
| * @return the amount of power used |
| */ |
| public float receiveEnergy(Type source, final float quantity, ForgeDirection from) |
| { |
| float used = quantity; |
| if (source == Type.ENGINE) |
| { |
| if (used < minEnergyReceived) |
| { |
| return 0; |
| } |
| else if (used > maxEnergyReceived) |
| { |
| used = maxEnergyReceived; |
| } |
| } |
| |
| updateSources(from); |
| |
| used = addEnergy(used); |
| |
| applyWork(); |
| |
| if (source == Type.ENGINE && type.eatsEngineExcess()) |
| { |
| return Math.min(quantity, maxEnergyReceived); |
| } |
| |
| return used; |
| } |
| } |
| |
| /** |
| * |
| * @return the amount the power changed by |
| */ |
| public float addEnergy(float quantity) |
| { |
| energyStored += quantity; |
| |
| if (energyStored > maxEnergyStored) |
| { |
| quantity -= energyStored - maxEnergyStored; |
| energyStored = maxEnergyStored; |
| } |
| else if (energyStored < 0) |
| { |
| quantity -= energyStored; |
| energyStored = 0; |
| } |
| |
| applyPerdition(); |
| |
| return quantity; |
| } |
| |
| public void setEnergy(float quantity) |
| { |
| this.energyStored = quantity; |
| validateEnergy(); |
| } |
| |
| public boolean isPowerSource(ForgeDirection from) |
| { |
| return powerSources[from.ordinal()] != 0; |
| } |
| |
| private void validateEnergy() |
| { |
| if (energyStored < 0) |
| { |
| energyStored = 0; |
| } |
| if (energyStored > maxEnergyStored) |
| { |
| energyStored = maxEnergyStored; |
| } |
| } |
| } |