diff --git a/src/APIs/buildcraft/api/core/BuildCraftAPI.java b/src/APIs/buildcraft/api/core/BuildCraftAPI.java new file mode 100644 index 00000000..c0c06bcd --- /dev/null +++ b/src/APIs/buildcraft/api/core/BuildCraftAPI.java @@ -0,0 +1,21 @@ +/** + * 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.core; + +import net.minecraft.block.Block; + +public class BuildCraftAPI +{ + + public static final int LAST_ORIGINAL_BLOCK = 122; + public static final int LAST_ORIGINAL_ITEM = 126; + + public static final boolean[] softBlocks = new boolean[Block.blocksList.length]; +} diff --git a/src/APIs/buildcraft/api/core/Position.java b/src/APIs/buildcraft/api/core/Position.java new file mode 100644 index 00000000..b3f6b3dd --- /dev/null +++ b/src/APIs/buildcraft/api/core/Position.java @@ -0,0 +1,161 @@ +/** + * 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.core; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; + +public class Position +{ + + public double x, y, z; + public ForgeDirection orientation; + + public Position(double ci, double cj, double ck) + { + x = ci; + y = cj; + z = ck; + orientation = ForgeDirection.UNKNOWN; + } + + public Position(double ci, double cj, double ck, ForgeDirection corientation) + { + x = ci; + y = cj; + z = ck; + orientation = corientation; + } + + public Position(Position p) + { + x = p.x; + y = p.y; + z = p.z; + orientation = p.orientation; + } + + public Position(NBTTagCompound nbttagcompound) + { + x = nbttagcompound.getDouble("i"); + y = nbttagcompound.getDouble("j"); + z = nbttagcompound.getDouble("k"); + + orientation = ForgeDirection.UNKNOWN; + } + + public Position(TileEntity tile) + { + x = tile.xCoord; + y = tile.yCoord; + z = tile.zCoord; + } + + public void moveRight(double step) + { + switch (orientation) + { + case SOUTH: + x = x - step; + break; + case NORTH: + x = x + step; + break; + case EAST: + z = z + step; + break; + case WEST: + z = z - step; + break; + default: + } + } + + public void moveLeft(double step) + { + moveRight(-step); + } + + public void moveForwards(double step) + { + switch (orientation) + { + case UP: + y = y + step; + break; + case DOWN: + y = y - step; + break; + case SOUTH: + z = z + step; + break; + case NORTH: + z = z - step; + break; + case EAST: + x = x + step; + break; + case WEST: + x = x - step; + break; + default: + } + } + + public void moveBackwards(double step) + { + moveForwards(-step); + } + + public void moveUp(double step) + { + switch (orientation) + { + case SOUTH: + case NORTH: + case EAST: + case WEST: + y = y + step; + break; + default: + } + + } + + public void moveDown(double step) + { + moveUp(-step); + } + + public void writeToNBT(NBTTagCompound nbttagcompound) + { + nbttagcompound.setDouble("i", x); + nbttagcompound.setDouble("j", y); + nbttagcompound.setDouble("k", z); + } + + @Override + public String toString() + { + return "{" + x + ", " + y + ", " + z + "}"; + } + + public Position min(Position p) + { + return new Position(p.x > x ? x : p.x, p.y > y ? y : p.y, p.z > z ? z : p.z); + } + + public Position max(Position p) + { + return new Position(p.x < x ? x : p.x, p.y < y ? y : p.y, p.z < z ? z : p.z); + } + +} diff --git a/src/APIs/buildcraft/api/core/SafeTimeTracker.java b/src/APIs/buildcraft/api/core/SafeTimeTracker.java new file mode 100644 index 00000000..628f4df7 --- /dev/null +++ b/src/APIs/buildcraft/api/core/SafeTimeTracker.java @@ -0,0 +1,57 @@ +/** + * 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.core; + +import net.minecraft.world.World; + +public class SafeTimeTracker +{ + + private long lastMark = Long.MIN_VALUE; + private long duration = 0; + private boolean marked; + + /** + * Return true if a given delay has passed since last time marked was called successfully. + */ + public boolean markTimeIfDelay(World world, long delay) + { + if (world == null) + return false; + + long currentTime = world.getWorldTime(); + + if (currentTime < lastMark) + { + lastMark = currentTime; + return false; + } + else if (lastMark + delay <= currentTime) + { + duration = currentTime - lastMark; + lastMark = world.getWorldTime(); + marked = true; + return true; + } + else + return false; + + } + + public long durationOfLastDelay() + { + return marked ? duration : 0; + } + + public void markTime(World world) + { + lastMark = world.getWorldTime(); + } +} diff --git a/src/APIs/buildcraft/api/gates/ActionManager.java b/src/APIs/buildcraft/api/gates/ActionManager.java new file mode 100644 index 00000000..26cfd2c7 --- /dev/null +++ b/src/APIs/buildcraft/api/gates/ActionManager.java @@ -0,0 +1,106 @@ +package buildcraft.api.gates; + +import buildcraft.api.transport.IPipe; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; + +public class ActionManager { + + public static Map triggers = new HashMap(); + public static Map actions = new HashMap(); + private static LinkedList triggerProviders = new LinkedList(); + private static LinkedList actionProviders = new LinkedList(); + + public static void registerTriggerProvider(ITriggerProvider provider) { + if (provider != null && !triggerProviders.contains(provider)) { + triggerProviders.add(provider); + } + } + + public static void registerTrigger(ITrigger trigger){ + triggers.put(trigger.getUniqueTag(), trigger); + } + + public static void registerAction(IAction action){ + actions.put(action.getUniqueTag(), action); + } + + public static LinkedList getNeighborTriggers(Block block, TileEntity entity) { + LinkedList triggers = new LinkedList(); + + for (ITriggerProvider provider : triggerProviders) { + LinkedList toAdd = provider.getNeighborTriggers(block, entity); + + if (toAdd != null) { + for (ITrigger t : toAdd) { + if (!triggers.contains(t)) { + triggers.add(t); + } + } + } + } + + return triggers; + } + + public static void registerActionProvider(IActionProvider provider) { + if (provider != null && !actionProviders.contains(provider)) { + actionProviders.add(provider); + } + } + + public static LinkedList getNeighborActions(Block block, TileEntity entity) { + LinkedList actions = new LinkedList(); + + for (IActionProvider provider : actionProviders) { + LinkedList toAdd = provider.getNeighborActions(block, entity); + + if (toAdd != null) { + for (IAction t : toAdd) { + if (!actions.contains(t)) { + actions.add(t); + } + } + } + } + + return actions; + } + + public static LinkedList getPipeTriggers(IPipe pipe) { + LinkedList triggers = new LinkedList(); + + for (ITriggerProvider provider : triggerProviders) { + LinkedList toAdd = provider.getPipeTriggers(pipe); + + if (toAdd != null) { + for (ITrigger t : toAdd) { + if (!triggers.contains(t)) { + triggers.add(t); + } + } + } + } + + return triggers; + } + + public static ITrigger getTriggerFromLegacyId(int legacyId){ + for(ITrigger trigger : triggers.values()){ + if(trigger.getLegacyId() == legacyId) + return trigger; + } + return null; + } + + public static IAction getActionFromLegacyId(int legacyId){ + for(IAction action : actions.values()){ + if(action.getLegacyId() == legacyId) + return action; + } + return null; + } +} diff --git a/src/APIs/buildcraft/api/gates/IAction.java b/src/APIs/buildcraft/api/gates/IAction.java new file mode 100644 index 00000000..90547d58 --- /dev/null +++ b/src/APIs/buildcraft/api/gates/IAction.java @@ -0,0 +1,27 @@ +package buildcraft.api.gates; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.util.Icon; + +public interface IAction { + + /** + * Return your ID from the old API here, this is only used to convert old + * saves to the new format. + */ + int getLegacyId(); + + String getUniqueTag(); + + @SideOnly(Side.CLIENT) + Icon getIcon(); + + @SideOnly(Side.CLIENT) + void registerIcons(IconRegister iconRegister); + + boolean hasParameter(); + + String getDescription(); +} diff --git a/src/APIs/buildcraft/api/gates/IActionProvider.java b/src/APIs/buildcraft/api/gates/IActionProvider.java new file mode 100644 index 00000000..6c64b57e --- /dev/null +++ b/src/APIs/buildcraft/api/gates/IActionProvider.java @@ -0,0 +1,23 @@ +/** + * 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.gates; + +import java.util.LinkedList; +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; + +public interface IActionProvider { + + /** + * Returns the list of actions available to a gate next to the given block. + */ + public abstract LinkedList getNeighborActions(Block block, TileEntity tile); + +} diff --git a/src/APIs/buildcraft/api/gates/IActionReceptor.java b/src/APIs/buildcraft/api/gates/IActionReceptor.java new file mode 100644 index 00000000..c4637adc --- /dev/null +++ b/src/APIs/buildcraft/api/gates/IActionReceptor.java @@ -0,0 +1,16 @@ +/** + * Copyright (c) SpaceToad, 2012 + * 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.gates; + +public interface IActionReceptor { + + public void actionActivated(IAction action); + +} diff --git a/src/APIs/buildcraft/api/gates/IOverrideDefaultTriggers.java b/src/APIs/buildcraft/api/gates/IOverrideDefaultTriggers.java new file mode 100644 index 00000000..8a2e47c6 --- /dev/null +++ b/src/APIs/buildcraft/api/gates/IOverrideDefaultTriggers.java @@ -0,0 +1,21 @@ +/** + * 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.gates; + +import java.util.LinkedList; + +/** + * This interface has to be implemented by a TileEntity or a Pipe that wants to provide triggers different from the ones installed by default with BuildCraft. + */ +public interface IOverrideDefaultTriggers { + + LinkedList getTriggers(); + +} diff --git a/src/APIs/buildcraft/api/gates/ITrigger.java b/src/APIs/buildcraft/api/gates/ITrigger.java new file mode 100644 index 00000000..ab59616b --- /dev/null +++ b/src/APIs/buildcraft/api/gates/ITrigger.java @@ -0,0 +1,47 @@ +package buildcraft.api.gates; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraftforge.common.ForgeDirection; + +public interface ITrigger { + + /** + * Return your ID from the old API here, this is only used to convert old + * saves to the new format. + */ + int getLegacyId(); + + String getUniqueTag(); + + @SideOnly(Side.CLIENT) + Icon getIcon(); + + @SideOnly(Side.CLIENT) + void registerIcons(IconRegister iconRegister); + + /** + * Return true if this trigger can accept parameters + */ + boolean hasParameter(); + + /** + * Return the trigger description in the UI + */ + String getDescription(); + + /** + * Return true if the tile given in parameter activates the trigger, given + * the parameters. + */ + boolean isTriggerActive(ForgeDirection side, TileEntity tile, ITriggerParameter parameter); + + /** + * Create parameters for the trigger. As for now, there is only one kind of + * trigger parameter available so this subprogram is final. + */ + ITriggerParameter createParameter(); +} diff --git a/src/APIs/buildcraft/api/gates/ITriggerParameter.java b/src/APIs/buildcraft/api/gates/ITriggerParameter.java new file mode 100644 index 00000000..cef436a6 --- /dev/null +++ b/src/APIs/buildcraft/api/gates/ITriggerParameter.java @@ -0,0 +1,18 @@ +package buildcraft.api.gates; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public interface ITriggerParameter { + + public abstract ItemStack getItemStack(); + + public abstract void set(ItemStack stack); + + public abstract void writeToNBT(NBTTagCompound compound); + + public abstract void readFromNBT(NBTTagCompound compound); + + public abstract ItemStack getItem(); + +} diff --git a/src/APIs/buildcraft/api/gates/ITriggerProvider.java b/src/APIs/buildcraft/api/gates/ITriggerProvider.java new file mode 100644 index 00000000..fe2271e0 --- /dev/null +++ b/src/APIs/buildcraft/api/gates/ITriggerProvider.java @@ -0,0 +1,29 @@ +/** + * 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.gates; + +import buildcraft.api.transport.IPipe; +import java.util.LinkedList; +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; + +public interface ITriggerProvider { + + /** + * Returns the list of triggers that are available from the pipe holding the gate. + */ + public abstract LinkedList getPipeTriggers(IPipe pipe); + + /** + * Returns the list of triggers available to a gate next to the given block. + */ + public abstract LinkedList getNeighborTriggers(Block block, TileEntity tile); + +} diff --git a/src/APIs/buildcraft/api/gates/TriggerParameter.java b/src/APIs/buildcraft/api/gates/TriggerParameter.java new file mode 100644 index 00000000..c76ce99a --- /dev/null +++ b/src/APIs/buildcraft/api/gates/TriggerParameter.java @@ -0,0 +1,79 @@ +/** + * 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.gates; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public class TriggerParameter implements ITriggerParameter { + + protected ItemStack stack; + + /* + * (non-Javadoc) + * + * @see net.minecraft.src.buildcraft.api.gates.ITriggerParameter#getItemStack() + */ + @Override + public ItemStack getItemStack() { + return stack; + } + + /* + * (non-Javadoc) + * + * @see net.minecraft.src.buildcraft.api.gates.ITriggerParameter#set(net.minecraft.src.ItemStack) + */ + @Override + public void set(ItemStack stack) { + if (stack != null) { + this.stack = stack.copy(); + this.stack.stackSize = 1; + } + } + + /* + * (non-Javadoc) + * + * @see net.minecraft.src.buildcraft.api.gates.ITriggerParameter#writeToNBT(net.minecraft.src.NBTTagCompound) + */ + @Override + public void writeToNBT(NBTTagCompound compound) { + if (stack != null) { + compound.setInteger("itemID", stack.itemID); + compound.setInteger("itemDMG", stack.getItemDamage()); + } + } + + /* + * (non-Javadoc) + * + * @see net.minecraft.src.buildcraft.api.gates.ITriggerParameter#readFromNBT(net.minecraft.src.NBTTagCompound) + */ + @Override + public void readFromNBT(NBTTagCompound compound) { + int itemID = compound.getInteger("itemID"); + + if (itemID != 0) { + stack = new ItemStack(itemID, 1, compound.getInteger("itemDMG")); + } + } + + /* + * (non-Javadoc) + * + * @see net.minecraft.src.buildcraft.api.gates.ITriggerParameter#getItem() + */ + @Override + public ItemStack getItem() { + return stack; + } + +} diff --git a/src/APIs/buildcraft/api/inventory/ISecuredInventory.java b/src/APIs/buildcraft/api/inventory/ISecuredInventory.java new file mode 100644 index 00000000..6ebb99b6 --- /dev/null +++ b/src/APIs/buildcraft/api/inventory/ISecuredInventory.java @@ -0,0 +1,23 @@ +package buildcraft.api.inventory; + +import net.minecraftforge.common.ForgeDirection; + +public interface ISecuredInventory { + + /** + * @param name + * @return true if the user/player with the given name has access permissions on this machine. + */ + boolean canAccess(String name); + + /** + * Informs the inventory with whose permissions the next item or liquid transaction will be performed. It is up to the inventory to determine the effect. + * + * @param orientation + * Orientation the transaction will be performed from. + * @param name + * Name of the user/player who owns the transaction. + */ + void prepareTransaction(ForgeDirection orientation, String name); + +} diff --git a/src/APIs/buildcraft/api/inventory/ISelectiveInventory.java b/src/APIs/buildcraft/api/inventory/ISelectiveInventory.java new file mode 100644 index 00000000..0e4d7045 --- /dev/null +++ b/src/APIs/buildcraft/api/inventory/ISelectiveInventory.java @@ -0,0 +1,23 @@ +package buildcraft.api.inventory; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.ForgeDirection; + +public interface ISelectiveInventory extends ISpecialInventory { + /** + * Requests specified items to be extracted from the inventory + * + * @param desired + * Array which can contain ItemStacks, Items, or classes describing the type of item accepted or excluded. + * @param exclusion + * If true desired items are not eligible for returning. + * @param doRemove + * If false no actual extraction may occur. + * @param from + * Orientation the ItemStack is requested from. + * @param maxItemCount + * Maximum amount of items to extract (spread over all returned item stacks) + * @return Array of item stacks extracted from the inventory + */ + ItemStack[] extractItem(Object[] desired, boolean exclusion, boolean doRemove, ForgeDirection from, int maxItemCount); +} diff --git a/src/APIs/buildcraft/api/inventory/ISpecialInventory.java b/src/APIs/buildcraft/api/inventory/ISpecialInventory.java new file mode 100644 index 00000000..27b735d4 --- /dev/null +++ b/src/APIs/buildcraft/api/inventory/ISpecialInventory.java @@ -0,0 +1,36 @@ +package buildcraft.api.inventory; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.ForgeDirection; + +public interface ISpecialInventory extends IInventory { + + /** + * Offers an ItemStack for addition to the inventory. + * + * @param stack + * ItemStack offered for addition. Do not manipulate this! + * @param doAdd + * If false no actual addition should take place. Implementors should simulate. + * @param from + * Orientation the ItemStack is offered from. + * @return Amount of items used from the passed stack. + */ + int addItem(ItemStack stack, boolean doAdd, ForgeDirection from); + + /** + * Requests items to be extracted from the inventory + * + * @param doRemove + * If false no actual extraction may occur. Implementors should simulate. + * Can be used to "peek" at what the result would be + * @param from + * Orientation the ItemStack is requested from. + * @param maxItemCount + * Maximum amount of items to extract (spread over all returned item stacks) + * @return Array of item stacks that were/would be extracted from the inventory + */ + ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount); + +} diff --git a/src/APIs/buildcraft/api/power/IPowerEmitter.java b/src/APIs/buildcraft/api/power/IPowerEmitter.java new file mode 100644 index 00000000..08a1b24e --- /dev/null +++ b/src/APIs/buildcraft/api/power/IPowerEmitter.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) SpaceToad, 2011-2012 + * 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.minecraftforge.common.ForgeDirection; + +/** + * Essentially only used for Wooden Power Pipe connection rules. + * + * This Tile Entity interface allows you to indicate that a block can emit power from a specific + * side. + * + * @author CovertJaguar + */ +public interface IPowerEmitter +{ + + public boolean canEmitPowerFrom(ForgeDirection side); +} diff --git a/src/APIs/buildcraft/api/power/IPowerReceptor.java b/src/APIs/buildcraft/api/power/IPowerReceptor.java new file mode 100644 index 00000000..f9f70932 --- /dev/null +++ b/src/APIs/buildcraft/api/power/IPowerReceptor.java @@ -0,0 +1,46 @@ +/** + * 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.world.World; +import net.minecraftforge.common.ForgeDirection; +import buildcraft.api.power.PowerHandler.PowerReceiver; + +/** + * This interface should be implemented by any Tile Entity that wishes to be able to receive power. + * + * @author CovertJaguar + */ +public interface IPowerReceptor +{ + + /** + * Get the PowerReceiver for this side of the block. You can return the same PowerReceiver for + * all sides or one for each side. + * + * You should NOT return null to this method unless you mean to NEVER receive power from that + * side. Returning null, after previous returning a PowerReceiver, will most likely cause pipe + * connections to derp out and engines to eventually explode. + * + * @param side + * @return + */ + public PowerReceiver getPowerReceiver(ForgeDirection side); + + /** + * Call back from the PowerHandler that is called when the stored power exceeds the activation + * power. + * + * It can be triggered by update() calls or power modification calls. + * + * @param workProvider + */ + public void doWork(PowerHandler workProvider); + + public World getWorld(); +} diff --git a/src/APIs/buildcraft/api/power/PowerHandler.java b/src/APIs/buildcraft/api/power/PowerHandler.java new file mode 100644 index 00000000..6a247d87 --- /dev/null +++ b/src/APIs/buildcraft/api/power/PowerHandler.java @@ -0,0 +1,455 @@ +/** + * 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 DEFUALT_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(); + } + + 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 bases on amount stored. + * + * @param perdition + */ + public void setPerdition(PerditionCalculator perdition) + { + this.perdition = perdition; + } + + public PerditionCalculator getPerdition() + { + if (perdition == null) + return DEFUALT_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 = DEFUALT_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() + { + 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; + } + } +} diff --git a/src/APIs/buildcraft/api/recipes/AssemblyRecipe.java b/src/APIs/buildcraft/api/recipes/AssemblyRecipe.java new file mode 100644 index 00000000..573db282 --- /dev/null +++ b/src/APIs/buildcraft/api/recipes/AssemblyRecipe.java @@ -0,0 +1,48 @@ +package buildcraft.api.recipes; + +import java.util.LinkedList; +import net.minecraft.item.ItemStack; + +public class AssemblyRecipe { + + public static LinkedList assemblyRecipes = new LinkedList(); + + public final ItemStack[] input; + public final ItemStack output; + public final float energy; + + public AssemblyRecipe(ItemStack[] input, int energy, ItemStack output) { + this.input = input; + this.output = output; + this.energy = energy; + } + + public boolean canBeDone(ItemStack[] items) { + + for (ItemStack in : input) { + + if (in == null) { + continue; + } + + int found = 0; // Amount of ingredient found in inventory + + for (ItemStack item : items) { + if (item == null) { + continue; + } + + if (item.isItemEqual(in)) { + found += item.stackSize; // Adds quantity of stack to amount + // found + } + } + + if (found < in.stackSize) + return false; // Return false if the amount of ingredient found + // is not enough + } + + return true; + } +} diff --git a/src/APIs/buildcraft/api/recipes/RefineryRecipes.java b/src/APIs/buildcraft/api/recipes/RefineryRecipes.java new file mode 100644 index 00000000..64985bf7 --- /dev/null +++ b/src/APIs/buildcraft/api/recipes/RefineryRecipes.java @@ -0,0 +1,126 @@ +/** + * 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.recipes; + +import com.google.common.base.Objects; +import java.util.Collections; +import java.util.SortedSet; +import java.util.TreeSet; +import net.minecraftforge.fluids.FluidStack; + +public final class RefineryRecipes { + + private static SortedSet recipes = new TreeSet(); + + public static void addRecipe(FluidStack ingredient, FluidStack result, int energy, int delay) { + addRecipe(ingredient, null, result, energy, delay); + } + + public static void addRecipe(FluidStack ingredient1, FluidStack ingredient2, FluidStack result, int energy, int delay) { + Recipe recipe = new Recipe(ingredient1, ingredient2, result, energy, delay); + recipes.add(recipe); + } + + public static SortedSet getRecipes() { + return Collections.unmodifiableSortedSet(recipes); + } + + public static Recipe findRefineryRecipe(FluidStack liquid1, FluidStack liquid2) { + for (Recipe recipe : recipes) { + if (recipe.matches(liquid1, liquid2)) + return recipe; + } + + return null; + } + + private RefineryRecipes() { + } + + public static final class Recipe implements Comparable { + + public final FluidStack ingredient1; + public final FluidStack ingredient2; + public final FluidStack result; + public final int energy; + public final int delay; + + private Recipe(FluidStack ingredient1, FluidStack ingredient2, FluidStack result, int energy, int delay) { + if (ingredient1 == null) + throw new IllegalArgumentException("First Ingredient cannot be null!"); + this.ingredient1 = ingredient1; + this.ingredient2 = ingredient2; + this.result = result; + this.energy = energy; + this.delay = delay; + } + + public boolean matches(FluidStack liquid1, FluidStack liquid2) { + + // No inputs, return. + if (liquid1 == null && liquid2 == null) + return false; + + // Return if two ingredients are required but only one was supplied. + if ((ingredient1 != null && ingredient2 != null) && (liquid1 == null || liquid2 == null)) + return false; + + if (liquid1 != null && liquid2 != null) { + if (liquid1.containsFluid(ingredient1) && liquid1.containsFluid(ingredient2)) + return true; + if (liquid1.containsFluid(ingredient2) && liquid1.containsFluid(ingredient1)) + return true; + } + + if (liquid1 != null) + return liquid1.containsFluid(ingredient1) || liquid1.containsFluid(ingredient2); + + if (liquid2 != null) + return liquid2.containsFluid(ingredient1) || liquid2.containsFluid(ingredient2); + + return false; + } + + // Compares to only the types of source materials. + // We consider non-null < null in order that one-ingredient recipe is checked after + // the failure of matching two-ingredient recipes which include that liquid. + @Override + public int compareTo(Recipe other) { + if (other == null) + return -1; + else if (ingredient1.getFluid() != other.ingredient1.getFluid()) + return ingredient1.getFluid().getName().compareTo(other.ingredient1.getFluid().getName()); + else if (ingredient1.amount != other.ingredient1.amount) + return other.ingredient1.amount - ingredient1.amount; + else if (ingredient2 == null) + return other.ingredient2 == null ? 0 : 1; + else if (other.ingredient2 == null) + return -1; + else if (ingredient2.getFluid() != other.ingredient2.getFluid()) + return ingredient2.getFluid().getName().compareTo(other.ingredient2.getFluid().getName()); + else if (ingredient2.amount != other.ingredient2.amount) + return other.ingredient2.amount - ingredient2.amount; + + return 0; + } + + // equals() should be consistent with compareTo(). + @Override + public boolean equals(Object obj) { + return obj instanceof Recipe + && Objects.equal(ingredient1, ((Recipe) obj).ingredient1) + && Objects.equal(ingredient2, ((Recipe) obj).ingredient2); + } + + // hashCode() should be overridden because equals() was overridden. + @Override + public int hashCode() { + return Objects.hashCode(ingredient1, ingredient2); + } + } +} diff --git a/src/APIs/buildcraft/api/tools/IToolPipette.java b/src/APIs/buildcraft/api/tools/IToolPipette.java new file mode 100644 index 00000000..d636523d --- /dev/null +++ b/src/APIs/buildcraft/api/tools/IToolPipette.java @@ -0,0 +1,40 @@ +package buildcraft.api.tools; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +public interface IToolPipette { + + /** + * @param pipette + * ItemStack of the pipette. + * @return Capacity of the pipette. + */ + int getCapacity(ItemStack pipette); + + /** + * @param pipette + * @return true if the pipette can pipette. + */ + boolean canPipette(ItemStack pipette); + + /** + * Fills the pipette with the given liquid stack. + * + * @param pipette + * @param liquid + * @param doFill + * @return Amount of liquid used in filling the pipette. + */ + int fill(ItemStack pipette, FluidStack liquid, boolean doFill); + + /** + * Drains liquid from the pipette + * + * @param pipette + * @param maxDrain + * @param doDrain + * @return Fluid stack representing the liquid and amount drained from the pipette. + */ + FluidStack drain(ItemStack pipette, int maxDrain, boolean doDrain); +} diff --git a/src/APIs/buildcraft/api/tools/IToolWrench.java b/src/APIs/buildcraft/api/tools/IToolWrench.java new file mode 100644 index 00000000..bd0c3c59 --- /dev/null +++ b/src/APIs/buildcraft/api/tools/IToolWrench.java @@ -0,0 +1,32 @@ +package buildcraft.api.tools; + +import net.minecraft.entity.player.EntityPlayer; + +/*** + * Implement this interface on subclasses of Item to have that item work as a wrench for buildcraft + */ +public interface IToolWrench { + + /*** + * Called to ensure that the wrench can be used. To get the ItemStack that is used, check player.inventory.getCurrentItem() + * + * @param player + * - The player doing the wrenching + * @param x + * ,y,z - The coordinates for the block being wrenched + * + * @return true if wrenching is allowed, false if not + */ + public boolean canWrench(EntityPlayer player, int x, int y, int z); + + /*** + * Callback after the wrench has been used. This can be used to decrease durability or for other purposes. To get the ItemStack that was used, check + * player.inventory.getCurrentItem() + * + * @param player + * - The player doing the wrenching + * @param x + * ,y,z - The coordinates of the block being wrenched + */ + public void wrenchUsed(EntityPlayer player, int x, int y, int z); +} diff --git a/src/APIs/buildcraft/api/transport/FacadeManager.java b/src/APIs/buildcraft/api/transport/FacadeManager.java new file mode 100644 index 00000000..28cbdd1a --- /dev/null +++ b/src/APIs/buildcraft/api/transport/FacadeManager.java @@ -0,0 +1,25 @@ +package buildcraft.api.transport; + +import java.lang.reflect.Method; +import net.minecraft.item.ItemStack; + +/** + * You can use this if you wish, but FML InterModComms are recommended. + * + * SYNTAX: add-facade:id@meta + */ +public class FacadeManager { + private static Method addFacade; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static void addFacade(ItemStack is) { + try { + if (addFacade == null) { + Class facade = Class.forName("buildcraft.transport.ItemFacade"); + addFacade = facade.getMethod("addFacade", ItemStack.class); + } + addFacade.invoke(null, is); + } catch (Exception ex) { + } + } +} diff --git a/src/APIs/buildcraft/api/transport/IExtractionHandler.java b/src/APIs/buildcraft/api/transport/IExtractionHandler.java new file mode 100644 index 00000000..e912f65b --- /dev/null +++ b/src/APIs/buildcraft/api/transport/IExtractionHandler.java @@ -0,0 +1,21 @@ +package buildcraft.api.transport; + +import net.minecraft.world.World; + +/** + * Implement and register with the PipeManager if you want to suppress connections from wooden pipes. + */ +public interface IExtractionHandler { + + /** + * Can this pipe extract items from the block located at these coordinates? + * param extractor can be null + */ + boolean canExtractItems(Object extractor, World world, int i, int j, int k); + + /** + * Can this pipe extract liquids from the block located at these coordinates? + * param extractor can be null + */ + boolean canExtractFluids(Object extractor, World world, int i, int j, int k); +} diff --git a/src/APIs/buildcraft/api/transport/IPassiveItemContribution.java b/src/APIs/buildcraft/api/transport/IPassiveItemContribution.java new file mode 100644 index 00000000..43a6735d --- /dev/null +++ b/src/APIs/buildcraft/api/transport/IPassiveItemContribution.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) SpaceToad, 2012 + * 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.transport; + +import net.minecraft.nbt.NBTTagCompound; + +public interface IPassiveItemContribution { + + public void readFromNBT(NBTTagCompound nbttagcompound); + + public void writeToNBT(NBTTagCompound nbttagcompound); + +} diff --git a/src/APIs/buildcraft/api/transport/IPipe.java b/src/APIs/buildcraft/api/transport/IPipe.java new file mode 100644 index 00000000..355ef4f1 --- /dev/null +++ b/src/APIs/buildcraft/api/transport/IPipe.java @@ -0,0 +1,45 @@ +/** + * 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.transport; + +import net.minecraft.tileentity.TileEntity; + +public interface IPipe { + + enum DrawingState { + DrawingPipe, DrawingRedWire, DrawingBlueWire, DrawingGreenWire, DrawingYellowWire, DrawingGate + } + + enum WireColor { + Red, Blue, Green, Yellow; + + public WireColor reverse() { + switch (this) { + case Red: + return Yellow; + case Blue: + return Green; + case Green: + return Blue; + default: + return Red; + } + } + } + + public boolean isWired(WireColor color); + + public boolean hasInterface(); + + public TileEntity getContainer(); + + public boolean isWireConnectedTo(TileEntity tile, WireColor color); + +} diff --git a/src/APIs/buildcraft/api/transport/IPipeConnection.java b/src/APIs/buildcraft/api/transport/IPipeConnection.java new file mode 100644 index 00000000..1e78ea26 --- /dev/null +++ b/src/APIs/buildcraft/api/transport/IPipeConnection.java @@ -0,0 +1,17 @@ +/** + * 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.transport; + +import net.minecraftforge.common.ForgeDirection; + +public interface IPipeConnection { + + public boolean isPipeConnected(ForgeDirection with); +} diff --git a/src/APIs/buildcraft/api/transport/IPipeEntry.java b/src/APIs/buildcraft/api/transport/IPipeEntry.java new file mode 100644 index 00000000..df20e1c4 --- /dev/null +++ b/src/APIs/buildcraft/api/transport/IPipeEntry.java @@ -0,0 +1,26 @@ +/** + * 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.transport; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.ForgeDirection; + +/** + * Interface used to put objects into pipes, implemented by pipe tile entities. + */ +public interface IPipeEntry { + + void entityEntering(ItemStack payload, ForgeDirection orientation); + + void entityEntering(IPipedItem item, ForgeDirection orientation); + + boolean acceptItems(); + +} diff --git a/src/APIs/buildcraft/api/transport/IPipeTile.java b/src/APIs/buildcraft/api/transport/IPipeTile.java new file mode 100644 index 00000000..261ceed4 --- /dev/null +++ b/src/APIs/buildcraft/api/transport/IPipeTile.java @@ -0,0 +1,17 @@ +/** + * 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.transport; + +public interface IPipeTile { + + IPipe getPipe(); + + boolean isInitialized(); +} diff --git a/src/APIs/buildcraft/api/transport/IPipedItem.java b/src/APIs/buildcraft/api/transport/IPipedItem.java new file mode 100644 index 00000000..bbb853e3 --- /dev/null +++ b/src/APIs/buildcraft/api/transport/IPipedItem.java @@ -0,0 +1,90 @@ +package buildcraft.api.transport; + +import buildcraft.api.core.Position; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; + +public interface IPipedItem { + + public abstract void remove(); + + /* GETTING & SETTING */ + public abstract void setWorld(World world); + + public abstract Position getPosition(); + + public abstract void setPosition(double x, double y, double z); + + /** + * @return the speed + */ + public abstract float getSpeed(); + + /** + * @param speed + * the speed to set + */ + public abstract void setSpeed(float speed); + + /** + * @return the item + */ + public abstract ItemStack getItemStack(); + + /** + * @param item + * the item to set + */ + public abstract void setItemStack(ItemStack item); + + /** + * @return the container + */ + public abstract TileEntity getContainer(); + + /** + * @param container + * the container to set + */ + public abstract void setContainer(TileEntity container); + + /** + * @return the entityId + */ + public abstract int getEntityId(); + + /** + * @param entityId + * the entityId to set + */ + public abstract void setEntityId(int entityId); + + /* SAVING & LOADING */ + public abstract void readFromNBT(NBTTagCompound nbttagcompound); + + public abstract void writeToNBT(NBTTagCompound nbttagcompound); + + public abstract EntityItem toEntityItem(ForgeDirection dir); + + public abstract float getEntityBrightness(float f); + + public abstract boolean isCorrupted(); + + public abstract void addContribution(String key, IPassiveItemContribution contribution); + + public abstract IPassiveItemContribution getContribution(String key); + + public abstract boolean hasContributions(); + + + /** + * @return the can this item be moved into this specific entity type. + * (basic BuildCraft PipedItems always return true) + */ + public abstract boolean canSinkTo(TileEntity entity); + +} diff --git a/src/APIs/buildcraft/api/transport/ISolidSideTile.java b/src/APIs/buildcraft/api/transport/ISolidSideTile.java new file mode 100644 index 00000000..627b0d88 --- /dev/null +++ b/src/APIs/buildcraft/api/transport/ISolidSideTile.java @@ -0,0 +1,7 @@ +package buildcraft.api.transport; + +import net.minecraftforge.common.ForgeDirection; + +public interface ISolidSideTile { + public boolean isSolidOnSide(ForgeDirection side); +} diff --git a/src/APIs/buildcraft/api/transport/PipeManager.java b/src/APIs/buildcraft/api/transport/PipeManager.java new file mode 100644 index 00000000..c78c86e2 --- /dev/null +++ b/src/APIs/buildcraft/api/transport/PipeManager.java @@ -0,0 +1,36 @@ +package buildcraft.api.transport; + +import java.util.ArrayList; +import java.util.List; +import net.minecraft.world.World; + +public abstract class PipeManager { + + public static List extractionHandlers = new ArrayList(); + + public static void registerExtractionHandler(IExtractionHandler handler) { + extractionHandlers.add(handler); + } + + /** + * param extractor can be null + */ + public static boolean canExtractItems(Object extractor, World world, int i, int j, int k) { + for (IExtractionHandler handler : extractionHandlers) + if (!handler.canExtractItems(extractor, world, i, j, k)) + return false; + + return true; + } + + /** + * param extractor can be null + */ + public static boolean canExtractFluids(Object extractor, World world, int i, int j, int k) { + for (IExtractionHandler handler : extractionHandlers) + if (!handler.canExtractFluids(extractor, world, i, j, k)) + return false; + + return true; + } +} diff --git a/src/APIs/dan200/computer/api/ComputerCraftAPI.java b/src/APIs/dan200/computer/api/ComputerCraftAPI.java new file mode 100644 index 00000000..9278dd0f --- /dev/null +++ b/src/APIs/dan200/computer/api/ComputerCraftAPI.java @@ -0,0 +1,163 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; +import java.lang.reflect.Method; +import net.minecraft.world.World; + +/** + * The static entry point to the ComputerCraft API. + * Members in this class must be called after mod_ComputerCraft has been initialised, + * but may be called before it is fully loaded. + */ +public class ComputerCraftAPI +{ + /** + * Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.
+ * Use in conjuction with createSaveDirMount() to create a unique place for your peripherals or media items to store files.
+ * @param world The world for which the save dir should be created. This should be the serverside world object. + * @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computer/disk" + * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason.
+ * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing. + * @see #createSaveDirMount(World, String) + */ + public static int createUniqueNumberedSaveDir( World world, String parentSubPath ) + { + findCC(); + if( computerCraft_createUniqueNumberedSaveDir != null ) + { + try { + return ((Integer)computerCraft_createUniqueNumberedSaveDir.invoke( null, world, parentSubPath )).intValue(); + } catch (Exception e){ + // It failed + } + } + return -1; + } + + /** + * Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it.
+ * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the + * users save directory onto a computers file system.
+ * @param world The world for which the save dir can be found. This should be the serverside world object. + * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42".
+ * Use createUniqueNumberedSaveDir() to create a new numbered folder to use. + * @param capacity The ammount of data that can be stored in the directory before it fills up, in bytes. + * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() + * to mount this on a Computers' file system. + * @see #createUniqueNumberedSaveDir(World, String) + * @see IComputerAccess#mount(String, IMount) + * @see IComputerAccess#mountWritable(String, IWritableMount) + * @see IMount + * @see IMountWritable + */ + public static IWritableMount createSaveDirMount( World world, String subPath, long capacity ) + { + findCC(); + if( computerCraft_createSaveDirMount != null ) + { + try { + return (IWritableMount)computerCraft_createSaveDirMount.invoke( null, world, subPath, capacity ); + } catch (Exception e){ + // It failed + } + } + return null; + } + + /** + * Creates a file system mount to a resource folder, and returns it.
+ * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder onto a computers file system.
+ * The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain resources with the same domain and path.
+ * @param class A class in whose jar to look first for the resources to mount. Using your main mod class is recommended. eg: MyMod.class + * @param domain The domain under which to look for resources. eg: "mymod" + * @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles" + * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() + * to mount this on a Computers' file system. + * @see IComputerAccess#mount(String, IMount) + * @see IComputerAccess#mountWritable(String, IMountWritable) + * @see IMount + */ + public static IMount createResourceMount( Class modClass, String domain, String subPath ) + { + findCC(); + if( computerCraft_createResourceMount != null ) + { + try { + return (IMount)computerCraft_createResourceMount.invoke( null, modClass, domain, subPath ); + } catch (Exception e){ + // It failed + } + } + return null; + } + + /** + * Registers a peripheral handler for a TileEntity that you do not have access to. Only + * use this if you want to expose IPeripheral on a TileEntity from another mod. For your own + * mod, just implement IPeripheral on the TileEntity directly. + * @see IPeripheral + * @see IPeripheralHandler + */ + public static void registerExternalPeripheral( Class clazz, IPeripheralHandler handler ) + { + findCC(); + if (computerCraft_registerExternalPeripheral != null) + { + try { + computerCraft_registerExternalPeripheral.invoke(null, clazz, handler); + } catch (Exception e){ + // It failed + } + } + } + + // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. + // Reflection is used here so you can develop your mod in MCP without decompiling ComputerCraft and including + // it in your solution. + + private static void findCC() + { + if( !ccSearched ) { + try { + computerCraft = Class.forName( "dan200.ComputerCraft" ); + computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class[] { + World.class, String.class + } ); + computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class[] { + World.class, String.class, Long.TYPE + } ); + computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class[] { + Class.class, String.class, String.class + } ); + computerCraft_registerExternalPeripheral = findCCMethod( "registerExternalPeripheral", new Class[] { + Class.class, IPeripheralHandler.class + } ); + } catch( Exception e ) { + net.minecraft.server.MinecraftServer.getServer().logInfo( "ComputerCraftAPI: ComputerCraft not found." ); + } finally { + ccSearched = true; + } + } + } + + private static Method findCCMethod( String name, Class[] args ) + { + try { + return computerCraft.getMethod( name, args ); + } catch( NoSuchMethodException e ) { + net.minecraft.server.MinecraftServer.getServer().logInfo( "ComputerCraftAPI: ComputerCraft method " + name + " not found." ); + return null; + } + } + + private static boolean ccSearched = false; + private static Class computerCraft = null; + private static Method computerCraft_createUniqueNumberedSaveDir = null; + private static Method computerCraft_createSaveDirMount = null; + private static Method computerCraft_createResourceMount = null; + private static Method computerCraft_registerExternalPeripheral = null; +} diff --git a/src/APIs/dan200/computer/api/IComputerAccess.java b/src/APIs/dan200/computer/api/IComputerAccess.java new file mode 100644 index 00000000..ff086a34 --- /dev/null +++ b/src/APIs/dan200/computer/api/IComputerAccess.java @@ -0,0 +1,89 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; + +/** + * The interface passed to peripherals by computers or turtles, providing methods + * that they can call. This should not be implemented by your classes. Do not interact + * with computers except via this interface. + */ +public interface IComputerAccess +{ + /** + * Mount a mount onto the computers' file system in a read only mode.
+ * @param desiredLoction The location on the computer's file system where you would like the mount to be mounted. + * @param mount The mount object to mount on the computer. These can be obtained by calling ComputerCraftAPI.createSaveDirMount(), ComputerCraftAPI.createResourceMount() or by creating your own objects that implement the IMount interface. + * @return The location on the computer's file system where you the mount was actually mounted, this may be different from desiredLocation if there was already a file in the desired location. Store this value if you wish to unmount the mount later. + * @see ComputerCraftAPI#createSaveDirMount(World, String) + * @see ComputerCraftAPI#createResourceMount(Class, String, String) + * @see #mountWritable(String, IWritableMount) + * @see #unmount(String) + * @see IMount + */ + public String mount( String desiredLocation, IMount mount ); + + /** + * Mount a mount onto the computers' file system in a writable mode.
+ * @param desiredLoction The location on the computer's file system where you would like the mount to be mounted. + * @param mount The mount object to mount on the computer. These can be obtained by calling ComputerCraftAPI.createSaveDirMount() or by creating your own objects that implement the IWritableMount interface. + * @return The location on the computer's file system where you the mount was actually mounted, this may be different from desiredLocation if there was already a file in the desired location. Store this value if you wish to unmount the mount later. + * @see ComputerCraftAPI#createSaveDirMount(World, String) + * @see ComputerCraftAPI#createResourceMount(Class, String, String) + * @see #mount(String, IMount) + * @see #unmount(String) + * @see IMount + */ + public String mountWritable( String desiredLocation, IWritableMount mount ); + + /** + * Unmounts a directory previously mounted onto the computers file system by mount() or mountWritable().
+ * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be able to + * access it. All directories mounted by a mount or mountWritable are automatically unmounted when the peripheral + * is attached if they have not been explicitly unmounted. + * @param location The desired location in the computers file system of the directory to unmount. + * This must be the location of a directory previously mounted by mount() or mountWritable(), as + * indicated by their return value. + * @see #mount(String, IMount) + * @see #mountWritable(String, IWritableMount) + */ + public void unmount( String location ); + + /** + * Returns the numerical ID of this computer.
+ * This is the same number obtained by calling os.getComputerID() or running the "id" program from lua, + * and is guarunteed unique. This number will be positive. + * @return The identifier. + */ + public int getID(); + + /** + * Causes an event to be raised on this computer, which the computer can respond to by calling + * os.pullEvent(). This can be used to notify the computer when things happen in the world or to + * this peripheral. + * @param event A string identifying the type of event that has occurred, this will be + * returned as the first value from os.pullEvent(). It is recommended that you + * you choose a name that is unique, and recognisable as originating from your + * peripheral. eg: If your peripheral type is "button", a suitable event would be + * "button_pressed". + * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will + * be supplied as extra return values to os.pullEvent(). Objects in the array will be converted + * to lua data types in the same fashion as the return values of IPeripheral.callMethod().
+ * You may supply null to indicate that no arguments are to be supplied. + * @see IPeripheral#callMethod + */ + public void queueEvent( String event, Object[] arguments ); + + /** + * Get a string, unique to the computer, by which the computer refers to this peripheral. + * For directly attached peripherals this will be "left","right","front","back",etc, but + * for peripherals attached remotely it will be different. It is good practice to supply + * this string when raising events to the computer, so that the computer knows from + * which peripheral the event came. + * @return A string unique to the computer, but not globally. + */ + public String getAttachmentName(); +} diff --git a/src/APIs/dan200/computer/api/IHostedPeripheral.java b/src/APIs/dan200/computer/api/IHostedPeripheral.java new file mode 100644 index 00000000..68cf3fd7 --- /dev/null +++ b/src/APIs/dan200/computer/api/IHostedPeripheral.java @@ -0,0 +1,44 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; +import dan200.computer.api.IPeripheral; + +/** + * A subclass of IPeripheral specifically for peripherals + * created by ITurtleUpgrade's of type Peripheral. When an + * IHostedPeripheral is created, its IPeripheral methods will be called + * just as if the peripheral was a seperate adjacent block in the world, + * and update() will be called once per tick. + * @see ITurtleUpgrade + */ +public interface IHostedPeripheral extends IPeripheral +{ + /** + * A method called on each hosted peripheral once per tick, on the main thread + * over the lifetime of the turtle or block. May be used to update the state + * of the peripheral, and may interact with IComputerAccess or ITurtleAccess + * however it likes at this time. + */ + public void update(); + + /** + * A method called whenever data is read from the Turtle's NBTTag, + * over the lifetime of the turtle. You should only use this for + * reading data you want to stay with the peripheral. + * @param nbttagcompound The peripheral's NBTTag + */ + public void readFromNBT( net.minecraft.nbt.NBTTagCompound nbttagcompound ); + + /** + * A method called whenever data is written to the Turtle's NBTTag, + * over the lifetime of the turtle. You should only use this for + * writing data you want to stay with the peripheral. + * @param nbttagcompound The peripheral's NBTTag. + * @param ID The turtle's ID. + */ + public void writeToNBT( net.minecraft.nbt.NBTTagCompound nbttagcompound ); +} diff --git a/src/APIs/dan200/computer/api/ILuaContext.java b/src/APIs/dan200/computer/api/ILuaContext.java new file mode 100644 index 00000000..eb319390 --- /dev/null +++ b/src/APIs/dan200/computer/api/ILuaContext.java @@ -0,0 +1,45 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; + +/** + * An interface passed to peripherals and ILuaObjects' by computers or turtles, providing methods + * that allow the peripheral call to wait for events before returning, just like in lua. + * This is very useful if you need to signal work to be performed on the main thread, and don't want to return + * until the work has been completed. + */ +public interface ILuaContext +{ + /** + * Wait for an event to occur on the computer, suspending the thread until it arises. This method is exactly equivalent to os.pullEvent() in lua. + * @param filter A specific event to wait for, or null to wait for any event + * @return An object array containing the name of the event that occurred, and any event parameters + * @throws Exception If the user presses CTRL+T to terminate the current program while pullEvent() is waiting for an event, a "Terminated" exception will be thrown here. + * Do not attempt to block this exception, unless you wish to prevent termination, which is not recommended. + * @throws InterruptedException If the user shuts down or reboots the computer while pullEvent() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computer will leak memory and end up in a broken state. + */ + public Object[] pullEvent( String filter ) throws Exception, InterruptedException; + + /** + * The same as pullEvent(), except "terminated" events are ignored. Only use this if you want to prevent program termination, which is not recommended. This method is exactly equivalent to os.pullEventRaw() in lua. + * @param filter A specific event to wait for, or null to wait for any event + * @return An object array containing the name of the event that occurred, and any event parameters + * @throws InterruptedException If the user shuts down or reboots the computer while pullEventRaw() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computer will leak memory and end up in a broken state. + * @see #pullEvent(String) + */ + public Object[] pullEventRaw( String filter ) throws InterruptedException; + + + /** + * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to coroutine.yield() in lua. Use pullEvent() if you wish to wait for events. + * @param arguments An object array containing the arguments to pass to coroutine.yield() + * @return An object array containing the return values from coroutine.yield() + * @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computer will leak memory and end up in a broken state. + * @see #pullEvent(String) + */ + public Object[] yield( Object[] arguments ) throws InterruptedException; +} diff --git a/src/APIs/dan200/computer/api/ILuaObject.java b/src/APIs/dan200/computer/api/ILuaObject.java new file mode 100644 index 00000000..a063fa5b --- /dev/null +++ b/src/APIs/dan200/computer/api/ILuaObject.java @@ -0,0 +1,26 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; + +/** + * An interface for representing custom objects returned by IPeripheral.callMethod() calls. + * Return objects implementing this interface to expose objects with methods to lua. + */ +public interface ILuaObject +{ + /** + * Get the names of the methods that this object implements. This works the same as IPeripheral.getMethodNames(). See that method for detailed documentation. + * @see IPeripheral#getMethodNames() + */ + public String[] getMethodNames(); + + /** + * Called when a user calls one of the methods that this object implements. This works the same as IPeripheral.callMethod(). See that method for detailed documentation. + * @see IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[]) + */ + public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws Exception; +} diff --git a/src/APIs/dan200/computer/api/IMedia.java b/src/APIs/dan200/computer/api/IMedia.java new file mode 100644 index 00000000..52660af0 --- /dev/null +++ b/src/APIs/dan200/computer/api/IMedia.java @@ -0,0 +1,57 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; +import net.minecraft.world.World; +import net.minecraft.item.ItemStack; + +/** + * Represents an item that can be placed in a disk drive and used by a Computer. + * Implement this interface on your Item class to allow it to be used in the drive. + */ +public interface IMedia +{ + /** + * Get a string representing the label of this item. Will be called vi disk.getLabel() in lua. + * @param stack The itemstack to inspect + * @return The label. ie: "Dan's Programs" + */ + public String getLabel( ItemStack stack ); + + /** + * Set a string representing the label of this item. Will be called vi disk.setLabel() in lua. + * @param stack The itemstack to modify. + * @param label The string to set the label to. + * @return true if the label was updated, false if the label may not be modified. + */ + public boolean setLabel( ItemStack stack, String label ); + + /** + * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: "Jonathon Coulton - Still Alive" + * @param stack The itemstack to inspect. + * @return The name, or null if this item does not represent an item with audio. + */ + public String getAudioTitle( ItemStack stack ); + + /** + * If this disk represents an item with audio (like a record), get the resource name of the audio track to play. + * @param stack The itemstack to inspect. + * @return The name, or null if this item does not represent an item with audio. + */ + public String getAudioRecordName( ItemStack stack ); + + /** + * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will be mounted onto the filesystem of the computer while the media is in the disk drive. + * @param stack The itemstack to inspect. + * @param world The world in which the item and disk drive reside. + * @return The mount, or null if this item does not represent an item with data. If the IMount returned also implements IWritableMount, it will mounted using mountWritable() + * @see IMount + * @see IWritableMount + * @see ComputerCraftAPI#createSaveDirMount(World, String) + * @see ComputerCraftAPI#createResourceMount(Class, String, String) + */ + public IMount createDataMount( ItemStack stack, World world ); +} diff --git a/src/APIs/dan200/computer/api/IMount.java b/src/APIs/dan200/computer/api/IMount.java new file mode 100644 index 00000000..69ff3231 --- /dev/null +++ b/src/APIs/dan200/computer/api/IMount.java @@ -0,0 +1,57 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +/** + * Represents a read only part of a virtual filesystem that can be mounted onto a computer using IComputerAccess.mount(). + * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount() or ComputerCraftAPI.createResourceMount(), or you're free to implement it yourselves! + * @see ComputerCraftAPI#createSaveDirMount(World, String) + * @see ComputerCraftAPI#createResourceMount(Class, String, String) + * @see IComputerAccess#mount(String, IMount) + * @see IWritableMount + */ +public interface IMount +{ + /** + * Returns whether a file with a given path exists or not. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return true if the file exists, false otherwise + */ + public boolean exists( String path ) throws IOException; + + /** + * Returns whether a file with a given path is a directory or not. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" + * @return true if the file exists and is a directory, false otherwise + */ + public boolean isDirectory( String path ) throws IOException; + + /** + * Returns the file names of all the files in a directory. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" + * @param contents A list of strings. Add all the file names to this list + */ + public void list( String path, List contents ) throws IOException; + + /** + * Returns the size of a file with a given path, in bytes + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return the size of the file, in bytes + */ + public long getSize( String path ) throws IOException; + + /** + * Opens a file with a given path, and returns an inputstream representing it's contents. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream representing the contents of the file + */ + public InputStream openForRead( String path ) throws IOException; +} diff --git a/src/APIs/dan200/computer/api/IPeripheral.java b/src/APIs/dan200/computer/api/IPeripheral.java new file mode 100644 index 00000000..67243180 --- /dev/null +++ b/src/APIs/dan200/computer/api/IPeripheral.java @@ -0,0 +1,106 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; + +/** + * The interface that defines a peripheral. This should be implemented by the + * TileEntity of any block that you wish to be interacted with by + * computer or turtle. + */ +public interface IPeripheral +{ + /** + * Should return a string that uniquely identifies this type of peripheral. + * This can be queried from lua by calling peripheral.getType() + * @return A string identifying the type of peripheral. + */ + public String getType(); + + /** + * Should return an array of strings that identify the methods that this + * peripheral exposes to Lua. This will be called once before each attachment, + * and should not change when called multiple times. + * @return An array of strings representing method names. + * @see #callMethod + */ + public String[] getMethodNames(); + + /** + * This is called when a lua program on an attached computer calls peripheral.call() with + * one of the methods exposed by getMethodNames().
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * @param computer The interface to the computer that is making the call. Remember that multiple + * computers can be attached to a peripheral at once. + * @param context The context of the currently running lua thread. This can be used to wait for events + * or otherwise yield. + * @param method An integer identifying which of the methods from getMethodNames() the computer + * wishes to call. The integer indicates the index into the getMethodNames() table + * that corresponds to the string passed into peripheral.call() + * @param arguments An array of objects, representing the arguments passed into peripheral.call().
+ * Lua values of type "string" will be represented by Object type String.
+ * Lua values of type "number" will be represented by Object type Double.
+ * Lua values of type "boolean" will be represented by Object type Boolean.
+ * Lua values of any other type will be represented by a null object.
+ * This array will be empty if no arguments are passed. + * @return An array of objects, representing values you wish to return to the lua program.
+ * Integers, Doubles, Floats, Strings, Booleans and null be converted to their corresponding lua type.
+ * All other types will be converted to nil.
+ * You may return null to indicate no values should be returned. + * @throws Exception If you throw any exception from this function, a lua error will be raised with the + * same message as your exception. Use this to throw appropriate errors if the wrong + * arguments are supplied to your method. + * @see #getMethodNames + */ + public Object[] callMethod( IComputerAccess computer, ILuaContext context, int method, Object[] arguments ) throws Exception; + + /** + * Is called before the computer attempts to attach to the peripheral, and should return whether to allow + * the attachment. Use this to restrict the number of computers that can attach, or to limit attachments to + * certain world directions.
+ * If true is returned, attach() will be called shortly afterwards, and the computer will be able to make method calls. + * If false is returned, attach() will not be called, and the peripheral will be invisible to the computer. + * @param side The world direction (0=bottom, 1=top, etc) that the computer lies relative to the peripheral. + * @return Whether to allow the attachment, as a boolean. + * @see #attach + */ + public boolean canAttachToSide( int side ); + + /** + * Is called when canAttachToSide has returned true, and a computer is attaching to the peripheral. + * This will occur when a peripheral is placed next to an active computer, when a computer is turned on next to a peripheral, + * or when a turtle travels into a square next to a peripheral. + * Between calls to attach() and detach(), the attached computer can make method calls on the peripheral using peripheral.call(). + * This method can be used to keep track of which computers are attached to the peripheral, or to take action when attachment + * occurs.
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * @param computer The interface to the computer that is being attached. Remember that multiple + * computers can be attached to a peripheral at once. + * @see #canAttachToSide + * @see #detach + */ + public void attach( IComputerAccess computer ); + + /** + * Is called when a computer is detaching from the peripheral. + * This will occur when a computer shuts down, when the peripheral is removed while attached to computers, + * or when a turtle moves away from a square attached to a peripheral. + * This method can be used to keep track of which computers are attached to the peripheral, or to take action when detachment + * occurs.
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * @param computer The interface to the computer that is being detached. Remember that multiple + * computers can be attached to a peripheral at once. + * @see #canAttachToSide + * @see #detach + */ + public void detach( IComputerAccess computer ); +} diff --git a/src/APIs/dan200/computer/api/IPeripheralHandler.java b/src/APIs/dan200/computer/api/IPeripheralHandler.java new file mode 100644 index 00000000..18487d85 --- /dev/null +++ b/src/APIs/dan200/computer/api/IPeripheralHandler.java @@ -0,0 +1,15 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; + +/** + * TODO: Document me + */ +public interface IPeripheralHandler +{ + public IHostedPeripheral getPeripheral( net.minecraft.tileentity.TileEntity tile ); +} diff --git a/src/APIs/dan200/computer/api/IWritableMount.java b/src/APIs/dan200/computer/api/IWritableMount.java new file mode 100644 index 00000000..7fa8db3f --- /dev/null +++ b/src/APIs/dan200/computer/api/IWritableMount.java @@ -0,0 +1,53 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computer.api; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +/** + * Represents a part of a virtual filesystem that can be mounted onto a computer using IComputerAccess.mount() or IComputerAccess.mountWritable(), that can also be written to. + * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount(), or you're free to implement it yourselves! + * @see ComputerCraftAPI#createSaveDirMount(World, String) + * @see IComputerAccess#mountWritable(String, IMount) + * @see IMount + */ +public interface IWritableMount extends IMount +{ + /** + * Creates a directory at a given path inside the virtual file system. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/mynewprograms" + */ + public void makeDirectory( String path ) throws IOException; + + /** + * Deletes a directory at a given path inside the virtual file system. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myoldprograms" + */ + public void delete( String path ) throws IOException; + + /** + * Opens a file with a given path, and returns an outputstream for writing to it. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream for writing to + */ + public OutputStream openForWrite( String path ) throws IOException; + + /** + * Opens a file with a given path, and returns an outputstream for appending to it. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream for writing to + */ + public OutputStream openForAppend( String path ) throws IOException; + + /** + * Get the ammount of free space on the mount, in bytes. You should decrease this value as the user writes to the mount, and write operations should fail once it reaches zero. + * @return The ammount of free space, in bytes. + */ + public long getRemainingSpace() throws IOException; +} diff --git a/src/APIs/dan200/turtle/api/ITurtleAccess.java b/src/APIs/dan200/turtle/api/ITurtleAccess.java new file mode 100644 index 00000000..f996bf47 --- /dev/null +++ b/src/APIs/dan200/turtle/api/ITurtleAccess.java @@ -0,0 +1,158 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.turtle.api; +import dan200.computer.api.*; + +/** + * The interface passed to upgrades by turtles, providing methods that they can call. + * This should not be implemented by your classes. Do not interact with turtles except via this interface and ITurtleUpgrade. + */ +public interface ITurtleAccess +{ + /** + * Returns the world in which the turtle resides. + * @return the world in which the turtle resides. + */ + public net.minecraft.world.World getWorld(); + + /** + * Returns a vector containing the integer block co-ordinates at which the turtle resides. + * @return a vector containing the integer block co-ordinates at which the turtle resides. + */ + public net.minecraft.util.Vec3 getPosition(); + + /** + * Returns a vector containing the co-ordinates at which the turtle is rendered. + * This will shift when the turtle is moving. + * @param f The subframe fraction + * @return a vector containing the integer block co-ordinates at which the turtle resides. + */ + public net.minecraft.util.Vec3 getVisualPosition( float f ); + + /** + * Returns the world direction the turtle is currently facing. + * @return the world direction the turtle is currently facing. + */ + public int getFacingDir(); + + /** + * Returns the size of the turtles inventory, in number of slots. This will currently always be 16. + * @return the size of the turtles inventory, in number of slots. This will currently always be 16. + */ + public int getInventorySize(); + + /** + * Returns which slot the turtle currently has selected in its inventory using turtle.select(). + * Unlike the 1-based lua representation, this will be between 0 and getInventorySize() - 1. + * @return which slot the turtle currently has selected in its inventory + */ + public int getSelectedSlot(); + + /** + * Returns the item stack that the turtle has in one of its inventory slots. + * @param index which inventory slot to retreive, should be between 0 and getInventorySize() - 1 + * @return the item stack that the turtle has in one of its inventory slots. May be null. + */ + public net.minecraft.item.ItemStack getSlotContents( int index ); + + /** + * Changes the item stack that the turtle has in one of its inventory slots. + * @param index which inventory slot to change, should be between 0 and getInventorySize() - 1 + * @param stack an item stack to put in the slot. May be null. + */ + public void setSlotContents( int index, net.minecraft.item.ItemStack stack ); + + /** + * Tries to store an item stack into the turtles current inventory, starting from the turtles + * currently selected inventory slot. + * @param stack The item stack to try and store. + * @return true if the stack was completely stored in the inventory, false if + * it was only partially stored, or could not fit at all. If false is returned + * and the stack was partially stored, the ItemStack passed into "stack" will now + * represent the stack of items that is left over. + */ + public boolean storeItemStack( net.minecraft.item.ItemStack stack ); + + /** + * Drops an item stack from the turtle onto the floor, or into an inventory is there is one + * adjacent to the turtle in the direction specified. + * @param stack The item stack to drop. + * @param dir The world direction to drop the item + * @return true if the stack was dropped, or completely stored in the adjacent inventory, false if + * it was only partially stored in the adjacent inventory, or could not fit at all. If false is returned + * and the stack was partially stored, the ItemStack passed into "stack" will now + * represent the stack of items that is left over. + */ + public boolean dropItemStack( net.minecraft.item.ItemStack stack, int dir ); + + /** + * "Deploys" an item stack in the direction specified. This simulates a player right clicking, and calls onItemUse() on the Item class. + * Will return true if some kind of deployment happened, and may modify the item stack. For block item types, this can be + * used to place blocks. Some kinds of items (such as shears when facing a sheep) may modify the turtles inventory during this call. + * @param stack The item stack to deploy + * @param dir The world direction to deploy the item + * @return true if the stack was deployed, false if it was not. + */ + public boolean deployWithItemStack( net.minecraft.item.ItemStack stack, int dir ); + + /** + * Tries to "attack" entities with an item stack in the direction specified. This simulates a player left clicking, but will + * not affect blocks. If an entity is attacked and killed during this call, its dropped items will end up in the turtles + * inventory. + * @param stack The item stack to attack with + * @param dir The world direction to attack with the item + * @return true if something was attacked, false if it was not + */ + public boolean attackWithItemStack( net.minecraft.item.ItemStack stack, int dir, float damageMultiplier ); + + /** + * Returns the current fuel level of the turtle, this is the same integer returned by turtle.getFuelLevel(), + * that decreases by 1 every time the turtle moves. Can be used to have your tool or peripheral require or supply + * fuel to the turtle. + * @return the fuel level + */ + public int getFuelLevel(); + + /** + * Tries to increase the fuel level of a turtle by burning an item stack. If the item passed in is a fuel source, fuel + * will increase and true will be returned. Otherwise, nothing will happen and false will be returned. + * @param stack The stack to try to refuel with + * @return Whether the turtle was refueled + */ + public boolean refuelWithItemStack( net.minecraft.item.ItemStack stack ); + + /** + * Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle. + * @return Whether the turtle was able to consume the ammount of fuel specified. Will return false if you supply a number + * greater than the current fuel level of the turtle. + */ + public boolean consumeFuel( int fuel ); + + /** + * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed + * on the main thread, so are guaranteed to be able to access Minecraft objects safely, and will be queued up + * with the turtles standard movement and tool commands. An issued command will return an unique integer, which will + * be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. Look at the + * lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality. + * @param handler an object which will execute the custom command when its point in the queue is reached + * @return the unique command identifier described above + * @see ITurtleCommandHandler + */ + public int issueCommand( ITurtleCommandHandler handler ); + + /** + * Returns the upgrade on the specified side of the turtle, if there is one. + * @return the upgrade on the specified side of the turtle, if there is one. + */ + public ITurtleUpgrade getUpgrade( TurtleSide side ); + + /** + * Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one. + * @return the peripheral created by the upgrade on the specified side of the turtle, if there is one. + */ + public IHostedPeripheral getPeripheral( TurtleSide side ); +} diff --git a/src/APIs/dan200/turtle/api/ITurtleCommandHandler.java b/src/APIs/dan200/turtle/api/ITurtleCommandHandler.java new file mode 100644 index 00000000..255d28e2 --- /dev/null +++ b/src/APIs/dan200/turtle/api/ITurtleCommandHandler.java @@ -0,0 +1,25 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.turtle.api; + +/** + * An interface for objects executing custom turtle commands, used with ITurtleAccess.issueCommand + * @see ITurtleAccess#issueCommand( ITurtleCommandHandler ) + */ +public interface ITurtleCommandHandler +{ + /** + * Will be called by the turtle on the main thread when it is time to execute the custom command. + * The handler should either perform the work of the command, and return true for success, or return + * false to indicate failure if the command cannot be executed at this time. + * @param turtle access to the turtle for whom the command was issued + * @return true for success, false for failure. If true is returned, the turtle will wait 0.4 seconds + * before executing the next command in its queue, as it does for the standard turtle commands. + * @see ITurtleAccess#issueCommand( ITurtleCommandHandler ) + */ + public boolean handleCommand( ITurtleAccess turtle ); +} diff --git a/src/APIs/dan200/turtle/api/ITurtleUpgrade.java b/src/APIs/dan200/turtle/api/ITurtleUpgrade.java new file mode 100644 index 00000000..3af5127b --- /dev/null +++ b/src/APIs/dan200/turtle/api/ITurtleUpgrade.java @@ -0,0 +1,92 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.turtle.api; +import net.minecraft.util.Icon; +import dan200.computer.api.*; + +/** + * The primary interface for defining an upgrade for Turtles. A turtle upgrade + * can either be a new tool, or a new peripheral. + * @see TurtleAPI#registerUpgrade( ITurtleUpgrade ) + */ +public interface ITurtleUpgrade +{ + /** + * Gets a unique numerical identifier representing this type of turtle upgrade. + * Like Minecraft block and item IDs, you should strive to make this number unique + * among all turtle upgrades that have been released for ComputerCraft. + * The ID must be in the range 64 to 255, as the ID is stored as an 8-bit value, + * and 0-64 is reserved for future use by ComputerCraft. The upgrade will + * fail registration if an already used ID is specified. + * @see TurtleAPI#registerUpgrade( ITurtleUpgrade ) + */ + public int getUpgradeID(); + + /** + * Return a String to describe this type of upgrade in turtle item names. + * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty". + */ + public String getAdjective(); + + /** + * Return whether this upgrade adds a tool or a peripheral to the turtle. + * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. + * @see TurtleUpgradeType for the differences between the two. + */ + public TurtleUpgradeType getType(); + + /** + * Return an item stack representing the type of item that a turtle must be crafted + * with to create a turtle which holds this upgrade. + * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. + */ + public net.minecraft.item.ItemStack getCraftingItem(); + + /** + * Return whether this turtle upgrade is an easter egg, and should be attempted to be hidden + * from the creative mode inventory and recipe book plugins. + */ + public boolean isSecret(); + + /** + * Will only be called for Peripheral upgrades. Creates a peripheral for a turtle + * being placed using this upgrade. The peripheral created will be stored + * for the lifetime of the turtle, will have update() called once-per-tick, and will be + * attach'd detach'd and have methods called in the same manner as a Computer peripheral. + * @param turtle Access to the turtle that the peripheral is being created for. + * @param side Which side of the turtle (left or right) that the upgrade resides on. + * @returns The newly created peripheral. You may return null if this upgrade is a Tool + * and this method is not expected to be called. + */ + public IHostedPeripheral createPeripheral( ITurtleAccess turtle, TurtleSide side ); + + /** + * Will only be called for Tool upgrades. Called when turtle.dig() or turtle.attack() is called + * by the turtle, and the tool is required to do some work. + * @param turtle Access to the turtle that the tool resides on. + * @param side Which side of the turtle (left or right) the tool resides on. + * @param verb Which action (dig or attack) the turtle is being called on to perform. + * @param direction Which world direction the action should be performed in, relative to the turtles + * position. This will either be up, down, or the direction the turtle is facing, depending on + * whether dig, digUp or digDown was called. + * @return Whether the turtle was able to perform the action, and hence whether the turtle.dig() + * or turtle.attack() lua method should return true. If true is returned, the tool will perform + * a swinging animation. You may return false if this upgrade is a Peripheral + * and this method is not expected to be called. + */ + public boolean useTool( ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, int direction ); + + /** + * Called to obtain the Icon to be used when rendering a turtle peripheral. Needs to be a "block" + * type Icon for now, as there is no way to determine which texture sheet an Icon is from by the + * Icon itself. + * @param turtle Access to the turtle that the peripheral resides on. + * @param side Which side of the turtle (left or right) the peripheral resides on. + * @return The Icon that you wish to be used to render your turtle peripheral. + */ + public Icon getIcon( ITurtleAccess turtle, TurtleSide side ); +} diff --git a/src/APIs/dan200/turtle/api/TurtleAPI.java b/src/APIs/dan200/turtle/api/TurtleAPI.java new file mode 100644 index 00000000..3e3c5c1f --- /dev/null +++ b/src/APIs/dan200/turtle/api/TurtleAPI.java @@ -0,0 +1,78 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.turtle.api; +import java.lang.reflect.Method; + +/** + * The static entry point to the ComputerCraft Turtle Upgrade API. + * Members in this class must be called after mod_CCTurtle has been initialised, + * but may be called before it is fully loaded. + */ +public class TurtleAPI +{ + /** + * Registers a new turtle upgrade for use in ComputerCraft. After calling this, + * users should be able to craft Turtles with your new upgrade. It is recommended to call + * this during the load() method of your mod. + * @throws Exception if you try to register an upgrade with an already used or reserved upgradeID + * @see ITurtleUpgrade + */ + public static void registerUpgrade( ITurtleUpgrade upgrade ) + { + if( upgrade != null ) + { + findCCTurtle(); + if( ccTurtle_registerTurtleUpgrade != null ) + { + try { + ccTurtle_registerTurtleUpgrade.invoke( null, new Object[]{ upgrade } ); + } catch( Exception e ) { + // It failed + } + } + } + } + + // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. + // Reflection is used here so you can develop your mod in MCP without decompiling ComputerCraft and including + // it in your solution. + + private static void findCCTurtle() + { + if( !ccTurtleSearched ) { + // Search for CCTurtle + try { + ccTurtle = Class.forName( "dan200.CCTurtle" ); + ccTurtle_registerTurtleUpgrade = findCCTurtleMethod( "registerTurtleUpgrade", new Class[] { + ITurtleUpgrade.class + } ); + + } catch( ClassNotFoundException e ) { + System.out.println("ComputerCraftAPI: CCTurtle not found."); + + } finally { + ccTurtleSearched = true; + + } + } + } + + private static Method findCCTurtleMethod( String name, Class[] args ) + { + try { + return ccTurtle.getMethod( name, args ); + + } catch( NoSuchMethodException e ) { + System.out.println("ComputerCraftAPI: CCTurtle method " + name + " not found."); + return null; + } + } + + private static boolean ccTurtleSearched = false; + private static Class ccTurtle = null; + private static Method ccTurtle_registerTurtleUpgrade = null; +} diff --git a/src/APIs/dan200/turtle/api/TurtleSide.java b/src/APIs/dan200/turtle/api/TurtleSide.java new file mode 100644 index 00000000..3459d777 --- /dev/null +++ b/src/APIs/dan200/turtle/api/TurtleSide.java @@ -0,0 +1,23 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.turtle.api; + +/** + * An enum representing the two sides of the turtle that a turtle upgrade might reside. + */ +public enum TurtleSide +{ + /** + * The turtles left side (where the pickaxe usually is on a Wireless Mining Turtle) + */ + Left, + + /** + * The turtles right side (where the modem usually is on a Wireless Mining Turtle) + */ + Right, +} diff --git a/src/APIs/dan200/turtle/api/TurtleUpgradeType.java b/src/APIs/dan200/turtle/api/TurtleUpgradeType.java new file mode 100644 index 00000000..a65fed8a --- /dev/null +++ b/src/APIs/dan200/turtle/api/TurtleUpgradeType.java @@ -0,0 +1,27 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.turtle.api; + +/** + * An enum representing the two different types of upgrades that an ITurtleUpgrade + * implementation can add to a turtle. + * @see ITurtleUpgrade + */ +public enum TurtleUpgradeType +{ + /** + * A tool is rendered as an item on the side of the turtle, and responds to the turtle.dig() + * and turtle.attack() methods (Such as pickaxe or sword on Mining and Melee turtles). + */ + Tool, + + /** + * A peripheral adds a special peripheral which is attached to the side of the turtle, + * and can be interacted with the peripheral API (Such as the modem on Wireless Turtles). + */ + Peripheral, +} diff --git a/src/APIs/dan200/turtle/api/TurtleVerb.java b/src/APIs/dan200/turtle/api/TurtleVerb.java new file mode 100644 index 00000000..a1b2531a --- /dev/null +++ b/src/APIs/dan200/turtle/api/TurtleVerb.java @@ -0,0 +1,26 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2013. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.turtle.api; + +/** + * An enum representing the two different actions that an ITurtleUpgrade of type + * Tool may be called on to perform by a turtle. + * @see ITurtleUpgrade + * @see ITurtleUpgrade#useTool + */ +public enum TurtleVerb +{ + /** + * The turtle called turtle.dig(), turtle.digUp() or turtle.digDown() + */ + Dig, + + /** + * The turtle called turtle.attack(), turtle.attackUp() or turtle.attackDown() + */ + Attack, +} diff --git a/src/APIs/ic2/api/Direction.java b/src/APIs/ic2/api/Direction.java new file mode 100644 index 00000000..71975b32 --- /dev/null +++ b/src/APIs/ic2/api/Direction.java @@ -0,0 +1,119 @@ +package ic2.api; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; + +/** + * Represents the 6 possible directions along the axis of a block. + */ +public enum Direction +{ + /** + * -X + */ + XN(0), + /** + * +X + */ + XP(1), + + /** + * -Y + */ + YN(2), // MC-Code starts with 0 here + /** + * +Y + */ + YP(3), // 1... + + /** + * -Z + */ + ZN(4), + /** + * +Z + */ + ZP(5); + + Direction(int dir) + { + this.dir = dir; + } + + /* + * public CoordinateTuple ApplyToCoordinates(CoordinateTuple coordinates) { CoordinateTuple ret + * = new CoordinateTuple(coordinates); + * + * ret.coords[dir/2] += GetSign(); + * + * return ret; } + */ + + /** + * Get the tile entity next to a tile entity following this direction. + * + * @param tileEntity tile entity to check + * @return Adjacent tile entity or null if none exists + */ + public TileEntity applyToTileEntity(TileEntity tileEntity) + { + int coords[] = { tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord }; + + coords[dir / 2] += getSign(); + + if (tileEntity.worldObj != null && tileEntity.worldObj.blockExists(coords[0], coords[1], coords[2])) + { + return tileEntity.worldObj.getBlockTileEntity(coords[0], coords[1], coords[2]); + } + else + { + return null; + } + } + + /** + * Get the inverse of this direction (XN -> XP, XP -> XN, etc.) + * + * @return Inverse direction + */ + public Direction getInverse() + { + int inverseDir = dir - getSign(); + + for (Direction direction : directions) + { + if (direction.dir == inverseDir) + return direction; + } + + return this; + } + + /** + * Convert this direction to a Minecraft side value. + * + * @return Minecraft side value + */ + public int toSideValue() + { + return (dir + 4) % 6; + } + + /** + * Determine direction sign (N for negative or P for positive). + * + * @return -1 if the direction is negative, +1 if the direction is positive + */ + private int getSign() + { + return (dir % 2) * 2 - 1; + } + + public ForgeDirection toForgeDirection() + { + return ForgeDirection.getOrientation(toSideValue()); + } + + private int dir; + public static final Direction[] directions = Direction.values(); +} diff --git a/src/APIs/ic2/api/energy/event/EnergyTileEvent.java b/src/APIs/ic2/api/energy/event/EnergyTileEvent.java new file mode 100644 index 00000000..43147f99 --- /dev/null +++ b/src/APIs/ic2/api/energy/event/EnergyTileEvent.java @@ -0,0 +1,17 @@ +package ic2.api.energy.event; + +import ic2.api.energy.tile.IEnergyTile; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.event.world.WorldEvent; + +public class EnergyTileEvent extends WorldEvent +{ + public final IEnergyTile energyTile; + + public EnergyTileEvent(IEnergyTile energyTile) + { + super(((TileEntity) energyTile).worldObj); + + this.energyTile = energyTile; + } +} diff --git a/src/APIs/ic2/api/energy/event/EnergyTileLoadEvent.java b/src/APIs/ic2/api/energy/event/EnergyTileLoadEvent.java new file mode 100644 index 00000000..09e0a19f --- /dev/null +++ b/src/APIs/ic2/api/energy/event/EnergyTileLoadEvent.java @@ -0,0 +1,23 @@ +package ic2.api.energy.event; + +import ic2.api.energy.tile.IEnergyTile; + +/** + * Event announcing new energy tiles. + * + * This event notifies subscribers of loaded energy tiles, e.g. after getting loaded through the + * chunk they are in or after being placed down by the player or another deployer mechanism. + * + * Every energy tile which wants to get connected to the IC2 Energy Network has to either post this + * event or alternatively call EnergyNet.addTileEntity(). + * + * You may use this event to build a static representation of energy tiles for your own energy grid + * implementation if you need to. It's not required if you always lookup energy paths on demand. + */ +public class EnergyTileLoadEvent extends EnergyTileEvent +{ + public EnergyTileLoadEvent(IEnergyTile energyTile) + { + super(energyTile); + } +} diff --git a/src/APIs/ic2/api/energy/event/EnergyTileSourceEvent.java b/src/APIs/ic2/api/energy/event/EnergyTileSourceEvent.java new file mode 100644 index 00000000..f2dd8158 --- /dev/null +++ b/src/APIs/ic2/api/energy/event/EnergyTileSourceEvent.java @@ -0,0 +1,32 @@ +package ic2.api.energy.event; + +import ic2.api.energy.tile.IEnergySource; + +/** + * Event announcing an energy source operation. + * + * This event notifies subscribers of energy sources trying to push energy into an energy grid. + * + * The amount field indicates the maximum amount of energy left to be distributed. You have to + * substract the amount of energy you accepted from 'amount'. + * + * The IEnergySource posting this event has to check 'amount' to see how much energy has not been + * used up and adjust its output buffer accordingly (usually buffer -= 'initial amount' - 'amount + * after posting the event') + */ +public class EnergyTileSourceEvent extends EnergyTileEvent +{ + /** + * Amount of energy provided by the energy source. + * + * amount needs to be adjusted to show the remaining unused energy. + */ + public int amount; + + public EnergyTileSourceEvent(IEnergySource energySource, int amount) + { + super(energySource); + + this.amount = amount; + } +} diff --git a/src/APIs/ic2/api/energy/event/EnergyTileUnloadEvent.java b/src/APIs/ic2/api/energy/event/EnergyTileUnloadEvent.java new file mode 100644 index 00000000..9378080d --- /dev/null +++ b/src/APIs/ic2/api/energy/event/EnergyTileUnloadEvent.java @@ -0,0 +1,24 @@ +package ic2.api.energy.event; + +import ic2.api.energy.tile.IEnergyTile; + +/** + * Event announcing terminated energy tiles. + * + * This event notifies subscribers of unloaded energy tiles, e.g. after getting unloaded through the + * chunk they are in or after being destroyed by the player or another block pick/destruction + * mechanism. + * + * Every energy tile which wants to get disconnected from the IC2 Energy Network has to either post + * this event or alternatively call EnergyNet.removeTileEntity(). + * + * You may use this event to build a static representation of energy tiles for your own energy grid + * implementation if you need to. It's not required if you always lookup energy paths on demand. + */ +public class EnergyTileUnloadEvent extends EnergyTileEvent +{ + public EnergyTileUnloadEvent(IEnergyTile energyTile) + { + super(energyTile); + } +} diff --git a/src/APIs/ic2/api/energy/tile/IEnergyAcceptor.java b/src/APIs/ic2/api/energy/tile/IEnergyAcceptor.java new file mode 100644 index 00000000..6b011588 --- /dev/null +++ b/src/APIs/ic2/api/energy/tile/IEnergyAcceptor.java @@ -0,0 +1,21 @@ +package ic2.api.energy.tile; + +import ic2.api.Direction; +import net.minecraft.tileentity.TileEntity; + +/** + * For internal usage only. + * + * @see IEnergySink + * @see IEnergyConductor + */ +public interface IEnergyAcceptor extends IEnergyTile +{ + /** + * Determine if this acceptor can accept current from an adjacent emitter in a direction. + * + * @param emitter energy emitter + * @param direction direction the energy is being received from + */ + boolean acceptsEnergyFrom(TileEntity emitter, Direction direction); +} diff --git a/src/APIs/ic2/api/energy/tile/IEnergyConductor.java b/src/APIs/ic2/api/energy/tile/IEnergyConductor.java new file mode 100644 index 00000000..f4bcc82d --- /dev/null +++ b/src/APIs/ic2/api/energy/tile/IEnergyConductor.java @@ -0,0 +1,51 @@ +package ic2.api.energy.tile; + +/** + * Tile entities which conduct energy pulses without buffering (mostly cables) have to implement + * this interface. + */ +public interface IEnergyConductor extends IEnergyAcceptor, IEnergyEmitter +{ + /** + * Energy loss for the conductor in EU per block. + * + * @return Energy loss + */ + double getConductionLoss(); + + /** + * Amount of energy the insulation will handle before shocking nearby players and mobs. + * + * @return Insulation energy absorption in EU + */ + int getInsulationEnergyAbsorption(); + + /** + * Amount of energy the insulation will handle before it is destroyed. Ensure that this value is + * greater than the insulation energy absorption + 64. + * + * @return Insulation-destroying energy in EU + */ + int getInsulationBreakdownEnergy(); + + /** + * Amount of energy the conductor will handle before it melts. + * + * @return Conductor-destroying energy in EU + */ + int getConductorBreakdownEnergy(); + + /** + * Remove the conductor's insulation if the insulation breakdown energy was exceeded. + * + * @see #getInsulationBreakdownEnergy() + */ + void removeInsulation(); + + /** + * Remove the conductor if the conductor breakdown energy was exceeded. + * + * @see #getConductorBreakdownEnergy() + */ + void removeConductor(); +} diff --git a/src/APIs/ic2/api/energy/tile/IEnergyEmitter.java b/src/APIs/ic2/api/energy/tile/IEnergyEmitter.java new file mode 100644 index 00000000..e53e2e90 --- /dev/null +++ b/src/APIs/ic2/api/energy/tile/IEnergyEmitter.java @@ -0,0 +1,22 @@ +package ic2.api.energy.tile; + +import ic2.api.Direction; +import net.minecraft.tileentity.TileEntity; + +/** + * For internal usage only. + * + * @see IEnergySource + * @see IEnergyConductor + */ +public interface IEnergyEmitter extends IEnergyTile +{ + /** + * Determine if this emitter can emit energy to an adjacent receiver. + * + * @param receiver receiver + * @param direction direction the receiver is from the emitter + * @return Whether energy should be emitted + */ + boolean emitsEnergyTo(TileEntity receiver, Direction direction); +} diff --git a/src/APIs/ic2/api/energy/tile/IEnergySink.java b/src/APIs/ic2/api/energy/tile/IEnergySink.java new file mode 100644 index 00000000..1f95b3d1 --- /dev/null +++ b/src/APIs/ic2/api/energy/tile/IEnergySink.java @@ -0,0 +1,42 @@ +package ic2.api.energy.tile; + +import ic2.api.Direction; + +/** + * Allows a tile entity (mostly a machine) to receive energy. + */ +public interface IEnergySink extends IEnergyAcceptor +{ + /** + * Determine how much energy the sink accepts. + * + * This value is unrelated to getMaxSafeInput(). + * + * Make sure that injectEnergy() does accepts energy if demandsEnergy() returns anything > 0. + * + * @return max accepted input in eu + */ + int demandsEnergy(); + + /** + * Transfer energy to the sink. + * + * @param directionFrom direction from which the energy comes from + * @param amount energy to be transferred + * @return Energy not consumed (leftover) + */ + int injectEnergy(Direction directionFrom, int amount); + + /** + * Determine the amount of eu which can be safely injected into the specific energy sink without + * exploding. + * + * Typical values are 32 for LV, 128 for MV, 512 for HV and 2048 for EV. A value of + * Integer.MAX_VALUE indicates no limit. + * + * This value is unrelated to demandsEnergy(). + * + * @return max safe input in eu + */ + int getMaxSafeInput(); +} diff --git a/src/APIs/ic2/api/energy/tile/IEnergySource.java b/src/APIs/ic2/api/energy/tile/IEnergySource.java new file mode 100644 index 00000000..d1e8a36b --- /dev/null +++ b/src/APIs/ic2/api/energy/tile/IEnergySource.java @@ -0,0 +1,14 @@ +package ic2.api.energy.tile; + +/** + * Allows a tile entity (mostly a generator) to emit energy. + */ +public interface IEnergySource extends IEnergyEmitter +{ + /** + * Maximum energy output provided by the source. If unsure, use Integer.MAX_VALUE. + * + * @return Maximum energy output + */ + int getMaxEnergyOutput(); +} diff --git a/src/APIs/ic2/api/energy/tile/IEnergyTile.java b/src/APIs/ic2/api/energy/tile/IEnergyTile.java new file mode 100644 index 00000000..12c1e6e9 --- /dev/null +++ b/src/APIs/ic2/api/energy/tile/IEnergyTile.java @@ -0,0 +1,18 @@ +package ic2.api.energy.tile; + +/** + * For internal usage only. + * + * @see IEnergySink + * @see IEnergySource + * @see IEnergyConductor + */ +public interface IEnergyTile +{ + /** + * Determine if this tile entity has been added to the energy network + * + * @return Whether the tile entity has been added + */ + boolean isAddedToEnergyNet(); +} diff --git a/src/APIs/ic2/api/item/IElectricItem.java b/src/APIs/ic2/api/item/IElectricItem.java new file mode 100644 index 00000000..91bc1e0d --- /dev/null +++ b/src/APIs/ic2/api/item/IElectricItem.java @@ -0,0 +1,54 @@ +package ic2.api.item; + +import net.minecraft.item.ItemStack; + +/** + * Provides the ability to store energy on the implementing item. + * + * The item should have a maximum damage of 13. + */ +public interface IElectricItem +{ + /** + * Determine if the item can be used in a machine or as an armor part to supply energy. + * + * @return Whether the item can supply energy + */ + boolean canProvideEnergy(ItemStack itemStack); + + /** + * Get the item ID to use for a charge energy greater than 0. + * + * @return Item ID to use + */ + int getChargedItemId(ItemStack itemStack); + + /** + * Get the item ID to use for a charge energy of 0. + * + * @return Item ID to use + */ + int getEmptyItemId(ItemStack itemStack); + + /** + * Get the item's maximum charge energy in EU. + * + * @return Maximum charge energy + */ + int getMaxCharge(ItemStack itemStack); + + /** + * Get the item's tier, lower tiers can't send energy to higher ones. Batteries are Tier 1, + * Energy Crystals are Tier 2, Lapotron Crystals are Tier 3. + * + * @return Item's tier + */ + int getTier(ItemStack itemStack); + + /** + * Get the item's transfer limit in EU per transfer operation. + * + * @return Transfer limit + */ + int getTransferLimit(ItemStack itemStack); +} diff --git a/src/APIs/ic2/api/item/IElectricItemManager.java b/src/APIs/ic2/api/item/IElectricItemManager.java new file mode 100644 index 00000000..d8a481fb --- /dev/null +++ b/src/APIs/ic2/api/item/IElectricItemManager.java @@ -0,0 +1,94 @@ +package ic2.api.item; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; + +/** + * This interface specifies a manager to handle the various tasks for electric items. + * + * The default implementation does the following: - store and retrieve the charge - handle charging, + * taking amount, tier, transfer limit, canProvideEnergy and simulate into account - replace item + * IDs if appropriate (getChargedItemId() and getEmptyItemId()) - update and manage the damage value + * for the visual charge indicator + * + * @note If you're implementing your own variant (ISpecialElectricItem), you can delegate to the + * default implementations through ElectricItem.rawManager. The default implementation is designed + * to minimize its dependency on its own constraints/structure and delegates most work back to the + * more atomic features in the gateway manager. + */ +public interface IElectricItemManager +{ + /** + * Charge an item with a specified amount of energy + * + * @param itemStack electric item's stack + * @param amount amount of energy to charge in EU + * @param tier tier of the charging device, has to be at least as high as the item to charge + * @param ignoreTransferLimit ignore the transfer limit specified by getTransferLimit() + * @param simulate don't actually change the item, just determine the return value + * @return Energy transferred into the electric item + */ + int charge(ItemStack itemStack, int amount, int tier, boolean ignoreTransferLimit, boolean simulate); + + /** + * Discharge an item by a specified amount of energy + * + * @param itemStack electric item's stack + * @param amount amount of energy to charge in EU + * @param tier tier of the discharging device, has to be at least as high as the item to + * discharge + * @param ignoreTransferLimit ignore the transfer limit specified by getTransferLimit() + * @param simulate don't actually discharge the item, just determine the return value + * @return Energy retrieved from the electric item + */ + int discharge(ItemStack itemStack, int amount, int tier, boolean ignoreTransferLimit, boolean simulate); + + /** + * Determine the charge level for the specified item + * + * @param itemStack ItemStack containing the electric item + * @return charge level in EU + */ + int getCharge(ItemStack itemStack); + + /** + * Determine if the specified electric item has at least a specific amount of EU. This is + * supposed to be used in the item code during operation, for example if you want to implement + * your own electric item. BatPacks are not taken into account. + * + * @param itemStack electric item's stack + * @param amount minimum amount of energy required + * @return true if there's enough energy + */ + boolean canUse(ItemStack itemStack, int amount); + + /** + * Try to retrieve a specific amount of energy from an Item, and if applicable, a BatPack. This + * is supposed to be used in the item code during operation, for example if you want to + * implement your own electric item. + * + * @param itemStack electric item's stack + * @param amount amount of energy to discharge in EU + * @param entity entity holding the item + * @return true if the operation succeeded + */ + boolean use(ItemStack itemStack, int amount, EntityLivingBase entity); + + /** + * Charge an item from the BatPack a player is wearing. This is supposed to be used in the item + * code during operation, for example if you want to implement your own electric item. use() + * already contains this functionality. + * + * @param itemStack electric item's stack + * @param entity entity holding the item + */ + void chargeFromArmor(ItemStack itemStack, EntityLivingBase entity); + + /** + * Get the tool tip to display for electric items. + * + * @param itemStack ItemStack to determine the tooltip for + * @return tool tip string or null for none + */ + String getToolTip(ItemStack itemStack); +} diff --git a/src/APIs/ic2/api/item/ISpecialElectricItem.java b/src/APIs/ic2/api/item/ISpecialElectricItem.java new file mode 100644 index 00000000..b73cf1dd --- /dev/null +++ b/src/APIs/ic2/api/item/ISpecialElectricItem.java @@ -0,0 +1,14 @@ +package ic2.api.item; + +import net.minecraft.item.ItemStack; + +public interface ISpecialElectricItem extends IElectricItem +{ + /** + * Supply a custom IElectricItemManager. + * + * @param itemStack ItemStack to get the manager for + * @return IElectricItemManager instance + */ + IElectricItemManager getManager(ItemStack itemStack); +} diff --git a/src/APIs/ic2/api/item/Items.java b/src/APIs/ic2/api/item/Items.java new file mode 100644 index 00000000..bd353561 --- /dev/null +++ b/src/APIs/ic2/api/item/Items.java @@ -0,0 +1,362 @@ +package ic2.api.item; + +import net.minecraft.item.ItemStack; + +/** + * Provides access to IC2 blocks and items. + * + * Some items can be acquired through the ore dictionary which is the recommended way. The items are + * initialized while IC2 is being loaded - try to use ModsLoaded() or load your mod after IC2. Some + * blocks/items can be disabled by a config setting, so it's recommended to check if they're null + * first. + * + * Getting the associated Block/Item for an ItemStack x: Blocks: Block.blocksList[x.itemID] Items: + * x.getItem() + */ +public final class Items +{ + /** + * Get an ItemStack for a specific item name, example: Items.getItem("resin") See the list below + * for item names. Make sure to copy() the ItemStack if you want to modify it. + * + * @param name item name + * @return The item or null if the item does not exist or an error occurred + */ + public static ItemStack getItem(String name) + { + try + { + if (Ic2Items == null) + Ic2Items = Class.forName(getPackage() + ".core.Ic2Items"); + + Object ret = Ic2Items.getField(name).get(null); + + if (ret instanceof ItemStack) + { + return (ItemStack) ret; + } + else + { + return null; + } + } + catch (Exception e) + { + System.out.println("IC2 API: Call getItem failed for " + name); + + return null; + } + } + + /* + * Possible values: + * + * ----- blocks ----- + * + * ores copperOre Copper Ore block, currently not meta sensitive, meta in ItemStack set to 0, + * ore dictionary: oreCopper, null with enableWorldGenOreCopper=false tinOre Tin Ore block, + * currently not meta sensitive, meta in ItemStack set to 0, ore dictionary: oreTin, null with + * enableWorldGenOreTin=false uraniumOre Tin Ore block, currently not meta sensitive, meta in + * ItemStack set to 0, ore dictionary: oreUranium, null with enableWorldGenOreUranium=false + * + * rubber related Rubber wood block, meta reflects the state, meta in ItemStack set to 0, ore + * dictionary: woodRubber (with meta 0), null with enableWorldGenTreeRubber=false dropped (as an + * item) -> metadata 0 block, no resin spot -> metadata 0 or 1 block, wet resin spot -> metadata + * 2-5 (according to the side) block, dry resin spot -> metadata 8-11 (wet state + 6) + * + * rubberWood rubberLeaves Rubber Leaves block, currently not meta sensitive, meta in ItemStack + * set to 0, null with enableWorldGenTreeRubber=false rubberSapling Rubber Sapling block, + * currently not meta sensitive, meta in ItemStack set to 0, null with + * enableWorldGenTreeRubber=false resinSheet Resin Sheet block, currently not meta sensitive + * rubberTrampoline Rubber Trampoline block, meta reflects internal state, meta in ItemStack set + * to 0 + * + * building/storage ironFence Iron Fence block, currently not meta sensitive + * + * reinforcedStone Reinforced Stone block, currently not meta sensitive reinforcedGlass + * Reinforced Glass block, currently not meta sensitive reinforcedDoorBlock Reinforced Door + * block, meta reflects the state (see vanilla doors), meta in ItemStack set to 0 + * + * constructionFoam Construction Foam block, currently not meta sensitive constructionFoamWall + * Construction Foam Wall block, meta = color, implements IPaintableBlock scaffold Scaffold + * block, meta reflects internal physical model data + * + * bronzeBlock Bronze block, meta sensitive copperBlock Copper block, meta sensitive tinBlock + * Tin block, meta sensitive uraniumBlock Uranium block, meta sensitive + * + * cables (when placed as a block, inventory items are different TE implements IEnergyConductor) + * copperCableBlock Copper Cable block, meta sensitive insulatedCopperCableBlock Insulated + * Copper Cable block, meta sensitive + * + * goldCableBlock Gold Cable block, meta sensitive insulatedGoldCableBlock Insulated Gold Cable + * block, meta sensitive doubleInsulatedGoldCableBlock Double Insulated Gold Cable block, meta + * sensitive + * + * ironCableBlock Iron Cable block, meta sensitive insulatedIronCableBlock Insulated Iron Cable + * block, meta sensitive doubleInsulatedIronCableBlock Double Insulated Iron Cable block, meta + * sensitive trippleInsulatedIronCableBlock Tripple Insulated Iron Cable block, meta sensitive + * + * glassFiberCableBlock Glass Fiber Cable block, meta sensitive + * + * tinCableBlock Tin Cable block, meta sensitive + * + * detectorCableBlock Detector Cable block, meta sensitive splitterCableBlock Splitter Cable + * block, meta sensitive + * + * generators + related (TE implements IEnergySource ex. reactorChamber) generator Generator + * block, meta sensitive geothermalGenerator Geothermal Generator block, meta sensitive + * waterMill Water Mill block, meta sensitive solarPanel Solar Panel block, meta sensitive + * windMill Wind Mill block, meta sensitive nuclearReactor Nuclear Reactor block, meta sensitive + * reactorChamber Reactor Chamber block, currently not meta sensitive + * + * energy storages (TE implements IEnergySource and IEnergyConductor) batBox BatBox block, meta + * sensitive mfeUnit MFE Unit block, meta sensitive mfsUnit MFS Unit block, meta sensitive + * + * transformers (TE implements IEnergySource and IEnergyConductor) lvTransformer LV Transformer + * block, meta sensitive mvTransformer MV Transformer block, meta sensitive hvTransformer HV + * Transformer block, meta sensitive + * + * machines + related (TE implements IEnergySink ex. machine, miningPipe, miningPipeTip) machine + * Machine block, meta sensitive advancedMachine Advanced Machine block, meta sensitive + * + * ironFurnace Iron Furnace block, meta sensitive electroFurnace Electro Furnace block, meta + * sensitive macerator Macerator block, meta sensitive extractor Extractor block, meta sensitive + * compressor Compressor block, meta sensitive canner Canner block, meta sensitive miner Miner + * block, meta sensitive pump Pump block, meta sensitive magnetizer Magnetizer block, meta + * sensitive electrolyzer Electrolyzer block, meta sensitive recycler Recycler block, meta + * sensitive inductionFurnace Induction Furnace block, meta sensitive massFabricator Mass + * Fabricator block, meta sensitive terraformer Terraformer block, meta sensitive teleporter + * Teleporter block, meta sensitive teslaCoil Tesla Coil block, meta sensitive luminator Passive + * (dark) Luminator block, meta = facing activeLuminator Active (bright) Luminator block, meta = + * facing + * + * miningPipe Mining Pipe block, currently not meta sensitive, meta in ItemStack set to 0 + * miningPipeTip Mining Pipe Tip block, currently not meta sensitive, meta in ItemStack set to 0 + * + * personal blocks personalSafe Personal Safe block, meta sensitive tradeOMat Trade-O-Mat block, + * meta sensitive energyOMat Energy-O-Mat block, meta sensitive + * + * explosives industrialTnt Industrial TNT block, currently not meta sensitive nuke Nuke block, + * currently not meta sensitive dynamiteStick Dynamite Stick block, meta = placement, meta in + * ItemStack set to 0 dynamiteStickWithRemote Dynamite Stick with Remote block, meta = + * placement, meta in ItemStack set to 0 + * + * Agriculture Stuff crop Crop Block, empty, not meta sensitive + * + * + * ----- items ----- + * + * rubber + related resin Resin item, currently not meta sensitive rubber Rubber item, currently + * not meta sensitive, ore dictionary: itemRubber + * + * ore drops uraniumDrop Uranium Drop item, currently not meta sensitive, ore dictionary: + * itemDropUranium + * + * dusts bronzeDust Bronze Dust item, currently not meta sensitive clayDust Clay Dust item, + * currently not meta sensitive coalDust Coal Dust item, currently not meta sensitive copperDust + * Copper Dust item, currently not meta sensitive goldDust Gold Dust item, currently not meta + * sensitive ironDust Iron Dust item, currently not meta sensitive silverDust Silver Dust item, + * currently not meta sensitive smallIronDust Small Iron Dust item, currently not meta sensitive + * tinDust Tin Dust item, currently not meta sensitive hydratedCoalDust Hydrated Coal Dust item, + * currently not meta sensitive + * + * ingots refinedIronIngot Refined Iron Ingot item, currently not meta sensitive, ore + * dictionary: ingotRefinedIron copperIngot Copper Ingot item, currently not meta sensitive, ore + * dictionary: ingotCopper tinIngot Tin Ingot item, currently not meta sensitive, ore + * dictionary: ingotTin bronzeIngot Bronze Ingot item, currently not meta sensitive, ore + * dictionary: ingotBronze mixedMetalIngot Mixed Metal Ingot item, currently not meta sensitive + * uraniumIngot Uranium Ingot item, currently not meta sensitive, ore dictionary: ingotUranium + * + * tools/weapons (without electric tools) treetap Treetap item, meta = damage value wrench + * Wrench item, meta = damage value cutter Insulation Cutter item, meta = damage value + * constructionFoamSprayer Construction Foam Sprayer item, meta = charges (as of v1.45) + * + * bronzePickaxe Bronze Pickaxe item, meta = damage value bronzeAxe Bronze Axe item, meta = + * damage value bronzeSword Bronze Sword item, meta = damage value bronzeShovel Bronze Shovel + * item, meta = damage value bronzeHoe Bronze Hoe item, meta = damage value + * + * el. tools/devices/weapons miningDrill Mining Drill item, meta = visual charge indicator, + * implements IElectricItem diamondDrill Diamond Tipped Mining Drill item, meta = visual charge + * indicator, implements IElectricItem chainsaw Chainsaw item, meta = visual charge indicator, + * implements IElectricItem electricWrench Electric Wrench item, meta = visual charge indicator, + * implements IElectricItem electricTreetap Electric Treetap item, meta = visual charge + * indicator, implements IElectricItem miningLaser Mining Laser item, meta = visual charge + * indicator, implements IElectricItem + * + * ecMeter EC-Mater item, currently not meta sensitive odScanner Ore Density Scanner item, meta + * = damage value for charge level, implements IElectricItem ovScanner Ore Value Scanner item, + * meta = visual charge indicator, implements IElectricItem + * + * frequencyTransmitter Frequency Transmitter item, currently not meta sensitive + * + * nanoSaber Idle Nano Saber item, meta = visual charge indicator, implements IElectricItem + * enabledNanoSaber Enabled Nano Saber item, meta = visual charge indicator, implements + * IElectricItem + * + * armor/wearable rubberBoots Rubber Boots item, meta = damage value + * + * bronzeHelmet Bronze Helmet Armor item, meta = damage value bronzeChestplate Bronze Chestplate + * Armor item, meta = damage value bronzeLeggings Bronze Leggings Armor item, meta = damage + * value bronzeBoots Bronze Boots Armor item, meta = damage value + * + * compositeArmor Composite Armor item, meta = damage value for charge level + * + * nanoHelmet Nano Helmet Armor item, meta = visual charge indicator, implements IElectricItem + * nanoBodyarmor Nano Bodyarmor item, meta = visual charge indicator, implements IElectricItem + * nanoLeggings Nano Leggings Armor item, meta = visual charge indicator, implements + * IElectricItem nanoBoots Nano Boots Armor item, meta = visual charge indicator, implements + * IElectricItem + * + * quantumHelmet Quantum Helmet Armor item, meta = visual charge indicator, implements + * IElectricItem quantumBodyarmor Quantum Bodyarmor item, meta = visual charge indicator, + * implements IElectricItem quantumLeggings Quantum Leggings Armor item, meta = visual charge + * indicator, implements IElectricItem quantumBoots Quantum Boots Armor item, meta = visual + * charge indicator, implements IElectricItem + * + * jetpack Jetpack item, meta = damage value for fuel level electricJetpack Electric Jetpack + * item, meta = visual charge indicator, implements IElectricItem + * + * batPack BatPack item, meta = visual charge indicator, implements IElectricItem, can provide + * energy lapPack LapPack item, meta = visual charge indicator, implements IElectricItem, can + * provide energy + * + * cfPack CF Pack item, meta = charges (as of v1.45) + * + * solarHelmet Solar Helmet item, currently not meta sensitive staticBoots Static Boots item, + * currently not meta sensitive + * + * batteries reBattery Empty RE Battery item, currently not meta sensitive, implements + * IElectricItem chargedReBattery RE Battery item, meta = visual charge indicator, implements + * IElectricItem, can provide energy energyCrystal Energy Crystal item, meta = visual charge + * indicator, implements IElectricItem, can provide energy lapotronCrystal Lapotron Crystal + * item, meta = visual charge indicator, implements IElectricItem, can provide energy suBattery + * SU Battery item, currently not meta sensitive + * + * cables copperCableItem Copper Cable item, meta sensitive insulatedCopperCableItem Insulated + * Copper Cable item, meta sensitive + * + * goldCableItem Gold Cable item, meta sensitive insulatedGoldCableItem Insulated Gold Cable + * item, meta sensitive doubleInsulatedGoldCableItem Double Insulated Gold Cable item, meta + * sensitive + * + * ironCableItem Iron Cable item, meta sensitive insulatedIronCableItem Insulated Iron Cable + * item, meta sensitive doubleInsulatedIronCableItem Double Insulated Iron Cable item, meta + * sensitive trippleInsulatedIronCableItem Tripple Insulated Iron Cable item, meta sensitive + * + * glassFiberCableItem Glass Fiber Cable item, meta sensitive + * + * tinCableItem Tin Cable item, meta sensitive + * + * detectorCableItem Detector Cable item, meta sensitive splitterCableItem Splitter Cable item, + * meta sensitive + * + * cells/containers (without reactor components) cell Empty Cell item, currently not meta + * sensitive lavaCell Lava Cell item, currently not meta sensitive hydratedCoalCell Hydrated + * Coal Cell item, currently not meta sensitive bioCell Bio Cell item, currently not meta + * sensitive coalfuelCell Coalfuel Cell item, currently not meta sensitive biofuelCell Biofuel + * Cell item, currently not meta sensitive waterCell Water Cell item, currently not meta + * sensitive electrolyzedWaterCell Electrolyzed Water Cell item, currently not meta sensitive + * + * fuelCan Empty Fuel Can item, currently not meta sensitive filledFuelCan Fuel Can item, meta = + * fuel value (as of v1.45) + * + * tinCan Empty Tin Can item, currently not meta sensitive filledTinCan Filled Tin Can item, + * currently not meta sensitive + * + * reactor components uraniumCell Uranium Cell item, meta = damage value coolingCell Cooling + * Cell item, meta = damage value + * + * depletedIsotopeCell Depleted Isotope Cell item, meta = damage value reEnrichedUraniumCell + * Re-Enriched Uranium Cell item, currently not meta sensitive nearDepletedUraniumCell + * Near-Depleted Uranium Cell item, currently not meta sensitive + * + * integratedReactorPlating Integrated Reactor Plating item, meta = damage value + * integratedHeatDisperser Integrated Heat Disperser item, meta = damage value + * + * terraformer blueprints terraformerBlueprint Empty Terraformer Blueprint item, currently not + * meta sensitive cultivationTerraformerBlueprint Cultivation Terraformer Blueprint item, + * currently not meta sensitive irrigationTerraformerBlueprint Irrigation Terraformer Blueprint + * item, currently not meta sensitive chillingTerraformerBlueprint Chilling Terraformer + * Blueprint item, currently not meta sensitive desertificationTerraformerBlueprint + * Desertification Terraformer Blueprint item, currently not meta sensitive + * flatificatorTerraformerBlueprint Flatificator Terraformer Blueprint item, currently not meta + * sensitive mushroomTerraformerBlueprint Mushroom Terraformer Blueprint item, currently not + * meta sensitive + * + * diamond chain coalBall Coal Ball item, currently not meta sensitive compressedCoalBall + * Compressed Coal Ball item, currently not meta sensitive coalChunk Coal Chunk item, currently + * not meta sensitive industrialDiamond Industrial Diamond item, currently not meta sensitive, + * DEPRECATED + * + * recycler chain scrap Scrap item, currently not meta sensitive scrapBox Scrap Box item, + * currently not meta sensitive + * + * fuel production chain hydratedCoalClump Hydrated Coal Clump item, currently not meta + * sensitive plantBall Plant Ball item, currently not meta sensitive compressedPlantBall + * Compressed Plant Ball item, currently not meta sensitive + * + * painting painter Painter item, currently not meta sensitive + * + * blackPainter Black Painter item, meta = damage value redPainter Red Painter item, meta = + * damage value greenPainter Green Painter item, meta = damage value brownPainter Brown Painter + * item, meta = damage value bluePainter Blue Painter item, meta = damage value purplePainter + * Purple Painter item, meta = damage value cyanPainter Cyan Painter item, meta = damage value + * lightGreyPainter Light Grey Painter item, meta = damage value darkGreyPainter Dark Grey + * Painter item, meta = damage value pinkPainter Pink Painter item, meta = damage value + * limePainter Lime Painter item, meta = damage value yellowPainter Yellow Painter item, meta = + * damage value cloudPainter Cloud Painter item, meta = damage value magentaPainter Magenta + * Painter item, meta = damage value orangePainter Orange Painter item, meta = damage value + * whitePainter White Painter item, meta = damage value + * + * explosives + related dynamite Throwable Dynamite item, currently not meta sensitive + * stickyDynamite Throwable Sticky Dynamite item, currently not meta sensitive + * + * remote Dynamite Remote item, currently not meta sensitive + * + * misc intermediate recipe ingredients electronicCircuit Electronic Circuit item, currently not + * meta sensitive advancedCircuit Advanced Circuit item, currently not meta sensitive + * + * advancedAlloy Advanced Alloy item, currently not meta sensitive + * + * carbonFiber Raw Carbon Fiber item, currently not meta sensitive carbonMesh Raw Carbon Mesh + * item, currently not meta sensitive carbonPlate Carbon Plate item, currently not meta + * sensitive + * + * matter UU-Matter item, currently not meta sensitive iridiumOre Iridium Ore item, currently + * not meta sensitive iridiumPlate Iridium Plate item, currently not meta sensitive + * + * upgrade modules overclockerUpgrade overclocker upgrade item, meta sensitive + * transformerUpgrade transformer upgrade item, meta sensitive energyStorageUpgrade energy + * storage upgrade item, meta sensitive + * + * misc coin Coin item, currently not meta sensitive reinforcedDoor Reinforced Door item, + * currently not meta sensitive constructionFoamPellet Construction Foam Pellet item, currently + * not meta sensitive cropSeed Crop seeds, stuff stored in NBT, don't use for crafting recipes! + * cropnalyzer Cropnalyzer handheld device fertilizer Basic IC2Item, used to provide nutrients + * toCropBlocks hydratingCell Cell used to hydrate Crops, meta = Content, 0 = Full, 9999 = Near + * empty electricHoe Electric Hoe, meta = charge level solarHelmet Solar Helmet item, currently + * not meta sensitive terraWart Terra Wart item, cures potion effects weedEx Weed-EX can, meta = + * uses left + */ + + /** + * Get the base IC2 package name, used internally. + * + * @return IC2 package name, if unable to be determined defaults to ic2 + */ + private static String getPackage() + { + Package pkg = Items.class.getPackage(); + + if (pkg != null) + { + String packageName = pkg.getName(); + + return packageName.substring(0, packageName.length() - ".api.item".length()); + } + + return "ic2"; + } + + private static Class Ic2Items; +} diff --git a/src/APIs/icbm/api/IBlockFrequency.java b/src/APIs/icbm/api/IBlockFrequency.java new file mode 100644 index 00000000..a92ce6d0 --- /dev/null +++ b/src/APIs/icbm/api/IBlockFrequency.java @@ -0,0 +1,26 @@ +package icbm.api; + +/** + * Applied to all blocks that has a frequency. + * + * @author Calclavia + */ + +public interface IBlockFrequency { + /** + * @param data + * - Pass an ItemStack if dealing with items with frequencies. + * @return The frequency of this object. + */ + public int getFrequency(); + + /** + * Sets the frequency + * + * @param frequency + * - The frequency of this object. + * @param data + * - Pass an ItemStack if dealing with items with frequencies. + */ + public void setFrequency(int frequency); +} diff --git a/src/APIs/icbm/api/ICBM.java b/src/APIs/icbm/api/ICBM.java new file mode 100644 index 00000000..3ab3736c --- /dev/null +++ b/src/APIs/icbm/api/ICBM.java @@ -0,0 +1,60 @@ +package icbm.api; + +import icbm.api.explosion.IExplosive; + +import java.lang.reflect.Method; + +/** + * General ICBM references. + * + * @author Calclavia + * + */ +public class ICBM { + /** + * Name of the channel and mod ID. + */ + public static final String NAME = "ICBM"; + + /** + * The version of ICBM. + */ + public static final String MAJOR_VERSION = "@MAJOR@"; + public static final String MINOR_VERSION = "@MINOR@"; + public static final String REVISION_VERSION = "@REVIS@"; + public static final String BUILD_VERSION = "@BUILD@"; + public static final String VERSION = MAJOR_VERSION + "." + MINOR_VERSION + + "." + REVISION_VERSION; + + /** + * The block ID in which ICBM starts with. ICBM Explosion will count up, + * ICBM Contraption will count down. + */ + public static final int BLOCK_ID_PREFIX = 3880; + + /** + * The item ID in which ICBM starts with. + */ + public static final int ITEM_ID_PREFIX = 3900; + + public static Class explosionManager; + + /** + * @return Gets an explosive object based on the name of the explosive. + */ + public static IExplosive getExplosive(String name) { + if (name != null) { + try { + Method method = explosionManager.getMethod("get", String.class); + return (IExplosive) method.invoke(null, name); + } catch (Exception e) { + System.out + .println("ICBM: Failed to get explosive with the name: " + + name); + e.printStackTrace(); + } + } + + return null; + } +} diff --git a/src/APIs/icbm/api/ICamouflageMaterial.java b/src/APIs/icbm/api/ICamouflageMaterial.java new file mode 100644 index 00000000..6683c8fc --- /dev/null +++ b/src/APIs/icbm/api/ICamouflageMaterial.java @@ -0,0 +1,13 @@ +package icbm.api; + +/** + * Applied to all blocks that can be used as a camouflage for the camouflage + * block. Use this interface if your block is not a normal block but yet would + * like it to be used as a camouflage material. + * + * @author Calclavia + * + */ +public interface ICamouflageMaterial { + +} diff --git a/src/APIs/icbm/api/IHackable.java b/src/APIs/icbm/api/IHackable.java new file mode 100644 index 00000000..6ce1ed78 --- /dev/null +++ b/src/APIs/icbm/api/IHackable.java @@ -0,0 +1,15 @@ +package icbm.api; + +import net.minecraft.entity.player.EntityPlayer; + +public interface IHackable { + /** + * Causes the machine to generate a new pass key + */ + public void generateNewKey(); + + /** + * Checks to see if the pass key matches the stored one + */ + public boolean tryForAccess(EntityPlayer player, String pass); +} diff --git a/src/APIs/icbm/api/IItemFrequency.java b/src/APIs/icbm/api/IItemFrequency.java new file mode 100644 index 00000000..bdc2917e --- /dev/null +++ b/src/APIs/icbm/api/IItemFrequency.java @@ -0,0 +1,28 @@ +package icbm.api; + +import net.minecraft.item.ItemStack; + +/** + * Applied to all items that has a frequency. + * + * @author Calclavia + */ + +public interface IItemFrequency { + /** + * @param data + * - Pass an ItemStack if dealing with items with frequencies. + * @return The frequency of this object. + */ + public int getFrequency(ItemStack itemStack); + + /** + * Sets the frequency + * + * @param frequency + * - The frequency of this object. + * @param data + * - Pass an ItemStack if dealing with items with frequencies. + */ + public void setFrequency(int frequency, ItemStack itemStack); +} diff --git a/src/APIs/icbm/api/ILauncherContainer.java b/src/APIs/icbm/api/ILauncherContainer.java new file mode 100644 index 00000000..f6ca90be --- /dev/null +++ b/src/APIs/icbm/api/ILauncherContainer.java @@ -0,0 +1,18 @@ +package icbm.api; + +/** + * Applied to TileEntities that contains missiles within them. + * + * @author Calclavia + * + */ +public interface ILauncherContainer { + public IMissile getContainingMissile(); + + public void setContainingMissile(IMissile missile); + + /** + * Retrieves the launcher controller controlling this container. + */ + public ILauncherController getController(); +} diff --git a/src/APIs/icbm/api/ILauncherController.java b/src/APIs/icbm/api/ILauncherController.java new file mode 100644 index 00000000..75226b62 --- /dev/null +++ b/src/APIs/icbm/api/ILauncherController.java @@ -0,0 +1,52 @@ +package icbm.api; + +import net.minecraft.item.ItemStack; +import universalelectricity.core.block.IElectricalStorage; +import universalelectricity.core.vector.Vector3; + +/** + * Applied to all launcher TileEntitiies that operates the launching of + * missiles. + * + * @author Calclavia + */ +public interface ILauncherController extends IElectricalStorage, + IBlockFrequency { + /** + * What type of launcher is this? + */ + public LauncherType getLauncherType(); + + /** + * Launches the missile into the specified target. + */ + public void launch(); + + /** + * Can the launcher launch the missile? + */ + public boolean canLaunch(); + + /** + * @return The status of the launcher. + */ + public String getStatus(); + + /** + * @return The target of the launcher. + */ + public Vector3 getTarget(); + + /** + * @param target + * Sets the target of the launcher + */ + public void setTarget(Vector3 target); + + /** + * Places a missile into the launcher. + */ + public void placeMissile(ItemStack itemStack); + + public IMissile getMissile(); +} \ No newline at end of file diff --git a/src/APIs/icbm/api/IMissile.java b/src/APIs/icbm/api/IMissile.java new file mode 100644 index 00000000..58508bad --- /dev/null +++ b/src/APIs/icbm/api/IMissile.java @@ -0,0 +1,55 @@ +package icbm.api; + +import icbm.api.explosion.IExplosiveContainer; +import universalelectricity.core.vector.Vector3; + +/** + * This is an interface applied by all missile entities. You may cast this into + * an @Entity. The "set" version of the function will make the entity do the + * action on the next tick. + * + * @author Calclavia + */ +public interface IMissile extends IExplosiveContainer { + /** + * Blows up this missile. It will detonate the missile with the appropriate + * explosion. + */ + public void explode(); + + public void setExplode(); + + /** + * Blows up this missile like a TNT explosion. Small explosion used for + * events such as a missile crashing or failure to explode will result in + * this function being called. + */ + public void normalExplode(); + + public void setNormalExplode(); + + /** + * Drops the specified missile as an item. + */ + public void dropMissileAsItem(); + + /** + * The amount of ticks this missile has been flying for. Returns -1 if the + * missile is not flying. + */ + public int getTicksInAir(); + + /** + * Gets the launcher this missile is launched from. + */ + public ILauncherContainer getLauncher(); + + /** + * Launches the missile into a specific target. + * + * @param target + */ + public void launch(Vector3 target); + + public void launch(Vector3 target, int height); +} diff --git a/src/APIs/icbm/api/IMissileLockable.java b/src/APIs/icbm/api/IMissileLockable.java new file mode 100644 index 00000000..8e948014 --- /dev/null +++ b/src/APIs/icbm/api/IMissileLockable.java @@ -0,0 +1,30 @@ +package icbm.api; + +import universalelectricity.core.vector.Vector3; + +/** + * Implement this to your entity if you want antiballistic missiles to be able + * to lock onto it. + * + * @author Calclavia + * + */ +public interface IMissileLockable { + /** + * Can this entity be locked on by a missile? + * + * @return True if so. + */ + public boolean canLock(IMissile missile); + + /** + * Gets the predicted position of this entity after a specified amount of + * ticks. + * + * @param ticks + * - The amount of time. + * @return The predicted Vector, or if not predictable, the current + * position. + */ + public Vector3 getPredictedPosition(int ticks); +} diff --git a/src/APIs/icbm/api/ITier.java b/src/APIs/icbm/api/ITier.java new file mode 100644 index 00000000..cdbee038 --- /dev/null +++ b/src/APIs/icbm/api/ITier.java @@ -0,0 +1,24 @@ +package icbm.api; + +/** + * This interface should be applied to all things that has a tier/level. + * + * @author Calclavia + * + */ +public interface ITier { + /** + * Gets the tier of this object + * + * @return - The tier + */ + public int getTier(); + + /** + * Sets the tier of the object + * + * @param tier + * - The tier to be set + */ + public void setTier(int tier); +} diff --git a/src/APIs/icbm/api/ITracker.java b/src/APIs/icbm/api/ITracker.java new file mode 100644 index 00000000..90f2cfc3 --- /dev/null +++ b/src/APIs/icbm/api/ITracker.java @@ -0,0 +1,11 @@ +package icbm.api; + +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface ITracker { + public void setTrackingEntity(ItemStack itemStack, Entity entity); + + public Entity getTrackingEntity(World worldObj, ItemStack itemStack); +} diff --git a/src/APIs/icbm/api/LauncherType.java b/src/APIs/icbm/api/LauncherType.java new file mode 100644 index 00000000..47313e91 --- /dev/null +++ b/src/APIs/icbm/api/LauncherType.java @@ -0,0 +1,11 @@ +package icbm.api; + +/** + * Types of missile launchers + * + * @author Calclavia + * + */ +public enum LauncherType { + TRADITIONAL, CRUISE +} \ No newline at end of file diff --git a/src/APIs/icbm/api/explosion/ExplosionEvent.java b/src/APIs/icbm/api/explosion/ExplosionEvent.java new file mode 100644 index 00000000..c1fd1a95 --- /dev/null +++ b/src/APIs/icbm/api/explosion/ExplosionEvent.java @@ -0,0 +1,121 @@ +package icbm.api.explosion; + +import net.minecraft.entity.Entity; +import net.minecraft.world.Explosion; +import net.minecraft.world.World; +import net.minecraftforge.event.Cancelable; +import net.minecraftforge.event.Event; + +/** + * Use ForgeSubscribe to subscribe to this event. This event is called every + * single time when an ICBM explosion happens. + * + * @author Calclavia + * + */ +@Cancelable +public class ExplosionEvent extends Event { + /** + * The explosion object. Can be cast into {@link Explosion}. This event can + * be canceled to prevent a specific part of an explosion from being + * executed. + */ + public World world; + public double x, y, z; + public IExplosion iExplosion; + + /** + * Pre-cast explosion class. + */ + public Explosion explosion; + + public ExplosionEvent(World world, IExplosion iExplosion) { + this.world = world; + this.iExplosion = iExplosion; + this.x = ((Explosion) iExplosion).explosionX; + this.y = ((Explosion) iExplosion).explosionY; + this.z = ((Explosion) iExplosion).explosionZ; + } + + /** + * Called before an explosive is detonated to check if detonation is + * possible. You may cancel and explosion here if needed. After this it will + * be a bit too late to prevent destruction without any losses. + * + * @author Calclavia + * + */ + @Cancelable + public static class ExplosivePreDetonationEvent extends Event { + public World world; + public Entity entity; + public double x, y, z; + + public IExplosive explosion; + public ExplosiveType type; + + public ExplosivePreDetonationEvent(World world, double x, double y, + double z, ExplosiveType type, IExplosive explosion) { + this.world = world; + this.type = type; + this.explosion = explosion; + } + + public ExplosivePreDetonationEvent(World world, Entity entity, + ExplosiveType type, IExplosive explosion) { + this.world = world; + this.entity = entity; + this.type = type; + this.explosion = explosion; + } + } + + /** + * Called when an explosion is constructed. + * + * @author Calclavia + * + */ + public static class ExplosionConstructionEvent extends ExplosionEvent { + public ExplosionConstructionEvent(World world, IExplosion explosion) { + super(world, explosion); + } + } + + /** + * Called before an explosion happens. + * + * @author Calclavia + * + */ + public static class PreExplosionEvent extends ExplosionEvent { + public PreExplosionEvent(World world, IExplosion explosion) { + super(world, explosion); + } + } + + /** + * Called while an explosion happens. May be called every single tick if + * explosion is procedural. (E.g: Red matter explosive) + * + * @author Calclavia + * + */ + public static class DoExplosionEvent extends ExplosionEvent { + public DoExplosionEvent(World world, IExplosion explosion) { + super(world, explosion); + } + } + + /** + * Called after an explosion happens. + * + * @author Calclavia + * + */ + public static class PostExplosionEvent extends ExplosionEvent { + public PostExplosionEvent(World world, IExplosion explosion) { + super(world, explosion); + } + } +} diff --git a/src/APIs/icbm/api/explosion/ExplosiveType.java b/src/APIs/icbm/api/explosion/ExplosiveType.java new file mode 100644 index 00000000..ef379041 --- /dev/null +++ b/src/APIs/icbm/api/explosion/ExplosiveType.java @@ -0,0 +1,21 @@ +package icbm.api.explosion; + +public enum ExplosiveType { + ALL, + /** An explosive in TNT block form. */ + BLOCK, + /** An explosive in item form such as a grenade. */ + ITEM, + /** An explosive in aircraft form such as a missile. */ + AIR, + /** An explosive in vehicle form such as a minecart. */ + VEHICLE; + + public static ExplosiveType get(int id) { + if (id >= 0 && id < ExplosiveType.values().length) { + return ExplosiveType.values()[id]; + } + + return null; + } +} diff --git a/src/APIs/icbm/api/explosion/IEMPBlock.java b/src/APIs/icbm/api/explosion/IEMPBlock.java new file mode 100644 index 00000000..2b1353f6 --- /dev/null +++ b/src/APIs/icbm/api/explosion/IEMPBlock.java @@ -0,0 +1,25 @@ +package icbm.api.explosion; + +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +/** + * Applied to all blocks that has a custom reaction to EMPs. Blocks not + * TileEntities. + * + * @author Calclavia + * + */ +public interface IEMPBlock { + /** + * Called when this block gets attacked by EMP. + * + * @param world + * - The world object. + * @param position + * - The position. + * @param empExplosive + * - The explosion + */ + public void onEMP(World world, Vector3 position, IExplosion empExplosive); +} diff --git a/src/APIs/icbm/api/explosion/IEMPItem.java b/src/APIs/icbm/api/explosion/IEMPItem.java new file mode 100644 index 00000000..9a77a6f0 --- /dev/null +++ b/src/APIs/icbm/api/explosion/IEMPItem.java @@ -0,0 +1,26 @@ +package icbm.api.explosion; + +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import universalelectricity.core.item.IItemElectric; + +/** + * Applied to all items that can be protected from EMP somehow. + * + * @author Calclavia + * + */ +public interface IEMPItem extends IItemElectric { + /** + * Called when this item is being EMPed + * + * @param itemStack + * - The itemstack attacked by EMP + * @param entity + * - The entity holding the item + * @param empExplosives + * - The IExplosive object + */ + public void onEMP(ItemStack itemStack, Entity entity, + IExplosion empExplosive); +} diff --git a/src/APIs/icbm/api/explosion/IExplosion.java b/src/APIs/icbm/api/explosion/IExplosion.java new file mode 100644 index 00000000..33c0e9ab --- /dev/null +++ b/src/APIs/icbm/api/explosion/IExplosion.java @@ -0,0 +1,25 @@ +package icbm.api.explosion; + +/** + * The actual explosion interface. Extends Explosion.java. + * + * @author Calclavia + * + */ +public interface IExplosion { + /** + * Called to initiate the explosion. + */ + public void explode(); + + /** + * @return The radius of effect of the explosion. + */ + public float getRadius(); + + /** + * @return The energy emitted by this explosive. In Joules and approximately + * based off of a real life equivalent. + */ + public float getEnergy(); +} diff --git a/src/APIs/icbm/api/explosion/IExplosive.java b/src/APIs/icbm/api/explosion/IExplosive.java new file mode 100644 index 00000000..7edb27a0 --- /dev/null +++ b/src/APIs/icbm/api/explosion/IExplosive.java @@ -0,0 +1,70 @@ +package icbm.api.explosion; + +import icbm.api.ITier; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; + +/** + * An interface used to find various types of explosive's information. + * + * @author Calclavia + * + */ +public interface IExplosive extends ITier { + /** + * @return Gets the explosive's ID. + */ + public int getID(); + + /** + * @return The unique name key in the ICBM language file. + */ + public String getUnlocalizedName(); + + /** + * @return Gets the specific translated name of the block versions of the + * explosive. + */ + public String getExplosiveName(); + + /** + * @return Gets the specific translated name of the grenade versions of the + * explosive. + */ + public String getGrenadeName(); + + /** + * @return Gets the specific translated name of the missile versions of the + * explosive. + */ + public String getMissileName(); + + /** + * @return Gets the specific translated name of the minecart versions of the + * explosive. + */ + public String getMinecartName(); + + /** + * @return The tier of the explosive. + */ + @Override + public int getTier(); + + /** + * Creates a new explosion at a given location. + * + * @param world + * The world in which the explosion takes place. + * @param x + * The X-Coord + * @param y + * The Y-Coord + * @param z + * The Z-Coord + * @param entity + * Entity that caused the explosion. + */ + public void createExplosion(World world, double x, double y, double z, + Entity entity); +} diff --git a/src/APIs/icbm/api/explosion/IExplosiveContainer.java b/src/APIs/icbm/api/explosion/IExplosiveContainer.java new file mode 100644 index 00000000..9cb3735e --- /dev/null +++ b/src/APIs/icbm/api/explosion/IExplosiveContainer.java @@ -0,0 +1,16 @@ +package icbm.api.explosion; + +import net.minecraft.nbt.NBTTagCompound; + +/** + * An object that contains a reference to IExplosive. Carried by explosives, + * grenades and missile entities etc. + * + * @author Calclavia + * + */ +public interface IExplosiveContainer { + public NBTTagCompound getTagCompound(); + + public IExplosive getExplosiveType(); +} diff --git a/src/APIs/icbm/api/explosion/IExplosiveIgnore.java b/src/APIs/icbm/api/explosion/IExplosiveIgnore.java new file mode 100644 index 00000000..036549a5 --- /dev/null +++ b/src/APIs/icbm/api/explosion/IExplosiveIgnore.java @@ -0,0 +1,11 @@ +package icbm.api.explosion; + +/** + * Applied to entities that ignore the affects of a specific explosion. + * + * @author Calclavia + * + */ +public interface IExplosiveIgnore { + public boolean canIgnore(IExplosion explosion); +} diff --git a/src/APIs/icbm/api/sentry/IAATarget.java b/src/APIs/icbm/api/sentry/IAATarget.java new file mode 100644 index 00000000..90aebb89 --- /dev/null +++ b/src/APIs/icbm/api/sentry/IAATarget.java @@ -0,0 +1,38 @@ +package icbm.api.sentry; + +/** + * Apply this to an entity if it is meant to be targeted by the AA Turret. + * + * @author Calclavia + * + */ +public interface IAATarget { + /** + * destroys the target with a boom. This is a forced way for the sentry too + * kill the target if it doesn't take damage + */ + public void destroyCraft(); + + /** + * Applies damage to the the target + * + * @param damage + * - damage in half HP + * @return the amount of HP left. Return -1 if this target can't take + * damage, and will be chance killed. Return 0 if this target is + * dead and destroyCraft() will be called. + */ + public int doDamage(int damage); + + /** + * Can this be targeted by automated targeting systems or AIs. Used to + * implement radar jammers, cloaking devices, and other addons for the + * Entity being targeted + * + * @param entity + * - entity that is targeting this, can be an Entity, + * EntityLiving, or TileEntity + * @return true if it can + */ + public boolean canBeTargeted(Object entity); +} diff --git a/src/APIs/org/modstats/IModstatsReporter.java b/src/APIs/org/modstats/IModstatsReporter.java new file mode 100644 index 00000000..8fe62722 --- /dev/null +++ b/src/APIs/org/modstats/IModstatsReporter.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) <2012>, Oleg Romanovskiy aka Shedar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.modstats; + +public interface IModstatsReporter +{ + public void registerMod(Object mod); + public void doManualCheck(); +} diff --git a/src/APIs/org/modstats/ModVersionData.java b/src/APIs/org/modstats/ModVersionData.java new file mode 100644 index 00000000..ab3fbcd0 --- /dev/null +++ b/src/APIs/org/modstats/ModVersionData.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) <2012>, Oleg Romanovskiy aka Shedar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.modstats; + +import java.util.HashMap; +import java.util.Map; + +public class ModVersionData +{ + public String prefix; + public String name; + public String version; + public String downloadUrl; + public String changeLogUrl; + + public Map extraFields; + + + public ModVersionData() + { + extraFields = new HashMap(); + } + + public ModVersionData(String prefix, String name, String version) + { + this.prefix = prefix; + this.name = name; + this.version = version; + extraFields = new HashMap(); + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + ((changeLogUrl == null) ? 0 : changeLogUrl.hashCode()); + result = prime * result + ((downloadUrl == null) ? 0 : downloadUrl.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((prefix == null) ? 0 : prefix.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ModVersionData other = (ModVersionData) obj; + if (changeLogUrl == null) + { + if (other.changeLogUrl != null) + return false; + } else if (!changeLogUrl.equals(other.changeLogUrl)) + return false; + if (downloadUrl == null) + { + if (other.downloadUrl != null) + return false; + } else if (!downloadUrl.equals(other.downloadUrl)) + return false; + if (name == null) + { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (prefix == null) + { + if (other.prefix != null) + return false; + } else if (!prefix.equals(other.prefix)) + return false; + if (version == null) + { + if (other.version != null) + return false; + } else if (!version.equals(other.version)) + return false; + return true; + } + + +} diff --git a/src/APIs/org/modstats/ModsUpdateEvent.java b/src/APIs/org/modstats/ModsUpdateEvent.java new file mode 100644 index 00000000..a29eb817 --- /dev/null +++ b/src/APIs/org/modstats/ModsUpdateEvent.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) <2012>, Oleg Romanovskiy aka Shedar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.modstats; + +import java.util.LinkedList; +import java.util.List; + +import net.minecraftforge.event.Cancelable; +import net.minecraftforge.event.Event; +import cpw.mods.fml.common.FMLLog; + +@Cancelable +public class ModsUpdateEvent extends Event +{ + private List updatedMods; + + public ModsUpdateEvent() + { + updatedMods = new LinkedList(); + } + + public void add(ModVersionData data) + { + if(!updatedMods.contains(data)) + { + updatedMods.add(data); + } + else + { + FMLLog.info("ModsUpdateEvent shouldn't have same mods data", data); + } + } + + public List getUpdatedMods() + { + return updatedMods; + } + +} diff --git a/src/APIs/org/modstats/ModstatInfo.java b/src/APIs/org/modstats/ModstatInfo.java new file mode 100644 index 00000000..1927e52f --- /dev/null +++ b/src/APIs/org/modstats/ModstatInfo.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) <2012>, Oleg Romanovskiy aka Shedar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.modstats; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ModstatInfo +{ + /** + * Modstats mod prefix. + * @return + */ + public String prefix(); + + /** + * Mod name. Use this if your mod doesn't have @Mod annotation + * @return + */ + public String name() default ""; + + /** + * Mod version. Use this if your mod doesn't have @Mod annotation + * @return + */ + public String version() default ""; +} diff --git a/src/APIs/org/modstats/Modstats.java b/src/APIs/org/modstats/Modstats.java new file mode 100644 index 00000000..c9753e4d --- /dev/null +++ b/src/APIs/org/modstats/Modstats.java @@ -0,0 +1,89 @@ +/** + * Copyright (c) <2012>, Oleg Romanovskiy aka Shedar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.modstats; + +import cpw.mods.fml.common.FMLLog; + +public class Modstats +{ + private static final Modstats INSTANCE = new Modstats(); + private static final String CLASS_TEMPLATE = "org.modstats.reporter.v%d.Reporter"; + private IModstatsReporter reporter; + + private Modstats() + { + reporter = locateReporter(); + } + + public IModstatsReporter getReporter() + { + return reporter; + } + + private IModstatsReporter locateReporter() + { + int i=1; + Class latest = null; + while(i<100) + { + try + { + Class candidate = Class.forName(String.format(CLASS_TEMPLATE, i)); + if(IModstatsReporter.class.isAssignableFrom(candidate)) + { + latest = candidate; + } + } + catch (Exception e) { + break; + } + i++; + } + if(latest == null) + { + FMLLog.warning("Modstats reporter class not found."); + } + else + { + try + { + return (IModstatsReporter)latest.newInstance(); + } catch (Exception e) + { + FMLLog.warning("Modstats reporter class can't be instantiated."); + } + } + return null; + } + + public static Modstats instance() + { + return INSTANCE; + } + +} diff --git a/src/APIs/org/modstats/reporter/v1/Config.java b/src/APIs/org/modstats/reporter/v1/Config.java new file mode 100644 index 00000000..708e3a93 --- /dev/null +++ b/src/APIs/org/modstats/reporter/v1/Config.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) <2012>, Oleg Romanovskiy aka Shedar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.modstats.reporter.v1; + +import java.io.File; + +import net.minecraftforge.common.Configuration; +import net.minecraftforge.common.Property; +import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.Loader; + +public class Config +{ + private static final String CONFIG_NAME = "modstats.cfg"; + + public boolean allowUpdates; + public boolean betaNotifications; + public boolean forCurrentMinecraftVersion; + public boolean logOnly; + + public Config() + { + File configLocation = new File(Loader.instance().getConfigDir(), CONFIG_NAME); + Configuration configuration = new Configuration(configLocation); + configuration.load(); + + Property prop = configuration.get("updates", "AllowUpdates", true); + prop.comment = "Allow to send current mod versions to the server and check for updates.\nIt allows to mod authors to see mod's popularity. Please don't disable it without necessity"; + allowUpdates = prop.getBoolean(true); + + prop = configuration.get("updates", "LogOnly", false); + prop.comment = "Don't display chat message, just add message to the log."; + logOnly = prop.getBoolean(false); + + prop = configuration.get("updates", "BetaNotifications", false); + prop.comment = "Set true to receive notifications about beta versions. Otherwise you will only receive information about stable versions"; + betaNotifications = prop.getBoolean(false); + + prop = configuration.get("updates", "ForCurrentMinecraftVersion", false); + prop.comment = "Check for updates only for current MC version.\nEx:if you have MC 1.4.2 and ForCurrentMinecraftVersion is true, then you wouldn't receive notifications about versions for MC 1.4.5"; + forCurrentMinecraftVersion = prop.getBoolean(false); + + configuration.save(); + + FMLLog.info("[Modstats] Config loaded. allowUpdates: %b, betaNotification: %b, strict: %b", allowUpdates, betaNotifications, forCurrentMinecraftVersion); + } + +} diff --git a/src/APIs/org/modstats/reporter/v1/DataSender.java b/src/APIs/org/modstats/reporter/v1/DataSender.java new file mode 100644 index 00000000..5cbbcc08 --- /dev/null +++ b/src/APIs/org/modstats/reporter/v1/DataSender.java @@ -0,0 +1,294 @@ +/** + * Copyright (c) <2012>, Oleg Romanovskiy aka Shedar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.modstats.reporter.v1; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.NetworkInterface; +import java.net.URL; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import net.minecraft.client.Minecraft; +import net.minecraft.crash.CallableMinecraftVersion; +import net.minecraftforge.common.MinecraftForge; + +import org.modstats.ModVersionData; +import org.modstats.ModsUpdateEvent; + +import argo.jdom.JdomParser; +import argo.jdom.JsonNode; +import argo.jdom.JsonRootNode; +import argo.jdom.JsonStringNode; +import argo.saj.InvalidSyntaxException; + +import com.google.common.base.Charsets; +import com.google.common.hash.Hashing; +import com.google.common.io.Files; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.versioning.ComparableVersion; + +class DataSender extends Thread +{ + private static final String urlAutoTemplate = "http://modstats.org/api/v1/report?mc=%s&user=%s&data=%s&sign=%s&beta=%b&strict=%b"; + private static final String urlManualTemplate = "http://modstats.org/api/v1/check?mc=%s&user=%s&data=%s&sign=%s&beta=%b&strict=%b"; + + private final Reporter reporter; + public final boolean manual; + + public DataSender(Reporter reporter, boolean manual) + { + this.reporter = reporter; + this.manual = manual; + } + + private String toHexString(byte[] bytes) { + char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + char[] hexChars = new char[bytes.length * 2]; + int v; + for ( int j = 0; j < bytes.length; j++ ) { + v = bytes[j] & 0xFF; + hexChars[j*2] = hexArray[v/16]; + hexChars[j*2 + 1] = hexArray[v%16]; + } + return new String(hexChars); + } + + private String getPlayerId() throws IOException + { + File statDir = new File(Minecraft.getMinecraft().mcDataDir, "stats"); + if(!statDir.exists()) + { + statDir.mkdirs(); + } + String mac = ""; + try + { + InetAddress address = InetAddress.getLocalHost(); + NetworkInterface ni = NetworkInterface.getByInetAddress(address); + byte[] macArray = ni.getHardwareAddress(); + if(macArray != null) + { + mac = toHexString(macArray); + } + } + catch(Exception ex) + { + } + File uidFile = new File(statDir, "player.uid"); + if(uidFile.exists() && uidFile.canRead() && uidFile.length() == 32+mac.length()) + { + String data = Files.toString(uidFile, Charsets.US_ASCII); + String storedMac = data.substring(32); + if(storedMac.equalsIgnoreCase(mac)) + return data.substring(0, 32); + } + uidFile.createNewFile(); + if(uidFile.canWrite()) + { + String uid = UUID.randomUUID().toString().replace("-", ""); + FileOutputStream output = new FileOutputStream(uidFile); + output.write((uid+mac).getBytes()); + output.close(); + return uid; + } + return ""; + } + + private String getSignature(String data) + { + return Hashing.md5().hashString(data).toString(); + } + + private String getData() + { + StringBuilder b = new StringBuilder(); + for (Map.Entry item : reporter.registeredMods.entrySet()) + { + b.append(item.getKey()).append("+").append(item.getValue().version).append("$"); + } + return b.toString(); + } + + private boolean checkIsNewer(String current, String received) + { + return new ComparableVersion(received).compareTo(new ComparableVersion(current)) > 0; + } + + + private void parseResponse(String response) + { + try + { + JsonRootNode json = (new JdomParser()).parse(response); + //empty result + if(!json.isNode("mods")) + { + FMLLog.info("[Modstats] Empty result"); + return; + } + List modList = json.getArrayNode("mods"); + ModsUpdateEvent event = new ModsUpdateEvent(); + for (JsonNode modObject : modList) + { + String prefix = modObject.getStringValue("code"); + if(!reporter.registeredMods.containsKey(prefix)) + { + FMLLog.warning("[Modstats] Extra mod '%s' in service response", prefix); + continue; + } + String version = modObject.getStringValue("ver"); + if(version==null || version.equals(reporter.registeredMods.get(prefix).version)) + { + continue; + } + if(checkIsNewer(reporter.registeredMods.get(prefix).version, version)) + { + ModVersionData data = new ModVersionData(prefix, reporter.registeredMods.get(prefix).name, version); + Map fields = modObject.getFields(); + for (Map.Entry entry : fields.entrySet()) + { + String fieldName = entry.getKey().getText(); + if(fieldName.equals("code") || fieldName.equals("ver")) + continue; + if(!(entry.getValue() instanceof JsonStringNode)) + { + FMLLog.warning(String.format("[Modstats] Too complex data in response for field '%s'.", fieldName)); + continue; + } + String value = ((JsonStringNode)entry.getValue()).getText(); + if(fieldName.equals("chlog")) + { + data.changeLogUrl = value; + } + else if(fieldName.equals("link")) + { + data.downloadUrl = value; + } + else + { + data.extraFields.put(fieldName, value); + } + } + event.add(data); + } + + } + if(event.getUpdatedMods().size() > 0) + { + MinecraftForge.EVENT_BUS.post(event); + } + if(!event.isCanceled() && event.getUpdatedMods().size() > 0) + { + List updatedModsToOutput = event.getUpdatedMods(); + StringBuilder builder = new StringBuilder("Updates found: "); + Iterator iterator = updatedModsToOutput.iterator(); + while(iterator.hasNext()) + { + ModVersionData modVersionData = iterator.next(); + builder.append(modVersionData.name) + .append(" (") + .append(modVersionData.version) + .append(")") + .append(iterator.hasNext()?",":"."); + } + FMLLog.info("[Modstats] %s", builder.toString()); + if(!reporter.config.logOnly && FMLCommonHandler.instance().getSide().isClient()) + { + Minecraft mc = FMLClientHandler.instance().getClient(); + int maxTries = 30; + while(mc.thePlayer==null && maxTries>0) + { + try + { + sleep(1000); + } catch (InterruptedException e) + { + } + maxTries--; + } + if(mc.thePlayer != null) + { + mc.thePlayer.addChatMessage(builder.toString()); + } + } + } + + } catch (InvalidSyntaxException e) + { + FMLLog.warning("[Modstats] Can't parse response: '%s'.", e.getMessage()); + } + } + + + @Override + public void run() + { + try + { + String data = getData(); + String playerId = getPlayerId(); + String hash = getSignature(playerId+"!"+data); + String template = manual?urlManualTemplate:urlAutoTemplate; + String mcVersion = new CallableMinecraftVersion(null).minecraftVersion(); + URL url = new URL(String.format(template, mcVersion, playerId, data, hash, reporter.config.betaNotifications, reporter.config.forCurrentMinecraftVersion)); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + String out = ""; + while ((line = reader.readLine()) != null) { + //in most cases it will contain just one line + out += line; + } + reader.close(); + parseResponse(out); + } catch (MalformedURLException e) + { + FMLLog.warning("[Modstats] Invalid stat report url"); + } catch (IOException e) + { + FMLLog.info("[Modstats] Stat wasn't reported '"+e.getMessage()+"'"); + } catch(Exception e) + { + FMLLog.warning("[Modstats] Something wrong: "+e.toString()); + } + } +} diff --git a/src/APIs/org/modstats/reporter/v1/Reporter.java b/src/APIs/org/modstats/reporter/v1/Reporter.java new file mode 100644 index 00000000..2744b6d7 --- /dev/null +++ b/src/APIs/org/modstats/reporter/v1/Reporter.java @@ -0,0 +1,145 @@ +/** + * Copyright (c) <2012>, Oleg Romanovskiy aka Shedar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.modstats.reporter.v1; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.ForgeSubscribe; +import net.minecraftforge.event.world.WorldEvent; + +import org.modstats.IModstatsReporter; +import org.modstats.ModVersionData; +import org.modstats.ModstatInfo; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.Mod; + + +public class Reporter implements IModstatsReporter +{ + + public Map registeredMods; + private DataSender sender; + public Config config; + + /** + * At least one auto check was completed successfully + */ + private boolean checkedAuto; + + public Reporter() + { + checkedAuto = false; + registeredMods = new ConcurrentHashMap(2, 0.9f, 1); + MinecraftForge.EVENT_BUS.register(this); + config = new Config(); + } + + + private void startCheck(boolean manual) + { + if(!config.allowUpdates) + return; + //only manual check is allowed on servers + if(!FMLCommonHandler.instance().getSide().isClient() && !manual) + return; + if(registeredMods.isEmpty()) + return; + DataSender currentSender = sender; + if(!manual && checkedAuto) + return; + if(currentSender!=null && (currentSender.manual == false || manual)) + return; + currentSender = new DataSender(this, manual); + currentSender.start(); + sender = currentSender; + + } + + @ForgeSubscribe + public void worldLoad(WorldEvent.Load event) + { + startCheck(false); + } + + + @Override + public void registerMod(Object mod) + { + if(!config.allowUpdates) + return; + if(mod == null) + { + FMLLog.warning("[Modstats] Can't register null mod."); + return; + } + ModstatInfo info = mod.getClass().getAnnotation(ModstatInfo.class); + if(info == null) + { + FMLLog.warning("[Modstats] ModstatsInfo annotation not found for given mod."); + return; + } + + if(info.prefix() == null || info.prefix().equals("")) + { + FMLLog.warning("[Modstats] Mod prefix can't be empty."); + return; + } + Mod modData = mod.getClass().getAnnotation(Mod.class); + ModVersionData data; + if(modData == null) + { + if(info.name() == null || info.name().equals("")) + { + FMLLog.warning("[Modstats] Mod name can't be empty."); + return; + } + if(info.version() == null || info.version().equals("")) + { + FMLLog.warning("[Modstats] Mod version can't be empty."); + return; + } + data = new ModVersionData(info.prefix(), info.name(), info.version()); + } + else + { + data = new ModVersionData(info.prefix(), modData.name(), modData.version()); + } + registeredMods.put(info.prefix(), data); + } + + @Override + public void doManualCheck() + { + startCheck(true); + } + +} diff --git a/src/APIs/thermalexpansion/api/item/IChargeableItem.java b/src/APIs/thermalexpansion/api/item/IChargeableItem.java new file mode 100644 index 00000000..6c638697 --- /dev/null +++ b/src/APIs/thermalexpansion/api/item/IChargeableItem.java @@ -0,0 +1,46 @@ +package thermalexpansion.api.item; + +import net.minecraft.item.ItemStack; + +/** + * Implement this interface on Item classes that support external manipulation of their internal + * energy storages. This interface does not provide methods for the underlying internal energy + * usage. + */ + +public interface IChargeableItem +{ + + /** + * Adds energy to an item. Returns the quantity of energy that was accepted. This should always + * return 0 if the item cannot be externally charged. + * + * @param theItem ItemStack to be charged. + * @param energy Maximum amount of energy to be sent into the item. + * @param doReceive If false, the charge will only be simulated. + * @return Amount of energy that was accepted by the item. + */ + public float receiveEnergy(ItemStack theItem, float energy, boolean doReceive); + + /** + * Removes energy from an item. Returns the quantity of energy that was removed. This should + * always return 0 if the item cannot be externally discharged. + * + * @param theItem ItemStack to be discharged. + * @param energy Maximum amount of energy to be removed from the item. + * @param doTransfer If false, the discharge will only be simulated. + * @return Amount of energy that was removed from the item. + */ + public float transferEnergy(ItemStack theItem, float energy, boolean doTransfer); + + /** + * Get the amount of energy currently stored in the item. + */ + public float getEnergyStored(ItemStack theItem); + + /** + * Get the max amount of energy that can be stored in the item. + */ + public float getMaxEnergyStored(ItemStack theItem); + +} diff --git a/src/APIs/universalelectricity/compatibility/Compatibility.java b/src/APIs/universalelectricity/compatibility/Compatibility.java new file mode 100644 index 00000000..a254f46b --- /dev/null +++ b/src/APIs/universalelectricity/compatibility/Compatibility.java @@ -0,0 +1,56 @@ +package universalelectricity.compatibility; + +import universalelectricity.core.UniversalElectricity; +import universalelectricity.core.electricity.NetworkLoader; +import cpw.mods.fml.common.Loader; + +/** + * The Universal Electricity compatiblity module allows your mod to be compatible with most major + * power systems in Minecraft. + * + * @author Calclavia, Micdoodle + * + */ +public class Compatibility +{ + /** + * Universal Electricity measures in Kilowatts. + * + * Multiply this to convert foreign energy into UE Joules. + */ + public static float BC3_RATIO = 1; + public static float IC2_RATIO = 0.4f; + + /** + * Multiply this to convert UE Joules into foreign energy. The reciprocal conversion ratio. + */ + public static float TO_IC2_RATIO = 1 / IC2_RATIO; + public static float TO_BC_RATIO = 1 / BC3_RATIO; + + /** + * You must call this function to enable the Universal Network module. + */ + public static void initiate() + { + /** + * Loads the configuration and sets all the values. + */ + UniversalElectricity.CONFIGURATION.load(); + IC2_RATIO = (float) UniversalElectricity.CONFIGURATION.get("Compatiblity", "IndustrialCraft Conversion Ratio", IC2_RATIO).getDouble(IC2_RATIO); + BC3_RATIO = (float) UniversalElectricity.CONFIGURATION.get("Compatiblity", "BuildCraft Conversion Ratio", BC3_RATIO).getDouble(BC3_RATIO); + TO_IC2_RATIO = 1 / IC2_RATIO; + TO_BC_RATIO = 1 / BC3_RATIO; + UniversalElectricity.CONFIGURATION.save(); + NetworkLoader.setNetworkClass(UniversalNetwork.class); + } + + public static boolean isIndustrialCraft2Loaded() + { + return Loader.isModLoaded("IC2"); + } + + public static boolean isBuildcraftLoaded() + { + return Loader.isModLoaded("BuildCraft|Energy"); + } +} diff --git a/src/APIs/universalelectricity/compatibility/ItemUniversalElectric.java b/src/APIs/universalelectricity/compatibility/ItemUniversalElectric.java new file mode 100644 index 00000000..19fb4a47 --- /dev/null +++ b/src/APIs/universalelectricity/compatibility/ItemUniversalElectric.java @@ -0,0 +1,150 @@ +package universalelectricity.compatibility; + +import ic2.api.item.IElectricItemManager; +import ic2.api.item.ISpecialElectricItem; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import thermalexpansion.api.item.IChargeableItem; +import universalelectricity.core.item.IItemElectric; +import universalelectricity.core.item.ItemElectric; + +public abstract class ItemUniversalElectric extends ItemElectric implements ISpecialElectricItem, IChargeableItem +{ + public static final float CHARGE_RATE = 0.005f; + + public ItemUniversalElectric(int id) + { + super(id); + } + + /** + * IC2 + */ + @Override + public int getChargedItemId(ItemStack itemStack) + { + return this.itemID; + } + + @Override + public int getEmptyItemId(ItemStack itemStack) + { + return this.itemID; + } + + @Override + public int getMaxCharge(ItemStack itemStack) + { + return (int) (this.getMaxElectricityStored(itemStack) * Compatibility.TO_IC2_RATIO); + } + + @Override + public int getTier(ItemStack itemStack) + { + return 1; + } + + @Override + public int getTransferLimit(ItemStack itemStack) + { + return (int) ((this.getMaxElectricityStored(itemStack) * CHARGE_RATE) * Compatibility.TO_IC2_RATIO); + } + + @Override + public IElectricItemManager getManager(ItemStack itemStack) + { + return IC2ElectricItemManager.MANAGER; + } + + @Override + public boolean canProvideEnergy(ItemStack itemStack) + { + return this.recharge(itemStack, 1, false) > 0; + } + + /** + * Thermal Expansion + */ + @Override + public float receiveEnergy(ItemStack theItem, float energy, boolean doReceive) + { + return this.recharge(theItem, energy * Compatibility.BC3_RATIO, doReceive) * Compatibility.TO_BC_RATIO; + } + + @Override + public float transferEnergy(ItemStack theItem, float energy, boolean doTransfer) + { + return this.discharge(theItem, energy * Compatibility.BC3_RATIO, doTransfer) * Compatibility.TO_BC_RATIO; + } + + @Override + public float getEnergyStored(ItemStack theItem) + { + return this.getElectricityStored(theItem) * Compatibility.TO_BC_RATIO; + } + + @Override + public float getMaxEnergyStored(ItemStack theItem) + { + return this.getMaxElectricityStored(theItem) * Compatibility.TO_BC_RATIO; + } + + public static class IC2ElectricItemManager implements IElectricItemManager + { + public static final IElectricItemManager MANAGER = new IC2ElectricItemManager(); + + private IItemElectric getElectricItem(ItemStack itemStack) + { + if (itemStack.getItem() instanceof IItemElectric) + { + return ((IItemElectric) itemStack.getItem()); + } + return null; + } + + @Override + public int charge(ItemStack itemStack, int amount, int tier, boolean ignoreTransferLimit, boolean simulate) + { + float inputElectricity = amount * Compatibility.IC2_RATIO; + return (int) (getElectricItem(itemStack).recharge(itemStack, inputElectricity, !simulate) * Compatibility.TO_IC2_RATIO); + } + + @Override + public int discharge(ItemStack itemStack, int amount, int tier, boolean ignoreTransferLimit, boolean simulate) + { + float outputElectricity = amount * Compatibility.IC2_RATIO; + return (int) (getElectricItem(itemStack).discharge(itemStack, outputElectricity, !simulate) * Compatibility.TO_IC2_RATIO); + } + + @Override + public boolean canUse(ItemStack itemStack, int amount) + { + return false; + } + + @Override + public int getCharge(ItemStack itemStack) + { + return 0; + } + + @Override + public boolean use(ItemStack itemStack, int amount, EntityLivingBase entity) + { + return false; + } + + @Override + public void chargeFromArmor(ItemStack itemStack, EntityLivingBase entity) + { + + } + + @Override + public String getToolTip(ItemStack itemStack) + { + return null; + } + + } +} diff --git a/src/APIs/universalelectricity/compatibility/TileEntityUniversalConductor.java b/src/APIs/universalelectricity/compatibility/TileEntityUniversalConductor.java new file mode 100644 index 00000000..8f14720f --- /dev/null +++ b/src/APIs/universalelectricity/compatibility/TileEntityUniversalConductor.java @@ -0,0 +1,224 @@ +package universalelectricity.compatibility; + +import ic2.api.Direction; +import ic2.api.energy.event.EnergyTileLoadEvent; +import ic2.api.energy.event.EnergyTileUnloadEvent; +import ic2.api.energy.tile.IEnergyAcceptor; +import ic2.api.energy.tile.IEnergySink; +import ic2.api.energy.tile.IEnergyTile; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.common.MinecraftForge; +import universalelectricity.core.block.IConnector; +import universalelectricity.core.electricity.ElectricityPack; +import universalelectricity.core.grid.IElectricityNetwork; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; +import universalelectricity.prefab.tile.TileEntityConductor; +import buildcraft.api.power.IPowerReceptor; +import buildcraft.api.power.PowerHandler; +import buildcraft.api.power.PowerHandler.PowerReceiver; + +/** + * A universal conductor class. + * + * Extend this class or use as a reference for your own implementation of compatible conductor + * tiles. + * + * @author micdoodle8 + * + */ +public abstract class TileEntityUniversalConductor extends TileEntityConductor implements IEnergySink, IPowerReceptor +{ + protected boolean addedToIC2Network = false; + + /* + * private DummyPowerProvider powerProvider; + * + * public TileEntityUniversalConductor() { this.powerProvider = new + * DummyPowerProvider(this.getNetwork(), this); this.powerProvider.configure(0, 0, 100, 0, 100); + * } + */ + @Override + public void setNetwork(IElectricityNetwork network) + { + super.setNetwork(network); + /* + * if (this.powerProvider != null) { this.powerProvider.network = network; } + */ + } + + @Override + public void invalidate() + { + this.unloadTileIC2(); + super.invalidate(); + } + + @Override + public void onChunkUnload() + { + this.unloadTileIC2(); + super.onChunkUnload(); + } + + private void unloadTileIC2() + { + if (this.addedToIC2Network && this.worldObj != null) + { + if (Compatibility.isIndustrialCraft2Loaded()) + { + MinecraftForge.EVENT_BUS.post(new EnergyTileUnloadEvent(this)); + } + + this.addedToIC2Network = false; + } + } + + @Override + public boolean canUpdate() + { + return true; + } + + @Override + public void updateEntity() + { + super.updateEntity(); + + if (!this.worldObj.isRemote && !this.addedToIC2Network) + { + if (Compatibility.isIndustrialCraft2Loaded()) + { + MinecraftForge.EVENT_BUS.post(new EnergyTileLoadEvent(this)); + } + + this.addedToIC2Network = true; + } + } + + /** + * IC2 Methods + */ + @Override + public boolean acceptsEnergyFrom(TileEntity emitter, Direction direction) + { + return emitter instanceof IEnergyTile; + } + + @Override + public boolean isAddedToEnergyNet() + { + return this.addedToIC2Network; + } + + @Override + public int demandsEnergy() + { + if (this.getNetwork() == null) + { + return 0; + } + + return (int) Math.floor(Math.min(this.getNetwork().getRequest(this).getWatts() * Compatibility.TO_IC2_RATIO, 100)); + } + + @Override + public int injectEnergy(Direction directionFrom, int amount) + { + if (this.getNetwork() == null) + { + return amount; + } + + return (int) Math.floor(this.getNetwork().produce(ElectricityPack.getFromWatts(amount, 120), VectorHelper.getTileEntityFromSide(this.worldObj, new Vector3(this), directionFrom.toForgeDirection()))); + } + + @Override + public int getMaxSafeInput() + { + return Integer.MAX_VALUE; + } + + @Override + public TileEntity[] getAdjacentConnections() + { + TileEntity[] adjecentConnections = new TileEntity[6]; + + for (byte i = 0; i < 6; i++) + { + ForgeDirection side = ForgeDirection.getOrientation(i); + TileEntity tileEntity = VectorHelper.getTileEntityFromSide(this.worldObj, new Vector3(this), side); + + if (tileEntity instanceof IConnector) + { + if (((IConnector) tileEntity).canConnect(side.getOpposite())) + { + adjecentConnections[i] = tileEntity; + } + } + else if (Compatibility.isIndustrialCraft2Loaded() && tileEntity instanceof IEnergyTile) + { + if (tileEntity instanceof IEnergyAcceptor) + { + if (((IEnergyAcceptor) tileEntity).acceptsEnergyFrom(this, Direction.values()[(i + 2) % 6].getInverse())) + { + adjecentConnections[i] = tileEntity; + } + } + else + { + adjecentConnections[i] = tileEntity; + } + } + else if (Compatibility.isBuildcraftLoaded() && tileEntity instanceof IPowerReceptor) + { + adjecentConnections[i] = tileEntity; + } + } + + return adjecentConnections; + } + + /** + * BuildCraft Methods + */ + @Override + public PowerReceiver getPowerReceiver(ForgeDirection side) + { + return null; + } + + @Override + public void doWork(PowerHandler workProvider) + { + + } + + @Override + public World getWorld() + { + return this.getWorldObj(); + } + /* + * @Override public int powerRequest(ForgeDirection from) { if (this.getNetwork() == null) { + * return 0; } + * + * return (int) + * Math.floor(Math.min(this.getNetwork().getRequest(VectorHelper.getTileEntityFromSide + * (this.worldObj, new Vector3(this), from)).getWatts() * Compatibility.TO_BC_RATIO, 100)); } + */ + /* + * private class DummyPowerProvider extends PowerProvider { public IElectricityNetwork network; + * private final TileEntityUniversalConductor conductor; + * + * public DummyPowerProvider(IElectricityNetwork network, TileEntityUniversalConductor + * conductor) { this.network = network; this.conductor = conductor; } + * + * @Override public void receiveEnergy(float quantity, ForgeDirection from) { if (this.network + * != null) { this.network.produce(ElectricityPack.getFromWatts(this.getEnergyStored(), 120), + * VectorHelper.getTileEntityFromSide(this.conductor.worldObj, new Vector3(this.conductor), + * from)); } } } + */ +} diff --git a/src/APIs/universalelectricity/compatibility/TileEntityUniversalElectrical.java b/src/APIs/universalelectricity/compatibility/TileEntityUniversalElectrical.java new file mode 100644 index 00000000..34782e49 --- /dev/null +++ b/src/APIs/universalelectricity/compatibility/TileEntityUniversalElectrical.java @@ -0,0 +1,240 @@ +package universalelectricity.compatibility; + +import ic2.api.Direction; +import ic2.api.energy.event.EnergyTileLoadEvent; +import ic2.api.energy.event.EnergyTileSourceEvent; +import ic2.api.energy.event.EnergyTileUnloadEvent; +import ic2.api.energy.tile.IEnergySink; +import ic2.api.energy.tile.IEnergySource; +import ic2.api.energy.tile.IEnergyTile; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.common.MinecraftForge; +import universalelectricity.core.electricity.ElectricityPack; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.tile.TileEntityElectrical; +import buildcraft.api.power.IPowerReceptor; +import buildcraft.api.power.PowerHandler; +import buildcraft.api.power.PowerHandler.PowerReceiver; +import buildcraft.api.power.PowerHandler.Type; + +/** + * A universal electricity tile used for tiles that consume or produce electricity. + * + * Extend this class or use as a reference for your own implementation of compatible electrical + * tiles. + * + * @author micdoodle8, Calclavia + * + */ +public abstract class TileEntityUniversalElectrical extends TileEntityElectrical implements IEnergySink, IEnergySource, IPowerReceptor +{ + protected boolean isAddedToEnergyNet; + public PowerHandler bcPowerHandler; + public Type bcBlockType = Type.MACHINE; + + public void initiate() + { + super.initiate(); + this.bcPowerHandler = new PowerHandler(this, this.bcBlockType); + this.bcPowerHandler.configure(0, 100, 0, (int) Math.ceil(this.getMaxEnergyStored() * Compatibility.BC3_RATIO)); + } + + @Override + public void updateEntity() + { + super.updateEntity(); + + // Register to the IC2 Network + if (!this.worldObj.isRemote && !this.isAddedToEnergyNet) + { + if (Compatibility.isIndustrialCraft2Loaded()) + { + MinecraftForge.EVENT_BUS.post(new EnergyTileLoadEvent(this)); + } + + this.isAddedToEnergyNet = true; + } + + this.produce(); + } + + @Override + public void produce() + { + if (!this.worldObj.isRemote) + { + for (ForgeDirection outputDirection : this.getOutputDirections()) + { + this.produceUE(outputDirection); + this.produceIC2(outputDirection); + this.produceBuildCraft(outputDirection); + } + } + + if (Compatibility.isBuildcraftLoaded()) + { + /** + * Cheat BuildCraft powerHandler and always empty energy inside of it. + */ + this.receiveElectricity(this.bcPowerHandler.getEnergyStored(), true); + this.bcPowerHandler.setEnergy(0); + } + } + + public void produceIC2(ForgeDirection outputDirection) + { + if (!this.worldObj.isRemote) + { + float provide = this.getProvide(outputDirection); + + if (this.getEnergyStored() >= provide && provide > 0) + { + if (Compatibility.isIndustrialCraft2Loaded()) + { + int ic2Provide = (int) Math.ceil(provide * Compatibility.TO_IC2_RATIO); + + EnergyTileSourceEvent event = new EnergyTileSourceEvent(this, ic2Provide); + MinecraftForge.EVENT_BUS.post(event); + this.setEnergyStored(this.getEnergyStored() - ((ic2Provide * Compatibility.IC2_RATIO) - (event.amount * Compatibility.IC2_RATIO))); + + } + } + } + } + + public void produceBuildCraft(ForgeDirection outputDirection) + { + if (!this.worldObj.isRemote) + { + float provide = this.getProvide(outputDirection); + + if (this.getEnergyStored() >= provide && provide > 0) + { + if (Compatibility.isBuildcraftLoaded()) + { + TileEntity tileEntity = new Vector3(this).modifyPositionFromSide(outputDirection).getTileEntity(this.worldObj); + + if (tileEntity instanceof IPowerReceptor) + { + PowerReceiver receiver = ((IPowerReceptor) tileEntity).getPowerReceiver(outputDirection.getOpposite()); + + if (receiver != null) + { + float bc3Provide = provide * Compatibility.TO_BC_RATIO; + float energyUsed = Math.min(receiver.receiveEnergy(this.bcBlockType, bc3Provide, outputDirection.getOpposite()), bc3Provide); + this.setEnergyStored(this.getEnergyStored() - (bc3Provide - (energyUsed * Compatibility.TO_BC_RATIO))); + } + } + } + } + } + } + + /** + * IC2 Methods + */ + @Override + public boolean acceptsEnergyFrom(TileEntity emitter, Direction direction) + { + return this.canConnect(direction.toForgeDirection()); + } + + @Override + public boolean isAddedToEnergyNet() + { + return this.isAddedToEnergyNet; + } + + @Override + public void invalidate() + { + this.unloadTileIC2(); + super.invalidate(); + } + + @Override + public void onChunkUnload() + { + this.unloadTileIC2(); + super.onChunkUnload(); + } + + private void unloadTileIC2() + { + if (this.isAddedToEnergyNet && this.worldObj != null) + { + if (Compatibility.isIndustrialCraft2Loaded()) + { + MinecraftForge.EVENT_BUS.post(new EnergyTileUnloadEvent(this)); + } + + this.isAddedToEnergyNet = false; + } + } + + @Override + public int demandsEnergy() + { + return (int) Math.ceil(this.getRequest(ForgeDirection.UNKNOWN) * Compatibility.TO_IC2_RATIO); + } + + @Override + public int injectEnergy(Direction directionFrom, int amount) + { + if (!directionFrom.toForgeDirection().equals(this.getInputDirections())) + { + return amount; + } + + float convertedEnergy = amount * Compatibility.IC2_RATIO; + + ElectricityPack toSend = ElectricityPack.getFromWatts(convertedEnergy, this.getVoltage()); + + int receive = (int) Math.floor(this.receiveElectricity(directionFrom.toForgeDirection(), toSend, true)); + + // Return the difference, since injectEnergy returns left over energy, and + // receiveElectricity returns energy used. + return (int) Math.floor(amount - receive * Compatibility.TO_IC2_RATIO); + } + + @Override + public int getMaxEnergyOutput() + { + return (int) Math.ceil(this.getProvide(ForgeDirection.UNKNOWN)); + } + + @Override + public boolean emitsEnergyTo(TileEntity receiver, Direction direction) + { + return receiver instanceof IEnergyTile && direction.toForgeDirection().equals(this.getOutputDirections()); + } + + @Override + public int getMaxSafeInput() + { + return Integer.MAX_VALUE; + } + + /** + * BuildCraft power support + */ + @Override + public PowerReceiver getPowerReceiver(ForgeDirection side) + { + return this.bcPowerHandler.getPowerReceiver(); + } + + @Override + public void doWork(PowerHandler workProvider) + { + + } + + @Override + public World getWorld() + { + return this.getWorldObj(); + } +} diff --git a/src/APIs/universalelectricity/compatibility/UniversalNetwork.java b/src/APIs/universalelectricity/compatibility/UniversalNetwork.java new file mode 100644 index 00000000..a74d41a7 --- /dev/null +++ b/src/APIs/universalelectricity/compatibility/UniversalNetwork.java @@ -0,0 +1,318 @@ +package universalelectricity.compatibility; + +import ic2.api.Direction; +import ic2.api.energy.tile.IEnergyAcceptor; +import ic2.api.energy.tile.IEnergySink; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.common.MinecraftForge; +import universalelectricity.core.block.IConductor; +import universalelectricity.core.block.IElectrical; +import universalelectricity.core.block.INetworkConnection; +import universalelectricity.core.block.INetworkProvider; +import universalelectricity.core.electricity.ElectricalEvent.ElectricityRequestEvent; +import universalelectricity.core.electricity.ElectricityPack; +import universalelectricity.core.grid.ElectricityNetwork; +import universalelectricity.core.grid.IElectricityNetwork; +import universalelectricity.core.path.Pathfinder; +import universalelectricity.core.path.PathfinderChecker; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; +import buildcraft.api.power.IPowerReceptor; +import cpw.mods.fml.common.FMLLog; + +/** + * A universal network that words with multiple energy systems. + * + * @author micdoodle8, Calclavia, Aidancbrady + * + */ +public class UniversalNetwork extends ElectricityNetwork +{ + @Override + public ElectricityPack getRequest(TileEntity... ignoreTiles) + { + List requests = new ArrayList(); + + Iterator it = this.getAcceptors().iterator(); + + while (it.hasNext()) + { + TileEntity tileEntity = it.next(); + + if (Arrays.asList(ignoreTiles).contains(tileEntity)) + { + continue; + } + + if (tileEntity instanceof IElectrical) + { + if (!tileEntity.isInvalid()) + { + if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) == tileEntity) + { + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + if (((IElectrical) tileEntity).canConnect(direction) && this.getConductors().contains(VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction))) + { + requests.add(ElectricityPack.getFromWatts(((IElectrical) tileEntity).getRequest(direction), ((IElectrical) tileEntity).getVoltage())); + } + } + continue; + } + } + } + + if (Compatibility.isIndustrialCraft2Loaded() && tileEntity instanceof IEnergySink) + { + if (!tileEntity.isInvalid()) + { + if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) == tileEntity) + { + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + if (((IEnergySink) tileEntity).acceptsEnergyFrom(VectorHelper.getTileEntityFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction), Direction.values()[(direction.ordinal() + 2) % 6]) && this.getConductors().contains(VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction))) + { + requests.add(ElectricityPack.getFromWatts(Math.min(((IEnergySink) tileEntity).demandsEnergy(), ((IEnergySink) tileEntity).getMaxSafeInput()) * Compatibility.IC2_RATIO, 120)); + } + } + + continue; + } + } + } + + if (Compatibility.isBuildcraftLoaded() && tileEntity instanceof IPowerReceptor) + { + if (!tileEntity.isInvalid()) + { + if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) == tileEntity) + { + /* + * TODO: Fix unkown direction + * + * TODO: Fix inaccurate BuildCraft request calculation. + */ + requests.add(ElectricityPack.getFromWatts(((IPowerReceptor) tileEntity).getPowerReceiver(ForgeDirection.UNKNOWN).getActivationEnergy() * Compatibility.BC3_RATIO, 120)); + continue; + } + } + } + } + + ElectricityPack mergedPack = ElectricityPack.merge(requests); + ElectricityRequestEvent evt = new ElectricityRequestEvent(mergedPack, ignoreTiles); + MinecraftForge.EVENT_BUS.post(evt); + return mergedPack; + } + + @Override + public void refresh() + { + this.electricalTiles.clear(); + + try + { + Iterator it = this.getConductors().iterator(); + + while (it.hasNext()) + { + IConductor conductor = it.next(); + + if (conductor == null) + { + it.remove(); + } + else if (((TileEntity) conductor).isInvalid()) + { + it.remove(); + } + else + { + conductor.setNetwork(this); + } + + for (int i = 0; i < conductor.getAdjacentConnections().length; i++) + { + TileEntity acceptor = conductor.getAdjacentConnections()[i]; + + if (!(acceptor instanceof IConductor)) + { + if (acceptor instanceof IElectrical) + { + ArrayList possibleDirections = null; + + if (this.electricalTiles.containsKey(acceptor)) + { + possibleDirections = this.electricalTiles.get(acceptor); + } + else + { + possibleDirections = new ArrayList(); + } + + if (((IElectrical) acceptor).canConnect(ForgeDirection.getOrientation(i)) && this.getConductors().contains(VectorHelper.getConnectorFromSide(acceptor.worldObj, new Vector3(acceptor), ForgeDirection.getOrientation(i)))) + { + possibleDirections.add(ForgeDirection.getOrientation(i)); + } + + this.electricalTiles.put(acceptor, possibleDirections); + continue; + } + + if (Compatibility.isIndustrialCraft2Loaded() && acceptor instanceof IEnergyAcceptor) + { + ArrayList possibleDirections = null; + + if (this.electricalTiles.containsKey(acceptor)) + { + possibleDirections = this.electricalTiles.get(acceptor); + } + else + { + possibleDirections = new ArrayList(); + } + + if (((IEnergyAcceptor) acceptor).acceptsEnergyFrom(VectorHelper.getTileEntityFromSide(acceptor.worldObj, new Vector3(acceptor), ForgeDirection.getOrientation(i)), Direction.values()[(i + 2) % 6]) && this.getConductors().contains(VectorHelper.getConnectorFromSide(acceptor.worldObj, new Vector3(acceptor), ForgeDirection.getOrientation(i)))) + { + possibleDirections.add(ForgeDirection.getOrientation(i)); + } + + this.electricalTiles.put(acceptor, possibleDirections); + continue; + } + + if (Compatibility.isBuildcraftLoaded() && acceptor instanceof IPowerReceptor) + { + ArrayList possibleDirections = null; + + if (this.electricalTiles.containsKey(acceptor)) + { + possibleDirections = this.electricalTiles.get(acceptor); + } + else + { + possibleDirections = new ArrayList(); + } + + if (this.getConductors().contains(VectorHelper.getConnectorFromSide(acceptor.worldObj, new Vector3(acceptor), ForgeDirection.getOrientation(i)))) + { + possibleDirections.add(ForgeDirection.getOrientation(i)); + } + + this.electricalTiles.put(acceptor, possibleDirections); + continue; + } + } + } + } + } + catch (Exception e) + { + FMLLog.severe("Universal Electricity: Failed to refresh conductor."); + e.printStackTrace(); + } + } + + @Override + public void merge(IElectricityNetwork network) + { + if (network != null && network != this) + { + UniversalNetwork newNetwork = new UniversalNetwork(); + newNetwork.getConductors().addAll(this.getConductors()); + newNetwork.getConductors().addAll(network.getConductors()); + newNetwork.refresh(); + } + } + + @Override + public void split(IConductor splitPoint) + { + if (splitPoint instanceof TileEntity) + { + this.getConductors().remove(splitPoint); + + /** + * Loop through the connected blocks and attempt to see if there are connections between + * the two points elsewhere. + */ + TileEntity[] connectedBlocks = splitPoint.getAdjacentConnections(); + + for (int i = 0; i < connectedBlocks.length; i++) + { + TileEntity connectedBlockA = connectedBlocks[i]; + + if (connectedBlockA instanceof INetworkConnection) + { + for (int ii = 0; ii < connectedBlocks.length; ii++) + { + final TileEntity connectedBlockB = connectedBlocks[ii]; + + if (connectedBlockA != connectedBlockB && connectedBlockB instanceof INetworkConnection) + { + Pathfinder finder = new PathfinderChecker(((TileEntity) splitPoint).worldObj, (INetworkConnection) connectedBlockB, splitPoint); + finder.init(new Vector3(connectedBlockA)); + + if (finder.results.size() > 0) + { + /** + * The connections A and B are still intact elsewhere. Set all + * references of wire connection into one network. + */ + + for (Vector3 node : finder.closedSet) + { + TileEntity nodeTile = node.getTileEntity(((TileEntity) splitPoint).worldObj); + + if (nodeTile instanceof INetworkProvider) + { + if (nodeTile != splitPoint) + { + ((INetworkProvider) nodeTile).setNetwork(this); + } + } + } + } + else + { + /** + * The connections A and B are not connected anymore. Give both of + * them a new network. + */ + IElectricityNetwork newNetwork = new UniversalNetwork(); + + for (Vector3 node : finder.closedSet) + { + TileEntity nodeTile = node.getTileEntity(((TileEntity) splitPoint).worldObj); + + if (nodeTile instanceof INetworkProvider) + { + if (nodeTile != splitPoint) + { + newNetwork.getConductors().add((IConductor) nodeTile); + } + } + } + + newNetwork.refresh(); + } + } + } + } + } + } + } + + @Override + public String toString() + { + return "UniversalNetwork[" + this.hashCode() + "|Wires:" + this.getConductors().size() + "|Acceptors:" + this.electricalTiles.size() + "]"; + } +} diff --git a/src/APIs/universalelectricity/core/UniversalElectricity.java b/src/APIs/universalelectricity/core/UniversalElectricity.java new file mode 100644 index 00000000..a2016d70 --- /dev/null +++ b/src/APIs/universalelectricity/core/UniversalElectricity.java @@ -0,0 +1,83 @@ +package universalelectricity.core; + +import java.io.File; + +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; +import net.minecraftforge.common.Configuration; +import net.minecraftforge.common.MinecraftForge; +import cpw.mods.fml.common.Loader; + +/** + * General Universal Electricity class. + * + * @author Calclavia + * + */ +public class UniversalElectricity +{ + /** + * The version of the Universal Electricity API. + */ + public static final String MAJOR_VERSION = "@MAJOR@"; + public static final String MINOR_VERSION = "@MINOR@"; + public static final String REVISION_VERSION = "@REVIS@"; + public static final String BUILD_VERSION = "@BUILD@"; + public static final String VERSION = MAJOR_VERSION + "." + MINOR_VERSION + "." + REVISION_VERSION; + + /** + * The Universal Electricity configuration file. + */ + public static final Configuration CONFIGURATION = new Configuration(new File(Loader.instance().getConfigDir(), "UniversalElectricity.cfg")); + + /** + * Is Universal Electricity currently being voltage sensitive? If so, all machines should + * explode under high voltage and react to different amounts of voltage differently. + */ + public static boolean isVoltageSensitive = false; + + /** + * Set this value to true if your mod contains and has the ability to transfer electricity via + * the ElectricityNetwork. Examples would be a mod that adds any sort of wire. This value will + * be true as long as there is a way to conduct electricity. + */ + @Deprecated + public static boolean isNetworkActive = false; + + /** + * A general material that can be used by machines. Breakable by hand, suitable for machines. + */ + public static final Material machine = new Material(MapColor.ironColor); + + private static boolean INIT = false; + + static + { + initiate(); + } + + public static void initiate() + { + if (!INIT) + { + /** + * Loads the configuration and sets all the values. + */ + CONFIGURATION.load(); + isVoltageSensitive = CONFIGURATION.get("Compatiblity", "Is Voltage Sensitive", isVoltageSensitive).getBoolean(isVoltageSensitive); + isNetworkActive = CONFIGURATION.get("Compatiblity", "Is Network Active", isNetworkActive).getBoolean(isNetworkActive); + CONFIGURATION.save(); + + try + { + MinecraftForge.EVENT_BUS.register(Class.forName("universalelectricity.core.electricity.ElectricityHelper").newInstance()); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + INIT = true; + } +} diff --git a/src/APIs/universalelectricity/core/block/IConductor.java b/src/APIs/universalelectricity/core/block/IConductor.java new file mode 100644 index 00000000..3adc83a1 --- /dev/null +++ b/src/APIs/universalelectricity/core/block/IConductor.java @@ -0,0 +1,17 @@ +package universalelectricity.core.block; + +public interface IConductor extends INetworkProvider, INetworkConnection +{ + /** + * Gets the resistance of the conductor. Used to calculate energy loss. A higher resistance + * means a higher energy loss. + * + * @return The amount of resistance in Ohms. + */ + public float getResistance(); + + /** + * @return The maximum amount of amps this conductor can handle before melting down. + */ + public float getCurrentCapacity(); +} diff --git a/src/APIs/universalelectricity/core/block/IConnector.java b/src/APIs/universalelectricity/core/block/IConnector.java new file mode 100644 index 00000000..c2f8f8ba --- /dev/null +++ b/src/APIs/universalelectricity/core/block/IConnector.java @@ -0,0 +1,18 @@ +package universalelectricity.core.block; + +import net.minecraftforge.common.ForgeDirection; + +/** + * Applied to TileEntities that can connect to an electrical network. + * + * @author Calclavia + * + */ +public interface IConnector +{ + + /** + * @return If the connection is possible. + */ + public boolean canConnect(ForgeDirection direction); +} diff --git a/src/APIs/universalelectricity/core/block/IElectrical.java b/src/APIs/universalelectricity/core/block/IElectrical.java new file mode 100644 index 00000000..7c4fe75c --- /dev/null +++ b/src/APIs/universalelectricity/core/block/IElectrical.java @@ -0,0 +1,53 @@ +package universalelectricity.core.block; + +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.electricity.ElectricityPack; + +/** + * Applied to all TileEntities that can interact with electricity. + * + * @author Calclavia, King_Lemming + * + */ +public interface IElectrical extends IConnector +{ + /** + * Adds electricity to an block. Returns the quantity of electricity that was accepted. This + * should always return 0 if the block cannot be externally charged. + * + * @param from Orientation the electricity is sent in from. + * @param receive Maximum amount of electricity to be sent into the block. + * @param doReceive If false, the charge will only be simulated. + * @return Amount of energy that was accepted by the block. + */ + public float receiveElectricity(ForgeDirection from, ElectricityPack receive, boolean doReceive); + + /** + * Adds electricity to an block. Returns the ElectricityPack, the electricity provided. This + * should always return null if the block cannot be externally discharged. + * + * @param from Orientation the electricity is requested from. + * @param energy Maximum amount of energy to be sent into the block. + * @param doReceive If false, the charge will only be simulated. + * @return Amount of energy that was given out by the block. + */ + public ElectricityPack provideElectricity(ForgeDirection from, ElectricityPack request, boolean doProvide); + + /** + * @return How much energy does this TileEntity want? + */ + public float getRequest(ForgeDirection direction); + + /** + * @return How much energy does this TileEntity want to provide? + */ + public float getProvide(ForgeDirection direction); + + /** + * Gets the voltage of this TileEntity. + * + * @return The amount of volts. E.g 120v or 240v + */ + public float getVoltage(); + +} diff --git a/src/APIs/universalelectricity/core/block/IElectricalStorage.java b/src/APIs/universalelectricity/core/block/IElectricalStorage.java new file mode 100644 index 00000000..758c34db --- /dev/null +++ b/src/APIs/universalelectricity/core/block/IElectricalStorage.java @@ -0,0 +1,24 @@ +package universalelectricity.core.block; + +/** + * This interface is to be applied to all TileEntities which stores electricity within them. + * + * @author Calclavia + */ +public interface IElectricalStorage +{ + /** + * Sets the amount of joules this unit has stored. + */ + public void setEnergyStored(float energy); + + /** + * * @return Get the amount of energy currently stored in the block. + */ + public float getEnergyStored(); + + /** + * @return Get the max amount of energy that can be stored in the block. + */ + public float getMaxEnergyStored(); +} diff --git a/src/APIs/universalelectricity/core/block/INetworkConnection.java b/src/APIs/universalelectricity/core/block/INetworkConnection.java new file mode 100644 index 00000000..e20669e4 --- /dev/null +++ b/src/APIs/universalelectricity/core/block/INetworkConnection.java @@ -0,0 +1,26 @@ +package universalelectricity.core.block; + +import net.minecraft.tileentity.TileEntity; + +/** + * Applied to TileEntities. + * + * @author Calclavia + * + */ +public interface INetworkConnection extends IConnector +{ + + /** + * Gets a list of all the connected TileEntities that this conductor is connected to. The + * array's length should be always the 6 adjacent wires. + * + * @return + */ + public TileEntity[] getAdjacentConnections(); + + /** + * Refreshes the conductor + */ + public void refresh(); +} diff --git a/src/APIs/universalelectricity/core/block/INetworkProvider.java b/src/APIs/universalelectricity/core/block/INetworkProvider.java new file mode 100644 index 00000000..1e2a6c44 --- /dev/null +++ b/src/APIs/universalelectricity/core/block/INetworkProvider.java @@ -0,0 +1,16 @@ +package universalelectricity.core.block; + +import universalelectricity.core.grid.IElectricityNetwork; + +/** + * Applied to TileEntities that has an instance of an electricity network. + * + * @author Calclavia + * + */ +public interface INetworkProvider +{ + public IElectricityNetwork getNetwork(); + + public void setNetwork(IElectricityNetwork network); +} diff --git a/src/APIs/universalelectricity/core/electricity/ElectricalEvent.java b/src/APIs/universalelectricity/core/electricity/ElectricalEvent.java new file mode 100644 index 00000000..35b9a296 --- /dev/null +++ b/src/APIs/universalelectricity/core/electricity/ElectricalEvent.java @@ -0,0 +1,61 @@ +package universalelectricity.core.electricity; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.event.Cancelable; +import net.minecraftforge.event.Event; +import universalelectricity.core.block.IElectrical; + +public class ElectricalEvent extends Event +{ + /** + * Call this to have your TileEntity produce power into the network. + * + * @author Calclavia + * + */ + @Cancelable + public static class ElectricityProduceEvent extends ElectricalEvent + { + public World world; + public IElectrical tileEntity; + + public ElectricityProduceEvent(IElectrical tileEntity) + { + this.tileEntity = tileEntity; + this.world = ((TileEntity) this.tileEntity).worldObj; + } + } + + /** + * Internal Events + * + * @author Calclavia + * + */ + @Cancelable + public static class ElectricityProductionEvent extends ElectricalEvent + { + public ElectricityPack electricityPack; + public TileEntity[] ignoreTiles; + + public ElectricityProductionEvent(ElectricityPack electricityPack, TileEntity... ignoreTiles) + { + this.electricityPack = electricityPack; + this.ignoreTiles = ignoreTiles; + } + } + + public static class ElectricityRequestEvent extends ElectricalEvent + { + public ElectricityPack electricityPack; + public TileEntity[] ignoreTiles; + + public ElectricityRequestEvent(ElectricityPack electricityPack, TileEntity... ignoreTiles) + { + this.electricityPack = electricityPack; + this.ignoreTiles = ignoreTiles; + } + } + +} diff --git a/src/APIs/universalelectricity/core/electricity/ElectricityDisplay.java b/src/APIs/universalelectricity/core/electricity/ElectricityDisplay.java new file mode 100644 index 00000000..56a20b4d --- /dev/null +++ b/src/APIs/universalelectricity/core/electricity/ElectricityDisplay.java @@ -0,0 +1,176 @@ +package universalelectricity.core.electricity; + +/** + * An easy way to display information on electricity for the client. + * + * @author Calclavia + */ + +public class ElectricityDisplay +{ + /** + * Universal Electricity's units are in KILOJOULES, KILOWATTS and KILOVOLTS. Try to make your + * energy ratio as close to real life as possible. + * + */ + public static enum ElectricUnit + { + AMPERE("Amp", "I"), AMP_HOUR("Amp Hour", "Ah"), VOLTAGE("Volt", "V"), WATT("Watt", "W"), + WATT_HOUR("Watt Hour", "Wh"), RESISTANCE("Ohm", "R"), CONDUCTANCE("Siemen", "S"), + JOULES("Joule", "J"); + + public String name; + public String symbol; + + private ElectricUnit(String name, String symbol) + { + this.name = name; + this.symbol = symbol; + } + + public String getPlural() + { + return this.name + "s"; + } + } + + public static enum MeasurementUnit + { + MICRO("Micro", "mi", 0.000001), MILLI("Milli", "m", 0.001), KILO("Kilo", "k", 1000), + MEGA("Mega", "M", 1000000), GIGA("Giga", "G", 1000000000); + + public String name; + public String symbol; + public double value; + + private MeasurementUnit(String name, String symbol, double value) + { + this.name = name; + this.symbol = symbol; + this.value = value; + } + + public String getName(boolean isSymbol) + { + if (isSymbol) + { + return symbol; + } + else + { + return name; + } + } + + public double process(double value) + { + return value / this.value; + } + } + + /** + * By default, mods should store energy in Kilo-Joules, hence a multiplier of 1/1000. + */ + public static String getDisplay(float value, ElectricUnit unit, int decimalPlaces, boolean isShort) + { + return getDisplay(value, unit, decimalPlaces, isShort, 1000); + } + + /** + * Displays the unit as text. Works only for positive numbers. + */ + public static String getDisplay(float value, ElectricUnit unit, int decimalPlaces, boolean isShort, float multiplier) + { + value *= multiplier; + + String unitName = unit.name; + + if (isShort) + { + unitName = unit.symbol; + } + else if (value > 1) + { + unitName = unit.getPlural(); + } + + if (value == 0) + { + return value + " " + unitName; + } + + if (value <= MeasurementUnit.MILLI.value) + { + return roundDecimals(MeasurementUnit.MICRO.process(value), decimalPlaces) + " " + MeasurementUnit.MICRO.getName(isShort) + unitName; + } + + if (value < 1) + { + return roundDecimals(MeasurementUnit.MILLI.process(value), decimalPlaces) + " " + MeasurementUnit.MILLI.getName(isShort) + unitName; + } + + if (value > MeasurementUnit.MEGA.value) + { + return roundDecimals(MeasurementUnit.MEGA.process(value), decimalPlaces) + " " + MeasurementUnit.MEGA.getName(isShort) + unitName; + } + + if (value > MeasurementUnit.KILO.value) + { + return roundDecimals(MeasurementUnit.KILO.process(value), decimalPlaces) + " " + MeasurementUnit.KILO.getName(isShort) + unitName; + } + + return roundDecimals(value, decimalPlaces) + " " + unitName; + } + + public static String getDisplay(float value, ElectricUnit unit) + { + return getDisplay(value, unit, 2, false); + } + + public static String getDisplayShort(float value, ElectricUnit unit) + { + return getDisplay(value, unit, 2, true); + } + + public static String getDisplayShort(float value, ElectricUnit unit, int decimalPlaces) + { + return getDisplay(value, unit, decimalPlaces, true); + } + + public static String getDisplaySimple(float value, ElectricUnit unit, int decimalPlaces) + { + if (value > 1) + { + if (decimalPlaces < 1) + { + return (int) value + " " + unit.getPlural(); + } + + return roundDecimals(value, decimalPlaces) + " " + unit.getPlural(); + } + + if (decimalPlaces < 1) + { + return (int) value + " " + unit.name; + } + + return roundDecimals(value, decimalPlaces) + " " + unit.name; + } + + /** + * Rounds a number to a specific number place places + * + * @param The number + * @return The rounded number + */ + public static double roundDecimals(double d, int decimalPlaces) + { + int j = (int) (d * Math.pow(10, decimalPlaces)); + return j / Math.pow(10, decimalPlaces); + } + + public static double roundDecimals(double d) + { + return roundDecimals(d, 2); + } +} diff --git a/src/APIs/universalelectricity/core/electricity/ElectricityHelper.java b/src/APIs/universalelectricity/core/electricity/ElectricityHelper.java new file mode 100644 index 00000000..e8b8b7eb --- /dev/null +++ b/src/APIs/universalelectricity/core/electricity/ElectricityHelper.java @@ -0,0 +1,206 @@ +package universalelectricity.core.electricity; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.event.ForgeSubscribe; +import universalelectricity.core.block.IConnector; +import universalelectricity.core.block.INetworkProvider; +import universalelectricity.core.electricity.ElectricalEvent.ElectricityProduceEvent; +import universalelectricity.core.grid.IElectricityNetwork; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; + +/** + * A helper class that provides additional useful functions to interact with the ElectricityNetwork + * + * @author Calclavia + * + */ +public class ElectricityHelper +{ + @ForgeSubscribe + public void onProduce(ElectricityProduceEvent evt) + { + // Needs work with shuffling to be able to evenly distribute to all + // connected networks + // instead of just defaulting to one of them. + Vector3 position = new Vector3((TileEntity) evt.tileEntity); + HashMap networks = new HashMap(); + + for (ForgeDirection direction : getDirections((TileEntity) evt.tileEntity)) + { + IElectricityNetwork network = getNetworkFromTileEntity(VectorHelper.getTileEntityFromSide(evt.world, position, direction), direction.getOpposite()); + + if (network != null) + { + networks.put(network, direction); + ElectricityPack provided = evt.tileEntity.provideElectricity(direction, network.getRequest((TileEntity) evt.tileEntity), true); + + if (provided != null && provided.getWatts() > 0) + { + network.produce(provided, (TileEntity) evt.tileEntity); + } + } + } + + /* + * ElectricityPack request = this.getNetwork().getRequest(this); + * + * if (request.getWatts() > 0) { List providedPacks = new + * ArrayList(); List tileEntities = new + * ArrayList(); + * + * for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { Vector3 position = new + * Vector3(this).modifyPositionFromSide(direction); TileEntity tileEntity = + * position.getTileEntity(this.worldObj); + * + * if (tileEntity instanceof IElectrical) { tileEntities.add(tileEntity); IElectrical + * electrical = (IElectrical) tileEntity; + * + * if (electrical.canConnect(direction.getOpposite())) { if + * (electrical.getProvide(direction.getOpposite()) > 0) { providedPacks.add + * (electrical.provideElectricity(direction.getOpposite(), request, true)); } } } } + * + * ElectricityPack mergedPack = ElectricityPack.merge(providedPacks); + * + * if (mergedPack.getWatts() > 0) { this.getNetwork().produce(mergedPack, + * tileEntities.toArray(new TileEntity[0])); } } + */ + } + + public static EnumSet getDirections(TileEntity tileEntity) + { + EnumSet possibleSides = EnumSet.noneOf(ForgeDirection.class); + + if (tileEntity instanceof IConnector) + { + for (int i = 0; i < 6; i++) + { + ForgeDirection direction = ForgeDirection.getOrientation(i); + if (((IConnector) tileEntity).canConnect(direction)) + { + possibleSides.add(direction); + } + } + } + + return possibleSides; + } + + @Deprecated + public static ElectricityPack produceFromMultipleSides(TileEntity tileEntity, ElectricityPack electricityPack) + { + return ElectricityHelper.produceFromMultipleSides(tileEntity, getDirections(tileEntity), electricityPack); + } + + /** + * Produces electricity from all specified sides. Use this as a simple helper function. + * + * @param tileEntity - The TileEntity consuming the electricity. + * @param approachDirection - The sides in which you can connect to. + * @param producePack - The amount of electricity to be produced. + * @return What remained in the electricity pack. + */ + @Deprecated + public static ElectricityPack produceFromMultipleSides(TileEntity tileEntity, EnumSet approachingDirection, ElectricityPack producingPack) + { + ElectricityPack remainingElectricity = producingPack.clone(); + + if (tileEntity != null && approachingDirection != null) + { + final Set connectedNetworks = ElectricityHelper.getNetworksFromMultipleSides(tileEntity, approachingDirection); + + if (connectedNetworks.size() > 0) + { + /** + * Requests an even amount of electricity from all sides. + */ + float wattsPerSide = (producingPack.getWatts() / connectedNetworks.size()); + float voltage = producingPack.voltage; + + for (IElectricityNetwork network : connectedNetworks) + { + if (wattsPerSide > 0 && producingPack.getWatts() > 0) + { + float amperes = Math.min(wattsPerSide / voltage, network.getRequest(tileEntity).getWatts() / voltage); + + if (amperes > 0) + { + network.produce(new ElectricityPack(amperes, voltage)); + remainingElectricity.amperes -= amperes; + } + } + } + } + } + + return remainingElectricity; + } + + /** + * @param tileEntity - The TileEntity's sides. + * @param approachingDirection - The directions that can be connected. + * @return A list of networks from all specified sides. There will be no repeated + * ElectricityNetworks and it will never return null. + */ + public static Set getNetworksFromMultipleSides(TileEntity tileEntity, EnumSet approachingDirection) + { + final Set connectedNetworks = new HashSet(); + + for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) + { + if (approachingDirection.contains(side)) + { + Vector3 position = new Vector3(tileEntity); + position.modifyPositionFromSide(side); + + TileEntity outputConductor = position.getTileEntity(tileEntity.worldObj); + IElectricityNetwork electricityNetwork = ElectricityHelper.getNetworkFromTileEntity(outputConductor, side); + + if (electricityNetwork != null) + { + connectedNetworks.add(electricityNetwork); + } + } + } + + return connectedNetworks; + } + + /** + * Tries to find the electricity network based in a tile entity and checks to see if it is a + * conductor. All machines should use this function to search for a connecting conductor around + * it. + * + * @param conductor - The TileEntity conductor + * @param approachDirection - The direction you are approaching this wire from. + * @return The ElectricityNetwork or null if not found. + */ + public static IElectricityNetwork getNetworkFromTileEntity(TileEntity tileEntity, ForgeDirection approachDirection) + { + if (tileEntity != null) + { + if (tileEntity instanceof INetworkProvider) + { + if (tileEntity instanceof IConnector) + { + if (((IConnector) tileEntity).canConnect(approachDirection.getOpposite())) + { + return ((INetworkProvider) tileEntity).getNetwork(); + } + } + else + { + return ((INetworkProvider) tileEntity).getNetwork(); + } + } + } + + return null; + } +} diff --git a/src/APIs/universalelectricity/core/electricity/ElectricityPack.java b/src/APIs/universalelectricity/core/electricity/ElectricityPack.java new file mode 100644 index 00000000..0bf6fded --- /dev/null +++ b/src/APIs/universalelectricity/core/electricity/ElectricityPack.java @@ -0,0 +1,196 @@ +package universalelectricity.core.electricity; + +import java.util.List; + +/** + * A simple way to store electrical data. + * + * @author Calclavia + * + */ +public class ElectricityPack implements Cloneable +{ + public float amperes; + public float voltage; + + public ElectricityPack(float amperes, float voltage) + { + this.amperes = amperes; + this.voltage = voltage; + } + + public ElectricityPack() + { + this(0, 0); + } + + public static ElectricityPack getFromWatts(float watts, float voltage) + { + return new ElectricityPack(watts / voltage, voltage); + } + + /** + * Merges multiple ElectricityPacks together to form one with an average voltage. + */ + public static ElectricityPack merge(ElectricityPack... packs) + { + float totalEnergy = 0; + float totalVoltage = 0; + + for (ElectricityPack pack : packs) + { + totalEnergy += pack.getWatts(); + totalVoltage += pack.voltage; + } + + if (totalEnergy <= 0 || totalVoltage <= 0) + { + return new ElectricityPack(); + } + + return ElectricityPack.getFromWatts(totalEnergy, totalVoltage / packs.length); + } + + public static ElectricityPack merge(List providedPacks) + { + return merge(providedPacks.toArray(new ElectricityPack[0])); + } + + /** + * @return Returns the ElectricityPack with the largest amount of energy. + */ + public static ElectricityPack max(ElectricityPack... packs) + { + ElectricityPack optimalPack = null; + + for (ElectricityPack pack : packs) + { + if (optimalPack == null || (optimalPack != null && pack.getWatts() > optimalPack.getWatts())) + { + optimalPack = pack; + } + } + + return optimalPack; + } + + /** + * @return Returns the ElectricityPack with the smallest amount of energy. + */ + public static ElectricityPack min(ElectricityPack... packs) + { + ElectricityPack optimalPack = null; + + for (ElectricityPack pack : packs) + { + if (optimalPack == null || (optimalPack != null && pack.getWatts() < optimalPack.getWatts())) + { + optimalPack = pack; + } + } + + return optimalPack; + } + + public float getWatts() + { + return getWatts(amperes, voltage); + } + + public float getConductance() + { + return getConductance(amperes, voltage); + } + + public float getResistance() + { + return getResistance(amperes, voltage); + } + + public static float getJoules(float watts, float seconds) + { + return watts * seconds; + } + + public static float getJoules(float amps, float voltage, float seconds) + { + return amps * voltage * seconds; + } + + public static float getWattsFromJoules(float joules, float seconds) + { + return joules / seconds; + } + + public static float getAmps(float watts, float voltage) + { + return watts / voltage; + } + + public static float getAmps(float ampHours) + { + return ampHours * 3600; + } + + public static float getAmpsFromWattHours(float wattHours, float voltage) + { + return getWatts(wattHours) / voltage; + } + + public static float getWattHoursFromAmpHours(float ampHours, float voltage) + { + return ampHours * voltage; + } + + public static float getAmpHours(float amps) + { + return amps / 3600; + } + + public static float getWatts(float amps, float voltage) + { + return amps * voltage; + } + + public static float getWatts(float wattHours) + { + return wattHours * 3600; + } + + public static float getWattHours(float watts) + { + return watts / 3600; + } + + public static float getWattHours(float amps, float voltage) + { + return getWattHours(getWatts(amps, voltage)); + } + + public static float getResistance(float amps, float voltage) + { + return voltage / amps; + } + + public static float getConductance(float amps, float voltage) + { + return amps / voltage; + } + + @Override + public String toString() + { + return "ElectricityPack [Amps:" + this.amperes + " Volts:" + this.voltage + "]"; + } + + @Override + public ElectricityPack clone() + { + return new ElectricityPack(this.amperes, this.voltage); + } + + public boolean isEqual(ElectricityPack electricityPack) + { + return this.amperes == electricityPack.amperes && this.voltage == electricityPack.voltage; + } +} diff --git a/src/APIs/universalelectricity/core/electricity/NetworkLoader.java b/src/APIs/universalelectricity/core/electricity/NetworkLoader.java new file mode 100644 index 00000000..08560cfc --- /dev/null +++ b/src/APIs/universalelectricity/core/electricity/NetworkLoader.java @@ -0,0 +1,64 @@ +package universalelectricity.core.electricity; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import universalelectricity.core.block.IConductor; +import universalelectricity.core.grid.IElectricityNetwork; +import cpw.mods.fml.common.FMLLog; + +@SuppressWarnings("unchecked") +public class NetworkLoader +{ + /** + * The default IElectricityNetwork used for primary electrical networks. + */ + public static Class NETWORK_CLASS; + public static final Set> NETWORK_CLASS_REGISTRY = new HashSet>(); + + static + { + setNetworkClass("universalelectricity.core.grid.ElectricityNetwork"); + } + + public static void setNetworkClass(Class networkClass) + { + NETWORK_CLASS_REGISTRY.add(networkClass); + NETWORK_CLASS = networkClass; + } + + public static void setNetworkClass(String className) + { + try + { + setNetworkClass((Class) Class.forName(className)); + } + catch (Exception e) + { + FMLLog.severe("Universal Electricity: Failed to set network class with name " + className); + e.printStackTrace(); + } + } + + public static IElectricityNetwork getNewNetwork(IConductor... conductors) + { + try + { + IElectricityNetwork network = NETWORK_CLASS.newInstance(); + network.getConductors().addAll(Arrays.asList(conductors)); + return network; + } + catch (InstantiationException e) + { + e.printStackTrace(); + } + catch (IllegalAccessException e) + { + e.printStackTrace(); + } + + return null; + } + +} \ No newline at end of file diff --git a/src/APIs/universalelectricity/core/grid/ElectricityNetwork.java b/src/APIs/universalelectricity/core/grid/ElectricityNetwork.java new file mode 100644 index 00000000..ef695f12 --- /dev/null +++ b/src/APIs/universalelectricity/core/grid/ElectricityNetwork.java @@ -0,0 +1,353 @@ +package universalelectricity.core.grid; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.common.MinecraftForge; +import universalelectricity.core.block.IConductor; +import universalelectricity.core.block.IConnector; +import universalelectricity.core.block.IElectrical; +import universalelectricity.core.block.INetworkConnection; +import universalelectricity.core.block.INetworkProvider; +import universalelectricity.core.electricity.ElectricalEvent.ElectricityProductionEvent; +import universalelectricity.core.electricity.ElectricalEvent.ElectricityRequestEvent; +import universalelectricity.core.electricity.ElectricityPack; +import universalelectricity.core.path.Pathfinder; +import universalelectricity.core.path.PathfinderChecker; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; +import cpw.mods.fml.common.FMLLog; + +/** + * An Electrical Network specifies a wire connection. Each wire connection line will have its own + * electrical network. + * + * !! Do not include this class if you do not intend to have custom wires in your mod. This will + * increase future compatibility. !! + * + * @author Calclavia + * + */ +public class ElectricityNetwork implements IElectricityNetwork +{ + public Map> electricalTiles = new HashMap>(); + + private final Set conductors = new HashSet(); + + @Override + public float produce(ElectricityPack electricity, TileEntity... ignoreTiles) + { + ElectricityProductionEvent evt = new ElectricityProductionEvent(electricity, ignoreTiles); + MinecraftForge.EVENT_BUS.post(evt); + + float energy = electricity.getWatts(); + float totalEnergy = energy; + float voltage = electricity.voltage; + + if (!evt.isCanceled()) + { + Set avaliableEnergyTiles = this.getAcceptors(); + + if (!avaliableEnergyTiles.isEmpty()) + { + final float totalEnergyRequest = this.getRequest(ignoreTiles).getWatts(); + + if (totalEnergyRequest > 0) + { + for (TileEntity tileEntity : avaliableEnergyTiles) + { + if (tileEntity instanceof IElectrical && !Arrays.asList(ignoreTiles).contains(tileEntity)) + { + IElectrical electricalTile = (IElectrical) tileEntity; + + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + if (electricalTile.canConnect(direction) && this.getConductors().contains(VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction))) + { + float energyToSend = totalEnergy * (electricalTile.getRequest(direction) / totalEnergyRequest); + + if (energyToSend > 0) + { + ElectricityPack electricityToSend = ElectricityPack.getFromWatts(energyToSend, voltage); + + // Calculate energy loss caused by resistance. + float ampsReceived = electricityToSend.amperes - (electricityToSend.amperes * electricityToSend.amperes * this.getTotalResistance()) / electricityToSend.voltage; + float voltsReceived = electricityToSend.voltage - (electricityToSend.amperes * this.getTotalResistance()); + + electricityToSend = new ElectricityPack(ampsReceived, voltsReceived); + + energy -= ((IElectrical) tileEntity).receiveElectricity(direction, electricityToSend, true); + } + } + } + } + } + } + } + } + + return energy; + } + + /** + * @return How much electricity this network needs. + */ + @Override + public ElectricityPack getRequest(TileEntity... ignoreTiles) + { + List requests = new ArrayList(); + + Iterator it = this.getAcceptors().iterator(); + + while (it.hasNext()) + { + TileEntity tileEntity = it.next(); + + if (Arrays.asList(ignoreTiles).contains(tileEntity)) + { + continue; + } + + if (tileEntity instanceof IElectrical) + { + if (!tileEntity.isInvalid()) + { + if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) == tileEntity) + { + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + if (((IElectrical) tileEntity).canConnect(direction) && this.getConductors().contains(VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction))) + { + requests.add(ElectricityPack.getFromWatts(((IElectrical) tileEntity).getRequest(direction), ((IElectrical) tileEntity).getVoltage())); + continue; + } + } + } + } + } + } + + ElectricityPack mergedPack = ElectricityPack.merge(requests); + ElectricityRequestEvent evt = new ElectricityRequestEvent(mergedPack, ignoreTiles); + MinecraftForge.EVENT_BUS.post(evt); + return mergedPack; + } + + /** + * @return Returns all producers in this electricity network. + */ + @Override + public Set getAcceptors() + { + return this.electricalTiles.keySet(); + } + + /** + * @param tile The tile to get connections for + * @return The list of directions that can be connected to for the provided tile + */ + @Override + public ArrayList getPossibleDirections(TileEntity tile) + { + return this.electricalTiles.containsKey(tile) ? this.electricalTiles.get(tile) : null; + } + + /** + * This function is called to refresh all conductors in this network + */ + @Override + public void refresh() + { + this.electricalTiles.clear(); + + try + { + Iterator it = this.conductors.iterator(); + + while (it.hasNext()) + { + IConductor conductor = it.next(); + + if (conductor == null) + { + it.remove(); + } + else if (((TileEntity) conductor).isInvalid()) + { + it.remove(); + } + else + { + conductor.setNetwork(this); + } + + for (int i = 0; i < conductor.getAdjacentConnections().length; i++) + { + TileEntity acceptor = conductor.getAdjacentConnections()[i]; + + if (!(acceptor instanceof IConductor) && acceptor instanceof IConnector) + { + ArrayList possibleDirections = null; + + if (this.electricalTiles.containsKey(acceptor)) + { + possibleDirections = this.electricalTiles.get(acceptor); + } + else + { + possibleDirections = new ArrayList(); + } + + possibleDirections.add(ForgeDirection.getOrientation(i)); + + this.electricalTiles.put(acceptor, possibleDirections); + } + } + } + } + catch (Exception e) + { + FMLLog.severe("Universal Electricity: Failed to refresh conductor."); + e.printStackTrace(); + } + } + + @Override + public float getTotalResistance() + { + float resistance = 0; + + for (IConductor conductor : this.conductors) + { + resistance += conductor.getResistance(); + } + + return resistance; + } + + @Override + public float getLowestCurrentCapacity() + { + float lowestAmperage = 0; + + for (IConductor conductor : this.conductors) + { + if (lowestAmperage == 0 || conductor.getCurrentCapacity() < lowestAmperage) + { + lowestAmperage = conductor.getCurrentCapacity(); + } + } + + return lowestAmperage; + } + + @Override + public Set getConductors() + { + return this.conductors; + } + + @Override + public void merge(IElectricityNetwork network) + { + if (network != null && network != this) + { + ElectricityNetwork newNetwork = new ElectricityNetwork(); + newNetwork.getConductors().addAll(this.getConductors()); + newNetwork.getConductors().addAll(network.getConductors()); + newNetwork.refresh(); + } + } + + @Override + public void split(IConductor splitPoint) + { + if (splitPoint instanceof TileEntity) + { + this.getConductors().remove(splitPoint); + + /** + * Loop through the connected blocks and attempt to see if there are connections between + * the two points elsewhere. + */ + TileEntity[] connectedBlocks = splitPoint.getAdjacentConnections(); + + for (int i = 0; i < connectedBlocks.length; i++) + { + TileEntity connectedBlockA = connectedBlocks[i]; + + if (connectedBlockA instanceof INetworkConnection) + { + for (int ii = 0; ii < connectedBlocks.length; ii++) + { + final TileEntity connectedBlockB = connectedBlocks[ii]; + + if (connectedBlockA != connectedBlockB && connectedBlockB instanceof INetworkConnection) + { + Pathfinder finder = new PathfinderChecker(((TileEntity) splitPoint).worldObj, (INetworkConnection) connectedBlockB, splitPoint); + finder.init(new Vector3(connectedBlockA)); + + if (finder.results.size() > 0) + { + /** + * The connections A and B are still intact elsewhere. Set all + * references of wire connection into one network. + */ + + for (Vector3 node : finder.closedSet) + { + TileEntity nodeTile = node.getTileEntity(((TileEntity) splitPoint).worldObj); + + if (nodeTile instanceof INetworkProvider) + { + if (nodeTile != splitPoint) + { + ((INetworkProvider) nodeTile).setNetwork(this); + } + } + } + } + else + { + /** + * The connections A and B are not connected anymore. Give both of + * them a new network. + */ + IElectricityNetwork newNetwork = new ElectricityNetwork(); + + for (Vector3 node : finder.closedSet) + { + TileEntity nodeTile = node.getTileEntity(((TileEntity) splitPoint).worldObj); + + if (nodeTile instanceof INetworkProvider) + { + if (nodeTile != splitPoint) + { + newNetwork.getConductors().add((IConductor) nodeTile); + } + } + } + + newNetwork.refresh(); + } + } + } + } + } + } + } + + @Override + public String toString() + { + return "ElectricityNetwork[" + this.hashCode() + "|Wires:" + this.conductors.size() + "|Acceptors:" + this.electricalTiles.size() + "]"; + } +} diff --git a/src/APIs/universalelectricity/core/grid/IElectricityNetwork.java b/src/APIs/universalelectricity/core/grid/IElectricityNetwork.java new file mode 100644 index 00000000..3f6f3005 --- /dev/null +++ b/src/APIs/universalelectricity/core/grid/IElectricityNetwork.java @@ -0,0 +1,38 @@ +package universalelectricity.core.grid; + +import net.minecraft.tileentity.TileEntity; +import universalelectricity.core.block.IConductor; +import universalelectricity.core.electricity.ElectricityPack; + +/** + * The Electrical Network in interface form. + * + * @author Calclavia + * + */ +public interface IElectricityNetwork extends IGridNetwork +{ + /** + * Produces electricity in this electrical network. + * + * @return Rejected energy in Joules. + */ + public float produce(ElectricityPack electricityPack, TileEntity... ignoreTiles); + + /** + * Gets the total amount of electricity requested/needed in the electricity network. + * + * @param ignoreTiles The TileEntities to ignore during this calculation (optional). + */ + public ElectricityPack getRequest(TileEntity... ignoreTiles); + + /** + * @return The total amount of resistance of this electrical network. In Ohms. + */ + public float getTotalResistance(); + + /** + * @return The lowest amount of current (amperage) that this electrical network can tolerate. + */ + public float getLowestCurrentCapacity(); +} diff --git a/src/APIs/universalelectricity/core/grid/IGridNetwork.java b/src/APIs/universalelectricity/core/grid/IGridNetwork.java new file mode 100644 index 00000000..26d55a8e --- /dev/null +++ b/src/APIs/universalelectricity/core/grid/IGridNetwork.java @@ -0,0 +1,66 @@ +package universalelectricity.core.grid; + +import java.util.ArrayList; +import java.util.Set; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; + +/** + * Implement this in your network class/interface if you plan to have your own network defined by + * specific conductors and acceptors. + * + * @author aidancbrady + * + * @param - the class/interface Type value in which you implement this + * @param - the class/interface Type which makes up the network's conductor Set + * @param - the class/interface Type which makes up the network's acceptor Set + */ +public interface IGridNetwork +{ + /** + * Refreshes and cleans up conductor references of this network, as well as updating the + * acceptor set. + */ + public void refresh(); + + /** + * Gets the Set of conductors that make up this network. + * + * @return conductor set + */ + public Set getConductors(); + + /** + * Gets the Set of AVAILABLE acceptors in this network. Make sure this doesn't include any stray + * acceptors which cannot accept resources. + * + * @return available acceptor set + */ + public Set getAcceptors(); + + /** + * Gets the list of possible connection directions for the provided TileEntity. Tile must be in + * this network. + * + * @param tile The tile to get connections for + * @return The list of directions that can be connected to for the provided tile + */ + public ArrayList getPossibleDirections(TileEntity tile); + + /** + * Creates a new network that makes up the current network and the network defined in the + * parameters. Be sure to refresh the new network inside this method. + * + * @param network - network to merge + */ + public void merge(N network); + + /** + * Splits a network by the conductor referenced in the parameters. It will then create and + * refresh the new independent networks possibly created by this operation. + * + * @param connection + */ + public void split(C connection); +} diff --git a/src/APIs/universalelectricity/core/item/ElectricItemHelper.java b/src/APIs/universalelectricity/core/item/ElectricItemHelper.java new file mode 100644 index 00000000..ef0d9657 --- /dev/null +++ b/src/APIs/universalelectricity/core/item/ElectricItemHelper.java @@ -0,0 +1,92 @@ +package universalelectricity.core.item; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +/** + * Some helper functions for electric items. + * + * @author Calclavia + * + */ +public class ElectricItemHelper +{ + /** + * Recharges an electric item. + * + * @param joules - The joules being provided to the electric item + * @return The total amount of joules provided by the provider. + */ + public static float chargeItem(ItemStack itemStack, float joules) + { + if (itemStack != null) + { + if (itemStack.getItem() instanceof IItemElectric) + { + return ((IItemElectric) itemStack.getItem()).recharge(itemStack, Math.min(((IItemElectric) itemStack.getItem()).getTransfer(itemStack), joules), true); + } + } + + return 0; + } + + /** + * Decharges an electric item. + * + * @param joules - The joules being withdrawn from the electric item + * @return The total amount of joules the provider received. + */ + public static float dischargeItem(ItemStack itemStack, float joules) + { + if (itemStack != null) + { + if (itemStack.getItem() instanceof IItemElectric) + { + return ((IItemElectric) itemStack.getItem()).discharge(itemStack, Math.min(((IItemElectric) itemStack.getItem()).getMaxElectricityStored(itemStack), joules), true); + } + } + + return 0; + } + + /** + * Returns an uncharged version of the electric item. Use this if you want the crafting recipe + * to use a charged version of the electric item instead of an empty version of the electric + * item + * + * @return An electrical ItemStack with a specific charge. + */ + public static ItemStack getWithCharge(ItemStack itemStack, float joules) + { + if (itemStack != null) + { + if (itemStack.getItem() instanceof IItemElectric) + { + ((IItemElectric) itemStack.getItem()).setElectricity(itemStack, joules); + return itemStack; + } + } + + return itemStack; + } + + public static ItemStack getWithCharge(Item item, float joules) + { + return getWithCharge(new ItemStack(item), joules); + } + + public static ItemStack getCloneWithCharge(ItemStack itemStack, float joules) + { + return getWithCharge(itemStack.copy(), joules); + } + + public static ItemStack getUncharged(ItemStack itemStack) + { + return getWithCharge(itemStack, 0); + } + + public static ItemStack getUncharged(Item item) + { + return getUncharged(new ItemStack(item)); + } +} diff --git a/src/APIs/universalelectricity/core/item/IItemElectric.java b/src/APIs/universalelectricity/core/item/IItemElectric.java new file mode 100644 index 00000000..cf3b1cf3 --- /dev/null +++ b/src/APIs/universalelectricity/core/item/IItemElectric.java @@ -0,0 +1,56 @@ +package universalelectricity.core.item; + +import net.minecraft.item.ItemStack; + +public interface IItemElectric +{ + /** + * Adds energy to an item. Returns the quantity of energy that was accepted. This should always + * return 0 if the item cannot be externally charged. + * + * @param itemStack ItemStack to be charged. + * @param energy Maximum amount of energy to be sent into the item. + * @param doRecharge If false, the charge will only be simulated. + * @return Amount of energy that was accepted by the item. + */ + public float recharge(ItemStack itemStack, float energy, boolean doRecharge); + + /** + * Removes energy from an item. Returns the quantity of energy that was removed. This should + * always return 0 if the item cannot be externally discharged. + * + * @param itemStack ItemStack to be discharged. + * @param energy Maximum amount of energy to be removed from the item. + * @param doDischarge If false, the discharge will only be simulated. + * @return Amount of energy that was removed from the item. + */ + public float discharge(ItemStack itemStack, float energy, boolean doDischarge); + + /** + * Get the amount of energy currently stored in the item. + */ + public float getElectricityStored(ItemStack theItem); + + /** + * Get the max amount of energy that can be stored in the item. + */ + public float getMaxElectricityStored(ItemStack theItem); + + /** + * Sets the amount of energy in the ItemStack. + * + * @param itemStack - the ItemStack. + * @param joules - Amount of electrical energy. + */ + public void setElectricity(ItemStack itemStack, float joules); + + /** + * @return the energy request this ItemStack demands. + */ + public float getTransfer(ItemStack itemStack); + + /** + * @return The voltage in which this item runs on. + */ + public float getVoltage(ItemStack itemStack); +} diff --git a/src/APIs/universalelectricity/core/item/ItemElectric.java b/src/APIs/universalelectricity/core/item/ItemElectric.java new file mode 100644 index 00000000..44921494 --- /dev/null +++ b/src/APIs/universalelectricity/core/item/ItemElectric.java @@ -0,0 +1,151 @@ +package universalelectricity.core.item; + +import java.util.List; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import universalelectricity.core.electricity.ElectricityDisplay; +import universalelectricity.core.electricity.ElectricityDisplay.ElectricUnit; + +/** + * Extend from this class if your item requires electricity or to be charged. Optionally, you can + * implement IItemElectric instead. + * + * @author Calclavia + * + */ +public abstract class ItemElectric extends Item implements IItemElectric +{ + public ItemElectric(int id) + { + super(id); + this.setMaxStackSize(1); + this.setMaxDamage(100); + this.setNoRepair(); + } + + @Override + public void addInformation(ItemStack itemStack, EntityPlayer entityPlayer, List list, boolean par4) + { + String color = ""; + float joules = this.getElectricityStored(itemStack); + + if (joules <= this.getMaxElectricityStored(itemStack) / 3) + { + color = "\u00a74"; + } + else if (joules > this.getMaxElectricityStored(itemStack) * 2 / 3) + { + color = "\u00a72"; + } + else + { + color = "\u00a76"; + } + + list.add(color + ElectricityDisplay.getDisplay(joules, ElectricUnit.JOULES) + "/" + ElectricityDisplay.getDisplay(this.getMaxElectricityStored(itemStack), ElectricUnit.JOULES)); + } + + /** + * Makes sure the item is uncharged when it is crafted and not charged. Change this if you do + * not want this to happen! + */ + @Override + public void onCreated(ItemStack itemStack, World par2World, EntityPlayer par3EntityPlayer) + { + this.setElectricity(itemStack, 0); + } + + @Override + public float recharge(ItemStack itemStack, float energy, boolean doReceive) + { + float rejectedElectricity = Math.max((this.getElectricityStored(itemStack) + energy) - this.getMaxElectricityStored(itemStack), 0); + float energyToReceive = energy - rejectedElectricity; + + if (doReceive) + { + this.setElectricity(itemStack, this.getElectricityStored(itemStack) + energyToReceive); + } + + return energyToReceive; + } + + @Override + public float discharge(ItemStack itemStack, float energy, boolean doTransfer) + { + float energyToTransfer = Math.min(this.getElectricityStored(itemStack), energy); + + if (doTransfer) + { + this.setElectricity(itemStack, this.getElectricityStored(itemStack) - energyToTransfer); + } + + return energyToTransfer; + } + + @Override + public float getVoltage(ItemStack itemStack) + { + return 120; + } + + @Override + public void setElectricity(ItemStack itemStack, float joules) + { + // Saves the frequency in the ItemStack + if (itemStack.getTagCompound() == null) + { + itemStack.setTagCompound(new NBTTagCompound()); + } + + float electricityStored = Math.max(Math.min(joules, this.getMaxElectricityStored(itemStack)), 0); + itemStack.getTagCompound().setFloat("electricity", electricityStored); + + /** + * Sets the damage as a percentage to render the bar properly. + */ + itemStack.setItemDamage((int) (100 - (electricityStored / getMaxElectricityStored(itemStack)) * 100)); + } + + @Override + public float getTransfer(ItemStack itemStack) + { + return this.getMaxElectricityStored(itemStack) - this.getElectricityStored(itemStack); + } + + /** + * This function is called to get the electricity stored in this item + * + * @return - The amount of electricity stored in watts + */ + @Override + public float getElectricityStored(ItemStack itemStack) + { + if (itemStack.getTagCompound() == null) + { + return 0; + } + + float electricityStored = itemStack.getTagCompound().getFloat("electricity"); + + /** + * Sets the damage as a percentage to render the bar properly. + */ + itemStack.setItemDamage((int) (100 - (electricityStored / getMaxElectricityStored(itemStack)) * 100)); + return electricityStored; + } + + @Override + public void getSubItems(int par1, CreativeTabs par2CreativeTabs, List par3List) + { + // Add an uncharged version of the electric item + par3List.add(ElectricItemHelper.getUncharged(new ItemStack(this))); + // Add an electric item to the creative list that is fully charged + ItemStack chargedItem = new ItemStack(this); + par3List.add(ElectricItemHelper.getWithCharge(chargedItem, this.getMaxElectricityStored(chargedItem))); + } +} diff --git a/src/APIs/universalelectricity/core/path/IPathCallBack.java b/src/APIs/universalelectricity/core/path/IPathCallBack.java new file mode 100644 index 00000000..c696cdc3 --- /dev/null +++ b/src/APIs/universalelectricity/core/path/IPathCallBack.java @@ -0,0 +1,25 @@ +package universalelectricity.core.path; + +import java.util.Set; + +import universalelectricity.core.vector.Vector3; + +public interface IPathCallBack +{ + /** + * @param finder - The Pathfinder object. + * @param currentNode - The node being iterated through. + * @return A set of nodes connected to the currentNode. Essentially one should return a set of + * neighboring nodes. + */ + public Set getConnectedNodes(Pathfinder finder, Vector3 currentNode); + + /** + * Called when looping through nodes. + * + * @param finder - The Pathfinder. + * @param node - The node being searched. + * @return True to stop the path finding operation. + */ + public boolean onSearch(Pathfinder finder, Vector3 node); +} \ No newline at end of file diff --git a/src/APIs/universalelectricity/core/path/Pathfinder.java b/src/APIs/universalelectricity/core/path/Pathfinder.java new file mode 100644 index 00000000..1bd57241 --- /dev/null +++ b/src/APIs/universalelectricity/core/path/Pathfinder.java @@ -0,0 +1,79 @@ +package universalelectricity.core.path; + +import java.util.HashSet; +import java.util.Set; + +import universalelectricity.core.vector.Vector3; + +/** + * A class that allows flexible pathfinding for different positions. Compared to AStar pathfinding, + * this version is faster but does not calculated the most optimal path. + * + * @author Calclavia + * + */ +public class Pathfinder +{ + /** + * A pathfinding call back interface used to call back on paths. + */ + public IPathCallBack callBackCheck; + + /** + * A list of nodes that the pathfinder already went through. + */ + public Set closedSet; + + /** + * The resulted path found by the pathfinder. Could be null if no path was found. + */ + public Set results; + + public Pathfinder(IPathCallBack callBack) + { + this.callBackCheck = callBack; + this.reset(); + } + + /** + * @return True on success finding, false on failure. + */ + public boolean findNodes(Vector3 currentNode) + { + this.closedSet.add(currentNode); + + if (this.callBackCheck.onSearch(this, currentNode)) + { + return false; + } + + for (Vector3 node : this.callBackCheck.getConnectedNodes(this, currentNode)) + { + if (!this.closedSet.contains(node)) + { + if (this.findNodes(node)) + { + return true; + } + } + } + + return false; + } + + /** + * Called to execute the pathfinding operation. + */ + public Pathfinder init(Vector3 startNode) + { + this.findNodes(startNode); + return this; + } + + public Pathfinder reset() + { + this.closedSet = new HashSet(); + this.results = new HashSet(); + return this; + } +} diff --git a/src/APIs/universalelectricity/core/path/PathfinderAStar.java b/src/APIs/universalelectricity/core/path/PathfinderAStar.java new file mode 100644 index 00000000..825d81ea --- /dev/null +++ b/src/APIs/universalelectricity/core/path/PathfinderAStar.java @@ -0,0 +1,175 @@ +package universalelectricity.core.path; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.vector.Vector3; + +/** + * An advanced version of pathfinding to find the shortest path between two points. Uses the A* + * Pathfinding algorithm. + * + * @author Calclavia + * + */ +public class PathfinderAStar extends Pathfinder +{ + /** + * A pathfinding call back interface used to call back on paths. + */ + public IPathCallBack callBackCheck; + + /** + * The set of tentative nodes to be evaluated, initially containing the start node + */ + public Set openSet; + + /** + * The map of navigated nodes storing the data of which position came from which in the format + * of: X came from Y. + */ + public HashMap navigationMap; + + /** + * Score values, used to determine the score for a path to evaluate how optimal the path is. + * G-Score is the cost along the best known path while F-Score is the total cost. + */ + public HashMap gScore, fScore; + + /** + * The node in which the pathfinder is trying to reach. + */ + public Vector3 goal; + + public PathfinderAStar(IPathCallBack callBack, Vector3 goal) + { + super(callBack); + this.goal = goal; + } + + @Override + public boolean findNodes(Vector3 start) + { + this.openSet.add(start); + this.gScore.put(start, 0d); + this.fScore.put(start, this.gScore.get(start) + getHeuristicEstimatedCost(start, this.goal)); + + while (!this.openSet.isEmpty()) + { + // Current is the node in openset having the lowest f_score[] value + Vector3 currentNode = null; + + double lowestFScore = 0; + + for (Vector3 node : this.openSet) + { + if (currentNode == null || this.fScore.get(node) < lowestFScore) + { + currentNode = node; + lowestFScore = this.fScore.get(node); + } + } + + if (currentNode == null) + { + break; + } + + if (this.callBackCheck.onSearch(this, currentNode)) + { + return false; + } + + if (currentNode.equals(this.goal)) + { + this.results = reconstructPath(this.navigationMap, goal); + return true; + } + + this.openSet.remove(currentNode); + this.closedSet.add(currentNode); + + for (Vector3 neighbor : getNeighborNodes(currentNode)) + { + double tentativeGScore = this.gScore.get(currentNode) + currentNode.distanceTo(neighbor); + + if (this.closedSet.contains(neighbor)) + { + if (tentativeGScore >= this.gScore.get(neighbor)) + { + continue; + } + } + + if (!this.openSet.contains(neighbor) || tentativeGScore < this.gScore.get(neighbor)) + { + this.navigationMap.put(neighbor, currentNode); + this.gScore.put(neighbor, tentativeGScore); + this.fScore.put(neighbor, gScore.get(neighbor) + getHeuristicEstimatedCost(neighbor, goal)); + this.openSet.add(neighbor); + } + } + } + + return false; + } + + @Override + public Pathfinder reset() + { + this.openSet = new HashSet(); + this.navigationMap = new HashMap(); + return super.reset(); + } + + /** + * A recursive function to back track and find the path in which we have analyzed. + */ + public Set reconstructPath(HashMap nagivationMap, Vector3 current_node) + { + Set path = new HashSet(); + path.add(current_node); + + if (nagivationMap.containsKey(current_node)) + { + path.addAll(reconstructPath(nagivationMap, nagivationMap.get(current_node))); + return path; + } + else + { + return path; + } + } + + /** + * @return An estimated cost between two points. + */ + public double getHeuristicEstimatedCost(Vector3 start, Vector3 goal) + { + return start.distanceTo(goal); + } + + /** + * @return A Set of neighboring Vector3 positions. + */ + public Set getNeighborNodes(Vector3 vector) + { + if (this.callBackCheck != null) + { + return this.callBackCheck.getConnectedNodes(this, vector); + } + else + { + Set neighbors = new HashSet(); + + for (int i = 0; i < 6; i++) + { + neighbors.add(vector.clone().modifyPositionFromSide(ForgeDirection.getOrientation(i))); + } + + return neighbors; + } + } +} diff --git a/src/APIs/universalelectricity/core/path/PathfinderChecker.java b/src/APIs/universalelectricity/core/path/PathfinderChecker.java new file mode 100644 index 00000000..ca242cb4 --- /dev/null +++ b/src/APIs/universalelectricity/core/path/PathfinderChecker.java @@ -0,0 +1,62 @@ +package universalelectricity.core.path; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.block.IConductor; +import universalelectricity.core.block.INetworkConnection; +import universalelectricity.core.vector.Vector3; + +/** + * Check if a conductor connects with another. + * + * @author Calclavia + * + */ +public class PathfinderChecker extends Pathfinder +{ + public PathfinderChecker(final World world, final INetworkConnection targetConnector, final INetworkConnection... ignoreConnector) + { + super(new IPathCallBack() + { + @Override + public Set getConnectedNodes(Pathfinder finder, Vector3 currentNode) + { + Set neighbors = new HashSet(); + + for (int i = 0; i < 6; i++) + { + ForgeDirection direction = ForgeDirection.getOrientation(i); + Vector3 position = currentNode.clone().modifyPositionFromSide(direction); + TileEntity connectedBlock = position.getTileEntity(world); + + if (connectedBlock instanceof IConductor && !Arrays.asList(ignoreConnector).contains(connectedBlock)) + { + if (((IConductor) connectedBlock).canConnect(direction.getOpposite())) + { + neighbors.add(position); + } + } + } + + return neighbors; + } + + @Override + public boolean onSearch(Pathfinder finder, Vector3 node) + { + if (node.getTileEntity(world) == targetConnector) + { + finder.results.add(node); + return true; + } + + return false; + } + }); + } +} diff --git a/src/APIs/universalelectricity/core/vector/Vector2.java b/src/APIs/universalelectricity/core/vector/Vector2.java new file mode 100644 index 00000000..1f130d4c --- /dev/null +++ b/src/APIs/universalelectricity/core/vector/Vector2.java @@ -0,0 +1,135 @@ +package universalelectricity.core.vector; + +/** + * Vector2 Class is used for defining objects in a 2D space. + * + * @author Calclavia + */ + +public class Vector2 implements Cloneable +{ + public double x; + public double y; + + public Vector2() + { + this(0, 0); + } + + public Vector2(double x, double y) + { + this.x = x; + this.y = y; + } + + /** + * Returns the integer floor value. + * + * @return + */ + public int intX() + { + return (int) Math.floor(this.x); + } + + public int intY() + { + return (int) Math.floor(this.y); + } + + /** + * Makes a new copy of this Vector. Prevents variable referencing problems. + */ + @Override + public Vector2 clone() + { + return new Vector2(this.x, this.y); + } + + public static double distance(Vector2 point1, Vector2 point2) + { + double xDifference = point1.x - point2.x; + double yDiference = point1.y - point2.y; + return Math.sqrt(xDifference * xDifference + yDiference * yDiference); + } + + public static double slope(Vector2 point1, Vector2 point2) + { + double xDifference = point1.x - point2.x; + double yDiference = point1.y - point2.y; + return yDiference / xDifference; + } + + public double distanceTo(Vector2 target) + { + double xDifference = this.x - target.x; + double yDifference = this.y - target.y; + return Math.sqrt(xDifference * xDifference + yDifference * yDifference); + } + + public Vector2 add(Vector2 par1) + { + this.x += par1.x; + this.y += par1.y; + return this; + } + + public Vector2 add(double par1) + { + this.x += par1; + this.y += par1; + return this; + } + + public Vector2 invert() + { + this.multiply(-1); + return this; + } + + public Vector2 multiply(double amount) + { + this.x *= amount; + this.y *= amount; + return this; + } + + public Vector2 round() + { + return new Vector2(Math.round(this.x), Math.round(this.y)); + } + + public Vector2 ceil() + { + return new Vector2(Math.ceil(this.x), Math.ceil(this.y)); + } + + public Vector2 floor() + { + return new Vector2(Math.floor(this.x), Math.floor(this.y)); + } + + @Override + public int hashCode() + { + return ("X:" + this.x + "Y:" + this.y).hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (o instanceof Vector2) + { + Vector2 vector = (Vector2) o; + return this.x == vector.x && this.y == vector.y; + } + + return false; + } + + @Override + public String toString() + { + return "Vector2 [" + this.x + "," + this.y + "]"; + } +} \ No newline at end of file diff --git a/src/APIs/universalelectricity/core/vector/Vector3.java b/src/APIs/universalelectricity/core/vector/Vector3.java new file mode 100644 index 00000000..ff0d7f42 --- /dev/null +++ b/src/APIs/universalelectricity/core/vector/Vector3.java @@ -0,0 +1,443 @@ +package universalelectricity.core.vector; + +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; + +/** + * Vector3 Class is used for defining objects in a 3D space. + * + * @author Calclavia + */ + +public class Vector3 implements Cloneable +{ + + public double x; + public double y; + public double z; + + public Vector3() + { + this(0, 0, 0); + } + + public Vector3(double x, double y, double z) + { + this.x = x; + this.y = y; + this.z = z; + } + + public Vector3(Entity par1) + { + this.x = par1.posX; + this.y = par1.posY; + this.z = par1.posZ; + } + + public Vector3(TileEntity par1) + { + this.x = par1.xCoord; + this.y = par1.yCoord; + this.z = par1.zCoord; + } + + public Vector3(Vec3 par1) + { + this.x = par1.xCoord; + this.y = par1.yCoord; + this.z = par1.zCoord; + } + + public Vector3(MovingObjectPosition par1) + { + this.x = par1.blockX; + this.y = par1.blockY; + this.z = par1.blockZ; + } + + public Vector3(ChunkCoordinates par1) + { + this.x = par1.posX; + this.y = par1.posY; + this.z = par1.posZ; + } + + public Vector3(ForgeDirection direction) + { + this.x = direction.offsetX; + this.y = direction.offsetY; + this.z = direction.offsetZ; + } + + /** + * Returns the coordinates as integers, ideal for block placement. + */ + public int intX() + { + return (int) Math.floor(this.x); + } + + public int intY() + { + return (int) Math.floor(this.y); + } + + public int intZ() + { + return (int) Math.floor(this.z); + } + + /** + * Makes a new copy of this Vector. Prevents variable referencing problems. + */ + @Override + public Vector3 clone() + { + return new Vector3(this.x, this.y, this.z); + } + + /** + * Easy block access functions. + * + * @param world + * @return + */ + public int getBlockID(IBlockAccess world) + { + return world.getBlockId(this.intX(), this.intY(), this.intZ()); + } + + public int getBlockMetadata(IBlockAccess world) + { + return world.getBlockMetadata(this.intX(), this.intY(), this.intZ()); + } + + public TileEntity getTileEntity(IBlockAccess world) + { + return world.getBlockTileEntity(this.intX(), this.intY(), this.intZ()); + } + + public boolean setBlock(World world, int id, int metadata, int notify) + { + return world.setBlock(this.intX(), this.intY(), this.intZ(), id, metadata, notify); + } + + public boolean setBlock(World world, int id, int metadata) + { + return this.setBlock(world, id, metadata, 3); + } + + public boolean setBlock(World world, int id) + { + return this.setBlock(world, id, 0); + } + + /** + * Converts this Vector3 into a Vector2 by dropping the Y axis. + */ + public Vector2 toVector2() + { + return new Vector2(this.x, this.z); + } + + /** + * Converts this vector three into a Minecraft Vec3 object + */ + public Vec3 toVec3() + { + return Vec3.createVectorHelper(this.x, this.y, this.z); + } + + public double getMagnitude() + { + return Math.sqrt(this.getMagnitudeSquared()); + } + + public double getMagnitudeSquared() + { + return x * x + y * y + z * z; + } + + public Vector3 normalize() + { + double d = getMagnitude(); + + if (d != 0) + { + multiply(1 / d); + } + return this; + } + + /** + * Gets the distance between two vectors + * + * @return The distance + */ + public static double distance(Vector3 par1, Vector3 par2) + { + double var2 = par1.x - par2.x; + double var4 = par1.y - par2.y; + double var6 = par1.z - par2.z; + return Math.sqrt(var2 * var2 + var4 * var4 + var6 * var6); + } + + public double distanceTo(Vector3 vector3) + { + double var2 = vector3.x - this.x; + double var4 = vector3.y - this.y; + double var6 = vector3.z - this.z; + return Math.sqrt(var2 * var2 + var4 * var4 + var6 * var6); + } + + public Vector3 add(Vector3 par1) + { + this.x += par1.x; + this.y += par1.y; + this.z += par1.z; + return this; + } + + public Vector3 add(double par1) + { + this.x += par1; + this.y += par1; + this.z += par1; + return this; + } + + public Vector3 subtract(Vector3 amount) + { + this.x -= amount.x; + this.y -= amount.y; + this.z -= amount.z; + return this; + } + + /** + * Multiplies the vector by negative one. + */ + public Vector3 invert() + { + this.multiply(-1); + return this; + } + + public Vector3 multiply(double amount) + { + this.x *= amount; + this.y *= amount; + this.z *= amount; + return this; + } + + public Vector3 multiply(Vector3 vec) + { + this.x *= vec.x; + this.y *= vec.y; + this.z *= vec.z; + return this; + } + + public static Vector3 subtract(Vector3 par1, Vector3 par2) + { + return new Vector3(par1.x - par2.x, par1.y - par2.y, par1.z - par2.z); + } + + public static Vector3 add(Vector3 par1, Vector3 par2) + { + return new Vector3(par1.x + par2.x, par1.y + par2.y, par1.z + par2.z); + } + + public static Vector3 add(Vector3 par1, double par2) + { + return new Vector3(par1.x + par2, par1.y + par2, par1.z + par2); + } + + public static Vector3 multiply(Vector3 vec1, Vector3 vec2) + { + return new Vector3(vec1.x * vec2.x, vec1.y * vec2.y, vec1.z * vec2.z); + } + + public static Vector3 multiply(Vector3 vec1, double vec2) + { + return new Vector3(vec1.x * vec2, vec1.y * vec2, vec1.z * vec2); + } + + public Vector3 round() + { + return new Vector3(Math.round(this.x), Math.round(this.y), Math.round(this.z)); + } + + public Vector3 ceil() + { + return new Vector3(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z)); + } + + public Vector3 floor() + { + return new Vector3(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z)); + } + + public Vector3 toRound() + { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + this.z = Math.round(this.z); + return this; + } + + public Vector3 toCeil() + { + this.x = Math.ceil(this.x); + this.y = Math.ceil(this.y); + this.z = Math.ceil(this.z); + return this; + } + + public Vector3 toFloor() + { + this.x = Math.floor(this.x); + this.y = Math.floor(this.y); + this.z = Math.floor(this.z); + return this; + } + + /** + * Gets all entities inside of this position in block space. + */ + public List getEntitiesWithin(World worldObj, Class par1Class) + { + return worldObj.getEntitiesWithinAABB(par1Class, AxisAlignedBB.getBoundingBox(this.intX(), this.intY(), this.intZ(), this.intX() + 1, this.intY() + 1, this.intZ() + 1)); + } + + /** + * Gets a position relative to a position's side + * + * @param position - The position + * @param side - The side. 0-5 + * @return The position relative to the original position's side + */ + public Vector3 modifyPositionFromSide(ForgeDirection side, double amount) + { + switch (side.ordinal()) + { + case 0: + this.y -= amount; + break; + case 1: + this.y += amount; + break; + case 2: + this.z -= amount; + break; + case 3: + this.z += amount; + break; + case 4: + this.x -= amount; + break; + case 5: + this.x += amount; + break; + } + return this; + } + + public Vector3 modifyPositionFromSide(ForgeDirection side) + { + this.modifyPositionFromSide(side, 1); + return this; + } + + /** + * Loads a Vector3 from an NBT compound. + */ + public static Vector3 readFromNBT(NBTTagCompound nbtCompound) + { + Vector3 tempVector = new Vector3(); + tempVector.x = nbtCompound.getDouble("x"); + tempVector.y = nbtCompound.getDouble("y"); + tempVector.z = nbtCompound.getDouble("z"); + return tempVector; + } + + /** + * Saves this Vector3 to disk + * + * @param prefix - The prefix of this save. Use some unique string. + * @param par1NBTTagCompound - The NBT compound object to save the data in + */ + public NBTTagCompound writeToNBT(NBTTagCompound par1NBTTagCompound) + { + par1NBTTagCompound.setDouble("x", this.x); + par1NBTTagCompound.setDouble("y", this.y); + par1NBTTagCompound.setDouble("z", this.z); + return par1NBTTagCompound; + } + + public static Vector3 UP() + { + return new Vector3(0, 1, 0); + } + + public static Vector3 DOWN() + { + return new Vector3(0, -1, 0); + } + + public static Vector3 NORTH() + { + return new Vector3(0, 0, -1); + } + + public static Vector3 SOUTH() + { + return new Vector3(0, 0, 1); + } + + public static Vector3 WEST() + { + return new Vector3(-1, 0, 0); + } + + public static Vector3 EAST() + { + return new Vector3(1, 0, 0); + } + + @Override + public int hashCode() + { + return ("X:" + this.x + "Y:" + this.y + "Z:" + this.z).hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (o instanceof Vector3) + { + Vector3 vector3 = (Vector3) o; + return this.x == vector3.x && this.y == vector3.y && this.z == vector3.z; + } + + return false; + } + + @Override + public String toString() + { + return "Vector3 [" + this.x + "," + this.y + "," + this.z + "]"; + } +} \ No newline at end of file diff --git a/src/APIs/universalelectricity/core/vector/VectorHelper.java b/src/APIs/universalelectricity/core/vector/VectorHelper.java new file mode 100644 index 00000000..e447b7e2 --- /dev/null +++ b/src/APIs/universalelectricity/core/vector/VectorHelper.java @@ -0,0 +1,52 @@ +package universalelectricity.core.vector; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.block.IConnector; + +public class VectorHelper +{ + public static final int[][] RELATIVE_MATRIX = { { 3, 2, 1, 0, 5, 4 }, { 4, 5, 0, 1, 2, 3 }, { 0, 1, 3, 2, 4, 5 }, { 0, 1, 2, 3, 5, 4 }, { 0, 1, 5, 4, 3, 2 }, { 0, 1, 4, 5, 2, 3 } }; + + /** + * Finds the direction relative to a base direction. + * + * @param front - The direction in which this block is facing/front. Use a number between 0 and + * 5. Default is 3. + * @param side - The side you are trying to find. A number between 0 and 5. + * @return The side relative to the facing direction. + */ + public static ForgeDirection getOrientationFromSide(ForgeDirection front, ForgeDirection side) + { + if (front != ForgeDirection.UNKNOWN && side != ForgeDirection.UNKNOWN) + { + return ForgeDirection.getOrientation(RELATIVE_MATRIX[front.ordinal()][side.ordinal()]); + } + return ForgeDirection.UNKNOWN; + } + + /** + * Gets a connector unit based on the given side. + */ + public static TileEntity getConnectorFromSide(World world, Vector3 position, ForgeDirection side) + { + TileEntity tileEntity = VectorHelper.getTileEntityFromSide(world, position, side); + + if (tileEntity instanceof IConnector) + { + if (((IConnector) tileEntity).canConnect(getOrientationFromSide(side, ForgeDirection.NORTH))) + { + return tileEntity; + } + } + + return null; + } + + public static TileEntity getTileEntityFromSide(World world, Vector3 position, ForgeDirection side) + { + return position.clone().modifyPositionFromSide(side).getTileEntity(world); + } + +} diff --git a/src/APIs/universalelectricity/prefab/ConductorChunkInitiate.java b/src/APIs/universalelectricity/prefab/ConductorChunkInitiate.java new file mode 100644 index 00000000..1404cb8a --- /dev/null +++ b/src/APIs/universalelectricity/prefab/ConductorChunkInitiate.java @@ -0,0 +1,58 @@ +package universalelectricity.prefab; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.ForgeSubscribe; +import net.minecraftforge.event.world.ChunkEvent; +import universalelectricity.core.block.INetworkConnection; + +/** + * A helper class to register chunk loading for your wires if you need them to be refreshed upon + * chunk load. This prevents the need for your wire to be refreshed. + * + * @author Calclavia, Aidancbrady + * + */ +public class ConductorChunkInitiate +{ + private static boolean onChunkLoadRegistered = false; + + /** + * Registers and initiates Universal Electricity's network loader. + */ + public static void register() + { + if (!onChunkLoadRegistered) + { + try + { + MinecraftForge.EVENT_BUS.register(new ConductorChunkInitiate()); + onChunkLoadRegistered = true; + } + catch (Exception e) + { + e.printStackTrace(); + } + } + } + + @ForgeSubscribe + public void onChunkLoad(ChunkEvent.Load event) + { + if (event.getChunk() != null) + { + for (Object obj : event.getChunk().chunkTileEntityMap.values()) + { + if (obj instanceof TileEntity) + { + TileEntity tileEntity = (TileEntity) obj; + + if (tileEntity instanceof INetworkConnection) + { + ((INetworkConnection) tileEntity).refresh(); + } + } + } + } + } +} diff --git a/src/APIs/universalelectricity/prefab/CustomDamageSource.java b/src/APIs/universalelectricity/prefab/CustomDamageSource.java new file mode 100644 index 00000000..5de8f52c --- /dev/null +++ b/src/APIs/universalelectricity/prefab/CustomDamageSource.java @@ -0,0 +1,42 @@ +package universalelectricity.prefab; + +import net.minecraft.util.DamageSource; +import cpw.mods.fml.common.registry.LanguageRegistry; + +public class CustomDamageSource extends DamageSource +{ + /** + * Use this damage source for all types of electrical attacks. + */ + public static final CustomDamageSource electrocution = ((CustomDamageSource) new CustomDamageSource("electrocution").setDamageBypassesArmor()).setDeathMessage("%1$s got electrocuted!"); + + public CustomDamageSource(String damageType) + { + super(damageType); + } + + @Deprecated + public CustomDamageSource setDeathMessage(String deathMessage) + { + LanguageRegistry.instance().addStringLocalization("death.attack." + this.damageType, deathMessage); + return this; + } + + @Override + public DamageSource setDamageBypassesArmor() + { + return super.setDamageBypassesArmor(); + } + + @Override + public DamageSource setDamageAllowedInCreativeMode() + { + return super.setDamageAllowedInCreativeMode(); + } + + @Override + public DamageSource setFireDamage() + { + return super.setFireDamage(); + } +} diff --git a/src/APIs/universalelectricity/prefab/RecipeHelper.java b/src/APIs/universalelectricity/prefab/RecipeHelper.java new file mode 100644 index 00000000..7471c1d8 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/RecipeHelper.java @@ -0,0 +1,192 @@ +package universalelectricity.prefab; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraftforge.common.Configuration; +import cpw.mods.fml.common.registry.GameRegistry; + +/** + * This class is used to replace recipes that are already added in the existing recipe pool for + * crafting and smelting. All recipe functions take account of the Forge Ore Dictionary. It also + * includes some recipe helper functions to shorten some of your function calls. + * + * @author Calclavia + * + */ +public class RecipeHelper +{ + public static List getRecipesByOutput(ItemStack output) + { + List list = new ArrayList(); + + for (Object obj : CraftingManager.getInstance().getRecipeList()) + { + if (obj instanceof IRecipe) + { + if (((IRecipe) obj).getRecipeOutput() == output) + { + list.add((IRecipe) obj); + } + } + } + + return list; + } + + /** + * Replaces a recipe with a new IRecipe. + * + * @return True if successful + */ + public static boolean replaceRecipe(IRecipe recipe, IRecipe newRecipe) + { + for (Object obj : CraftingManager.getInstance().getRecipeList()) + { + if (obj instanceof IRecipe) + { + if (((IRecipe) obj).equals(recipe) || obj == recipe) + { + CraftingManager.getInstance().getRecipeList().remove(obj); + CraftingManager.getInstance().getRecipeList().add(newRecipe); + return true; + } + } + } + + return false; + } + + /** + * Replaces a recipe with the resulting ItemStack with a new IRecipe. + * + * @return True if successful + */ + public static boolean replaceRecipe(ItemStack recipe, IRecipe newRecipe) + { + if (removeRecipe(recipe)) + { + CraftingManager.getInstance().getRecipeList().add(newRecipe); + return true; + } + + return false; + } + + /** + * Removes a recipe by its IRecipe class. + * + * @return True if successful + */ + public static boolean removeRecipe(IRecipe recipe) + { + for (Object obj : CraftingManager.getInstance().getRecipeList()) + { + if (obj != null) + { + if (obj instanceof IRecipe) + { + if (((IRecipe) obj).equals(recipe) || obj == recipe) + { + CraftingManager.getInstance().getRecipeList().remove(obj); + return true; + } + } + } + } + + return false; + } + + /** + * Removes the first recipe found by its output. + * + * @return True if successful + */ + public static boolean removeRecipe(ItemStack stack) + { + for (Object obj : CraftingManager.getInstance().getRecipeList()) + { + if (obj != null) + { + if (obj instanceof IRecipe) + { + if (((IRecipe) obj).getRecipeOutput() != null) + { + if (((IRecipe) obj).getRecipeOutput().isItemEqual(stack)) + { + CraftingManager.getInstance().getRecipeList().remove(obj); + return true; + } + } + } + } + } + + return false; + } + + /** + * Removes all recipes found that has this output. You may use this with Forge Ore Dictionary to + * remove all recipes with the FoD ID. + * + * @return True if successful + */ + public static boolean removeRecipes(ItemStack... itemStacks) + { + boolean didRemove = false; + + for (Iterator itr = CraftingManager.getInstance().getRecipeList().iterator(); itr.hasNext();) + { + Object obj = itr.next(); + + if (obj != null) + { + if (obj instanceof IRecipe) + { + if (((IRecipe) obj).getRecipeOutput() != null) + { + for (ItemStack itemStack : itemStacks) + { + if (((IRecipe) obj).getRecipeOutput().isItemEqual(itemStack)) + { + itr.remove(); + didRemove = true; + break; + } + } + } + } + } + } + + return didRemove; + } + + /** + * Use this function if you want to check if the recipe is allowed in the configuration file. + */ + public static void addRecipe(IRecipe recipe, String name, Configuration configuration, boolean defaultBoolean) + { + if (configuration != null) + { + configuration.load(); + + if (configuration.get("Crafting", "Allow " + name + " Crafting", defaultBoolean).getBoolean(defaultBoolean)) + { + GameRegistry.addRecipe(recipe); + } + + configuration.save(); + } + } + + public static void addRecipe(IRecipe recipe, Configuration config, boolean defaultBoolean) + { + addRecipe(recipe, recipe.getRecipeOutput().getItemName(), config, defaultBoolean); + } +} diff --git a/src/APIs/universalelectricity/prefab/SlotSpecific.java b/src/APIs/universalelectricity/prefab/SlotSpecific.java new file mode 100644 index 00000000..989df4b8 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/SlotSpecific.java @@ -0,0 +1,95 @@ +package universalelectricity.prefab; + +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +/** + * Creates a slot with a specific amount of items that matches the slot's requirements. Allows easy + * shift right clicking management and slot blocking in classes. In your container you can use + * this.getSlot(i).isItemValid to justify the player's shift clicking actions to match the slot. + * + * @author Calclavia + * + */ +public class SlotSpecific extends Slot +{ + public ItemStack[] validItemStacks = new ItemStack[0]; + public Class[] validClasses = new Class[0]; + + public boolean isInverted = false; + public boolean isMetadataSensitive = false; + + public SlotSpecific(IInventory par2IInventory, int par3, int par4, int par5, ItemStack... itemStacks) + { + super(par2IInventory, par3, par4, par5); + this.setItemStacks(itemStacks); + } + + public SlotSpecific(IInventory par2IInventory, int par3, int par4, int par5, Class... validClasses) + { + super(par2IInventory, par3, par4, par5); + this.setClasses(validClasses); + } + + public SlotSpecific setMetadataSensitive() + { + this.isMetadataSensitive = true; + return this; + } + + public SlotSpecific setItemStacks(ItemStack... validItemStacks) + { + this.validItemStacks = validItemStacks; + return this; + } + + public SlotSpecific setClasses(Class... validClasses) + { + this.validClasses = validClasses; + return this; + } + + public SlotSpecific toggleInverted() + { + this.isInverted = !this.isInverted; + return this; + } + + /** + * Check if the stack is a valid item for this slot. Always true beside for the armor slots. + */ + @Override + public boolean isItemValid(ItemStack compareStack) + { + boolean returnValue = false; + + for (ItemStack itemStack : this.validItemStacks) + { + if (compareStack.isItemEqual(itemStack) || (!this.isMetadataSensitive && compareStack.itemID == itemStack.itemID)) + { + returnValue = true; + break; + } + } + + if (!returnValue) + { + for (Class clazz : this.validClasses) + { + if (clazz.equals(compareStack.getItem().getClass()) || clazz.isInstance(compareStack.getItem())) + { + returnValue = true; + break; + } + } + } + + if (this.isInverted) + { + return !returnValue; + } + + return returnValue; + } +} diff --git a/src/APIs/universalelectricity/prefab/TranslationHelper.java b/src/APIs/universalelectricity/prefab/TranslationHelper.java new file mode 100644 index 00000000..72d365a7 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/TranslationHelper.java @@ -0,0 +1,88 @@ +package universalelectricity.prefab; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.registry.LanguageRegistry; +import cpw.mods.fml.relauncher.Side; + +/** + * A class to help you out with translations. + * + * @author Calclavia + * + */ +public class TranslationHelper +{ + /** + * Loads all the language files for a mod. This supports the loading of "child" language files + * for sub-languages to be loaded all from one file instead of creating multiple of them. An + * example of this usage would be different Spanish sub-translations (es_MX, es_YU). + * + * @param languagePath - The path to the mod's language file folder. + * @param languageSupported - The languages supported. E.g: new String[]{"en_US", "en_AU", + * "en_UK"} + * @return The amount of language files loaded successfully. + */ + public static int loadLanguages(String languagePath, String[] languageSupported) + { + int languages = 0; + + /** + * Load all languages. + */ + for (String language : languageSupported) + { + LanguageRegistry.instance().loadLocalization(languagePath + language + ".properties", language, false); + + if (LanguageRegistry.instance().getStringLocalization("children", language) != "") + { + try + { + String[] children = LanguageRegistry.instance().getStringLocalization("children", language).split(","); + + for (String child : children) + { + if (child != "" || child != null) + { + LanguageRegistry.instance().loadLocalization(languagePath + language + ".properties", child, false); + languages++; + } + } + } + catch (Exception e) + { + FMLLog.severe("Failed to load a child language file."); + e.printStackTrace(); + } + } + + languages++; + } + + return languages; + } + + /** + * Gets the local text of your translation based on the given key. This will look through your + * mod's translation file that was previously registered. Make sure you enter the full name + * + * @param key - e.g tile.block.name + * @return The translated string or the default English translation if none was found. + */ + public static String getLocal(String key) + { + String text = null; + + if (FMLCommonHandler.instance().getEffectiveSide() == Side.CLIENT) + { + text = LanguageRegistry.instance().getStringLocalization(key); + } + + if (text == null || text == "") + { + text = LanguageRegistry.instance().getStringLocalization(key, "en_US"); + } + + return text; + } +} diff --git a/src/APIs/universalelectricity/prefab/block/BlockAdvanced.java b/src/APIs/universalelectricity/prefab/block/BlockAdvanced.java new file mode 100644 index 00000000..7d38de24 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/block/BlockAdvanced.java @@ -0,0 +1,200 @@ +package universalelectricity.prefab.block; + +import java.lang.reflect.Method; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * An advanced block class that is to be extended for wrenching capabilities. + */ +public abstract class BlockAdvanced extends Block +{ + public BlockAdvanced(int id, Material material) + { + super(id, material); + this.setHardness(0.6f); + } + + /** + * DO NOT OVERRIDE THIS FUNCTION! Called when the block is right clicked by the player. This + * modified version detects electric items and wrench actions on your machine block. Do not + * override this function. Use onMachineActivated instead! (It does the same thing) + * + * @param world The World Object. + * @param x , y, z The coordinate of the block. + * @param side The side the player clicked on. + * @param hitX , hitY, hitZ The position the player clicked on relative to the block. + */ + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ) + { + int metadata = world.getBlockMetadata(x, y, z); + + /** + * Check if the player is holding a wrench or an electric item. If so, call the wrench + * event. + */ + if (this.isUsableWrench(entityPlayer, entityPlayer.inventory.getCurrentItem(), x, y, z)) + { + this.damageWrench(entityPlayer, entityPlayer.inventory.getCurrentItem(), x, y, z); + + if (entityPlayer.isSneaking()) + { + if (this.onSneakUseWrench(world, x, y, z, entityPlayer, side, hitX, hitY, hitZ)) + { + return true; + } + } + + if (this.onUseWrench(world, x, y, z, entityPlayer, side, hitX, hitY, hitZ)) + { + return true; + } + } + + if (entityPlayer.isSneaking()) + { + if (this.onSneakMachineActivated(world, x, y, z, entityPlayer, side, hitX, hitY, hitZ)) + { + return true; + } + } + + return this.onMachineActivated(world, x, y, z, entityPlayer, side, hitX, hitY, hitZ); + } + + /** + * A function that denotes if an itemStack is a wrench that can be used. Override this for more + * wrench compatibility. Compatible with Buildcraft and IC2 wrench API via reflection. + * + * @return True if it is a wrench. + */ + public boolean isUsableWrench(EntityPlayer entityPlayer, ItemStack itemStack, int x, int y, int z) + { + if (entityPlayer != null && itemStack != null) + { + Class wrenchClass = itemStack.getItem().getClass(); + + /** + * UE and Buildcraft + */ + try + { + Method methodCanWrench = wrenchClass.getMethod("canWrench", EntityPlayer.class, Integer.TYPE, Integer.TYPE, Integer.TYPE); + return (Boolean) methodCanWrench.invoke(itemStack.getItem(), entityPlayer, x, y, z); + } + catch (NoClassDefFoundError e) + { + } + catch (Exception e) + { + } + + /** + * Industrialcraft + */ + try + { + if (wrenchClass == Class.forName("ic2.core.item.tool.ItemToolWrench") || wrenchClass == Class.forName("ic2.core.item.tool.ItemToolWrenchElectric")) + { + return itemStack.getItemDamage() < itemStack.getMaxDamage(); + } + } + catch (Exception e) + { + } + } + + return false; + } + + /** + * This function damages a wrench. Works with Buildcraft and Industrialcraft wrenches. + * + * @return True if damage was successfull. + */ + public boolean damageWrench(EntityPlayer entityPlayer, ItemStack itemStack, int x, int y, int z) + { + if (this.isUsableWrench(entityPlayer, itemStack, x, y, z)) + { + Class wrenchClass = itemStack.getItem().getClass(); + + /** + * UE and Buildcraft + */ + try + { + Method methodWrenchUsed = wrenchClass.getMethod("wrenchUsed", EntityPlayer.class, Integer.TYPE, Integer.TYPE, Integer.TYPE); + methodWrenchUsed.invoke(itemStack.getItem(), entityPlayer, x, y, z); + return true; + } + catch (Exception e) + { + } + + /** + * Industrialcraft + */ + try + { + if (wrenchClass == Class.forName("ic2.core.item.tool.ItemToolWrench") || wrenchClass == Class.forName("ic2.core.item.tool.ItemToolWrenchElectric")) + { + Method methodWrenchDamage = wrenchClass.getMethod("damage", ItemStack.class, Integer.TYPE, EntityPlayer.class); + methodWrenchDamage.invoke(itemStack.getItem(), itemStack, 1, entityPlayer); + return true; + } + } + catch (Exception e) + { + } + } + + return false; + } + + /** + * Called when the machine is right clicked by the player + * + * @return True if something happens + */ + public boolean onMachineActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ) + { + return false; + } + + /** + * Called when the machine is being wrenched by a player while sneaking. + * + * @return True if something happens + */ + public boolean onSneakMachineActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ) + { + return false; + } + + /** + * Called when a player uses a wrench on the machine + * + * @return True if some happens + */ + public boolean onUseWrench(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ) + { + return false; + } + + /** + * Called when a player uses a wrench on the machine while sneaking. Only works with the UE + * wrench. + * + * @return True if some happens + */ + public boolean onSneakUseWrench(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ) + { + return this.onUseWrench(world, x, y, z, entityPlayer, side, hitX, hitY, hitZ); + } + +} diff --git a/src/APIs/universalelectricity/prefab/block/BlockConductor.java b/src/APIs/universalelectricity/prefab/block/BlockConductor.java new file mode 100644 index 00000000..1664c97f --- /dev/null +++ b/src/APIs/universalelectricity/prefab/block/BlockConductor.java @@ -0,0 +1,193 @@ +package universalelectricity.prefab.block; + +import java.util.List; + +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import universalelectricity.core.block.IConductor; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.tile.TileEntityConductor; + +public abstract class BlockConductor extends BlockContainer +{ + public boolean isWireCollision = true; + public Vector3 minVector = new Vector3(0.3, 0.3, 0.3); + public Vector3 maxVector = new Vector3(0.7, 0.7, 0.7); + + public BlockConductor(int id, Material material) + { + super(id, material); + } + + /** + * Called whenever the block is added into the world. Args: world, x, y, z + */ + @Override + public void onBlockAdded(World world, int x, int y, int z) + { + super.onBlockAdded(world, x, y, z); + + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + + if (tileEntity instanceof IConductor) + { + ((IConductor) tileEntity).refresh(); + } + } + + /** + * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed + * (coordinates passed are their own) Args: x, y, z, neighbor blockID + */ + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, int blockID) + { + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + + if (tileEntity instanceof IConductor) + { + ((IConductor) tileEntity).refresh(); + } + } + + /** + * Returns a bounding box from the pool of bounding boxes (this means this box can change after + * the pool has been cleared to be reused) + */ + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) + { + this.setBlockBoundsBasedOnState(world, x, y, z); + return super.getCollisionBoundingBoxFromPool(world, x, y, z); + } + + @Override + public AxisAlignedBB getSelectedBoundingBoxFromPool(World world, int x, int y, int z) + { + this.setBlockBoundsBasedOnState(world, x, y, z); + return super.getSelectedBoundingBoxFromPool(world, x, y, z); + } + + /** + * Returns the bounding box of the wired rectangular prism to render. + */ + @Override + public void setBlockBoundsBasedOnState(IBlockAccess world, int x, int y, int z) + { + if (this.isWireCollision) + { + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + + if (tileEntity instanceof TileEntityConductor) + { + TileEntity[] connectable = ((TileEntityConductor) tileEntity).getAdjacentConnections(); + + if (connectable != null) + { + float minX = (float) this.minVector.x; + float minY = (float) this.minVector.y; + float minZ = (float) this.minVector.z; + float maxX = (float) this.maxVector.x; + float maxY = (float) this.maxVector.y; + float maxZ = (float) this.maxVector.z; + + if (connectable[0] != null) + { + minY = 0.0F; + } + + if (connectable[1] != null) + { + maxY = 1.0F; + } + + if (connectable[2] != null) + { + minZ = 0.0F; + } + + if (connectable[3] != null) + { + maxZ = 1.0F; + } + + if (connectable[4] != null) + { + minX = 0.0F; + } + + if (connectable[5] != null) + { + maxX = 1.0F; + } + + this.setBlockBounds(minX, minY, minZ, maxX, maxY, maxZ); + } + } + } + } + + @Override + public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB axisalignedbb, List list, Entity entity) + { + if (this.isWireCollision) + { + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + + if (tileEntity instanceof TileEntityConductor) + { + TileEntity[] connectable = ((TileEntityConductor) tileEntity).getAdjacentConnections(); + + this.setBlockBounds((float) this.minVector.x, (float) this.minVector.y, (float) this.minVector.z, (float) this.maxVector.x, (float) this.maxVector.y, (float) this.maxVector.z); + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + + if (connectable[4] != null) + { + this.setBlockBounds(0, (float) this.minVector.y, (float) this.minVector.z, (float) this.maxVector.x, (float) this.maxVector.y, (float) this.maxVector.z); + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + } + + if (connectable[5] != null) + { + this.setBlockBounds((float) this.minVector.x, (float) this.minVector.y, (float) this.minVector.z, 1, (float) this.maxVector.y, (float) this.maxVector.z); + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + } + + if (connectable[0] != null) + { + this.setBlockBounds((float) this.minVector.x, 0, (float) this.minVector.z, (float) this.maxVector.x, (float) this.maxVector.y, (float) this.maxVector.z); + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + } + + if (connectable[1] != null) + { + this.setBlockBounds((float) this.minVector.x, (float) this.minVector.y, (float) this.minVector.z, (float) this.maxVector.x, 1, (float) this.maxVector.z); + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + } + + if (connectable[2] != null) + { + this.setBlockBounds((float) this.minVector.x, (float) this.minVector.y, 0, (float) this.maxVector.x, (float) this.maxVector.y, (float) this.maxVector.z); + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + } + + if (connectable[3] != null) + { + this.setBlockBounds((float) this.minVector.x, (float) this.minVector.y, (float) this.minVector.z, (float) this.maxVector.x, (float) this.maxVector.y, 1); + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + } + + this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } + } + else + { + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + } + } +} diff --git a/src/APIs/universalelectricity/prefab/block/BlockRotatable.java b/src/APIs/universalelectricity/prefab/block/BlockRotatable.java new file mode 100644 index 00000000..5d19fdd9 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/block/BlockRotatable.java @@ -0,0 +1,68 @@ +package universalelectricity.prefab.block; + +import net.minecraft.block.material.Material; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; + +/** + * A block that can rotate based on placed position and wrenching. + * + * @author Calclavia + * + */ +public abstract class BlockRotatable extends BlockTile +{ + public BlockRotatable(int id, Material material) + { + super(id, material); + } + + @Override + public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase entityLiving, ItemStack itemStack) + { + int angle = MathHelper.floor_double((entityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3; + int change = 3; + + switch (angle) + { + case 0: + change = 2; + break; + + case 1: + change = 5; + break; + + case 2: + change = 3; + break; + + case 3: + change = 4; + break; + } + + world.setBlockMetadataWithNotify(x, y, z, change, 3); + } + + @Override + public boolean onUseWrench(World world, int x, int y, int z, EntityPlayer par5EntityPlayer, int side, float hitX, float hitY, float hitZ) + { + this.rotateBlock(world, x, y, z, ForgeDirection.getOrientation(side)); + return true; + } + + public static boolean rotateBlock(World worldObj, int x, int y, int z, ForgeDirection axis, int mask) + { + int rotMeta = worldObj.getBlockMetadata(x, y, z); + int masked = rotMeta & ~mask; + ForgeDirection orientation = ForgeDirection.getOrientation(rotMeta & mask); + ForgeDirection rotated = orientation.getRotation(axis); + worldObj.setBlockMetadataWithNotify(x, y, z, rotated.ordinal() & mask | masked, 3); + return true; + } +} \ No newline at end of file diff --git a/src/APIs/universalelectricity/prefab/block/BlockTile.java b/src/APIs/universalelectricity/prefab/block/BlockTile.java new file mode 100644 index 00000000..e6bb26e5 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/block/BlockTile.java @@ -0,0 +1,122 @@ +package universalelectricity.prefab.block; + +import java.util.Random; + +import net.minecraft.block.ITileEntityProvider; +import net.minecraft.block.material.Material; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +/** + * An advanced block class that is to be extended for wrenching capabilities. + */ +public abstract class BlockTile extends BlockAdvanced implements ITileEntityProvider +{ + public BlockTile(int id, Material material) + { + super(id, material); + this.isBlockContainer = true; + } + + /** + * Called whenever the block is added into the world. Args: world, x, y, z + */ + @Override + public void onBlockAdded(World par1World, int par2, int par3, int par4) + { + super.onBlockAdded(par1World, par2, par3, par4); + } + + /** + * ejects contained items into the world, and notifies neighbours of an update, as appropriate + */ + @Override + public void breakBlock(World world, int x, int y, int z, int par5, int par6) + { + this.dropEntireInventory(world, x, y, z, par5, par6); + super.breakBlock(world, x, y, z, par5, par6); + world.removeBlockTileEntity(x, y, z); + } + + /** + * Called when the block receives a BlockEvent - see World.addBlockEvent. By default, passes it + * on to the tile entity at this location. Args: world, x, y, z, blockID, EventID, event + * parameter + */ + @Override + public boolean onBlockEventReceived(World par1World, int par2, int par3, int par4, int par5, int par6) + { + super.onBlockEventReceived(par1World, par2, par3, par4, par5, par6); + TileEntity tileentity = par1World.getBlockTileEntity(par2, par3, par4); + return tileentity != null ? tileentity.receiveClientEvent(par5, par6) : false; + } + + /** + * Override this if you don't need it. This will eject all items out of this machine if it has + * an inventory. + */ + public void dropEntireInventory(World world, int x, int y, int z, int par5, int par6) + { + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + + if (tileEntity != null) + { + if (tileEntity instanceof IInventory) + { + IInventory inventory = (IInventory) tileEntity; + + for (int var6 = 0; var6 < inventory.getSizeInventory(); ++var6) + { + ItemStack var7 = inventory.getStackInSlot(var6); + + if (var7 != null) + { + Random random = new Random(); + float var8 = random.nextFloat() * 0.8F + 0.1F; + float var9 = random.nextFloat() * 0.8F + 0.1F; + float var10 = random.nextFloat() * 0.8F + 0.1F; + + while (var7.stackSize > 0) + { + int var11 = random.nextInt(21) + 10; + + if (var11 > var7.stackSize) + { + var11 = var7.stackSize; + } + + var7.stackSize -= var11; + EntityItem var12 = new EntityItem(world, (x + var8), (y + var9), (z + var10), new ItemStack(var7.itemID, var11, var7.getItemDamage())); + + if (var7.hasTagCompound()) + { + var12.getEntityItem().setTagCompound((NBTTagCompound) var7.getTagCompound().copy()); + } + + float var13 = 0.05F; + var12.motionX = ((float) random.nextGaussian() * var13); + var12.motionY = ((float) random.nextGaussian() * var13 + 0.2F); + var12.motionZ = ((float) random.nextGaussian() * var13); + world.spawnEntityInWorld(var12); + } + } + } + } + } + } + + /** + * Returns the TileEntity used by this block. You should use the metadata sensitive version of + * this to get the maximum optimization! + */ + @Override + public TileEntity createNewTileEntity(World var1) + { + return null; + } + +} diff --git a/src/APIs/universalelectricity/prefab/network/IPacketReceiver.java b/src/APIs/universalelectricity/prefab/network/IPacketReceiver.java new file mode 100644 index 00000000..65f63833 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/network/IPacketReceiver.java @@ -0,0 +1,15 @@ +package universalelectricity.prefab.network; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet250CustomPayload; + +import com.google.common.io.ByteArrayDataInput; + +public interface IPacketReceiver +{ + /** + * Sends some data to the tile entity. + */ + public void handlePacketData(INetworkManager network, int packetType, Packet250CustomPayload packet, EntityPlayer player, ByteArrayDataInput dataStream); +} diff --git a/src/APIs/universalelectricity/prefab/network/PacketManager.java b/src/APIs/universalelectricity/prefab/network/PacketManager.java new file mode 100644 index 00000000..311f2933 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/network/PacketManager.java @@ -0,0 +1,336 @@ +package universalelectricity.prefab.network; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.Packet250CustomPayload; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; + +import cpw.mods.fml.common.network.IPacketHandler; +import cpw.mods.fml.common.network.PacketDispatcher; +import cpw.mods.fml.common.network.Player; + +/** + * This class is used for sending and receiving packets between the server and the client. You can + * directly use this by registering this packet manager with NetworkMod. Example: + * + * @NetworkMod(channels = { "BasicComponents" }, clientSideRequired = true, serverSideRequired = + * false, packetHandler = PacketManager.class) + * + * Check out {@link #BasicComponents} for better reference. + * + * @author Calclavia + */ +public class PacketManager implements IPacketHandler, IPacketReceiver +{ + public enum PacketType + { + UNSPECIFIED, TILEENTITY; + + public static PacketType get(int id) + { + if (id >= 0 && id < PacketType.values().length) + { + return PacketType.values()[id]; + } + return UNSPECIFIED; + } + } + + /** + * Writes a compressed NBTTagCompound to the OutputStream + */ + public static void writeNBTTagCompound(NBTTagCompound tag, DataOutputStream dataStream) throws IOException + { + if (tag == null) + { + dataStream.writeShort(-1); + } + else + { + byte[] var2 = CompressedStreamTools.compress(tag); + dataStream.writeShort((short) var2.length); + dataStream.write(var2); + } + } + + public static void writeNBTTagCompound(NBTTagCompound tag, ByteArrayDataOutput dataStream) throws IOException + { + if (tag == null) + { + dataStream.writeShort(-1); + } + else + { + byte[] var2 = CompressedStreamTools.compress(tag); + dataStream.writeShort((short) var2.length); + dataStream.write(var2); + } + } + + /** + * Reads a compressed NBTTagCompount in a ByteStream. + */ + public static NBTTagCompound readNBTTagCompound(DataInputStream dataStream) throws IOException + { + short var1 = dataStream.readShort(); + + if (var1 < 0) + { + return null; + } + else + { + byte[] var2 = new byte[var1]; + dataStream.readFully(var2); + return CompressedStreamTools.decompress(var2); + } + } + + public static NBTTagCompound readNBTTagCompound(ByteArrayDataInput dataStream) throws IOException + { + short var1 = dataStream.readShort(); + + if (var1 < 0) + { + return null; + } + else + { + byte[] var2 = new byte[var1]; + dataStream.readFully(var2); + return CompressedStreamTools.decompress(var2); + } + } + + @SuppressWarnings("resource") + public static Packet getPacketWithID(String channelName, int id, Object... sendData) + { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + + try + { + data.writeInt(id); + data = encodeDataStream(data, sendData); + + Packet250CustomPayload packet = new Packet250CustomPayload(); + packet.channel = channelName; + packet.data = bytes.toByteArray(); + packet.length = packet.data.length; + + return packet; + } + catch (IOException e) + { + System.out.println("Failed to create packet."); + e.printStackTrace(); + } + + return null; + } + + public static Packet getPacket(String channelName, Object... sendData) + { + return getPacketWithID(channelName, PacketType.UNSPECIFIED.ordinal(), sendData); + } + + /** + * Gets a packet for the tile entity. + * + * @return + */ + @SuppressWarnings("resource") + public static Packet getPacket(String channelName, TileEntity sender, Object... sendData) + { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + + try + { + data.writeInt(PacketType.TILEENTITY.ordinal()); + + data.writeInt(sender.xCoord); + data.writeInt(sender.yCoord); + data.writeInt(sender.zCoord); + data = encodeDataStream(data, sendData); + + Packet250CustomPayload packet = new Packet250CustomPayload(); + packet.channel = channelName; + packet.data = bytes.toByteArray(); + packet.length = packet.data.length; + + return packet; + } + catch (IOException e) + { + System.out.println("Failed to create packet."); + e.printStackTrace(); + } + + return null; + } + + /** + * Sends packets to clients around a specific coordinate. A wrapper using Vector3. See + * {@PacketDispatcher} for detailed information. + */ + public static void sendPacketToClients(Packet packet, World worldObj, Vector3 position, double range) + { + try + { + PacketDispatcher.sendPacketToAllAround(position.x, position.y, position.z, range, worldObj.provider.dimensionId, packet); + } + catch (Exception e) + { + System.out.println("Sending packet to client failed."); + e.printStackTrace(); + } + } + + /** + * Sends a packet to all the clients on this server. + */ + public static void sendPacketToClients(Packet packet, World worldObj) + { + try + { + PacketDispatcher.sendPacketToAllInDimension(packet, worldObj.provider.dimensionId); + } + catch (Exception e) + { + System.out.println("Sending packet to client failed."); + e.printStackTrace(); + } + } + + public static void sendPacketToClients(Packet packet) + { + try + { + PacketDispatcher.sendPacketToAllPlayers(packet); + } + catch (Exception e) + { + System.out.println("Sending packet to client failed."); + e.printStackTrace(); + } + } + + public static DataOutputStream encodeDataStream(DataOutputStream data, Object... sendData) + { + try + { + for (Object dataValue : sendData) + { + if (dataValue instanceof Integer) + { + data.writeInt((Integer) dataValue); + } + else if (dataValue instanceof Float) + { + data.writeFloat((Float) dataValue); + } + else if (dataValue instanceof Double) + { + data.writeDouble((Double) dataValue); + } + else if (dataValue instanceof Byte) + { + data.writeByte((Byte) dataValue); + } + else if (dataValue instanceof Boolean) + { + data.writeBoolean((Boolean) dataValue); + } + else if (dataValue instanceof String) + { + data.writeUTF((String) dataValue); + } + else if (dataValue instanceof Short) + { + data.writeShort((Short) dataValue); + } + else if (dataValue instanceof Long) + { + data.writeLong((Long) dataValue); + } + else if (dataValue instanceof NBTTagCompound) + { + writeNBTTagCompound((NBTTagCompound) dataValue, data); + } + } + + return data; + } + catch (IOException e) + { + System.out.println("Packet data encoding failed."); + e.printStackTrace(); + } + + return data; + } + + @Override + public void onPacketData(INetworkManager network, Packet250CustomPayload packet, Player player) + { + try + { + ByteArrayDataInput data = ByteStreams.newDataInput(packet.data); + + int packetTypeID = data.readInt(); + + PacketType packetType = PacketType.get(packetTypeID); + + if (packetType == PacketType.TILEENTITY) + { + int x = data.readInt(); + int y = data.readInt(); + int z = data.readInt(); + + World world = ((EntityPlayer) player).worldObj; + + if (world != null) + { + TileEntity tileEntity = world.getBlockTileEntity(x, y, z); + + if (tileEntity != null) + { + if (tileEntity instanceof IPacketReceiver) + { + ((IPacketReceiver) tileEntity).handlePacketData(network, packetTypeID, packet, ((EntityPlayer) player), data); + } + } + } + } + else + { + this.handlePacketData(network, packetTypeID, packet, ((EntityPlayer) player), data); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + @Override + public void handlePacketData(INetworkManager network, int packetType, Packet250CustomPayload packet, EntityPlayer player, ByteArrayDataInput dataStream) + { + + } +} \ No newline at end of file diff --git a/src/APIs/universalelectricity/prefab/ore/OreGenBase.java b/src/APIs/universalelectricity/prefab/ore/OreGenBase.java new file mode 100644 index 00000000..f17f433e --- /dev/null +++ b/src/APIs/universalelectricity/prefab/ore/OreGenBase.java @@ -0,0 +1,98 @@ +package universalelectricity.prefab.ore; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraftforge.common.Configuration; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.oredict.OreDictionary; +import cpw.mods.fml.common.FMLLog; + +/** + * This class is used for storing ore generation data. If you are too lazy to generate your own + * ores, you can do {@link #OreGenerator.addOre()} to add your ore to the list of ores to generate. + * + * @author Calclavia + * + */ +public abstract class OreGenBase +{ + public String name; + + public String oreDictionaryName; + + public boolean shouldGenerate = false; + + public int blockIndexTexture; + + public ItemStack oreStack; + + public int oreID; + + public int oreMeta; + + /** + * What harvest level does this machine need to be acquired? + */ + public int harvestLevel; + + /** + * The predefined tool classes are "pickaxe", "shovel", "axe". You can add others for custom + * tools. + */ + public String harvestTool; + + /** + * @param name - The name of the ore for display + * @param textureFile - The 16x16 png texture of your ore to override + * @param minGenerateLevel - The highest generation level of your ore + * @param maxGenerateLevel - The lowest generation level of your ore + * @param amountPerChunk - The amount of ores to generate per chunk + * @param amountPerBranch - The amount of ores to generate in a clutter. E.g coal generates with + * a lot of other coal next to it. How much do you want? + */ + public OreGenBase(String name, String oreDiectionaryName, ItemStack stack, String harvestTool, int harvestLevel) + { + if (stack != null) + { + this.name = name; + this.harvestTool = harvestTool; + this.harvestLevel = harvestLevel; + this.oreDictionaryName = oreDiectionaryName; + this.oreStack = stack; + this.oreID = stack.itemID; + this.oreMeta = stack.getItemDamage(); + + OreDictionary.registerOre(oreDictionaryName, stack); + MinecraftForge.setBlockHarvestLevel(Block.blocksList[stack.itemID], stack.getItemDamage(), harvestTool, harvestLevel); + } + else + { + FMLLog.severe("ItemStack is null while registering ore generation!"); + } + } + + public OreGenBase enable(Configuration config) + { + this.shouldGenerate = shouldGenerateOre(config, this.name); + return this; + } + + /** + * Checks the config file and see if Universal Electricity should generate this ore + */ + private static boolean shouldGenerateOre(Configuration configuration, String oreName) + { + configuration.load(); + boolean shouldGenerate = configuration.get("Ore_Generation", "Generate " + oreName, true).getBoolean(true); + configuration.save(); + return shouldGenerate; + } + + public abstract void generate(World world, Random random, int varX, int varZ); + + public abstract boolean isOreGeneratedInWorld(World world, IChunkProvider chunkGenerator); +} diff --git a/src/APIs/universalelectricity/prefab/ore/OreGenReplace.java b/src/APIs/universalelectricity/prefab/ore/OreGenReplace.java new file mode 100644 index 00000000..6f674e6a --- /dev/null +++ b/src/APIs/universalelectricity/prefab/ore/OreGenReplace.java @@ -0,0 +1,153 @@ +package universalelectricity.prefab.ore; + +import java.util.Random; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.ChunkProviderEnd; +import net.minecraft.world.gen.ChunkProviderGenerate; +import net.minecraft.world.gen.ChunkProviderHell; + +/** + * This class is used for storing ore generation data. If you are too lazy to generate your own + * ores, you can do {@link #OreGenerator.ORES_TO_GENERATE.add()} to add your ore to the list of ores + * to generate. + * + * @author Calclavia + * + */ +public class OreGenReplace extends OreGenBase +{ + + public int minGenerateLevel; + public int maxGenerateLevel; + public int amountPerChunk; + public int amountPerBranch; + public int replaceID; + + /** + * Dimensions to ignore ore generation + */ + public boolean ignoreSurface = false; + public boolean ignoreNether = true; + public boolean ignoreEnd = true; + + /** + * @param name - The name of the ore for display + * @param textureFile - The 16x16 png texture of your ore to override + * @param minGenerateLevel - The highest generation level of your ore + * @param maxGenerateLevel - The lowest generation level of your ore + * @param amountPerChunk - The amount of ores to generate per chunk + * @param amountPerBranch - The amount of ores to generate in a clutter. E.g coal generates with + * a lot of other coal next to it. How much do you want? + */ + public OreGenReplace(String name, String oreDiectionaryName, ItemStack stack, int replaceID, int minGenerateLevel, int maxGenerateLevel, int amountPerChunk, int amountPerBranch, String harvestTool, int harvestLevel) + { + super(name, oreDiectionaryName, stack, harvestTool, harvestLevel); + this.minGenerateLevel = minGenerateLevel; + this.maxGenerateLevel = maxGenerateLevel; + this.amountPerChunk = amountPerChunk; + this.amountPerBranch = amountPerBranch; + this.replaceID = replaceID; + } + + @Override + public void generate(World world, Random random, int varX, int varZ) + { + try + { + for (int i = 0; i < this.amountPerChunk; i++) + { + int x = varX + random.nextInt(16); + int z = varZ + random.nextInt(16); + int y = random.nextInt(Math.max(this.maxGenerateLevel - this.minGenerateLevel, 0)) + this.minGenerateLevel; + this.generateReplace(world, random, x, y, z); + } + } + catch (Exception e) + { + System.out.println("Error generating ore: " + this.name); + e.printStackTrace(); + } + } + + public boolean generateReplace(World par1World, Random par2Random, int par3, int par4, int par5) + { + float var6 = par2Random.nextFloat() * (float) Math.PI; + double var7 = par3 + 8 + MathHelper.sin(var6) * this.amountPerBranch / 8.0F; + double var9 = par3 + 8 - MathHelper.sin(var6) * this.amountPerBranch / 8.0F; + double var11 = par5 + 8 + MathHelper.cos(var6) * this.amountPerBranch / 8.0F; + double var13 = par5 + 8 - MathHelper.cos(var6) * this.amountPerBranch / 8.0F; + double var15 = par4 + par2Random.nextInt(3) - 2; + double var17 = par4 + par2Random.nextInt(3) - 2; + + for (int var19 = 0; var19 <= this.amountPerBranch; ++var19) + { + double var20 = var7 + (var9 - var7) * var19 / this.amountPerBranch; + double var22 = var15 + (var17 - var15) * var19 / this.amountPerBranch; + double var24 = var11 + (var13 - var11) * var19 / this.amountPerBranch; + double var26 = par2Random.nextDouble() * this.amountPerBranch / 16.0D; + double var28 = (MathHelper.sin(var19 * (float) Math.PI / this.amountPerBranch) + 1.0F) * var26 + 1.0D; + double var30 = (MathHelper.sin(var19 * (float) Math.PI / this.amountPerBranch) + 1.0F) * var26 + 1.0D; + int var32 = MathHelper.floor_double(var20 - var28 / 2.0D); + int var33 = MathHelper.floor_double(var22 - var30 / 2.0D); + int var34 = MathHelper.floor_double(var24 - var28 / 2.0D); + int var35 = MathHelper.floor_double(var20 + var28 / 2.0D); + int var36 = MathHelper.floor_double(var22 + var30 / 2.0D); + int var37 = MathHelper.floor_double(var24 + var28 / 2.0D); + + for (int var38 = var32; var38 <= var35; ++var38) + { + double var39 = (var38 + 0.5D - var20) / (var28 / 2.0D); + + if (var39 * var39 < 1.0D) + { + for (int var41 = var33; var41 <= var36; ++var41) + { + double var42 = (var41 + 0.5D - var22) / (var30 / 2.0D); + + if (var39 * var39 + var42 * var42 < 1.0D) + { + for (int var44 = var34; var44 <= var37; ++var44) + { + double var45 = (var44 + 0.5D - var24) / (var28 / 2.0D); + + int block = par1World.getBlockId(var38, var41, var44); + if (var39 * var39 + var42 * var42 + var45 * var45 < 1.0D && (this.replaceID == 0 || block == this.replaceID)) + { + par1World.setBlock(var38, var41, var44, this.oreID, this.oreMeta, 2); + } + } + } + } + } + } + } + + return true; + } + + @Override + public boolean isOreGeneratedInWorld(World world, IChunkProvider chunkGenerator) + { + if (!this.shouldGenerate) + { + return false; + } + if (this.ignoreSurface && chunkGenerator instanceof ChunkProviderGenerate) + { + return false; + } + if (this.ignoreNether && chunkGenerator instanceof ChunkProviderHell) + { + return false; + } + if (this.ignoreEnd && chunkGenerator instanceof ChunkProviderEnd) + { + return false; + } + return true; + } +} diff --git a/src/APIs/universalelectricity/prefab/ore/OreGenReplaceStone.java b/src/APIs/universalelectricity/prefab/ore/OreGenReplaceStone.java new file mode 100644 index 00000000..151be2d4 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/ore/OreGenReplaceStone.java @@ -0,0 +1,17 @@ +package universalelectricity.prefab.ore; + +import net.minecraft.item.ItemStack; + +public class OreGenReplaceStone extends OreGenReplace +{ + public OreGenReplaceStone(String name, String oreDiectionaryName, ItemStack stack, int minGenerateLevel, int maxGenerateLevel, int amountPerChunk, int amountPerBranch, String harvestTool, int harvestLevel) + { + super(name, oreDiectionaryName, stack, 1, minGenerateLevel, maxGenerateLevel, amountPerChunk, amountPerBranch, harvestTool, harvestLevel); + } + + // A simplified version of the constructor + public OreGenReplaceStone(String name, String oreDiectionaryName, ItemStack stack, int maxGenerateLevel, int amountPerChunk, int amountPerBranch) + { + this(name, oreDiectionaryName, stack, 0, maxGenerateLevel, amountPerChunk, amountPerBranch, "pickaxe", 1); + } +} diff --git a/src/APIs/universalelectricity/prefab/ore/OreGenerator.java b/src/APIs/universalelectricity/prefab/ore/OreGenerator.java new file mode 100644 index 00000000..e0b2796a --- /dev/null +++ b/src/APIs/universalelectricity/prefab/ore/OreGenerator.java @@ -0,0 +1,78 @@ +package universalelectricity.prefab.ore; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import cpw.mods.fml.common.IWorldGenerator; +import cpw.mods.fml.common.registry.GameRegistry; + +public class OreGenerator implements IWorldGenerator +{ + public static boolean isInitiated = false; + + /** + * Add your ore data to this list of ores for it to automatically generate! No hassle indeed! + */ + private static final List ORES_TO_GENERATE = new ArrayList(); + + /** + * Adds an ore to the ore generate list. Do this in pre-init. + */ + public static void addOre(OreGenBase data) + { + if (!isInitiated) + { + GameRegistry.registerWorldGenerator(new OreGenerator()); + } + + ORES_TO_GENERATE.add(data); + } + + /** + * Checks to see if this ore + * + * @param oreName + * @return + */ + public static boolean oreExists(String oreName) + { + for (OreGenBase ore : ORES_TO_GENERATE) + { + if (ore.oreDictionaryName == oreName) + { + return true; + } + } + + return false; + } + + /** + * Removes an ore to the ore generate list. Do this in init. + */ + public static void removeOre(OreGenBase data) + { + ORES_TO_GENERATE.remove(data); + } + + @Override + public void generate(Random rand, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) + { + chunkX = chunkX << 4; + chunkZ = chunkZ << 4; + + // Checks to make sure this is the normal + // world + for (OreGenBase oreData : ORES_TO_GENERATE) + { + if (oreData.shouldGenerate && oreData.isOreGeneratedInWorld(world, chunkGenerator)) + { + oreData.generate(world, rand, chunkX, chunkZ); + } + + } + } +} diff --git a/src/APIs/universalelectricity/prefab/potion/CustomPotion.java b/src/APIs/universalelectricity/prefab/potion/CustomPotion.java new file mode 100644 index 00000000..0dc997ca --- /dev/null +++ b/src/APIs/universalelectricity/prefab/potion/CustomPotion.java @@ -0,0 +1,35 @@ +package universalelectricity.prefab.potion; + +import net.minecraft.potion.Potion; + +public abstract class CustomPotion extends Potion +{ + /** + * Creates a new type of potion + * + * @param id - The ID of this potion. Make it greater than 20. + * @param isBadEffect - Is this potion a good potion or a bad one? + * @param color - The color of this potion. + * @param name - The name of this potion. + */ + public CustomPotion(int id, boolean isBadEffect, int color, String name) + { + super(id, isBadEffect, color); + this.setPotionName("potion." + name); + Potion.potionTypes[this.getId()] = this; + } + + @Override + public Potion setIconIndex(int par1, int par2) + { + super.setIconIndex(par1, par2); + return this; + } + + @Override + protected Potion setEffectiveness(double par1) + { + super.setEffectiveness(par1); + return this; + } +} diff --git a/src/APIs/universalelectricity/prefab/potion/CustomPotionEffect.java b/src/APIs/universalelectricity/prefab/potion/CustomPotionEffect.java new file mode 100644 index 00000000..788b623d --- /dev/null +++ b/src/APIs/universalelectricity/prefab/potion/CustomPotionEffect.java @@ -0,0 +1,40 @@ +package universalelectricity.prefab.potion; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; + +public class CustomPotionEffect extends PotionEffect +{ + public CustomPotionEffect(int potionID, int duration, int amplifier) + { + super(potionID, duration, amplifier); + } + + public CustomPotionEffect(Potion potion, int duration, int amplifier) + { + this(potion.getId(), duration, amplifier); + } + + /** + * Creates a potion effect with custom curable items. + * + * @param curativeItems - ItemStacks that can cure this potion effect + */ + public CustomPotionEffect(int potionID, int duration, int amplifier, List curativeItems) + { + super(potionID, duration, amplifier); + + if (curativeItems == null) + { + this.setCurativeItems(new ArrayList()); + } + else + { + this.setCurativeItems(curativeItems); + } + } +} diff --git a/src/APIs/universalelectricity/prefab/tile/IRotatable.java b/src/APIs/universalelectricity/prefab/tile/IRotatable.java new file mode 100644 index 00000000..ec515f94 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/tile/IRotatable.java @@ -0,0 +1,23 @@ +package universalelectricity.prefab.tile; + +import net.minecraftforge.common.ForgeDirection; + +/** + * The interface is applied to TileEntities that can rotate. + * + * @author Calclavia + * + */ + +public interface IRotatable +{ + /** + * @return Gets the facing direction. Always returns the front side of the block. + */ + public ForgeDirection getDirection(); + + /** + * @param Sets the facing direction. + */ + public void setDirection(ForgeDirection direection); +} diff --git a/src/APIs/universalelectricity/prefab/tile/TileEntityAdvanced.java b/src/APIs/universalelectricity/prefab/tile/TileEntityAdvanced.java new file mode 100644 index 00000000..9a0c20b2 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/tile/TileEntityAdvanced.java @@ -0,0 +1,60 @@ +package universalelectricity.prefab.tile; + +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; + +/** + * A TileEntity with some pre-added functionalities. + * + * @author Calclavia + * + */ +public abstract class TileEntityAdvanced extends TileEntity +{ + protected long ticks = 0; + + @Override + public void updateEntity() + { + if (this.ticks == 0) + { + this.initiate(); + } + + if (this.ticks >= Long.MAX_VALUE) + { + this.ticks = 1; + } + + this.ticks++; + } + + /** + * Called on the TileEntity's first tick. + */ + public void initiate() + { + } + + @Override + public int getBlockMetadata() + { + if (this.blockMetadata == -1) + { + this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord); + } + + return this.blockMetadata; + } + + @Override + public Block getBlockType() + { + if (this.blockType == null) + { + this.blockType = Block.blocksList[this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord)]; + } + + return this.blockType; + } +} diff --git a/src/APIs/universalelectricity/prefab/tile/TileEntityConductor.java b/src/APIs/universalelectricity/prefab/tile/TileEntityConductor.java new file mode 100644 index 00000000..7f1942f0 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/tile/TileEntityConductor.java @@ -0,0 +1,129 @@ +package universalelectricity.prefab.tile; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.block.IConductor; +import universalelectricity.core.block.IConnector; +import universalelectricity.core.block.INetworkProvider; +import universalelectricity.core.electricity.NetworkLoader; +import universalelectricity.core.grid.IElectricityNetwork; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * This tile entity pre-fabricated for all conductors. + * + * @author Calclavia + * + */ +public abstract class TileEntityConductor extends TileEntityAdvanced implements IConductor +{ + private IElectricityNetwork network; + + public TileEntity[] adjacentConnections = null; + + @Override + public void invalidate() + { + if (!this.worldObj.isRemote) + { + this.getNetwork().split(this); + } + + super.invalidate(); + } + + @Override + public boolean canUpdate() + { + return false; + } + + @Override + public IElectricityNetwork getNetwork() + { + if (this.network == null) + { + this.setNetwork(NetworkLoader.getNewNetwork(this)); + } + + return this.network; + } + + @Override + public void setNetwork(IElectricityNetwork network) + { + this.network = network; + } + + @Override + public void refresh() + { + if (!this.worldObj.isRemote) + { + this.adjacentConnections = null; + + for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) + { + TileEntity tileEntity = VectorHelper.getConnectorFromSide(this.worldObj, new Vector3(this), side); + + if (tileEntity != null) + { + if (tileEntity.getClass() == this.getClass() && tileEntity instanceof INetworkProvider) + { + this.getNetwork().merge(((INetworkProvider) tileEntity).getNetwork()); + } + } + } + + this.getNetwork().refresh(); + } + } + + @Override + public TileEntity[] getAdjacentConnections() + { + /** + * Cache the adjacentConnections. + */ + if (this.adjacentConnections == null) + { + this.adjacentConnections = new TileEntity[6]; + + for (byte i = 0; i < 6; i++) + { + ForgeDirection side = ForgeDirection.getOrientation(i); + TileEntity tileEntity = VectorHelper.getConnectorFromSide(this.worldObj, new Vector3(this), side); + + if (tileEntity instanceof IConnector) + { + if (((IConnector) tileEntity).canConnect(side.getOpposite())) + { + this.adjacentConnections[i] = tileEntity; + } + } + } + } + + return this.adjacentConnections; + } + + @Override + public boolean canConnect(ForgeDirection direction) + { + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public AxisAlignedBB getRenderBoundingBox() + { + return AxisAlignedBB.getAABBPool().getAABB(this.xCoord, this.yCoord, this.zCoord, this.xCoord + 1, this.yCoord + 1, this.zCoord + 1); + } +} diff --git a/src/APIs/universalelectricity/prefab/tile/TileEntityElectrical.java b/src/APIs/universalelectricity/prefab/tile/TileEntityElectrical.java new file mode 100644 index 00000000..284f4172 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/tile/TileEntityElectrical.java @@ -0,0 +1,220 @@ +package universalelectricity.prefab.tile; + +import java.util.EnumSet; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import universalelectricity.core.block.IElectrical; +import universalelectricity.core.block.IElectricalStorage; +import universalelectricity.core.electricity.ElectricityHelper; +import universalelectricity.core.electricity.ElectricityPack; +import universalelectricity.core.grid.IElectricityNetwork; +import universalelectricity.core.item.ElectricItemHelper; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; + +public abstract class TileEntityElectrical extends TileEntityAdvanced implements IElectrical, IElectricalStorage +{ + public float energyStored = 0; + + /** + * Recharges electric item. + */ + public void recharge(ItemStack itemStack) + { + this.setEnergyStored(this.getEnergyStored() - ElectricItemHelper.chargeItem(itemStack, this.getProvide(ForgeDirection.UNKNOWN))); + } + + /** + * Discharges electric item. + */ + public void discharge(ItemStack itemStack) + { + this.setEnergyStored(this.getEnergyStored() + ElectricItemHelper.dischargeItem(itemStack, this.getProvide(ForgeDirection.UNKNOWN))); + } + + /** + * Called to produce the potential electricity inside this block. + */ + public void produce() + { + if (!this.worldObj.isRemote) + { + for (ForgeDirection outputDirection : this.getOutputDirections()) + { + this.produceUE(outputDirection); + } + } + } + + /** + * Produces UE power towards a specific direction. + * + * @param outputDirection - The output direction. + */ + public void produceUE(ForgeDirection outputDirection) + { + if (!this.worldObj.isRemote) + { + float provide = this.getProvide(outputDirection); + + if (provide > 0) + { + TileEntity outputTile = VectorHelper.getConnectorFromSide(this.worldObj, new Vector3(this), outputDirection); + IElectricityNetwork outputNetwork = ElectricityHelper.getNetworkFromTileEntity(outputTile, outputDirection); + + if (outputNetwork != null) + { + ElectricityPack powerRequest = outputNetwork.getRequest(this); + + if (powerRequest.getWatts() > 0) + { + ElectricityPack sendPack = ElectricityPack.min(ElectricityPack.getFromWatts(this.getEnergyStored(), this.getVoltage()), ElectricityPack.getFromWatts(provide, this.getVoltage())); + float rejectedPower = outputNetwork.produce(sendPack, this); + this.setEnergyStored(this.getEnergyStored() - (sendPack.getWatts() - rejectedPower)); + } + } + } + } + } + + /** + * The electrical input direction. + * + * @return The direction that electricity is entered into the tile. Return null for no input. By + * default you can accept power from all sides. + */ + public EnumSet getInputDirections() + { + return EnumSet.allOf(ForgeDirection.class); + } + + /** + * The electrical output direction. + * + * @return The direction that electricity is output from the tile. Return null for no output. By + * default it will return an empty EnumSet. + */ + public EnumSet getOutputDirections() + { + return EnumSet.noneOf(ForgeDirection.class); + } + + @Override + public float receiveElectricity(ForgeDirection from, ElectricityPack receive, boolean doReceive) + { + if (this.getInputDirections().contains(from)) + { + return this.receiveElectricity(receive, doReceive); + } + + return 0; + } + + @Override + public ElectricityPack provideElectricity(ForgeDirection from, ElectricityPack request, boolean doProvide) + { + if (this.getOutputDirections().contains(from)) + { + return this.provideElectricity(request, doProvide); + } + + return new ElectricityPack(); + } + + /** + * A non-side specific version of receiveElectricity for you to optionally use it internally. + */ + public float receiveElectricity(ElectricityPack receive, boolean doReceive) + { + if (receive != null) + { + float prevEnergyStored = this.getEnergyStored(); + float newStoredEnergy = Math.min(this.getEnergyStored() + receive.getWatts(), this.getMaxEnergyStored()); + + if (doReceive) + { + this.setEnergyStored(newStoredEnergy); + } + + return Math.max(newStoredEnergy - prevEnergyStored, 0); + } + + return 0; + } + + public float receiveElectricity(float energy, boolean doReceive) + { + return this.receiveElectricity(ElectricityPack.getFromWatts(energy, this.getVoltage()), doReceive); + } + + /** + * A non-side specific version of provideElectricity for you to optionally use it internally. + */ + public ElectricityPack provideElectricity(ElectricityPack request, boolean doProvide) + { + if (request != null) + { + float requestedEnergy = Math.min(request.getWatts(), this.energyStored); + + if (doProvide) + { + this.setEnergyStored(this.energyStored - requestedEnergy); + } + + return ElectricityPack.getFromWatts(requestedEnergy, this.getVoltage()); + } + + return new ElectricityPack(); + } + + public ElectricityPack provideElectricity(float energy, boolean doProvide) + { + return this.provideElectricity(ElectricityPack.getFromWatts(energy, this.getVoltage()), doProvide); + } + + @Override + public void setEnergyStored(float energy) + { + this.energyStored = Math.max(Math.min(energy, this.getMaxEnergyStored()), 0); + } + + @Override + public float getEnergyStored() + { + return this.energyStored; + } + + @Override + public boolean canConnect(ForgeDirection direction) + { + if (direction == null || direction.equals(ForgeDirection.UNKNOWN)) + { + return false; + } + + return this.getInputDirections().contains(direction) || this.getOutputDirections().contains(direction); + } + + @Override + public float getVoltage() + { + return 120; + } + + @Override + public void readFromNBT(NBTTagCompound nbt) + { + super.readFromNBT(nbt); + this.energyStored = nbt.getFloat("energyStored"); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) + { + super.writeToNBT(nbt); + nbt.setFloat("energyStored", this.energyStored); + } +} diff --git a/src/APIs/universalelectricity/prefab/vector/Region2.java b/src/APIs/universalelectricity/prefab/vector/Region2.java new file mode 100644 index 00000000..6d52a746 --- /dev/null +++ b/src/APIs/universalelectricity/prefab/vector/Region2.java @@ -0,0 +1,36 @@ +package universalelectricity.prefab.vector; + +import universalelectricity.core.vector.Vector2; + +public class Region2 +{ + public Vector2 min; + public Vector2 max; + + public Region2() + { + this(new Vector2(), new Vector2()); + } + + public Region2(Vector2 min, Vector2 max) + { + this.min = min; + this.max = max; + } + + /** + * Checks if a point is located inside a region + */ + public boolean isIn(Vector2 point) + { + return (point.x > this.min.x && point.x < this.max.x) && (point.y > this.min.y && point.y < this.max.y); + } + + /** + * Returns whether the given region intersects with this one. + */ + public boolean isIn(Region2 region) + { + return region.max.x > this.min.x && region.min.x < this.max.x ? (region.max.y > this.min.y && region.min.y < this.max.y ? true : false) : false; + } +} diff --git a/src/APIs/universalelectricity/prefab/vector/Region3.java b/src/APIs/universalelectricity/prefab/vector/Region3.java new file mode 100644 index 00000000..278a984b --- /dev/null +++ b/src/APIs/universalelectricity/prefab/vector/Region3.java @@ -0,0 +1,131 @@ +package universalelectricity.prefab.vector; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +/** + * A cubical region class. + * + * @author Calclavia + */ +public class Region3 +{ + public Vector3 min; + public Vector3 max; + + public Region3() + { + this(new Vector3(), new Vector3()); + } + + public Region3(Vector3 min, Vector3 max) + { + this.min = min; + this.max = max; + } + + public Region3(AxisAlignedBB aabb) + { + this.min = new Vector3(aabb.minX, aabb.minY, aabb.minZ); + this.max = new Vector3(aabb.maxX, aabb.maxY, aabb.maxZ); + } + + public AxisAlignedBB toAABB() + { + return AxisAlignedBB.getBoundingBox(this.min.x, this.min.y, this.min.z, this.max.x, this.max.y, this.max.z); + } + + public Region2 toRegion2() + { + return new Region2(this.min.toVector2(), this.max.toVector2()); + } + + /** + * Checks if a point is located inside a region + */ + public boolean isIn(Vector3 point) + { + return (point.x > this.min.x && point.x < this.max.x) && (point.y > this.min.y && point.y < this.max.y) && (point.z > this.min.z && point.z < this.max.z); + } + + /** + * Returns whether the given region intersects with this one. + */ + public boolean isIn(Region3 region) + { + return region.max.x > this.min.x && region.min.x < this.max.x ? (region.max.y > this.min.y && region.min.y < this.max.y ? region.max.z > this.min.z && region.min.z < this.max.z : false) : false; + } + + public void expand(Vector3 difference) + { + this.min.subtract(difference); + this.max.add(difference); + } + + /** + * @return List of vectors within this region. + */ + public List getVectors() + { + List vectors = new ArrayList(); + + for (int x = this.min.intX(); x < this.max.intX(); x++) + { + for (int y = this.min.intY(); x < this.max.intY(); y++) + { + for (int z = this.min.intZ(); x < this.max.intZ(); z++) + { + vectors.add(new Vector3(x, y, z)); + } + } + } + + return vectors; + } + + public List getVectors(Vector3 center, int radius) + { + List vectors = new ArrayList(); + + for (int x = this.min.intX(); x < this.max.intX(); x++) + { + for (int y = this.min.intY(); x < this.max.intY(); y++) + { + for (int z = this.min.intZ(); x < this.max.intZ(); z++) + { + Vector3 vector3 = new Vector3(x, y, z); + + if (center.distanceTo(vector3) <= radius) + { + vectors.add(vector3); + } + } + } + } + + return vectors; + } + + /** + * Returns all entities in this region. + */ + public List getEntities(World world, Class entityClass) + { + return world.getEntitiesWithinAABB(entityClass, this.toAABB()); + } + + public List getEntitiesExlude(World world, Entity entity) + { + return world.getEntitiesWithinAABBExcludingEntity(entity, this.toAABB()); + } + + public List getEntities(World world) + { + return this.getEntities(world, Entity.class); + } +}