// Path: src/main/java/cn/academy/energy/api/IFItemManager.java
// public final class IFItemManager implements EnergyItemManager {
// 
//     public static IFItemManager instance = new IFItemManager();
// 
//     private IFItemManager() {
//     }
// 
//     public double getEnergy(ItemStack stack) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
//         return StackUtils.loadTag(stack).getDouble("energy");
//     }
// 
//     public double getMaxEnergy(ItemStack stack) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
//         return item.getMaxEnergy();
//     }
// 
//     public void setEnergy(ItemStack stack, double amt) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
//         amt = Math.min(item.getMaxEnergy(), amt);
//         StackUtils.loadTag(stack).setDouble("energy", amt);
// 
//         int approxDamage = (int) Math.round((1 - amt / getMaxEnergy(stack)) * stack.getMaxDamage());
//         stack.setItemDamage(approxDamage);
//     }
// 
//     /**
//      * @return How much energy NOT transfered into stack
//      */
//     public double charge(ItemStack stack, double amt) {
//         return charge(stack, amt, false);
//     }
// 
//     /**
//      * @param stack
//      * @param amt Energy trying to charge into stack, can be negative
//      * @param ignoreBandwidth
//      * @return How much energy NOT transfered into stack
//      */
//     public double charge(ItemStack stack, double amt, boolean ignoreBandwidth) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
//         double lim = ignoreBandwidth ? Double.MAX_VALUE : item.getBandwidth();
//         double cur = getEnergy(stack);
//         double spare = 0.0;
//         if (amt + cur > item.getMaxEnergy()) {
//             spare = cur + amt - item.getMaxEnergy();
//             amt = item.getMaxEnergy() - cur;
//         }
// 
//         double namt = Math.signum(amt) * Math.min(Math.abs(amt), lim);
//         spare += amt - namt;
// 
//         setEnergy(stack, cur + namt);
//         return spare;
//     }
// 
//     public String getDescription(ItemStack stack) {
//         return String.format("%.0f/%.0f IF", getEnergy(stack), getMaxEnergy(stack));
//     }
// 
//     @Override
//     public boolean isSupported(ItemStack stack) {
//         return stack.getItem() instanceof ImagEnergyItem;
//     }
// 
//     @Override
//     public double pull(ItemStack stack, double amt, boolean ignoreBandwidth) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
// 
//         double cur = getEnergy(stack);
//         double give = Math.min(amt, cur);
//         if (!ignoreBandwidth) {
//             give = Math.min(give, item.getBandwidth());
//         }
//         setEnergy(stack, cur - give);
// 
//         return give;
//     }
// 
// }
// 
// Path: src/main/java/cn/academy/energy/api/block/IWirelessGenerator.java
// public interface IWirelessGenerator extends IWirelessUser {
// 
//     /**
//      * @param req How much energy is required
//      * @return How much energy this generator can provide. Must be guaranteed 0<=ret<=req
//      */
//     public double getProvidedEnergy(double req);
// 
//     /**
//      * @return Max energy transmitted each tick
//      */
//     public double getBandwidth();
// 
// }
// 
// Path: src/main/java/cn/annoreg/core/StorageOption.java
// public class StorageOption {
// 
//     public enum Option {
//         NULL,
//         DATA,
//         INSTANCE,
//         UPDATE,
// 
//         /**
//          * Used only in deserialization.
//          * Will use the option contained in the data.
//          */
//         AUTO,
// 
//         /**
//          * Allow the instance to be null.
//          * You can use this option directly, or use <code>@Instance(nullable=true)</code>
//          */
//         NULLABLE_INSTANCE,
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Null {
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Data {
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Instance {
//         boolean nullable() default false;
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Update {
//     }
// 
//     /**
//      * Used only in server-to-client network call.
//      * Used on argument with the type of EntityPlayer.
//      * If Target is given, the message is only sent to this player.
//      * With this annotation, the StorageOption of INSTANCE is used.
//      * @author acaly
//      *
//      */
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Target {
// 
//         RangeOption range() default RangeOption.SINGLE;
// 
//         public enum RangeOption {
//             SINGLE,
//             EXCEPT,
//         }
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface RangedTarget {
//         double range() default -1; //The hardcoded range option. The TargetPoint converter can choose to ignore this parameter.
//     }
// }


import cn.academy.energy.api.IFItemManager;
import cn.academy.energy.api.block.IWirelessGenerator;
import cn.annoreg.core.RegNetworkCall;
import cn.annoreg.core.StorageOption;
import cn.annoreg.core.StorageOption.Data;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side;

    public double getEnergy() {
        return energy;
    }

    public void setEnergy(double energy) {
        this.energy = energy;
    }

    @Override
    public double getBandwidth() {
        return bandwidth;
    }

    /**
     * Try to charge a ItemStack with the buffer energy within the generator.
     */
    public void tryChargeStack(ItemStack stack) {
        if (IFItemManager.instance.isSupported(stack)) {
            double cangive = Math.min(energy, bandwidth);
            double ret = IFItemManager.instance.charge(stack, cangive);
            energy -= (cangive - ret);
        }
    }

    /**
     * Get the energy generated by the generator this tick.
     */
    public abstract double getGeneration(double required);

// Path: src/main/java/cn/academy/energy/api/IFItemManager.java
// public final class IFItemManager implements EnergyItemManager {
// 
//     public static IFItemManager instance = new IFItemManager();
// 
//     private IFItemManager() {
//     }
// 
//     public double getEnergy(ItemStack stack) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
//         return StackUtils.loadTag(stack).getDouble("energy");
//     }
// 
//     public double getMaxEnergy(ItemStack stack) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
//         return item.getMaxEnergy();
//     }
// 
//     public void setEnergy(ItemStack stack, double amt) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
//         amt = Math.min(item.getMaxEnergy(), amt);
//         StackUtils.loadTag(stack).setDouble("energy", amt);
// 
//         int approxDamage = (int) Math.round((1 - amt / getMaxEnergy(stack)) * stack.getMaxDamage());
//         stack.setItemDamage(approxDamage);
//     }
// 
//     /**
//      * @return How much energy NOT transfered into stack
//      */
//     public double charge(ItemStack stack, double amt) {
//         return charge(stack, amt, false);
//     }
// 
//     /**
//      * @param stack
//      * @param amt Energy trying to charge into stack, can be negative
//      * @param ignoreBandwidth
//      * @return How much energy NOT transfered into stack
//      */
//     public double charge(ItemStack stack, double amt, boolean ignoreBandwidth) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
//         double lim = ignoreBandwidth ? Double.MAX_VALUE : item.getBandwidth();
//         double cur = getEnergy(stack);
//         double spare = 0.0;
//         if (amt + cur > item.getMaxEnergy()) {
//             spare = cur + amt - item.getMaxEnergy();
//             amt = item.getMaxEnergy() - cur;
//         }
// 
//         double namt = Math.signum(amt) * Math.min(Math.abs(amt), lim);
//         spare += amt - namt;
// 
//         setEnergy(stack, cur + namt);
//         return spare;
//     }
// 
//     public String getDescription(ItemStack stack) {
//         return String.format("%.0f/%.0f IF", getEnergy(stack), getMaxEnergy(stack));
//     }
// 
//     @Override
//     public boolean isSupported(ItemStack stack) {
//         return stack.getItem() instanceof ImagEnergyItem;
//     }
// 
//     @Override
//     public double pull(ItemStack stack, double amt, boolean ignoreBandwidth) {
//         ImagEnergyItem item = (ImagEnergyItem) stack.getItem();
// 
//         double cur = getEnergy(stack);
//         double give = Math.min(amt, cur);
//         if (!ignoreBandwidth) {
//             give = Math.min(give, item.getBandwidth());
//         }
//         setEnergy(stack, cur - give);
// 
//         return give;
//     }
// 
// }
// 
// Path: src/main/java/cn/academy/energy/api/block/IWirelessGenerator.java
// public interface IWirelessGenerator extends IWirelessUser {
// 
//     /**
//      * @param req How much energy is required
//      * @return How much energy this generator can provide. Must be guaranteed 0<=ret<=req
//      */
//     public double getProvidedEnergy(double req);
// 
//     /**
//      * @return Max energy transmitted each tick
//      */
//     public double getBandwidth();
// 
// }
// 
// Path: src/main/java/cn/annoreg/core/StorageOption.java
// public class StorageOption {
// 
//     public enum Option {
//         NULL,
//         DATA,
//         INSTANCE,
//         UPDATE,
// 
//         /**
//          * Used only in deserialization.
//          * Will use the option contained in the data.
//          */
//         AUTO,
// 
//         /**
//          * Allow the instance to be null.
//          * You can use this option directly, or use <code>@Instance(nullable=true)</code>
//          */
//         NULLABLE_INSTANCE,
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Null {
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Data {
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Instance {
//         boolean nullable() default false;
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Update {
//     }
// 
//     /**
//      * Used only in server-to-client network call.
//      * Used on argument with the type of EntityPlayer.
//      * If Target is given, the message is only sent to this player.
//      * With this annotation, the StorageOption of INSTANCE is used.
//      * @author acaly
//      *
//      */
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface Target {
// 
//         RangeOption range() default RangeOption.SINGLE;
// 
//         public enum RangeOption {
//             SINGLE,
//             EXCEPT,
//         }
//     }
// 
//     @Retention(RetentionPolicy.RUNTIME)
//     public @interface RangedTarget {
//         double range() default -1; //The hardcoded range option. The TargetPoint converter can choose to ignore this parameter.
//     }
// }


// Path: src/main/java/infstudio/exoticpower/tileentity/TileEntityGenerator.java
import cn.academy.energy.api.IFItemManager;
import cn.academy.energy.api.block.IWirelessGenerator;
import cn.annoreg.core.RegNetworkCall;
import cn.annoreg.core.StorageOption;
import cn.annoreg.core.StorageOption.Data;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side;


    public double getEnergy() {
        return energy;
    }

    public void setEnergy(double energy) {
        this.energy = energy;
    }

    @Override
    public double getBandwidth() {
        return bandwidth;
    }

    /**
     * Try to charge a ItemStack with the buffer energy within the generator.
     */
    public void tryChargeStack(ItemStack stack) {
        if (IFItemManager.instance.isSupported(stack)) {
            double cangive = Math.min(energy, bandwidth);
            double ret = IFItemManager.instance.charge(stack, cangive);
            energy -= (cangive - ret);
        }
    }

    /**
     * Get the energy generated by the generator this tick.
     */
    public abstract double getGeneration(double required);

    @RegNetworkCall(side = Side.CLIENT, thisStorage = StorageOption.Option.INSTANCE)