diff options
| author | Lance5057 <Lance5057@gmail.com> | 2016-04-20 05:15:15 -0500 |
|---|---|---|
| committer | Lance5057 <Lance5057@gmail.com> | 2016-04-20 05:15:15 -0500 |
| commit | c7aa1eada63170a2fb6945af26398702849030f5 (patch) | |
| tree | 5749abd3c4a42ae115b92820fb2a3db8f00af433 /src/api/java/mekanism | |
| parent | f0dbe7a46426355f9eab6eb3933277664baafc57 (diff) | |
Wrench changes, start of unified armor renderer
API's in flux, please fix.
Diffstat (limited to 'src/api/java/mekanism')
62 files changed, 5785 insertions, 0 deletions
diff --git a/src/api/java/mekanism/api/Chunk3D.java b/src/api/java/mekanism/api/Chunk3D.java new file mode 100644 index 0000000..f469d5d --- /dev/null +++ b/src/api/java/mekanism/api/Chunk3D.java @@ -0,0 +1,118 @@ +package mekanism.api; + +import net.minecraft.entity.Entity; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +/** + * Chunk3D - an integer-based way to keep track of and perform operations on chunks in a Minecraft-based environment. This also takes + * in account the dimension the chunk is in. + * @author aidancbrady + * + */ +public class Chunk3D +{ + public int dimensionId; + + public int xCoord; + public int zCoord; + + /** + * Creates a Chunk3D object from the given x and z coordinates, as well as a dimension. + * @param x - chunk x location + * @param z - chunk z location + * @param dimension - the dimension this Chunk3D is in + */ + public Chunk3D(int x, int z, int dimension) + { + xCoord = x; + zCoord = z; + + dimensionId = dimension; + } + + /** + * Creates a Chunk3D from an entity based on it's location and dimension. + * @param entity - the entity to get the Chunk3D object from + */ + public Chunk3D(Entity entity) + { + xCoord = ((int)entity.posX) >> 4; + zCoord = ((int)entity.posZ) >> 4; + + dimensionId = entity.dimension; + } + + /** + * Creates a Chunk3D from a Coord4D based on it's coordinates and dimension. + * @param coord - the Coord4D object to get this Chunk3D from + */ + public Chunk3D(Coord4D coord) + { + xCoord = coord.xCoord >> 4; + zCoord = coord.zCoord >> 4; + + dimensionId = coord.dimensionId; + } + + /** + * Whether or not this chunk exists in the given world. + * @param world - the world to check in + * @return if the chunk exists + */ + public boolean exists(World world) + { + return world.getChunkProvider().chunkExists(xCoord, zCoord); + } + + /** + * Gets a Chunk object corresponding to this Chunk3D's coordinates. + * @param world - the world to get the Chunk object from + * @return the corresponding Chunk object + */ + public Chunk getChunk(World world) + { + return world.getChunkFromChunkCoords(xCoord, zCoord); + } + + /** + * Returns this Chunk3D in the Minecraft-based ChunkCoordIntPair format. + * @return this Chunk3D as a ChunkCoordIntPair + */ + public ChunkCoordIntPair toPair() + { + return new ChunkCoordIntPair(xCoord, zCoord); + } + + @Override + public Coord4D clone() + { + return new Coord4D(xCoord, zCoord, dimensionId); + } + + @Override + public String toString() + { + return "[Chunk3D: " + xCoord + ", " + zCoord + ", dim=" + dimensionId + "]"; + } + + @Override + public boolean equals(Object obj) + { + return obj instanceof Chunk3D && + ((Chunk3D)obj).xCoord == xCoord && + ((Chunk3D)obj).zCoord == zCoord && + ((Chunk3D)obj).dimensionId == dimensionId; + } + + @Override + public int hashCode() + { + int code = 1; + code = 31 * code + xCoord; + code = 31 * code + zCoord; + code = 31 * code + dimensionId; + return code; + } +} diff --git a/src/api/java/mekanism/api/Coord4D.java b/src/api/java/mekanism/api/Coord4D.java new file mode 100644 index 0000000..1a0f7e4 --- /dev/null +++ b/src/api/java/mekanism/api/Coord4D.java @@ -0,0 +1,421 @@ +package mekanism.api; + +import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; +import io.netty.buffer.ByteBuf; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MathHelper; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.ArrayList; + +/** + * Coord4D - an integer-based way to keep track of and perform operations on blocks in a Minecraft-based environment. This also takes + * in account the dimension the coordinate is in. + * @author aidancbrady + * + */ +public class Coord4D +{ + public int xCoord; + public int yCoord; + public int zCoord; + + public int dimensionId; + + /** + * Creates a Coord4D WITHOUT a dimensionId. Don't use unless absolutely necessary. + * @param x - x coordinate + * @param y - y coordinate + * @param z - z coordinate + */ + public Coord4D(int x, int y, int z) + { + xCoord = x; + yCoord = y; + zCoord = z; + + dimensionId = 0; + } + + /** + * Creates a Coord4D from an entity's position, rounded down. + * @param entity - entity to create the Coord4D from + */ + public Coord4D(Entity entity) + { + xCoord = (int)entity.posX; + yCoord = (int)entity.posY; + zCoord = (int)entity.posZ; + + dimensionId = entity.worldObj.provider.dimensionId; + } + + /** + * Creates a Coord4D from the defined x, y, z, and dimension values. + * @param x - x coordinate + * @param y - y coordinate + * @param z - z coordinate + * @param dimension - dimension ID + */ + public Coord4D(int x, int y, int z, int dimension) + { + xCoord = x; + yCoord = y; + zCoord = z; + + dimensionId = dimension; + } + + public Coord4D(MovingObjectPosition mop) + { + xCoord = mop.blockX; + yCoord = mop.blockY; + zCoord = mop.blockZ; + } + + /** + * Gets the metadata of the block representing this Coord4D. + * @param world - world this Coord4D is in + * @return the metadata of this Coord4D's block + */ + public int getMetadata(IBlockAccess world) + { + return world.getBlockMetadata(xCoord, yCoord, zCoord); + } + + /** + * Gets the TileEntity of the block representing this Coord4D. + * @param world - world this Coord4D is in + * @return the TileEntity of this Coord4D's block + */ + public TileEntity getTileEntity(IBlockAccess world) + { + if(world instanceof World && !exists((World)world)) + { + return null; + } + + return world.getTileEntity(xCoord, yCoord, zCoord); + } + + /** + * Gets the Block value of the block representing this Coord4D. + * @param world - world this Coord4D is in + * @return the Block value of this Coord4D's block + */ + public Block getBlock(IBlockAccess world) + { + if(world instanceof World && !exists((World)world)) + { + return null; + } + + return world.getBlock(xCoord, yCoord, zCoord); + } + + /** + * Writes this Coord4D's data to an NBTTagCompound. + * @param nbtTags - tag compound to write to + * @return the tag compound with this Coord4D's data + */ + public NBTTagCompound write(NBTTagCompound nbtTags) + { + nbtTags.setInteger("x", xCoord); + nbtTags.setInteger("y", yCoord); + nbtTags.setInteger("z", zCoord); + nbtTags.setInteger("dimensionId", dimensionId); + + return nbtTags; + } + + /** + * Writes this Coord4D's data to an ArrayList for packet transfer. + * @param data - the ArrayList to add the data to + */ + public void write(ArrayList data) + { + data.add(xCoord); + data.add(yCoord); + data.add(zCoord); + data.add(dimensionId); + } + + /** + * Writes this Coord4D's data to a ByteBuf for packet transfer. + * @param dataStream - the ByteBuf to add the data to + */ + public void write(ByteBuf dataStream) + { + dataStream.writeInt(xCoord); + dataStream.writeInt(yCoord); + dataStream.writeInt(zCoord); + dataStream.writeInt(dimensionId); + } + + /** + * Translates this Coord4D by the defined x, y, and z values. + * @param x - x value to translate + * @param y - y value to translate + * @param z - z value to translate + * @return translated Coord4D + */ + public Coord4D translate(int x, int y, int z) + { + xCoord += x; + yCoord += y; + zCoord += z; + + return this; + } + + /** + * Translates this Coord4D by the defined Coord4D's coordinates, regardless of dimension. + * @param coord - coordinates to translate by + * @return translated Coord4D + */ + public Coord4D translate(Coord4D coord) + { + translate(coord.xCoord, coord.yCoord, coord.zCoord); + + return this; + } + + /** + * Creates and returns a new Coord4D translated to the defined offsets of the side. + * @param side - side to translate this Coord4D to + * @return translated Coord4D + */ + public Coord4D getFromSide(ForgeDirection side) + { + return getFromSide(side, 1); + } + + /** + * Creates and returns a new Coord4D translated to the defined offsets of the side by the defined amount. + * @param side - side to translate this Coord4D to + * @param amount - how far to translate this Coord4D + * @return translated Coord4D + */ + public Coord4D getFromSide(ForgeDirection side, int amount) + { + return new Coord4D(xCoord+(side.offsetX*amount), yCoord+(side.offsetY*amount), zCoord+(side.offsetZ*amount), dimensionId); + } + + public ItemStack getStack(IBlockAccess world) + { + Block block = getBlock(world); + + if(block == null || block == Blocks.air) + { + return null; + } + + return new ItemStack(block, 1, getMetadata(world)); + } + + /** + * Returns a new Coord4D from a defined TileEntity's xCoord, yCoord and zCoord values. + * @param tileEntity - TileEntity at the location that will represent this Coord4D + * @return the Coord4D object from the TileEntity + */ + public static Coord4D get(TileEntity tileEntity) + { + return new Coord4D(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, tileEntity.getWorldObj().provider.dimensionId); + } + + /** + * Returns a new Coord4D from a tag compound. + * @param tag - tag compound to read from + * @return the Coord4D from the tag compound + */ + public static Coord4D read(NBTTagCompound tag) + { + return new Coord4D(tag.getInteger("x"), tag.getInteger("y"), tag.getInteger("z"), tag.getInteger("id")); + } + + /** + * Returns a new Coord4D from a ByteBuf. + * @param dataStream - data input to read from + * @return the Coord4D from the data input + */ + public static Coord4D read(ByteBuf dataStream) + { + return new Coord4D(dataStream.readInt(), dataStream.readInt(), dataStream.readInt(), dataStream.readInt()); + } + + /** + * Creates and returns a new Coord4D with values representing the difference between the defined Coord4D + * @param other - the Coord4D to subtract from this + * @return a Coord4D representing the distance between the defined Coord4D + */ + public Coord4D difference(Coord4D other) + { + return new Coord4D(xCoord-other.xCoord, yCoord-other.yCoord, zCoord-other.zCoord, dimensionId); + } + + /** + * A method used to find the ForgeDirection represented by the distance of the defined Coord4D. Most likely won't have many + * applicable uses. + * @param other - Coord4D to find the side difference of + * @return ForgeDirection representing the side the defined relative Coord4D is on to this + */ + public ForgeDirection sideDifference(Coord4D other) + { + Coord4D diff = difference(other); + + for(ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) + { + if(side.offsetX == diff.xCoord && side.offsetY == diff.yCoord && side.offsetZ == diff.zCoord) + { + return side; + } + } + + return ForgeDirection.UNKNOWN; + } + + /** + * Gets the distance to a defined Coord4D. + * @param obj - the Coord4D to find the distance to + * @return the distance to the defined Coord4D + */ + public int distanceTo(Coord4D obj) + { + int subX = xCoord - obj.xCoord; + int subY = yCoord - obj.yCoord; + int subZ = zCoord - obj.zCoord; + return (int)MathHelper.sqrt_double(subX * subX + subY * subY + subZ * subZ); + } + + /** + * Whether or not the defined side of this Coord4D is visible. + * @param side - side to check + * @param world - world this Coord4D is in + * @return + */ + public boolean sideVisible(ForgeDirection side, IBlockAccess world) + { + return world.isAirBlock(xCoord+side.offsetX, yCoord+side.offsetY, zCoord+side.offsetZ); + } + + /** + * Gets a TargetPoint with the defined range from this Coord4D with the appropriate coordinates and dimension ID. + * @param range - the range the packet can be sent in of this Coord4D + * @return TargetPoint relative to this Coord4D + */ + public TargetPoint getTargetPoint(double range) + { + return new TargetPoint(dimensionId, xCoord, yCoord, zCoord, range); + } + + /** + * Steps this Coord4D in the defined side's offset without creating a new value. + * @param side - side to step towards + * @return this Coord4D + */ + public Coord4D step(ForgeDirection side) + { + return translate(side.offsetX, side.offsetY, side.offsetZ); + } + + /** + * Whether or not the chunk this Coord4D is in exists and is loaded. + * @param world - world this Coord4D is in + * @return the chunk of this Coord4D + */ + public boolean exists(World world) + { + return world.getChunkProvider() == null || world.getChunkProvider().chunkExists(xCoord >> 4, zCoord >> 4); + } + + /** + * Gets the chunk this Coord4D is in. + * @param world - world this Coord4D is in + * @return the chunk of this Coord4D + */ + public Chunk getChunk(World world) + { + return world.getChunkFromBlockCoords(xCoord, zCoord); + } + + /** + * Gets the Chunk3D object with chunk coordinates correlating to this Coord4D's location + * @return Chunk3D with correlating chunk coordinates. + */ + public Chunk3D getChunk3D() + { + return new Chunk3D(this); + } + + /** + * Whether or not the block this Coord4D represents is an air block. + * @param world - world this Coord4D is in + * @return if this Coord4D is an air block + */ + public boolean isAirBlock(IBlockAccess world) + { + return world.isAirBlock(xCoord, yCoord, zCoord); + } + + /** + * Whether or not this block this Coord4D represents is replaceable. + * @param world - world this Coord4D is in + * @return if this Coord4D is replaceable + */ + public boolean isReplaceable(IBlockAccess world) + { + return getBlock(world).isReplaceable(world, xCoord, yCoord, zCoord); + } + + /** + * Gets a bounding box that contains the area this Coord4D would take up in a world. + * @return this Coord4D's bounding box + */ + public AxisAlignedBB getBoundingBox() + { + return AxisAlignedBB.getBoundingBox(xCoord, yCoord, zCoord, xCoord+1, yCoord+1, zCoord+1); + } + + @Override + public Coord4D clone() + { + return new Coord4D(xCoord, yCoord, zCoord, dimensionId); + } + + @Override + public String toString() + { + return "[Coord4D: " + xCoord + ", " + yCoord + ", " + zCoord + ", dim=" + dimensionId + "]"; + } + + @Override + public boolean equals(Object obj) + { + return obj instanceof Coord4D && + ((Coord4D)obj).xCoord == xCoord && + ((Coord4D)obj).yCoord == yCoord && + ((Coord4D)obj).zCoord == zCoord && + ((Coord4D)obj).dimensionId == dimensionId; + } + + @Override + public int hashCode() + { + int code = 1; + code = 31 * code + xCoord; + code = 31 * code + yCoord; + code = 31 * code + zCoord; + code = 31 * code + dimensionId; + return code; + } +}
\ No newline at end of file diff --git a/src/api/java/mekanism/api/EnumColor.java b/src/api/java/mekanism/api/EnumColor.java new file mode 100644 index 0000000..df9ba74 --- /dev/null +++ b/src/api/java/mekanism/api/EnumColor.java @@ -0,0 +1,112 @@ +package mekanism.api; + +import net.minecraft.util.StatCollector; + +/** + * Simple color enum for adding colors to in-game GUI strings of text. + * @author AidanBrady + * + */ +public enum EnumColor +{ + BLACK("\u00a70", "black", "Black", new int[] {0, 0, 0}, 0), + DARK_BLUE("\u00a71", "darkBlue", "Blue", new int[] {0, 0, 170}, 4), + DARK_GREEN("\u00a72", "darkGreen", "Green", new int[] {0, 170, 0}, 2), + DARK_AQUA("\u00a73", "darkAqua", "Cyan", new int[] {0, 255, 255}, 6), + DARK_RED("\u00a74", "darkRed", null, new int[] {170, 0, 0}, -1), + PURPLE("\u00a75", "purple", "Purple", new int[] {170, 0, 170}, 5), + ORANGE("\u00a76", "orange", "Orange", new int[] {255, 170, 0}, 14), + GREY("\u00a77", "grey", "LightGray", new int[] {170, 170, 170}, 7), + DARK_GREY("\u00a78", "darkGrey", "Gray", new int[] {85, 85, 85}, 8), + INDIGO("\u00a79", "indigo", "LightBlue", new int[] {85, 85, 255}, 12), + BRIGHT_GREEN("\u00a7a", "brightGreen", "Lime", new int[] {85, 255, 85}, 10), + AQUA("\u00a7b", "aqua", null, new int[] {85, 255, 255}, -1), + RED("\u00a7c", "red", "Red", new int[] {255, 0, 0}, 1), + PINK("\u00a7d", "pink", "Magenta", new int[] {255, 85, 255}, 13), + YELLOW("\u00a7e", "yellow", "Yellow", new int[] {255, 255, 85}, 11), + WHITE("\u00a7f", "white", "White", new int[] {255, 255, 255}, 15), + //Extras for dye-completeness + BROWN("\u00a76", "brown", "Brown", new int[] {150, 75, 0}, 3), + BRIGHT_PINK("\u00a7d", "brightPink", "Pink", new int[] {255, 192, 203}, 9); + + public static EnumColor[] DYES = new EnumColor[] {BLACK, RED, DARK_GREEN, BROWN, DARK_BLUE, PURPLE, DARK_AQUA, GREY, DARK_GREY, BRIGHT_PINK, BRIGHT_GREEN, YELLOW, INDIGO, PINK, ORANGE, WHITE}; + + /** The color code that will be displayed */ + public final String code; + + public final int[] rgbCode; + + public final int mcMeta; + + /** A friendly name of the color. */ + public String unlocalizedName; + + public String dyeName; + + private EnumColor(String s, String n, String dye, int[] rgb, int meta) + { + code = s; + unlocalizedName = n; + dyeName = dye; + rgbCode = rgb; + mcMeta = meta; + } + + /** + * Gets the localized name of this color by translating the unlocalized name. + * @return localized name + */ + public String getLocalizedName() + { + return StatCollector.translateToLocal("color." + unlocalizedName); + } + + public String getDyeName() + { + return StatCollector.translateToLocal("dye." + unlocalizedName); + } + + public String getOreDictName() + { + return dyeName; + } + + /** + * Gets the name of this color with it's color prefix code. + * @return the color's name and color prefix + */ + public String getName() + { + return code + getLocalizedName(); + } + + public String getDyedName() + { + return code + getDyeName(); + } + + /** + * Gets the 0-1 of this color's RGB value by dividing by 255 (used for OpenGL coloring). + * @param index - R:0, G:1, B:2 + * @return the color value + */ + public float getColor(int index) + { + return (float)rgbCode[index]/255F; + } + + /** + * Gets the value of this color mapped to MC in-game item colors present in dyes and wool. + * @return mc meta value + */ + public int getMetaValue() + { + return mcMeta; + } + + @Override + public String toString() + { + return code; + } +} diff --git a/src/api/java/mekanism/api/IClientTicker.java b/src/api/java/mekanism/api/IClientTicker.java new file mode 100644 index 0000000..2288973 --- /dev/null +++ b/src/api/java/mekanism/api/IClientTicker.java @@ -0,0 +1,8 @@ +package mekanism.api; + +public interface IClientTicker +{ + public void clientTick(); + + public boolean needsTicks(); +} diff --git a/src/api/java/mekanism/api/IConfigurable.java b/src/api/java/mekanism/api/IConfigurable.java new file mode 100644 index 0000000..512fabf --- /dev/null +++ b/src/api/java/mekanism/api/IConfigurable.java @@ -0,0 +1,27 @@ +package mekanism.api; + +import net.minecraft.entity.player.EntityPlayer; + +/** + * Implement this in your TileEntity class if your block can be modified by a Configurator. + * @author aidancbrady + * + */ +public interface IConfigurable +{ + /** + * Called when a player shift-right clicks this block with a Configurator. + * @param player - the player who clicked the block + * @param side - the side the block was clicked on + * @return whether or not an action was performed + */ + public boolean onSneakRightClick(EntityPlayer player, int side); + + /** + * Called when a player right clicks this block with a Configurator. + * @param player - the player who clicked the block + * @param side - the side the block was clicked on + * @return whether or not an action was performed + */ + public boolean onRightClick(EntityPlayer player, int side); +} diff --git a/src/api/java/mekanism/api/IFilterAccess.java b/src/api/java/mekanism/api/IFilterAccess.java new file mode 100644 index 0000000..abdcf29 --- /dev/null +++ b/src/api/java/mekanism/api/IFilterAccess.java @@ -0,0 +1,31 @@ +package mekanism.api; + +import net.minecraft.nbt.NBTTagCompound; + +/** + * Implement this in your TileEntity class if you wish for Mekanism filters to be able to store any of their + * information. + * @author aidancbrady + * + */ +public interface IFilterAccess +{ + /** + * Collects the TileEntity's filter card data into the parameterized NBTTagCompound. + * @param nbtTags - the NBTTagCompound of the filter card ItemStack + * @return the NBTTagCompound that now contains the TileEntity's filter card data + */ + public NBTTagCompound getFilterData(NBTTagCompound nbtTags); + + /** + * Retrieves the TileEntity's data contained in the filter card based on the given NBTTagCompopund. + * @param nbtTags - the NBTTagCompound of the filter card ItemStack + */ + public void setFilterData(NBTTagCompound nbtTags); + + /** + * A String name of this TileEntity that will be displayed as the type of data on the filter card. + * @return the String name of this TileEntity + */ + public String getDataType(); +} diff --git a/src/api/java/mekanism/api/IHeatTransfer.java b/src/api/java/mekanism/api/IHeatTransfer.java new file mode 100644 index 0000000..da682e1 --- /dev/null +++ b/src/api/java/mekanism/api/IHeatTransfer.java @@ -0,0 +1,28 @@ +package mekanism.api; + +import net.minecraftforge.common.util.ForgeDirection; + +public interface IHeatTransfer +{ + /**The value of the zero point of our temperature scale in kelvin*/ + public static final double AMBIENT_TEMP = 300; + + /**The heat transfer coefficient for air*/ + public static final double AIR_INVERSE_COEFFICIENT = 10000; + + public double getTemp(); + + public double getInverseConductionCoefficient(); + + public double getInsulationCoefficient(ForgeDirection side); + + public void transferHeatTo(double heat); + + public double[] simulateHeat(); + + public double applyTemperatureChange(); + + public boolean canConnectHeat(ForgeDirection side); + + public IHeatTransfer getAdjacent(ForgeDirection side); +} diff --git a/src/api/java/mekanism/api/IMekWrench.java b/src/api/java/mekanism/api/IMekWrench.java new file mode 100644 index 0000000..6ac4b05 --- /dev/null +++ b/src/api/java/mekanism/api/IMekWrench.java @@ -0,0 +1,8 @@ +package mekanism.api; + +import net.minecraft.entity.player.EntityPlayer; + +public interface IMekWrench +{ + public boolean canUseWrench(EntityPlayer player, int x, int y, int z); +} diff --git a/src/api/java/mekanism/api/ISalinationSolar.java b/src/api/java/mekanism/api/ISalinationSolar.java new file mode 100644 index 0000000..20e3e1e --- /dev/null +++ b/src/api/java/mekanism/api/ISalinationSolar.java @@ -0,0 +1,11 @@ +package mekanism.api; + +/** + * Implement this class in a TileEntity if you wish for it to be able to heat up a Salination Plant. + * @author aidancbrady + * + */ +public interface ISalinationSolar +{ + public boolean seesSun(); +} diff --git a/src/api/java/mekanism/api/ItemRetriever.java b/src/api/java/mekanism/api/ItemRetriever.java new file mode 100644 index 0000000..c2820f0 --- /dev/null +++ b/src/api/java/mekanism/api/ItemRetriever.java @@ -0,0 +1,112 @@ +package mekanism.api; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +/** + * Use this class's 'getItem()' method to retrieve ItemStacks from the 'Mekanism' + * class. + * @author AidanBrady + * + */ +public final class ItemRetriever +{ + /** The 'MekanismItems' class that items are retrieved from. */ + private static Class MekanismItems; + + /** The 'MekanismBlocks' class that blocks are retrieved from. */ + private static Class MekanismBlocks; + + /** + * Attempts to retrieve an ItemStack of an item with the declared identifier. + * + * Mekanism identifiers follow an easy-to-remember pattern. All identifiers + * are identical to the String returned by 'getItemName().' None include spaces, + * and all start with a capital letter. The name that shows up in-game can be + * stripped down to identifier form by removing spaces and all non-alphabetic + * characters (,./'=-_). Below is an example: + * + * ItemStack enrichedAlloy = ItemRetriever.getItem("EnrichedAlloy"); + * + * Note that for items or blocks that have specific metadata you will need to create + * a new ItemStack with that specified value, as this will only return an ItemStack + * with the meta value '0.' + * + * Make sure you run this in or after FMLPostInitializationEvent runs, because most + * items are registered when FMLInitializationEvent runs. However, some items ARE + * registered later in order to hook into other mods. In a rare circumstance you may + * have to add "after:Mekanism" in the @Mod 'dependencies' annotation. + * + * @param identifier - a String to be searched in the 'MekanismItems' class + * @return an ItemStack of the declared identifier, otherwise null. + */ + public static ItemStack getItem(String identifier) + { + try { + if(MekanismItems == null) + { + MekanismItems = Class.forName("mekanism.common.MekanismItems"); + } + + Object ret = MekanismItems.getField(identifier).get(null); + + if(ret instanceof Item) + { + return new ItemStack((Item)ret, 1); + } + else { + return null; + } + } catch(Exception e) { + System.err.println("Error retrieving item with identifier '" + identifier + "': " + e.getMessage()); + return null; + } + } + + /** + * Attempts to retrieve an ItemStack of a block with the declared identifier. + * + * Mekanism identifiers follow an easy-to-remember pattern. All identifiers + * are identical to the String returned by 'getItemName().' None include spaces, + * and all start with a capital letter. The name that shows up in-game can be + * stripped down to identifier form by removing spaces and all non-alphabetic + * characters (,./'=-_). Below is an example: + * + * ItemStack enrichedAlloy = ItemRetriever.getItem("EnrichedAlloy"); + * + * Note that for items or blocks that have specific metadata you will need to create + * a new ItemStack with that specified value, as this will only return an ItemStack + * with the meta value '0.' + * + * Make sure you run this in or after FMLPostInitializationEvent runs, because most + * items are registered when FMLInitializationEvent runs. However, some items ARE + * registered later in order to hook into other mods. In a rare circumstance you may + * have to add "after:Mekanism" in the @Mod 'dependencies' annotation. + * + * @param identifier - a String to be searched in the 'MekanismBlocks' class + * @return an ItemStack of the declared identifier, otherwise null. + */ + public static ItemStack getBlock(String identifier) + { + try { + if(MekanismBlocks == null) + { + MekanismBlocks = Class.forName("mekanism.common.MekanismBlocks"); + } + + Object ret = MekanismBlocks.getField(identifier).get(null); + + if(ret instanceof Block) + { + return new ItemStack((Block)ret, 1); + } + else { + return null; + } + } catch(Exception e) { + System.err.println("Error retrieving block with identifier '" + identifier + "': " + e.getMessage()); + return null; + } + } +} diff --git a/src/api/java/mekanism/api/MekanismAPI.java b/src/api/java/mekanism/api/MekanismAPI.java new file mode 100644 index 0000000..abdd6da --- /dev/null +++ b/src/api/java/mekanism/api/MekanismAPI.java @@ -0,0 +1,50 @@ +package mekanism.api; + +import java.util.HashSet; +import java.util.Set; + +import mekanism.api.util.BlockInfo; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraftforge.oredict.OreDictionary; +import cpw.mods.fml.common.eventhandler.Event; + +public class MekanismAPI +{ + //Add a BlockInfo value here if you don't want a certain block to be picked up by cardboard boxes + private static Set<BlockInfo> cardboardBoxIgnore = new HashSet<BlockInfo>(); + + /** Mekanism debug mode */ + public static boolean debug = false; + + public static boolean isBlockCompatible(Item item, int meta) + { + for(BlockInfo i : cardboardBoxIgnore) + { + if(i.block == Block.getBlockFromItem(item) && (i.meta == OreDictionary.WILDCARD_VALUE || i.meta == meta)) + { + return false; + } + } + + return true; + } + + public static void addBoxBlacklist(Block block, int meta) + { + cardboardBoxIgnore.add(new BlockInfo(block, meta)); + } + + public static void removeBoxBlacklist(Block block, int meta) + { + cardboardBoxIgnore.remove(new BlockInfo(block, meta)); + } + + public static Set<BlockInfo> getBoxIgnore() + { + return cardboardBoxIgnore; + } + + public static class BoxBlacklistEvent extends Event {} +} diff --git a/src/api/java/mekanism/api/MekanismConfig.java b/src/api/java/mekanism/api/MekanismConfig.java new file mode 100644 index 0000000..2f9ea68 --- /dev/null +++ b/src/api/java/mekanism/api/MekanismConfig.java @@ -0,0 +1,137 @@ +package mekanism.api; + +import java.util.HashMap; +import java.util.Map; + +import mekanism.api.util.UnitDisplayUtils.EnergyType; +import mekanism.api.util.UnitDisplayUtils.TempType; + +public class MekanismConfig +{ + public static class general + { + public static boolean updateNotifications = true; + public static boolean controlCircuitOreDict = true; + public static boolean logPackets = false; + public static boolean dynamicTankEasterEgg = false; + public static boolean voiceServerEnabled = true; + public static boolean cardboardSpawners = true; + public static boolean enableWorldRegeneration = true; + public static boolean creativeOverrideElectricChest = true; + public static boolean spawnBabySkeletons = true; + public static int obsidianTNTBlastRadius = 12; + public static int osmiumPerChunk = 12; + public static int copperPerChunk = 16; + public static int tinPerChunk = 14; + public static int saltPerChunk = 2; + public static int obsidianTNTDelay = 100; + public static int UPDATE_DELAY = 10; + public static int VOICE_PORT = 36123; + public static int maxUpgradeMultiplier = 10; + public static int userWorldGenVersion = 0; + public static double ENERGY_PER_REDSTONE = 10000; + public static int ETHENE_BURN_TIME = 40; + public static double DISASSEMBLER_USAGE = 10; + public static EnergyType activeType = EnergyType.J; + public static TempType tempUnit = TempType.K; + public static double TO_IC2; + public static double TO_TE; + public static double FROM_H2; + public static double FROM_IC2; + public static double FROM_TE; + public static int laserRange; + public static double laserEnergyNeededPerHardness; + public static double minerSilkMultiplier = 6; + public static boolean blacklistIC2; + public static boolean blacklistRF; + public static boolean destroyDisabledBlocks; + public static boolean enableAmbientLighting; + public static int ambientLightingLevel; + public static boolean prefilledPortableTanks; + public static double armoredJetpackDamageRatio; + public static int armoredJetpackDamageMax; + public static boolean aestheticWorldDamage; + public static boolean opsBypassRestrictions; + public static double solarEvaporationSpeed; + public static int maxJetpackGas; + public static int maxScubaGas; + public static int maxFlamethrowerGas; + } + + public static class client + { + public static boolean enablePlayerSounds = true; + public static boolean enableMachineSounds = true; + public static boolean fancyUniversalCableRender = true; + public static boolean holidays = true; + public static float baseSoundVolume = 1F; + public static boolean machineEffects = true; + public static boolean oldTransmitterRender = false; + public static boolean replaceSoundsWhenResuming = true; + public static boolean renderCTM = true; + } + + public static class machines + { + private static Map<String, Boolean> config = new HashMap<String, Boolean>(); + + public static boolean isEnabled(String type) + { + return config.get(type) != null && config.get(type); + } + + public static void setEntry(String type, boolean enabled) + { + config.put(type, enabled); + } + } + + public static class usage + { + public static double enrichmentChamberUsage; + public static double osmiumCompressorUsage; + public static double combinerUsage; + public static double crusherUsage; + public static double factoryUsage; + public static double metallurgicInfuserUsage; + public static double purificationChamberUsage; + public static double energizedSmelterUsage; + public static double digitalMinerUsage; + public static double electricPumpUsage; + public static double rotaryCondensentratorUsage; + public static double oxidationChamberUsage; + public static double chemicalInfuserUsage; + public static double chemicalInjectionChamberUsage; + public static double precisionSawmillUsage; + public static double chemicalDissolutionChamberUsage; + public static double chemicalWasherUsage; + public static double chemicalCrystallizerUsage; + public static double seismicVibratorUsage; + public static double pressurizedReactionBaseUsage; + public static double fluidicPlenisherUsage; + public static double laserUsage; + public static double gasCentrifugeUsage; + public static double heavyWaterElectrolysisUsage; + } + + public static class generators + { + public static double advancedSolarGeneration; + public static double bioGeneration; + public static double heatGeneration; + public static double heatGenerationLava; + public static double heatGenerationNether; + public static double solarGeneration; + + public static double windGenerationMin; + public static double windGenerationMax; + + public static int windGenerationMinY; + public static int windGenerationMaxY; + } + + public static class tools + { + public static double armorSpawnRate; + } +} diff --git a/src/api/java/mekanism/api/Pos3D.java b/src/api/java/mekanism/api/Pos3D.java new file mode 100644 index 0000000..75f83a0 --- /dev/null +++ b/src/api/java/mekanism/api/Pos3D.java @@ -0,0 +1,458 @@ +package mekanism.api; + +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MathHelper; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Pos3D - a way of performing operations on objects in a three dimensional environment. + * @author aidancbrady + * + */ +public class Pos3D +{ + public double xPos; + public double yPos; + public double zPos; + + public Pos3D() + { + this(0, 0, 0); + } + + public Pos3D(Vec3 vec) + { + xPos = vec.xCoord; + yPos = vec.yCoord; + zPos = vec.zCoord; + } + + public Pos3D(MovingObjectPosition mop) + { + xPos = mop.blockX; + yPos = mop.blockY; + zPos = mop.blockZ; + } + + public Pos3D(double x, double y, double z) + { + xPos = x; + yPos = y; + zPos = z; + } + + public Pos3D(Coord4D coord) + { + xPos = coord.xCoord; + yPos = coord.yCoord; + zPos = coord.zCoord; + } + + /** + * Creates a Pos3D with an entity's posX, posY, and posZ values. + * @param entity - entity to create the Pos3D from + */ + public Pos3D(Entity entity) + { + this(entity.posX, entity.posY, entity.posZ); + } + + /** + * Creates a Pos3D with a TileEntity's xCoord, yCoord and zCoord values. + * @param tileEntity - TileEntity to create the Pos3D from + */ + public Pos3D(TileEntity tileEntity) + { + this(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); + } + + /** + * Returns a new Pos3D from a tag compound. + * @param tag - tag compound to read from + * @return the Pos3D from the tag compound + */ + public static Pos3D read(NBTTagCompound tag) + { + return new Pos3D(tag.getDouble("x"), tag.getDouble("y"), tag.getDouble("z")); + } + + /** + * Writes this Pos3D's data to an NBTTagCompound. + * @param nbtTags - tag compound to write to + * @return the tag compound with this Pos3D's data + */ + public NBTTagCompound write(NBTTagCompound nbtTags) + { + nbtTags.setDouble("x", xPos); + nbtTags.setDouble("y", yPos); + nbtTags.setDouble("z", zPos); + + return nbtTags; + } + + /** + * Creates and returns a Pos3D with values representing the difference between this and the Pos3D in the parameters. + * @param pos - Pos3D to subtract + * @return difference of the two Pos3Ds + */ + public Pos3D diff(Pos3D pos) + { + return new Pos3D(xPos-pos.xPos, yPos-pos.yPos, zPos-pos.zPos); + } + + /** + * Creates a new Pos3D from the motion of an entity. + * @param entity + * @return Pos3D representing the motion of the given entity + */ + public static Pos3D fromMotion(Entity entity) + { + return new Pos3D(entity.motionX, entity.motionY, entity.motionZ); + } + + /** + * Creates a new Coord4D representing this Pos3D in the provided dimension. + * @param dimensionId - the dimension this Pos3D is in + * @return Coord4D representing this Pos3D + */ + public Coord4D getCoord(int dimensionId) + { + return new Coord4D((int)xPos, (int)yPos, (int)zPos, dimensionId); + } + + /** + * Centres a block-derived Pos3D + */ + public Pos3D centre() + { + return translate(0.5, 0.5, 0.5); + } + + /** + * Translates this Pos3D by the defined values. + * @param x - amount to translate on the x axis + * @param y - amount to translate on the y axis + * @param z - amount to translate on the z axis + * @return the translated Pos3D + */ + public Pos3D translate(double x, double y, double z) + { + xPos += x; + yPos += y; + zPos += z; + + return this; + } + + /** + * Performs the same operation as translate(x, y, z), but with a Pos3D value instead. + * @param pos - Pos3D value to translate by + * @return translated Pos3D + */ + public Pos3D translate(Pos3D pos) + { + return translate(pos.xPos, pos.yPos, pos.zPos); + } + + /** + * Performs the same operation as translate(x, y, z), but by a set amount in a ForgeDirection + */ + public Pos3D translate(ForgeDirection direction, double amount) + { + return translate(direction.offsetX * amount, direction.offsetY * amount, direction.offsetZ * amount); + } + + /** + * Performs the same operation as translate(x, y, z), but by a set amount in a ForgeDirection + */ + public Pos3D translateExcludingSide(ForgeDirection direction, double amount) + { + if(direction.offsetX == 0) xPos += amount; + if(direction.offsetY == 0) yPos += amount; + if(direction.offsetZ == 0) zPos += amount; + + return this; + } + + /** + * Returns the distance between this and the defined Pos3D. + * @param pos - the Pos3D to find the distance to + * @return the distance between this and the defined Pos3D + */ + public double distance(Pos3D pos) + { + double subX = xPos - pos.xPos; + double subY = yPos - pos.yPos; + double subZ = zPos - pos.zPos; + return MathHelper.sqrt_double(subX * subX + subY * subY + subZ * subZ); + } + + /** + * Rotates this Pos3D by the defined yaw value. + * @param yaw - yaw to rotate by + * @return rotated Pos3D + */ + public Pos3D rotateYaw(double yaw) + { + double yawRadians = Math.toRadians(yaw); + + double x = xPos; + double z = zPos; + + if(yaw != 0) + { + xPos = x * Math.cos(yawRadians) - z * Math.sin(yawRadians); + zPos = z * Math.cos(yawRadians) + x * Math.sin(yawRadians); + } + + return this; + } + + public Pos3D rotatePitch(double pitch) + { + double pitchRadians = Math.toRadians(pitch); + + double y = yPos; + double z = zPos; + + if(pitch != 0) + { + yPos = y * Math.cos(pitchRadians) - z * Math.sin(pitchRadians); + zPos = z * Math.cos(pitchRadians) + y * Math.sin(pitchRadians); + } + + return this; + } + + public Pos3D rotate(double yaw, double pitch) + { + return rotate(yaw, pitch, 0); + } + + public Pos3D rotate(double yaw, double pitch, double roll) + { + double yawRadians = Math.toRadians(yaw); + double pitchRadians = Math.toRadians(pitch); + double rollRadians = Math.toRadians(roll); + + double x = xPos; + double y = yPos; + double z = zPos; + + xPos = x * Math.cos(yawRadians) * Math.cos(pitchRadians) + z * (Math.cos(yawRadians) * Math.sin(pitchRadians) * Math.sin(rollRadians) - Math.sin(yawRadians) * Math.cos(rollRadians)) + y * (Math.cos(yawRadians) * Math.sin(pitchRadians) * Math.cos(rollRadians) + Math.sin(yawRadians) * Math.sin(rollRadians)); + zPos = x * Math.sin(yawRadians) * Math.cos(pitchRadians) + z * (Math.sin(yawRadians) * Math.sin(pitchRadians) * Math.sin(rollRadians) + Math.cos(yawRadians) * Math.cos(rollRadians)) + y * (Math.sin(yawRadians) * Math.sin(pitchRadians) * Math.cos(rollRadians) - Math.cos(yawRadians) * Math.sin(rollRadians)); + yPos = -x * Math.sin(pitchRadians) + z * Math.cos(pitchRadians) * Math.sin(rollRadians) + y * Math.cos(pitchRadians) * Math.cos(rollRadians); + + return this; + } + + public Pos3D multiply(Pos3D pos) + { + xPos *= pos.xPos; + yPos *= pos.yPos; + zPos *= pos.zPos; + + return this; + } + + /** + * Scales this Pos3D by the defined x, y, an z values. + * @param x - x value to scale by + * @param y - y value to scale by + * @param z - z value to scale by + * @return scaled Pos3D + */ + public Pos3D scale(double x, double y, double z) + { + xPos *= x; + yPos *= y; + zPos *= z; + + return this; + } + + /** + * Performs the same operation as scale(x, y, z), but with a value representing all three dimensions. + * @param scale - value to scale by + * @return scaled Pos3D + */ + public Pos3D scale(double scale) + { + return scale(scale, scale, scale); + } + + public Pos3D rotate(float angle, Pos3D axis) + { + return translateMatrix(getRotationMatrix(angle, axis), this); + } + + public double[] getRotationMatrix(float angle) + { + double[] matrix = new double[16]; + Pos3D axis = clone().normalize(); + + double x = axis.xPos; + double y = axis.yPos; + double z = axis.zPos; + + angle *= 0.0174532925D; + + float cos = (float)Math.cos(angle); + float ocos = 1.0F - cos; + float sin = (float)Math.sin(angle); + + matrix[0] = (x * x * ocos + cos); + matrix[1] = (y * x * ocos + z * sin); + matrix[2] = (x * z * ocos - y * sin); + matrix[4] = (x * y * ocos - z * sin); + matrix[5] = (y * y * ocos + cos); + matrix[6] = (y * z * ocos + x * sin); + matrix[8] = (x * z * ocos + y * sin); + matrix[9] = (y * z * ocos - x * sin); + matrix[10] = (z * z * ocos + cos); + matrix[15] = 1.0F; + + return matrix; + } + + public static Pos3D translateMatrix(double[] matrix, Pos3D translation) + { + double x = translation.xPos * matrix[0] + translation.yPos * matrix[1] + translation.zPos * matrix[2] + matrix[3]; + double y = translation.xPos * matrix[4] + translation.yPos * matrix[5] + translation.zPos * matrix[6] + matrix[7]; + double z = translation.xPos * matrix[8] + translation.yPos * matrix[9] + translation.zPos * matrix[10] + matrix[11]; + + translation.xPos = x; + translation.yPos = y; + translation.zPos = z; + + return translation; + } + + public static double[] getRotationMatrix(float angle, Pos3D axis) + { + return axis.getRotationMatrix(angle); + } + + public double anglePreNorm(Pos3D pos2) + { + return Math.acos(dotProduct(pos2)); + } + + public static double anglePreNorm(Pos3D pos1, Pos3D pos2) + { + return Math.acos(pos1.clone().dotProduct(pos2)); + } + + public double dotProduct(Pos3D pos) + { + return xPos * pos.xPos + yPos * pos.yPos + zPos * pos.zPos; + } + + public Pos3D crossProduct(Pos3D compare) + { + return clone().toCrossProduct(compare); + } + + public Pos3D toCrossProduct(Pos3D compare) + { + double newX = yPos * compare.zPos - zPos * compare.yPos; + double newY = zPos * compare.xPos - xPos * compare.zPos; + double newZ = xPos * compare.yPos - yPos * compare.xPos; + + xPos = newX; + yPos = newY; + zPos = newZ; + + return this; + } + + public Pos3D xCrossProduct() + { + return new Pos3D(0.0D, zPos, -yPos); + } + + public Pos3D zCrossProduct() + { + return new Pos3D(-yPos, xPos, 0.0D); + } + + public Pos3D getPerpendicular() + { + if(zPos == 0) + { + return zCrossProduct(); + } + + return xCrossProduct(); + } + + public Pos3D floor() + { + return new Pos3D(Math.floor(xPos), Math.floor(yPos), Math.floor(zPos)); + } + + public double getMagnitude() + { + return Math.sqrt(xPos * xPos + yPos * yPos + zPos * zPos); + } + + public Pos3D normalize() + { + double d = getMagnitude(); + + if (d != 0) + { + this.scale(1 / d); + } + + return this; + } + + public static AxisAlignedBB getAABB(Pos3D pos1, Pos3D pos2) + { + return AxisAlignedBB.getBoundingBox( + Math.min(pos1.xPos, pos2.xPos), + Math.min(pos1.yPos, pos2.yPos), + Math.min(pos1.zPos, pos2.zPos), + Math.max(pos1.xPos, pos2.xPos), + Math.max(pos1.yPos, pos2.yPos), + Math.max(pos1.zPos, pos2.zPos) + ); + } + + @Override + public Pos3D clone() + { + return new Pos3D(xPos, yPos, zPos); + } + + @Override + public String toString() + { + return "[Pos3D: " + xPos + ", " + yPos + ", " + zPos + "]"; + } + + @Override + public boolean equals(Object obj) + { + return obj instanceof Pos3D && + ((Pos3D)obj).xPos == xPos && + ((Pos3D)obj).yPos == yPos && + ((Pos3D)obj).zPos == zPos; + } + + @Override + public int hashCode() + { + int code = 1; + code = 31 * code + new Double(xPos).hashCode(); + code = 31 * code + new Double(yPos).hashCode(); + code = 31 * code + new Double(zPos).hashCode(); + return code; + } +} diff --git a/src/api/java/mekanism/api/Range4D.java b/src/api/java/mekanism/api/Range4D.java new file mode 100644 index 0000000..40905a6 --- /dev/null +++ b/src/api/java/mekanism/api/Range4D.java @@ -0,0 +1,114 @@ +package mekanism.api; + +import net.minecraft.entity.player.EntityPlayer; +import cpw.mods.fml.common.FMLCommonHandler; + +public class Range4D +{ + public int dimensionId; + + public int xMin; + public int yMin; + public int zMin; + public int xMax; + public int yMax; + public int zMax; + + public Range4D(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, int dimension) + { + xMin = minX; + yMin = minY; + zMin = minZ; + xMax = maxX; + yMax = maxY; + zMax = maxZ; + + dimensionId = dimension; + } + + public Range4D(Chunk3D chunk) + { + xMin = chunk.xCoord*16; + yMin = 0; + zMin = chunk.zCoord*16; + xMax = xMin+16; + yMax = 255; + zMax = zMin+16; + + dimensionId = chunk.dimensionId; + } + + public Range4D(Coord4D coord) + { + xMin = coord.xCoord; + yMin = coord.yCoord; + zMin = coord.zCoord; + + xMax = coord.xCoord+1; + yMax = coord.yCoord+1; + zMax = coord.zCoord+1; + + dimensionId = coord.dimensionId; + } + + public static Range4D getChunkRange(EntityPlayer player) + { + int radius = FMLCommonHandler.instance().getMinecraftServerInstance().getConfigurationManager().getViewDistance(); + + return new Range4D(new Chunk3D(player)).expandChunks(radius); + } + + public Range4D expandChunks(int chunks) + { + xMin -= chunks*16; + xMax += chunks*16; + zMin -= chunks*16; + zMax += chunks*16; + + return this; + } + + public boolean intersects(Range4D range) + { + return (xMax+1 - 1.E-05D > range.xMin) && (range.xMax+1 - 1.E-05D > xMin) && (yMax+1 - 1.E-05D > range.yMin) && (range.yMax+1 - 1.E-05D > yMin) && (zMax+1 - 1.E-05D > range.zMin) && (range.zMax+1 - 1.E-05D > zMin); + } + + @Override + public Range4D clone() + { + return new Range4D(xMin, yMin, zMin, xMax, yMax, zMax, dimensionId); + } + + @Override + public String toString() + { + return "[Range4D: " + xMin + ", " + yMin + ", " + zMin + ", " + xMax + ", " + yMax + ", " + zMax + ", dim=" + dimensionId + "]"; + } + + @Override + public boolean equals(Object obj) + { + return obj instanceof Range4D && + ((Range4D)obj).xMin == xMin && + ((Range4D)obj).yMin == yMin && + ((Range4D)obj).zMin == zMin && + ((Range4D)obj).xMax == xMax && + ((Range4D)obj).yMax == yMax && + ((Range4D)obj).zMax == zMax && + ((Range4D)obj).dimensionId == dimensionId; + } + + @Override + public int hashCode() + { + int code = 1; + code = 31 * code + xMin; + code = 31 * code + yMin; + code = 31 * code + zMin; + code = 31 * code + xMax; + code = 31 * code + yMax; + code = 31 * code + zMax; + code = 31 * code + dimensionId; + return code; + } +} diff --git a/src/api/java/mekanism/api/TabProxy.java b/src/api/java/mekanism/api/TabProxy.java new file mode 100644 index 0000000..c562c02 --- /dev/null +++ b/src/api/java/mekanism/api/TabProxy.java @@ -0,0 +1,42 @@ +package mekanism.api; + +import net.minecraft.creativetab.CreativeTabs; + +/** + * Class used to indirectly reference the Mekanism creative tab. + * @author AidanBrady + * + */ +public final class TabProxy +{ + /** The 'Mekanism' class where the tab instance is stored. */ + public static Class Mekanism; + + /** + * Attempts to get the Mekanism creative tab instance from the 'Mekanism' class. Will return + * the tab if the mod is loaded, but otherwise will return the defined 'preferred' creative tab. This way + * you don't need to worry about NPEs! + * @return Mekanism creative tab if can, otherwise preferred tab + */ + public static CreativeTabs tabMekanism(CreativeTabs preferred) + { + try { + if(Mekanism == null) + { + Mekanism = Class.forName("mekanism.common.Mekanism"); + } + + Object ret = Mekanism.getField("tabMekanism").get(null); + + if(ret instanceof CreativeTabs) + { + return (CreativeTabs)ret; + } + + return preferred; + } catch(Exception e) { + System.err.println("Error retrieving Mekanism creative tab."); + return preferred; + } + } +} diff --git a/src/api/java/mekanism/api/energy/EnergizedItemManager.java b/src/api/java/mekanism/api/energy/EnergizedItemManager.java new file mode 100644 index 0000000..165bdf6 --- /dev/null +++ b/src/api/java/mekanism/api/energy/EnergizedItemManager.java @@ -0,0 +1,60 @@ +package mekanism.api.energy; + +import net.minecraft.item.ItemStack; + +public class EnergizedItemManager +{ + /** + * Discharges an IEnergizedItem with the defined amount of energy. + * @param itemStack - ItemStack to discharge + * @param amount - amount of energy to discharge from the item, usually the total amount of energy needed in a TileEntity + * @return amount of energy discharged + */ + public static double discharge(ItemStack itemStack, double amount) + { + if(itemStack != null) + { + if(itemStack.getItem() instanceof IEnergizedItem) + { + IEnergizedItem energizedItem = (IEnergizedItem)itemStack.getItem(); + + if(energizedItem.canSend(itemStack)) + { + double energyToUse = Math.min(energizedItem.getMaxTransfer(itemStack), Math.min(energizedItem.getEnergy(itemStack), amount)); + energizedItem.setEnergy(itemStack, energizedItem.getEnergy(itemStack) - energyToUse); + + return energyToUse; + } + } + } + + return 0; + } + + /** + * Charges an IEnergizedItem with the defined amount of energy. + * @param itemStack - ItemStack to charge + * @param amount - amount of energy to charge the item with, usually the total amount of energy stored in a TileEntity + * @return amount of energy charged + */ + public static double charge(ItemStack itemStack, double amount) + { + if(itemStack != null) + { + if(itemStack.getItem() instanceof IEnergizedItem) + { + IEnergizedItem energizedItem = (IEnergizedItem)itemStack.getItem(); + + if(energizedItem.canReceive(itemStack)) + { + double energyToSend = Math.min(energizedItem.getMaxTransfer(itemStack), Math.min(energizedItem.getMaxEnergy(itemStack) - energizedItem.getEnergy(itemStack), amount)); + energizedItem.setEnergy(itemStack, energizedItem.getEnergy(itemStack) + energyToSend); + + return energyToSend; + } + } + } + + return 0; + } +} diff --git a/src/api/java/mekanism/api/energy/EnergyStack.java b/src/api/java/mekanism/api/energy/EnergyStack.java new file mode 100644 index 0000000..3f57621 --- /dev/null +++ b/src/api/java/mekanism/api/energy/EnergyStack.java @@ -0,0 +1,14 @@ +package mekanism.api.energy; + +/** + * Created by ben on 27/03/15. + */ +public class EnergyStack +{ + public double amount; + + public EnergyStack(double newAmount) + { + amount = newAmount; + } +} diff --git a/src/api/java/mekanism/api/energy/ICableOutputter.java b/src/api/java/mekanism/api/energy/ICableOutputter.java new file mode 100644 index 0000000..015379c --- /dev/null +++ b/src/api/java/mekanism/api/energy/ICableOutputter.java @@ -0,0 +1,18 @@ +package mekanism.api.energy; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Implement this if your TileEntity is capable of outputting energy to cables, overriding Mekanism's default implementation. + * @author AidanBrady + * + */ +public interface ICableOutputter +{ + /** + * Whether or not this block can output to a cable on a specific side. + * @param side - side to check + * @return if the block can output + */ + public boolean canOutputTo(ForgeDirection side); +} diff --git a/src/api/java/mekanism/api/energy/IEnergizedItem.java b/src/api/java/mekanism/api/energy/IEnergizedItem.java new file mode 100644 index 0000000..b672545 --- /dev/null +++ b/src/api/java/mekanism/api/energy/IEnergizedItem.java @@ -0,0 +1,59 @@ +package mekanism.api.energy; + +import net.minecraft.item.ItemStack; + +/** + * Implement this in an item's class if it should be able to store electricity. + * @author aidancbrady + * + */ +public interface IEnergizedItem +{ + /** + * Gets and returns the amount of energy stored in this item. + * @param itemStack - the ItemStack to check + * @return energy stored + */ + public double getEnergy(ItemStack itemStack); + + /** + * Sets this item's stored energy value to a new amount. + * @param itemStack - the ItemStack who's energy value is to be change + * @param amount - new amount of energy + */ + public void setEnergy(ItemStack itemStack, double amount); + + /** + * Gets and returns this item's maximum amount of energy that can be stored. + * @param itemStack - the ItemStack to check + * @return maximum energy + */ + public double getMaxEnergy(ItemStack itemStack); + + /** + * Gets and returns how much energy this item can transfer to and from charging slots. + * @param itemStack - the ItemStack to check + * @return transfer amount + */ + public double getMaxTransfer(ItemStack itemStack); + + /** + * Gets and returns whether or not this item can receive energy from a charging slot. + * @param itemStack - the ItemStack to check + * @return if the item can receive energy + */ + public boolean canReceive(ItemStack itemStack); + + /** + * Gets and returns whether or not this item can send energy to a charging slot. + * @param itemStack - the ItemStack to check + * @return if the item can send energy + */ + public boolean canSend(ItemStack itemStack); + + /** + * Returns whether or not this item contains metadata-specific subtypes instead of using metadata for damage display. + * @return if the item contains metadata-specific subtypes + */ + public boolean isMetadataSpecific(ItemStack itemStack); +} diff --git a/src/api/java/mekanism/api/energy/IStrictEnergyAcceptor.java b/src/api/java/mekanism/api/energy/IStrictEnergyAcceptor.java new file mode 100644 index 0000000..53edc68 --- /dev/null +++ b/src/api/java/mekanism/api/energy/IStrictEnergyAcceptor.java @@ -0,0 +1,25 @@ +package mekanism.api.energy; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Implement this if your TileEntity can accept energy at a floating-point double value from Universal Cables. + * @author AidanBrady + * + */ +public interface IStrictEnergyAcceptor extends IStrictEnergyStorage +{ + /** + * Transfer a certain amount of energy to this acceptor. + * @param amount - amount to transfer + * @return energy used + */ + public double transferEnergyToAcceptor(ForgeDirection side, double amount); + + /** + * Whether or not this tile entity accepts energy from a certain side. + * @param side - side to check + * @return if tile entity accepts energy + */ + public boolean canReceiveEnergy(ForgeDirection side); +} diff --git a/src/api/java/mekanism/api/energy/IStrictEnergyStorage.java b/src/api/java/mekanism/api/energy/IStrictEnergyStorage.java new file mode 100644 index 0000000..fd560fa --- /dev/null +++ b/src/api/java/mekanism/api/energy/IStrictEnergyStorage.java @@ -0,0 +1,27 @@ +package mekanism.api.energy; + +/** + * Mekanism-specific energy storage for TileEntities, already implemented in IStrictEnergyAcceptor. + * @author aidancbrady + * + */ +public interface IStrictEnergyStorage +{ + /** + * Gets the amount of energy this TileEntity is currently storing. + * @return stored energy + */ + public double getEnergy(); + + /** + * Sets the amount of stored energy of this TileEntity to a new amount. + * @param energy - new energy value + */ + public void setEnergy(double energy); + + /** + * Gets the maximum amount of energy this TileEntity can store. + * @return maximum energy + */ + public double getMaxEnergy(); +} diff --git a/src/api/java/mekanism/api/energy/package-info.java b/src/api/java/mekanism/api/energy/package-info.java new file mode 100644 index 0000000..8f3d371 --- /dev/null +++ b/src/api/java/mekanism/api/energy/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|energy") +package mekanism.api.energy; +import cpw.mods.fml.common.API;
\ No newline at end of file diff --git a/src/api/java/mekanism/api/gas/Gas.java b/src/api/java/mekanism/api/gas/Gas.java new file mode 100644 index 0000000..f05be52 --- /dev/null +++ b/src/api/java/mekanism/api/gas/Gas.java @@ -0,0 +1,221 @@ +package mekanism.api.gas; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.IIcon; +import net.minecraft.util.StatCollector; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; + +/** + * Gas - a class used to set specific properties of gasses when used or seen in-game. + * @author aidancbrady + * + */ +public class Gas +{ + private String name; + + private String unlocalizedName; + + private Fluid fluid; + + private IIcon icon; + + private boolean visible = true; + + private boolean from_fluid = false; + + /** + * Creates a new Gas object with a defined name or key value. + * @param s - name or key to associate this Gas with + */ + public Gas(String s) + { + unlocalizedName = name = s; + } + + /** + * Creates a new Gas object that corresponds to the given Fluid + */ + public Gas(Fluid f) + { + unlocalizedName = name = f.getName(); + icon = f.getStillIcon(); + fluid = f; + from_fluid = true; + } + + /** + * Gets the name (key) of this Gas. This is NOT a translated or localized display name. + * @return this Gas's name or key + */ + public String getName() + { + return name; + } + + /** + * Whether or not this is a visible gas. + * @return if this gas is visible + */ + public boolean isVisible() + { + return visible; + } + + /** + * Sets this gas's "visible" state to a new value. Setting it to 'false' will treat this gas as an internal gas, and it will not be displayed or accessed by other mods. + * @param v - new visible state + * @return this Gas object + */ + public Gas setVisible(boolean v) + { + visible = v; + + return this; + } + + /** + * Gets the unlocalized name of this Gas. + * @return this Gas's unlocalized name + */ + public String getUnlocalizedName() + { + return "gas." + unlocalizedName; + } + + /** + * Translates this Gas's unlocalized name and returns it as localized. + * @return this Gas's localized name + */ + public String getLocalizedName() + { + return StatCollector.translateToLocal(getUnlocalizedName()); + } + + /** + * Sets the unlocalized name of this Gas. + * @param s - unlocalized name to set + * @return this Gas object + */ + public Gas setUnlocalizedName(String s) + { + unlocalizedName = s; + + return this; + } + + /** + * Gets the IIcon associated with this Gas. + * @return associated IIcon + */ + public IIcon getIcon() + { + if(from_fluid) + { + return this.getFluid().getIcon(); + } + + return icon; + } + + /** + * Sets this gas's icon. + * @param i - IIcon to associate with this Gas + * @return this Gas object + */ + public Gas setIcon(IIcon i) + { + icon = i; + + if(hasFluid()) + { + fluid.setIcons(getIcon()); + } + + from_fluid = false; + + return this; + } + + /** + * Gets the ID associated with this gas. + * @return the associated gas ID + */ + public int getID() + { + return GasRegistry.getGasID(this); + } + + /** + * Writes this Gas to a defined tag compound. + * @param nbtTags - tag compound to write this Gas to + * @return the tag compound this gas was written to + */ + public NBTTagCompound write(NBTTagCompound nbtTags) + { + nbtTags.setString("gasName", getName()); + + return nbtTags; + } + + /** + * Returns the Gas stored in the defined tag compound. + * @param nbtTags - tag compound to get the Gas from + * @return Gas stored in the tag compound + */ + public static Gas readFromNBT(NBTTagCompound nbtTags) + { + if(nbtTags == null || nbtTags.hasNoTags()) + { + return null; + } + + return GasRegistry.getGas(nbtTags.getString("gasName")); + } + + /** + * Whether or not this Gas has an associated fluid. + * @return if this gas has a fluid + */ + public boolean hasFluid() + { + return fluid != null; + } + + /** + * Gets the fluid associated with this Gas. + * @return fluid associated with this gas + */ + public Fluid getFluid() + { + return fluid; + } + + /** + * Registers a new fluid out of this Gas or gets one from the FluidRegistry. + * @return this Gas object + */ + public Gas registerFluid() + { + if(fluid == null) + { + if(FluidRegistry.getFluid(getName()) == null) + { + fluid = new Fluid(getName()).setGaseous(true); + FluidRegistry.registerFluid(fluid); + } + else { + fluid = FluidRegistry.getFluid(getName()); + } + } + + return this; + } + + @Override + public String toString() + { + return name; + } +} diff --git a/src/api/java/mekanism/api/gas/GasNetwork.java b/src/api/java/mekanism/api/gas/GasNetwork.java new file mode 100644 index 0000000..ea81d12 --- /dev/null +++ b/src/api/java/mekanism/api/gas/GasNetwork.java @@ -0,0 +1,358 @@ +package mekanism.api.gas; + +import com.google.common.collect.Lists; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.Event; +import mekanism.api.Coord4D; +import mekanism.api.transmitters.DynamicNetwork; +import mekanism.api.transmitters.IGridTransmitter; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.*; + +/** + * A DynamicNetwork extension created specifically for the transfer of Gasses. By default this is server-only, but if ticked on + * the client side and if it's posted events are handled properly, it has the capability to visually display gasses network-wide. + * @author aidancbrady + * + */ +public class GasNetwork extends DynamicNetwork<IGasHandler, GasNetwork> +{ + public int transferDelay = 0; + + public boolean didTransfer; + public boolean prevTransfer; + + public float gasScale; + + public Gas refGas; + + public GasStack buffer; + public int prevStored; + + public int prevTransferAmount = 0; + + public GasNetwork() {} + + public GasNetwork(Collection<GasNetwork> networks) + { + for(GasNetwork net : networks) + { + if(net != null) + { + if(FMLCommonHandler.instance().getEffectiveSide().isClient()) + { + if(net.refGas != null && net.gasScale > gasScale) + { + gasScale = net.gasScale; + refGas = net.refGas; + buffer = net.buffer; + + net.gasScale = 0; + net.refGas = null; + net.buffer = null; + } + } else + { + if(net.buffer != null) + { + if(buffer == null) + { + buffer = net.buffer.copy(); + } else + { + if(buffer.isGasEqual(net.buffer)) + { + buffer.amount += net.buffer.amount; + } + else if(net.buffer.amount > buffer.amount) + { + buffer = net.buffer.copy(); + } + + } + + net.buffer = null; + } + } + + adoptTransmittersAndAcceptorsFrom(net); + net.deregister(); + } + } + + gasScale = getScale(); + + register(); + } + + @Override + public void absorbBuffer(IGridTransmitter<IGasHandler, GasNetwork> transmitter) + { + Object b = transmitter.getBuffer(); + + if(!(b instanceof GasStack) || ((GasStack)b).getGas() == null || ((GasStack)b).amount == 0) + { + return; + } + + GasStack gas = (GasStack)b; + + if(buffer == null || buffer.getGas() == null || buffer.amount == 0) + { + buffer = gas.copy(); + gas.amount = 0; + return; + } + + //TODO better multiple buffer impl + if(buffer.isGasEqual(gas)) + { + buffer.amount += gas.amount; + } + + gas.amount = 0; + } + + @Override + public void clampBuffer() + { + if(buffer != null && buffer.amount > getCapacity()) + { + buffer.amount = capacity; + } + } + + public int getGasNeeded() + { + return getCapacity()-(buffer != null ? buffer.amount : 0); + } + + public int tickEmit(GasStack stack) + { + List<IGasHandler> availableAcceptors = Lists.newArrayList(); + + availableAcceptors.addAll(getAcceptors(stack.getGas())); + + Collections.shuffle(availableAcceptors); + + int toSend = stack.amount; + int prevSending = toSend; + + if(!availableAcceptors.isEmpty()) + { + int divider = availableAcceptors.size(); + int remaining = toSend % divider; + int sending = (toSend-remaining)/divider; + + for(IGasHandler acceptor : availableAcceptors) + { + int currentSending = sending; + EnumSet<ForgeDirection> sides = acceptorDirections.get(Coord4D.get((TileEntity)acceptor)); + + if(remaining > 0) + { + currentSending++; + remaining--; + } + + for(ForgeDirection side : sides) + { + int prev = toSend; + + toSend -= acceptor.receiveGas(side, new GasStack(stack.getGas(), currentSending), true); + + if(toSend < prev) + { + break; + } + } + } + } + + int sent = prevSending-toSend; + + if(sent > 0 && FMLCommonHandler.instance().getEffectiveSide().isServer()) + { + didTransfer = true; + transferDelay = 2; + } + + return sent; + } + + public int emit(GasStack stack, boolean doTransfer) + { + if(buffer != null && buffer.getGas() != stack.getGas()) + { + return 0; + } + + int toUse = Math.min(getGasNeeded(), stack.amount); + + if(doTransfer) + { + if(buffer == null) + { + buffer = stack.copy(); + buffer.amount = toUse; + } + else { + buffer.amount += toUse; + } + } + + return toUse; + } + + @Override + public void onUpdate() + { + super.onUpdate(); + + if(FMLCommonHandler.instance().getEffectiveSide().isServer()) + { + prevTransferAmount = 0; + + if(transferDelay == 0) + { + didTransfer = false; + } + else { + transferDelay--; + } + + int stored = buffer != null ? buffer.amount : 0; + + if(stored != prevStored) + { + needsUpdate = true; + } + + prevStored = stored; + + if(didTransfer != prevTransfer || needsUpdate) + { + MinecraftForge.EVENT_BUS.post(new GasTransferEvent(this, buffer, didTransfer)); + needsUpdate = false; + } + + prevTransfer = didTransfer; + + if(buffer != null) + { + prevTransferAmount = tickEmit(buffer); + buffer.amount -= prevTransferAmount; + + if(buffer.amount <= 0) + { + buffer = null; + } + } + } + } + + @Override + public void clientTick() + { + super.clientTick(); + + gasScale = Math.max(gasScale, getScale()); + + if(didTransfer && gasScale < 1) + { + gasScale = Math.max(getScale(), Math.min(1, gasScale+0.02F)); + } + else if(!didTransfer && gasScale > 0) + { + gasScale = Math.max(getScale(), Math.max(0, gasScale-0.02F)); + + if(gasScale == 0) + { + buffer = null; + } + } + } + + @Override + public Set<IGasHandler> getAcceptors(Object data) + { + Gas type = (Gas)data; + Set<IGasHandler> toReturn = new HashSet<IGasHandler>(); + + if(FMLCommonHandler.instance().getEffectiveSide().isClient()) + { + return toReturn; + } + + for(Coord4D coord : possibleAcceptors.keySet()) + { + EnumSet<ForgeDirection> sides = acceptorDirections.get(coord); + TileEntity tile = coord.getTileEntity(getWorld()); + + if(!(tile instanceof IGasHandler) || sides == null || sides.isEmpty()) + { + continue; + } + + IGasHandler acceptor = (IGasHandler)tile; + + for(ForgeDirection side : sides) + { + if(acceptor != null && acceptor.canReceiveGas(side, type)) + { + toReturn.add(acceptor); + break; + } + } + } + + return toReturn; + } + + public static class GasTransferEvent extends Event + { + public final GasNetwork gasNetwork; + + public final GasStack transferType; + public final boolean didTransfer; + + public GasTransferEvent(GasNetwork network, GasStack type, boolean did) + { + gasNetwork = network; + transferType = type; + didTransfer = did; + } + } + + public float getScale() + { + return Math.min(1, (buffer == null || getCapacity() == 0 ? 0 : (float)buffer.amount/getCapacity())); + } + + @Override + public String toString() + { + return "[GasNetwork] " + transmitters.size() + " transmitters, " + possibleAcceptors.size() + " acceptors."; + } + + @Override + public String getNeededInfo() + { + return Integer.toString(getGasNeeded()); + } + + @Override + public String getStoredInfo() + { + return buffer != null ? buffer.getGas().getLocalizedName() + " (" + buffer.amount + ")" : "None"; + } + + @Override + public String getFlowInfo() + { + return Integer.toString(prevTransferAmount) + "/t"; + } +} diff --git a/src/api/java/mekanism/api/gas/GasRegistry.java b/src/api/java/mekanism/api/gas/GasRegistry.java new file mode 100644 index 0000000..25db966 --- /dev/null +++ b/src/api/java/mekanism/api/gas/GasRegistry.java @@ -0,0 +1,113 @@ +package mekanism.api.gas; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraftforge.fluids.Fluid; + +public class GasRegistry +{ + private static ArrayList<Gas> registeredGasses = new ArrayList<Gas>(); + + /** + * Register a new gas into GasRegistry. + * @param gas - Gas to register + * @return the gas that has been registered, pulled right out of GasRegistry + */ + public static Gas register(Gas gas) + { + if(gas == null) + { + return null; + } + + registeredGasses.add(gas); + + return getGas(gas.getName()); + } + + /** + * Gets the gas associated with the defined ID. + * @param id - ID to check + * @return gas associated with defined ID + */ + public static Gas getGas(int id) + { + if(id == -1) + { + return null; + } + + return registeredGasses.get(id); + } + + /** + * Gets the gas associated with the defined fluid. + * @param f - fluid to check + * @return the gas associated with the fluid + */ + public static Gas getGas(Fluid f) + { + for(Gas gas : getRegisteredGasses()) + { + if(gas.hasFluid() && gas.getFluid() == f) + { + return gas; + } + } + + return null; + } + + /** + * Whether or not GasRegistry contains a gas with the specified name + * @param name - name to check + * @return if GasRegistry contains a gas with the defined name + */ + public static boolean containsGas(String name) + { + return getGas(name) != null; + } + + /** + * Gets the list of all gasses registered in GasRegistry. + * @return a cloned list of all registered gasses + */ + public static List<Gas> getRegisteredGasses() + { + return (List<Gas>)registeredGasses.clone(); + } + + /** + * Gets the gas associated with the specified name. + * @param name - name of the gas to get + * @return gas associated with the name + */ + public static Gas getGas(String name) + { + for(Gas gas : registeredGasses) + { + if(gas.getName().toLowerCase().equals(name.toLowerCase())) + { + return gas; + } + } + + return null; + } + + /** + * Gets the gas ID of a specified gas. + * @param gas - gas to get the ID from + * @return gas ID + */ + public static int getGasID(Gas gas) + { + if(gas == null || !containsGas(gas.getName())) + { + return -1; + } + + return registeredGasses.indexOf(gas); + } +} diff --git a/src/api/java/mekanism/api/gas/GasStack.java b/src/api/java/mekanism/api/gas/GasStack.java new file mode 100644 index 0000000..05e5ae6 --- /dev/null +++ b/src/api/java/mekanism/api/gas/GasStack.java @@ -0,0 +1,132 @@ +package mekanism.api.gas; + +import net.minecraft.nbt.NBTTagCompound; + +/** + * GasStack - a specified amount of a defined Gas with certain properties. + * @author aidancbrady + * + */ +public class GasStack +{ + private Gas type; + + public int amount; + + /** + * Creates a new GasStack with a defined gas ID and quantity. + * @param id - gas ID to associate this GasStack to, will perform a GasRegistry lookup in the constructor + * @param quantity - amount of gas to be referenced in this GasStack + */ + public GasStack(int id, int quantity) + { + type = GasRegistry.getGas(id); + amount = quantity; + } + + /** + * Creates a new GasStack with a defined Gas type and quantity. + * @param gas - gas type of the stack + * @param quantity - amount of gas to be referenced in this GasStack + */ + public GasStack(Gas gas, int quantity) + { + type = gas; + amount = quantity; + } + + private GasStack() {} + + /** + * Gets the Gas type of this GasStack. + * @return this GasStack's Gas type + */ + public Gas getGas() + { + return type; + } + + public GasStack withAmount(int newAmount) + { + amount = newAmount; + + return this; + } + + /** + * Writes this GasStack to a defined tag compound. + * @param nbtTags - tag compound to write to + * @return tag compound with this GasStack's data + */ + public NBTTagCompound write(NBTTagCompound nbtTags) + { + type.write(nbtTags); + nbtTags.setInteger("amount", amount); + + return nbtTags; + } + + /** + * Reads this GasStack's data from a defined tag compound. + * @param nbtTags - tag compound to read from + */ + public void read(NBTTagCompound nbtTags) + { + type = Gas.readFromNBT(nbtTags); + amount = nbtTags.getInteger("amount"); + } + + /** + * Returns the GasStack stored in the defined tag compound, or null if it doesn't exist. + * @param nbtTags - tag compound to read from + * @return GasStack stored in the tag compound + */ + public static GasStack readFromNBT(NBTTagCompound nbtTags) + { + if(nbtTags == null || nbtTags.hasNoTags()) + { + return null; + } + + GasStack stack = new GasStack(); + stack.read(nbtTags); + + if(stack.getGas() == null || stack.amount <= 0) + { + return null; + } + + return stack; + } + + /** + * Returns a copied form of this GasStack. + * @return copied GasStack + */ + public GasStack copy() + { + return new GasStack(type, amount); + } + + /** + * Whether or not this GasStack's gas type is equal to the other defined GasStack. + * @param stack - GasStack to check + * @return if the GasStacks contain the same gas type + */ + public boolean isGasEqual(GasStack stack) + { + return stack != null && getGas() == stack.getGas(); + } + + @Override + public String toString() + { + return "[" + type + ", " + amount + "]"; + } + + @Override + public int hashCode() + { + return type == null ? 0 : type.getID(); + } +} diff --git a/src/api/java/mekanism/api/gas/GasTank.java b/src/api/java/mekanism/api/gas/GasTank.java new file mode 100644 index 0000000..a5d4c20 --- /dev/null +++ b/src/api/java/mekanism/api/gas/GasTank.java @@ -0,0 +1,252 @@ +package mekanism.api.gas; + +import net.minecraft.nbt.NBTTagCompound; + +/** + * An optional way of managing and/or storing gasses. Would be very useful in TileEntity and Entity gas storage. + * @author aidancbrady + * + */ +public class GasTank +{ + public GasStack stored; + + private int maxGas; + + private GasTank() {} + + /** + * Creates a tank with a defined capacity. + * @param max - the maximum amount of gas this GasTank can hold + */ + public GasTank(int max) + { + maxGas = max; + } + + /** + * Sets this tank's GasStack value to a new value. Will cap the amount to this GasTank's capacity. + * @param stack - value to set this tank's GasStack value to + */ + public void setGas(GasStack stack) + { + stored = stack; + + if(stored != null) + { + stored.amount = Math.min(getMaxGas(), stored.amount); + } + } + + /** + * Draws a specified amount of gas out of this tank. + * @param amount - amount to draw + * @param doDraw - if the gas should actually be removed from this tank + * @return gas taken from this GasTank as a GasStack value + */ + public GasStack draw(int amount, boolean doDraw) + { + if(stored == null || amount <= 0) + { + return null; + } + + GasStack ret = new GasStack(getGas().getGas(), Math.min(getStored(), amount)); + + if(ret.amount > 0) + { + if(doDraw) + { + stored.amount -= ret.amount; + + if(stored.amount <= 0) + { + stored = null; + } + } + + return ret; + } + + return null; + } + + /** + * Adds a specified amount of gas to this tank. + * @param amount - the GasStack for this tank to receive + * @param doReceive - if the gas should actually be added to this tank + * @return the amount of gas accepted by this tank + */ + public int receive(GasStack amount, boolean doReceive) + { + if(amount == null || (stored != null && !(stored.amount != getMaxGas() && stored.isGasEqual(amount)))) + { + return 0; + } + + int toFill = Math.min(getMaxGas()-getStored(), amount.amount); + + if(doReceive) + { + if(stored == null) + { + stored = amount.copy().withAmount(getStored()+toFill); + } + else { + stored.amount = Math.min(getMaxGas(), getStored()+amount.amount); + } + } + + return toFill; + } + + /** + * If this GasTank can receive the specified type of gas. Will return false if this tank does not need anymore gas. + * @param gas - gas to check + * @return if this GasTank can accept the defined gas + */ + public boolean canReceive(Gas gas) + { + if(getNeeded() == 0 || stored != null && (gas != null && gas != stored.getGas())) + { + return false; + } + + return true; + } + + /** + * If this GasTank can receive the specified type of gas. Will return TRUE if this tank does not need anymore gas. + * @param gas - gas to check + * @return if this GasTank can accept the defined gas + */ + public boolean canReceiveType(Gas gas) + { + if(stored != null && (gas != null && gas != stored.getGas())) + { + return false; + } + + return true; + } + + /** + * If this GasTank can be drawn of the specified type of gas. Will return false if this tank does not contain any gas. + * @param gas - gas to check + * @return if this GasTank can be drawn of the defined gas + */ + public boolean canDraw(Gas gas) + { + if(stored == null || (gas != null && gas != stored.getGas())) + { + return false; + } + + return true; + } + + /** + * Gets the amount of gas needed by this GasTank. + * @return + */ + public int getNeeded() + { + return getMaxGas()-getStored(); + } + + /** + * Gets the maximum amount of gas this tank can hold. + * @return - max gas + */ + public int getMaxGas() + { + return maxGas; + } + + /** + * Sets the maximum amount of gas this tank can hold + */ + public void setMaxGas(int capacity) + { + maxGas = capacity; + } + + /** + * Gets the GasStack held by this GasTank. + * @return - GasStakc held by this tank + */ + public GasStack getGas() + { + return stored; + } + + /** + * Gets the type of gas currently stored in this GasTank. + * @return gas type contained + */ + public Gas getGasType() + { + return stored != null ? stored.getGas() : null; + } + + /** + * Gets the amount of gas stored by this GasTank. + * @return amount of gas stored + */ + public int getStored() + { + return stored != null ? stored.amount : 0; + } + + /** + * Writes this tank to a defined tag compound. + * @param nbtTags - tag compound to write to + * @return tag compound with this tank's data + */ + public NBTTagCompound write(NBTTagCompound nbtTags) + { + if(stored != null && stored.getGas() != null) + { + nbtTags.setTag("stored", stored.write(new NBTTagCompound())); + } + + nbtTags.setInteger("maxGas", maxGas); + + return nbtTags; + } + + /** + * Reads this tank's data from a defined tag compound. + * @param nbtTags - tag compound to read from + */ + public void read(NBTTagCompound nbtTags) + { + if(nbtTags.hasKey("stored")) + { + stored = GasStack.readFromNBT(nbtTags.getCompoundTag("stored")); + } + + if(nbtTags.hasKey("maxGas") && nbtTags.getInteger("maxGas") != 0) + { + maxGas = nbtTags.getInteger("maxGas"); + } + } + + /** + * Returns the tank stored in the defined tag compound, or null if it doesn't exist. + * @param nbtTags - tag compound to read from + * @return tank stored in the tag compound + */ + public static GasTank readFromNBT(NBTTagCompound nbtTags) + { + if(nbtTags == null || nbtTags.hasNoTags()) + { + return null; + } + + GasTank tank = new GasTank(); + tank.read(nbtTags); + + return tank; + } +} diff --git a/src/api/java/mekanism/api/gas/GasTransmission.java b/src/api/java/mekanism/api/gas/GasTransmission.java new file mode 100644 index 0000000..c043eb8 --- /dev/null +++ b/src/api/java/mekanism/api/gas/GasTransmission.java @@ -0,0 +1,181 @@ +package mekanism.api.gas; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import mekanism.api.Coord4D; +import mekanism.api.transmitters.ITransmitterTile; +import mekanism.api.transmitters.TransmissionType; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * A handy class containing several utilities for efficient gas transfer. + * @author AidanBrady + * + */ +public final class GasTransmission +{ + /** + * Gets all the acceptors around a tile entity. + * @param tileEntity - center tile entity + * @return array of IGasAcceptors + */ + public static IGasHandler[] getConnectedAcceptors(TileEntity tileEntity) + { + IGasHandler[] acceptors = new IGasHandler[] {null, null, null, null, null, null}; + + for(ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS) + { + TileEntity acceptor = Coord4D.get(tileEntity).getFromSide(orientation).getTileEntity(tileEntity.getWorldObj()); + + if(acceptor instanceof IGasHandler) + { + acceptors[orientation.ordinal()] = (IGasHandler)acceptor; + } + } + + return acceptors; + } + + /** + * Gets all the tube connections around a tile entity. + * @param tileEntity - center tile entity + * @return array of ITubeConnections + */ + public static ITubeConnection[] getConnections(TileEntity tileEntity) + { + ITubeConnection[] connections = new ITubeConnection[] {null, null, null, null, null, null}; + + for(ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS) + { + TileEntity connection = Coord4D.get(tileEntity).getFromSide(orientation).getTileEntity(tileEntity.getWorldObj()); + + if(canConnect(connection, orientation)) + { + connections[orientation.ordinal()] = (ITubeConnection)connection; + } + } + + return connections; + } + + /** + * Whether or not a TileEntity can connect to a specified tile on a specified side. + * @param tileEntity - TileEntity to attempt connection to + * @param side - side to attempt connection on + * @return if this tile and side are connectable + */ + public static boolean canConnect(TileEntity tileEntity, ForgeDirection side) + { + if(tileEntity instanceof ITubeConnection && (!(tileEntity instanceof ITransmitterTile) || TransmissionType.checkTransmissionType(((ITransmitterTile)tileEntity).getTransmitter(), TransmissionType.GAS))) + { + if(((ITubeConnection)tileEntity).canTubeConnect(side.getOpposite())) + { + return true; + } + } + + return false; + } + + /** + * Removes a specified amount of gas from an IGasItem. + * @param itemStack - ItemStack of the IGasItem + * @param type - type of gas to remove from the IGasItem, null if it doesn't matter + * @param amount - amount of gas to remove from the ItemStack + * @return the GasStack removed by the IGasItem + */ + public static GasStack removeGas(ItemStack itemStack, Gas type, int amount) + { + if(itemStack != null && itemStack.getItem() instanceof IGasItem) + { + IGasItem item = (IGasItem)itemStack.getItem(); + + if(type != null && item.getGas(itemStack) != null && item.getGas(itemStack).getGas() != type || !item.canProvideGas(itemStack, type)) + { + return null; + } + + return item.removeGas(itemStack, amount); + } + + return null; + } + + /** + * Adds a specified amount of gas to an IGasItem. + * @param itemStack - ItemStack of the IGasItem + * @param stack - stack to add to the IGasItem + * @return amount of gas accepted by the IGasItem + */ + public static int addGas(ItemStack itemStack, GasStack stack) + { + if(itemStack != null && itemStack.getItem() instanceof IGasItem && ((IGasItem)itemStack.getItem()).canReceiveGas(itemStack, stack.getGas())) + { + return ((IGasItem)itemStack.getItem()).addGas(itemStack, stack.copy()); + } + + return 0; + } + + /** + * Emits gas from a central block by splitting the received stack among the sides given. + * @param sides - the list of sides to output from + * @param stack - the stack to output + * @param from - the TileEntity to output from + * @return the amount of gas emitted + */ + public static int emit(List<ForgeDirection> sides, GasStack stack, TileEntity from) + { + if(stack == null) + { + return 0; + } + + List<IGasHandler> availableAcceptors = new ArrayList<IGasHandler>(); + IGasHandler[] possibleAcceptors = getConnectedAcceptors(from); + + for(int i = 0; i < possibleAcceptors.length; i++) + { + IGasHandler handler = possibleAcceptors[i]; + + if(handler != null && handler.canReceiveGas(ForgeDirection.getOrientation(i).getOpposite(), stack.getGas())) + { + availableAcceptors.add(handler); + } + } + + Collections.shuffle(availableAcceptors); + + int toSend = stack.amount; + int prevSending = toSend; + + if(!availableAcceptors.isEmpty()) + { + int divider = availableAcceptors.size(); + int remaining = toSend % divider; + int sending = (toSend-remaining)/divider; + + for(IGasHandler acceptor : availableAcceptors) + { + int currentSending = sending; + + if(remaining > 0) + { + currentSending++; + remaining--; + } + + ForgeDirection dir = ForgeDirection.getOrientation(Arrays.asList(possibleAcceptors).indexOf(acceptor)).getOpposite(); + toSend -= acceptor.receiveGas(dir, new GasStack(stack.getGas(), currentSending), true); + } + } + + return prevSending-toSend; + } +} diff --git a/src/api/java/mekanism/api/gas/IGasHandler.java b/src/api/java/mekanism/api/gas/IGasHandler.java new file mode 100644 index 0000000..e069523 --- /dev/null +++ b/src/api/java/mekanism/api/gas/IGasHandler.java @@ -0,0 +1,47 @@ +package mekanism.api.gas; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Implement this if your tile entity accepts gas from an external source. + * @author AidanBrady + * + */ +public interface IGasHandler +{ + /** + * Transfer a certain amount of gas to this block. + * @param stack - gas to add + * @return gas added + */ + public int receiveGas(ForgeDirection side, GasStack stack, boolean doTransfer); + + @Deprecated + public int receiveGas(ForgeDirection side, GasStack stack); + + /** + * Draws a certain amount of gas from this block. + * @param amount - amount to draw + * @return gas drawn + */ + public GasStack drawGas(ForgeDirection side, int amount, boolean doTransfer); + + @Deprecated + public GasStack drawGas(ForgeDirection side, int amount); + + /** + * Whether or not this block can accept gas from a certain side. + * @param side - side to check + * @param type - type of gas to check + * @return if block accepts gas + */ + public boolean canReceiveGas(ForgeDirection side, Gas type); + + /** + * Whether or not this block can be drawn of gas from a certain side. + * @param side - side to check + * @param type - type of gas to check + * @return if block can be drawn of gas + */ + public boolean canDrawGas(ForgeDirection side, Gas type); +} diff --git a/src/api/java/mekanism/api/gas/IGasItem.java b/src/api/java/mekanism/api/gas/IGasItem.java new file mode 100644 index 0000000..9c7d332 --- /dev/null +++ b/src/api/java/mekanism/api/gas/IGasItem.java @@ -0,0 +1,81 @@ +package mekanism.api.gas; + +import net.minecraft.item.ItemStack; + +/** + * Implement this in your item class if it can store or transfer certain gasses. + * @author AidanBrady + * + */ +public interface IGasItem +{ + /** + * Gets the rate of transfer this item can handle. + * @return + */ + public int getRate(ItemStack itemstack); + + /** + * Adds a defined amount of a certain gas to an item. + * @param itemstack - the itemstack to add gas to + * @param type - the type of gas to add + * @param amount - the amount of gas to add + * @return the gas that was accepted by the item + */ + public int addGas(ItemStack itemstack, GasStack stack); + + /** + * Removes the defined amount of a certain gas from the item. + * @param itemstack - the itemstack to remove gas from + * @param type - the type of gas to remove + * @param amount - the amount of gas to remove + * @return the gas that was removed by the item + */ + public GasStack removeGas(ItemStack itemstack, int amount); + + /** + * Whether or not this storage tank be given a specific gas. + * @param itemstack - the itemstack to check + * @param type - the type of gas the tank can possibly receive + * @return if the item be charged + */ + public boolean canReceiveGas(ItemStack itemstack, Gas type); + + /** + * Whether or not this item can give a gas receiver a certain type of gas. + * @param itemstack - the itemstack to check + * @param type - the type of gas the tank can provide + * @return if the item can provide gas + */ + public boolean canProvideGas(ItemStack itemstack, Gas type); + + /** + * Get the gas of a declared type. + * @param type - type of gas + * @param data - ItemStack parameter if necessary + * @return gas stored + */ + public GasStack getGas(ItemStack itemstack); + + /** + * Set the gas of a declared type to a new amount; + * @param type - type of gas + * @param data - ItemStack parameter if necessary + * @param amount - amount to store + */ + public void setGas(ItemStack itemstack, GasStack stack); + + /** + * Gets the maximum amount of gas this tile entity can store. + * @param type - type of gas + * @param data - ItemStack parameter if necessary + * @return maximum gas + */ + public int getMaxGas(ItemStack itemstack); + + /** + * Returns whether or not this item contains metadata-specific subtypes instead of using metadata for damage display. + * @return if the item contains metadata-specific subtypes + */ + public boolean isMetadataSpecific(ItemStack itemstack); +} diff --git a/src/api/java/mekanism/api/gas/IGasTransmitter.java b/src/api/java/mekanism/api/gas/IGasTransmitter.java new file mode 100644 index 0000000..57ec4c1 --- /dev/null +++ b/src/api/java/mekanism/api/gas/IGasTransmitter.java @@ -0,0 +1,10 @@ +package mekanism.api.gas; + +import mekanism.api.transmitters.IGridTransmitter; + +import net.minecraft.tileentity.TileEntity; + +public interface IGasTransmitter extends IGridTransmitter<IGasHandler, GasNetwork> +{ + public boolean canTransferGasToTube(TileEntity tile); +} diff --git a/src/api/java/mekanism/api/gas/ITubeConnection.java b/src/api/java/mekanism/api/gas/ITubeConnection.java new file mode 100644 index 0000000..b669fed --- /dev/null +++ b/src/api/java/mekanism/api/gas/ITubeConnection.java @@ -0,0 +1,18 @@ +package mekanism.api.gas; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Implement this if your block can connect to Pressurized Tubes. + * @author AidanBrady + * + */ +public interface ITubeConnection +{ + /** + * Whether or not a tube can connect to a certain orientation. + * @param side - orientation to check + * @return if a tube can connect + */ + public boolean canTubeConnect(ForgeDirection side); +} diff --git a/src/api/java/mekanism/api/gas/OreGas.java b/src/api/java/mekanism/api/gas/OreGas.java new file mode 100644 index 0000000..316169c --- /dev/null +++ b/src/api/java/mekanism/api/gas/OreGas.java @@ -0,0 +1,38 @@ +package mekanism.api.gas; + +import net.minecraft.util.StatCollector; + +public class OreGas extends Gas +{ + private String oreName; + private OreGas cleanGas; + + public OreGas(String s, String name) + { + super(s); + + oreName = name; + } + + public boolean isClean() + { + return getCleanGas() == null; + } + + public OreGas getCleanGas() + { + return cleanGas; + } + + public OreGas setCleanGas(OreGas gas) + { + cleanGas = gas; + + return this; + } + + public String getOreName() + { + return StatCollector.translateToLocal(oreName); + } +} diff --git a/src/api/java/mekanism/api/gas/package-info.java b/src/api/java/mekanism/api/gas/package-info.java new file mode 100644 index 0000000..4418451 --- /dev/null +++ b/src/api/java/mekanism/api/gas/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|gas") +package mekanism.api.gas; +import cpw.mods.fml.common.API;
\ No newline at end of file diff --git a/src/api/java/mekanism/api/infuse/InfuseObject.java b/src/api/java/mekanism/api/infuse/InfuseObject.java new file mode 100644 index 0000000..a86c02f --- /dev/null +++ b/src/api/java/mekanism/api/infuse/InfuseObject.java @@ -0,0 +1,21 @@ +package mekanism.api.infuse; + +/** + * InfuseObject - an object associated with an ItemStack that can modify a Metallurgic Infuser's internal infuse. + * @author AidanBrady + * + */ +public class InfuseObject +{ + /** The type of infuse this item stores */ + public InfuseType type; + + /** How much infuse this item stores */ + public int stored; + + public InfuseObject(InfuseType infusion, int i) + { + type = infusion; + stored = i; + } +} diff --git a/src/api/java/mekanism/api/infuse/InfuseRegistry.java b/src/api/java/mekanism/api/infuse/InfuseRegistry.java new file mode 100644 index 0000000..308b9c5 --- /dev/null +++ b/src/api/java/mekanism/api/infuse/InfuseRegistry.java @@ -0,0 +1,113 @@ +package mekanism.api.infuse; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.item.ItemStack; + +/** + * Use this class to add a new object that registers as an infuse object. + * @author AidanBrady + * + */ +public class InfuseRegistry +{ + /** The (private) map of ItemStacks and their related InfuseObjects. */ + private static Map<ItemStack, InfuseObject> infuseObjects = new HashMap<ItemStack, InfuseObject>(); + + /** The (private) map of infuse names and their corresponding InfuseTypes. */ + private static Map<String, InfuseType> infuseTypes = new HashMap<String, InfuseType>(); + + /** + * Registers an InfuseType into the registry. Call this in PreInit! + * @param infuse + */ + public static void registerInfuseType(InfuseType infuse) + { + if(infuseTypes.containsKey(infuse.name)) + { + return; + } + + infuseTypes.put(infuse.name, infuse); + } + + /** + * Gets an InfuseType from it's name, or null if it doesn't exist. + * @param name - the name of the InfuseType to get + * @return the name's corresponding InfuseType + */ + public static InfuseType get(String name) + { + if(name.equals("null")) + { + return null; + } + + return infuseTypes.get(name); + } + + /** + * Whether or not the registry contains a correspondent InfuseType to a name. + * @param name - the name to check + * @return if the name has a coorespondent InfuseType + */ + public static boolean contains(String name) + { + return get(name) != null; + } + + /** + * Registers a block or item that serves as an infuse object. An infuse object will store a certain type and amount of infuse, + * and will deliver this amount to the Metallurgic Infuser's buffer of infuse. The item's stack size will be decremented when + * it is placed in the Metallurgic Infuser's infuse slot, and the machine can accept the type and amount of infuse stored in the + * object. + * @param itemStack - stack the infuse object is linked to -- stack size is ignored + * @param infuseObject - the infuse object with the type and amount data + */ + public static void registerInfuseObject(ItemStack itemStack, InfuseObject infuseObject) + { + if(getObject(itemStack) != null) + { + return; + } + + infuseObjects.put(itemStack, infuseObject); + } + + /** + * Gets the InfuseObject data from an ItemStack. + * @param itemStack - the ItemStack to check + * @return the ItemStack's InfuseObject + */ + public static InfuseObject getObject(ItemStack itemStack) + { + for(Map.Entry<ItemStack, InfuseObject> obj : infuseObjects.entrySet()) + { + if(itemStack.isItemEqual(obj.getKey())) + { + return obj.getValue(); + } + } + + return null; + } + + /** + * Gets the private map for InfuseObjects. + * @return private InfuseObject map + */ + public static final Map<ItemStack, InfuseObject> getObjectMap() + { + return infuseObjects; + } + + /** + * Gets the private map for InfuseTypes. + * @return private InfuseType map + */ + public static final Map<String, InfuseType> getInfuseMap() + { + return infuseTypes; + } +} diff --git a/src/api/java/mekanism/api/infuse/InfuseType.java b/src/api/java/mekanism/api/infuse/InfuseType.java new file mode 100644 index 0000000..1f5215c --- /dev/null +++ b/src/api/java/mekanism/api/infuse/InfuseType.java @@ -0,0 +1,47 @@ +package mekanism.api.infuse; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; + +/** + * The types of infuse currently available in Mekanism. + * @author AidanBrady + * + */ +public final class InfuseType +{ + /** The name of this infusion */ + public String name; + + /** The location of this infuse's GUI texture */ + public ResourceLocation texture; + + /** The infuse's GUI texture X offset. */ + public int texX; + + /** The infuse's GUI texture Y offset. */ + public int texY; + + /** The unlocalized name of this type. */ + public String unlocalizedName; + + public InfuseType(String s, ResourceLocation location, int x, int y) + { + name = s; + texture = location; + texX = x; + texY = y; + } + + public InfuseType setUnlocalizedName(String name) + { + unlocalizedName = name; + + return this; + } + + public String getLocalizedName() + { + return StatCollector.translateToLocal(unlocalizedName); + } +} diff --git a/src/api/java/mekanism/api/infuse/package-info.java b/src/api/java/mekanism/api/infuse/package-info.java new file mode 100644 index 0000000..8718996 --- /dev/null +++ b/src/api/java/mekanism/api/infuse/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|infuse") +package mekanism.api.infuse; +import cpw.mods.fml.common.API;
\ No newline at end of file diff --git a/src/api/java/mekanism/api/lasers/ILaserReceptor.java b/src/api/java/mekanism/api/lasers/ILaserReceptor.java new file mode 100644 index 0000000..641f3ca --- /dev/null +++ b/src/api/java/mekanism/api/lasers/ILaserReceptor.java @@ -0,0 +1,10 @@ +package mekanism.api.lasers; + +import net.minecraftforge.common.util.ForgeDirection; + +public interface ILaserReceptor +{ + public void receiveLaserEnergy(double energy, ForgeDirection side); + + public boolean canLasersDig(); +} diff --git a/src/api/java/mekanism/api/lasers/package-info.java b/src/api/java/mekanism/api/lasers/package-info.java new file mode 100644 index 0000000..b456937 --- /dev/null +++ b/src/api/java/mekanism/api/lasers/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|laser") +package mekanism.api.lasers; +import cpw.mods.fml.common.API;
\ No newline at end of file diff --git a/src/api/java/mekanism/api/package-info.java b/src/api/java/mekanism/api/package-info.java new file mode 100644 index 0000000..2b9fcab --- /dev/null +++ b/src/api/java/mekanism/api/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|core") +package mekanism.api; +import cpw.mods.fml.common.API;
\ No newline at end of file diff --git a/src/api/java/mekanism/api/reactor/IFusionReactor.java b/src/api/java/mekanism/api/reactor/IFusionReactor.java new file mode 100644 index 0000000..9d9d96d --- /dev/null +++ b/src/api/java/mekanism/api/reactor/IFusionReactor.java @@ -0,0 +1,66 @@ +package mekanism.api.reactor; + +import mekanism.api.IHeatTransfer; +import mekanism.api.gas.GasTank; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidTank; + +public interface IFusionReactor extends IHeatTransfer +{ + public void addTemperatureFromEnergyInput(double energyAdded); + + public void simulate(); + + public FluidTank getWaterTank(); + + public FluidTank getSteamTank(); + + public GasTank getDeuteriumTank(); + + public GasTank getTritiumTank(); + + public GasTank getFuelTank(); + + public double getBufferedEnergy(); + + public void setBufferedEnergy(double energy); + + public double getPlasmaTemp(); + + public void setPlasmaTemp(double temp); + + public double getCaseTemp(); + + public void setCaseTemp(double temp); + + public double getBufferSize(); + + public void formMultiblock(); + + public boolean isFormed(); + + public void setInjectionRate(int rate); + + public int getInjectionRate(); + + public boolean isBurning(); + + public void setBurning(boolean burn); + + public int getMinInjectionRate(boolean active); + + public double getMaxPlasmaTemperature(boolean active); + + public double getMaxCasingTemperature(boolean active); + + public double getIgnitionTemperature(boolean active); + + public double getPassiveGeneration(boolean active, boolean current); + + public int getSteamPerTick(boolean current); + + public void updateTemperatures(); + + public ItemStack[] getInventory(); +} diff --git a/src/api/java/mekanism/api/reactor/INeutronCapture.java b/src/api/java/mekanism/api/reactor/INeutronCapture.java new file mode 100644 index 0000000..6171a7f --- /dev/null +++ b/src/api/java/mekanism/api/reactor/INeutronCapture.java @@ -0,0 +1,6 @@ +package mekanism.api.reactor; + +public interface INeutronCapture extends IReactorBlock +{ + public int absorbNeutrons(int neutrons); +} diff --git a/src/api/java/mekanism/api/reactor/IReactorBlock.java b/src/api/java/mekanism/api/reactor/IReactorBlock.java new file mode 100644 index 0000000..b3b8518 --- /dev/null +++ b/src/api/java/mekanism/api/reactor/IReactorBlock.java @@ -0,0 +1,12 @@ +package mekanism.api.reactor; + + +public interface IReactorBlock +{ + public boolean isFrame(); + + public void setReactor(IFusionReactor reactor); + + public IFusionReactor getReactor(); + +} diff --git a/src/api/java/mekanism/api/reactor/package-info.java b/src/api/java/mekanism/api/reactor/package-info.java new file mode 100644 index 0000000..6a00fc6 --- /dev/null +++ b/src/api/java/mekanism/api/reactor/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|reactor") +package mekanism.api.reactor; +import cpw.mods.fml.common.API;
\ No newline at end of file diff --git a/src/api/java/mekanism/api/recipe/RecipeHelper.java b/src/api/java/mekanism/api/recipe/RecipeHelper.java new file mode 100644 index 0000000..1040aa2 --- /dev/null +++ b/src/api/java/mekanism/api/recipe/RecipeHelper.java @@ -0,0 +1,319 @@ +package mekanism.api.recipe; + +import java.lang.reflect.Method; + +import mekanism.api.gas.GasStack; +import mekanism.api.infuse.InfuseType; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +/** + * SET TO BE REMOVED NEXT MINOR MEKANISM VERSION, PLEASE USE IMC INSTEAD. + * Use this handy class to add recipes to Mekanism machinery. + * @author AidanBrady + * + */ +@Deprecated +public final class RecipeHelper +{ + /** + * Add an Enrichment Chamber recipe. + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addEnrichmentChamberRecipe(ItemStack input, ItemStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addEnrichmentChamberRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add an Osmium Compressor recipe. + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addOsmiumCompressorRecipe(ItemStack input, ItemStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addOsmiumCompressorRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Combiner recipe. + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addCombinerRecipe(ItemStack input, ItemStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addCombinerRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Crusher recipe. + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addCrusherRecipe(ItemStack input, ItemStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addCrusherRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Purification Chamber recipe. + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addPurificationChamberRecipe(ItemStack input, ItemStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addPurificationChamberRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Chemical Oxidizer recipe. + * @param input - input ItemStack + * @param output - output GasStack + */ + public static void addChemicalOxidizerRecipe(ItemStack input, GasStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addChemicalOxidizerRecipe", ItemStack.class, GasStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Chemical Infuser recipe. + * @param leftInput - left input GasStack + * @param rightInput - right input GasStack + * @param output - output GasStack + */ + public static void addChemicalInfuserRecipe(GasStack leftInput, GasStack rightInput, GasStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addChemicalInfuserRecipe", GasStack.class, GasStack.class, GasStack.class); + m.invoke(null, leftInput, rightInput, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Precision Sawmill recipe. + * @param input - input ItemStack + * @param primaryOutput - guaranteed output + * @param secondaryOutput - possible extra output + * @param chance - probability of obtaining extra output + */ + public static void addPrecisionSawmillRecipe(ItemStack input, ItemStack primaryOutput, ItemStack secondaryOutput, double chance) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addPrecisionSawmillRecipe", ItemStack.class, ItemStack.class, ItemStack.class, Double.TYPE); + m.invoke(null, input, primaryOutput, secondaryOutput, chance); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Precision Sawmill recipe with no chance output + * @param input - input ItemStack + * @param primaryOutput - guaranteed output + */ + public static void addPrecisionSawmillRecipe(ItemStack input, ItemStack primaryOutput) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addPrecisionSawmillRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, primaryOutput); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Chemical Injection Chamber recipe. + * @param input - input AdvancedInput + * @param output - output ItemStack + */ + public static void addChemicalInjectionChamberRecipe(ItemStack input, String gasName, ItemStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addChemicalInjectionChamberRecipe", ItemStack.class, String.class, ItemStack.class); + m.invoke(null, input, gasName, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add an Electrolytic Separator recipe. + * @param input - input FluidStack + * @param energy - required energy + * @param leftOutput - left output GasStack + * @param rightOutput - right output GasStack + */ + public static void addElectrolyticSeparatorRecipe(FluidStack input, double energy, GasStack leftOutput, GasStack rightOutput) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addElectrolyticSeparatorRecipe", FluidStack.class, Double.TYPE, GasStack.class, GasStack.class); + m.invoke(null, input, energy, leftOutput, rightOutput); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Chemical Dissolution Chamber recipe. + * @param input - input ItemStack + * @param output - output GasStack + */ + public static void addChemicalDissolutionChamberRecipe(ItemStack input, GasStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addChemicalDissolutionChamberRecipe", ItemStack.class, GasStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Chemical Washer recipe. + * @param input - input GasStack + * @param output - output GasStack + */ + public static void addChemicalWasherRecipe(GasStack input, GasStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addChemicalWasherRecipe", GasStack.class, GasStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Chemical Crystallizer recipe. + * @param input - input GasStack + * @param output - output ItemStack + */ + public static void addChemicalCrystallizerRecipe(GasStack input, ItemStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addChemicalCrystallizerRecipe", GasStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Metallurgic Infuser recipe. + * @param infuse - which Infuse to use + * @param amount - how much Infuse to use + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addMetallurgicInfuserRecipe(InfuseType infuse, int amount, ItemStack input, ItemStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addMetallurgicInfuserRecipe", InfuseType.class, Integer.TYPE, ItemStack.class, ItemStack.class); + m.invoke(null, infuse, amount, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Pressurized Reaction Chamber recipe. + * @param inputSolid - input ItemStack + * @param inputFluid - input FluidStack + * @param inputGas - input GasStack + * @param outputSolid - output ItemStack + * @param outputGas - output GasStack + * @param extraEnergy - extra energy needed by the recipe + * @param ticks - amount of ticks it takes for this recipe to complete + */ + public static void addPRCRecipe(ItemStack inputSolid, FluidStack inputFluid, GasStack inputGas, ItemStack outputSolid, GasStack outputGas, double extraEnergy, int ticks) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addPRCRecipe", ItemStack.class, FluidStack.class, GasStack.class, ItemStack.class, GasStack.class, Double.TYPE, Integer.TYPE); + m.invoke(null, inputSolid, inputFluid, inputGas, outputSolid, outputGas, extraEnergy, ticks); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Solar Evaporation Plant recipe. + * @param input - input GasStack + * @param output - output GasStack + */ + public static void addSolarEvaporationRecipe(FluidStack input, FluidStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addSolarEvaporationRecipe", FluidStack.class, FluidStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } + + /** + * Add a Solar Neutron Activator recipe. + * @param input - input GasStack + * @param output - output GasStack + */ + public static void addSolarNeutronRecipe(GasStack input, GasStack output) + { + try { + Class recipeClass = Class.forName("mekanism.common.recipe.RecipeHandler"); + Method m = recipeClass.getMethod("addSolarEvaporationRecipe", GasStack.class, GasStack.class); + m.invoke(null, input, output); + } catch(Exception e) { + System.err.println("Error while adding recipe: " + e.getMessage()); + } + } +} diff --git a/src/api/java/mekanism/api/recipe/package-info.java b/src/api/java/mekanism/api/recipe/package-info.java new file mode 100644 index 0000000..f166da4 --- /dev/null +++ b/src/api/java/mekanism/api/recipe/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|recipe") +package mekanism.api.recipe; +import cpw.mods.fml.common.API;
\ No newline at end of file diff --git a/src/api/java/mekanism/api/transmitters/DynamicNetwork.java b/src/api/java/mekanism/api/transmitters/DynamicNetwork.java new file mode 100644 index 0000000..ee4e8a2 --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/DynamicNetwork.java @@ -0,0 +1,456 @@ +package mekanism.api.transmitters; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.Event; +import mekanism.api.Coord4D; +import mekanism.api.IClientTicker; +import mekanism.api.Range4D; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.*; +import java.util.Map.Entry; + +public abstract class DynamicNetwork<A, N extends DynamicNetwork<A, N>> implements IClientTicker, INetworkDataHandler +{ + public LinkedHashSet<IGridTransmitter<A, N>> transmitters = Sets.newLinkedHashSet(); + public LinkedHashSet<IGridTransmitter<A, N>> transmittersToAdd = Sets.newLinkedHashSet(); + public LinkedHashSet<IGridTransmitter<A, N>> transmittersAdded = Sets.newLinkedHashSet(); + + public HashMap<Coord4D, A> possibleAcceptors = new HashMap<Coord4D, A>(); + public HashMap<Coord4D, EnumSet<ForgeDirection>> acceptorDirections = new HashMap<Coord4D, EnumSet<ForgeDirection>>(); + public HashMap<IGridTransmitter<A, N>, EnumSet<ForgeDirection>> changedAcceptors = Maps.newHashMap(); + + private Set<DelayQueue> updateQueue = new LinkedHashSet<DelayQueue>(); + + protected Range4D packetRange = null; + + protected int capacity = 0; + protected double meanCapacity = 0; + + protected boolean needsUpdate = false; + protected int updateDelay = 0; + + protected boolean firstUpdate = true; + protected World worldObj = null; + + public void addNewTransmitters(Collection<IGridTransmitter<A, N>> newTransmitters) + { + transmittersToAdd.addAll(newTransmitters); + } + + public void commit() + { + if(!transmittersToAdd.isEmpty()) + { + for(IGridTransmitter<A, N> transmitter : transmittersToAdd) + { + if(transmitter.isValid()) + { + if(worldObj == null) + { + worldObj = transmitter.world(); + } + + for(ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) + { + updateTransmitterOnSide(transmitter, side); + } + + transmitter.setTransmitterNetwork((N)this); + absorbBuffer(transmitter); + transmitters.add(transmitter); + } + } + + updateCapacity(); + clampBuffer(); + queueClientUpdate(Lists.newArrayList(transmittersToAdd)); + transmittersToAdd.clear(); + } + + if(!changedAcceptors.isEmpty()) + { + for(Entry<IGridTransmitter<A, N>, EnumSet<ForgeDirection>> entry : changedAcceptors.entrySet()) + { + IGridTransmitter<A, N> transmitter = entry.getKey(); + + if(transmitter.isValid()) + { + EnumSet<ForgeDirection> directionsChanged = entry.getValue(); + + for(ForgeDirection side : directionsChanged) + { + updateTransmitterOnSide(transmitter, side); + } + } + } + + changedAcceptors.clear(); + } + } + + public void updateTransmitterOnSide(IGridTransmitter<A, N> transmitter, ForgeDirection side) + { + A acceptor = transmitter.getAcceptor(side); + Coord4D acceptorCoord = transmitter.coord().getFromSide(side); + EnumSet<ForgeDirection> directions = acceptorDirections.get(acceptorCoord); + + if(acceptor != null) + { + possibleAcceptors.put(acceptorCoord, acceptor); + + if(directions != null) + { + directions.add(side.getOpposite()); + } + else { + acceptorDirections.put(acceptorCoord, EnumSet.of(side.getOpposite())); + } + } + else { + if(directions != null) + { + directions.remove(side.getOpposite()); + + if(directions.isEmpty()) + { + possibleAcceptors.remove(acceptorCoord); + acceptorDirections.remove(acceptorCoord); + } + } + else { + possibleAcceptors.remove(acceptorCoord); + acceptorDirections.remove(acceptorCoord); + } + } + + } + + public abstract void absorbBuffer(IGridTransmitter<A, N> transmitter); + + public abstract void clampBuffer(); + + public void invalidate() + { + //Remove invalid transmitters first for share calculations + for(Iterator<IGridTransmitter<A, N>> iter = transmitters.iterator(); iter.hasNext();) + { + IGridTransmitter<A, N> transmitter = iter.next(); + + if(!transmitter.isValid()) + { + iter.remove(); + continue; + } + } + + //Clamp the new buffer + clampBuffer(); + + //Update all shares + for(IGridTransmitter<A, N> transmitter : transmitters) + { + transmitter.updateShare(); + } + + //Now invalidate the transmitters + for(IGridTransmitter<A, N> transmitter : transmitters) + { + invalidateTransmitter(transmitter); + } + + transmitters.clear(); + deregister(); + } + + public void invalidateTransmitter(IGridTransmitter<A, N> transmitter) + { + if(!worldObj.isRemote && transmitter.isValid()) + { + transmitter.takeShare(); + transmitter.setTransmitterNetwork(null); + TransmitterNetworkRegistry.registerOrphanTransmitter(transmitter); + } + } + + public void acceptorChanged(IGridTransmitter<A, N> transmitter, ForgeDirection side) + { + EnumSet<ForgeDirection> directions = changedAcceptors.get(transmitter); + + if(directions != null) + { + directions.add(side); + } + else { + changedAcceptors.put(transmitter, EnumSet.of(side)); + } + + TransmitterNetworkRegistry.registerChangedNetwork(this); + } + + public void adoptTransmittersAndAcceptorsFrom(N net) + { + for(IGridTransmitter<A, N> transmitter : net.transmitters) + { + transmitter.setTransmitterNetwork((N)this); + transmitters.add(transmitter); + transmittersAdded.add(transmitter); + } + + possibleAcceptors.putAll(net.possibleAcceptors); + + for(Entry<Coord4D, EnumSet<ForgeDirection>> entry : net.acceptorDirections.entrySet()) + { + Coord4D coord = entry.getKey(); + + if(acceptorDirections.containsKey(coord)) + { + acceptorDirections.get(coord).addAll(entry.getValue()); + } + else { + acceptorDirections.put(coord, entry.getValue()); + } + } + + } + + public Range4D getPacketRange() + { + if(packetRange == null) + { + return genPacketRange(); + } + + return packetRange; + } + + protected Range4D genPacketRange() + { + if(getSize() == 0) + { + deregister(); + return null; + } + + IGridTransmitter<A, N> initTransmitter = transmitters.iterator().next(); + Coord4D initCoord = initTransmitter.coord(); + + int minX = initCoord.xCoord; + int minY = initCoord.yCoord; + int minZ = initCoord.zCoord; + int maxX = initCoord.xCoord; + int maxY = initCoord.yCoord; + int maxZ = initCoord.zCoord; + + for(IGridTransmitter transmitter : transmitters) + { + Coord4D coord = transmitter.coord(); + + if(coord.xCoord < minX) minX = coord.xCoord; + if(coord.yCoord < minY) minY = coord.yCoord; + if(coord.zCoord < minZ) minZ = coord.zCoord; + if(coord.xCoord > maxX) maxX = coord.xCoord; + if(coord.yCoord > maxY) maxY = coord.yCoord; + if(coord.zCoord > maxZ) maxZ = coord.zCoord; + } + + return new Range4D(minX, minY, minZ, maxX, maxY, maxZ, initTransmitter.world().provider.dimensionId); + } + + public void register() + { + if(FMLCommonHandler.instance().getEffectiveSide().isServer()) + { + TransmitterNetworkRegistry.getInstance().registerNetwork(this); + } + else { + MinecraftForge.EVENT_BUS.post(new ClientTickUpdate(this, (byte)1)); + } + } + + public void deregister() + { + transmitters.clear(); + + if(FMLCommonHandler.instance().getEffectiveSide().isServer()) + { + TransmitterNetworkRegistry.getInstance().removeNetwork(this); + } + else { + MinecraftForge.EVENT_BUS.post(new ClientTickUpdate(this, (byte)0)); + } + } + + public int getSize() + { + return transmitters.size(); + } + + public int getAcceptorSize() + { + return possibleAcceptors.size(); + } + + public synchronized void updateCapacity() + { + updateMeanCapacity(); + capacity = (int)meanCapacity * transmitters.size(); + } + + /** + * Override this if things can have variable capacity along the network. + * @return An 'average' value of capacity. Calculate it how you will. + */ + protected synchronized void updateMeanCapacity() + { + if(transmitters.size() > 0) + { + meanCapacity = transmitters.iterator().next().getCapacity(); + } + else { + meanCapacity = 0; + } + } + + public int getCapacity() + { + return capacity; + } + + public World getWorld() + { + return worldObj; + } + + public abstract Set<A> getAcceptors(Object data); + + public void tick() + { + onUpdate(); + } + + public void onUpdate() + { + if(FMLCommonHandler.instance().getEffectiveSide().isServer()) + { + Iterator<DelayQueue> i = updateQueue.iterator(); + + try { + while(i.hasNext()) + { + DelayQueue q = i.next(); + + if(q.delay > 0) + { + q.delay--; + } + else { + transmittersAdded.addAll(transmitters); + updateDelay = 1; + i.remove(); + } + } + } catch(Exception e) {} + + if(updateDelay > 0) + { + updateDelay--; + + if(updateDelay == 0) + { + MinecraftForge.EVENT_BUS.post(new TransmittersAddedEvent(this, firstUpdate, (Collection)transmittersAdded)); + firstUpdate = false; + transmittersAdded.clear(); + needsUpdate = true; + } + } + } + } + + @Override + public boolean needsTicks() + { + return getSize() > 0; + } + + @Override + public void clientTick() {} + + public void queueClientUpdate(Collection<IGridTransmitter<A, N>> newTransmitters) + { + transmittersAdded.addAll(newTransmitters); + updateDelay = 3; + } + + public static class TransmittersAddedEvent extends Event + { + public DynamicNetwork<?, ?> network; + public boolean newNetwork; + public Collection<IGridTransmitter> newTransmitters; + + public TransmittersAddedEvent(DynamicNetwork net, boolean newNet, Collection<IGridTransmitter> added) + { + network = net; + newNetwork = newNet; + newTransmitters = added; + } + } + + public static class ClientTickUpdate extends Event + { + public DynamicNetwork network; + public byte operation; /*0 remove, 1 add*/ + + public ClientTickUpdate(DynamicNetwork net, byte b) + { + network = net; + operation = b; + } + } + + public static class NetworkClientRequest extends Event + { + public TileEntity tileEntity; + + public NetworkClientRequest(TileEntity tile) + { + tileEntity = tile; + } + } + + public void addUpdate(EntityPlayer player) + { + updateQueue.add(new DelayQueue(player)); + } + + public static class DelayQueue + { + public EntityPlayer player; + public int delay; + + public DelayQueue(EntityPlayer p) + { + player = p; + delay = 5; + } + + @Override + public int hashCode() + { + return player.hashCode(); + } + + @Override + public boolean equals(Object o) + { + return o instanceof DelayQueue && ((DelayQueue)o).player.equals(this.player); + } + } +} diff --git a/src/api/java/mekanism/api/transmitters/IBlockableConnection.java b/src/api/java/mekanism/api/transmitters/IBlockableConnection.java new file mode 100644 index 0000000..f6811fb --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/IBlockableConnection.java @@ -0,0 +1,10 @@ +package mekanism.api.transmitters; + +import net.minecraftforge.common.util.ForgeDirection; + +public interface IBlockableConnection +{ + public boolean canConnectMutual(ForgeDirection side); + + public boolean canConnect(ForgeDirection side); +} diff --git a/src/api/java/mekanism/api/transmitters/IGridTransmitter.java b/src/api/java/mekanism/api/transmitters/IGridTransmitter.java new file mode 100644 index 0000000..9d82d48 --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/IGridTransmitter.java @@ -0,0 +1,64 @@ +package mekanism.api.transmitters; + +import mekanism.api.Coord4D; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.Collection; + +public interface IGridTransmitter<A, N extends DynamicNetwork<A, N>> extends ITransmitter +{ + public boolean hasTransmitterNetwork(); + + /** + * Gets the network currently in use by this transmitter segment. + * @return network this transmitter is using + */ + public N getTransmitterNetwork(); + + /** + * Sets this transmitter segment's network to a new value. + * @param network - network to set to + */ + public void setTransmitterNetwork(N network); + + public int getTransmitterNetworkSize(); + + public int getTransmitterNetworkAcceptorSize(); + + public String getTransmitterNetworkNeeded(); + + public String getTransmitterNetworkFlow(); + + public String getTransmitterNetworkBuffer(); + + public double getTransmitterNetworkCapacity(); + + public int getCapacity(); + + public World world(); + + public Coord4D coord(); + + public Coord4D getAdjacentConnectableTransmitterCoord(ForgeDirection side); + + public A getAcceptor(ForgeDirection side); + + public boolean isValid(); + + public boolean isOrphan(); + + public void setOrphan(boolean orphaned); + + public N createEmptyNetwork(); + + public N mergeNetworks(Collection<N> toMerge); + + public N getExternalNetwork(Coord4D from); + + public void takeShare(); + + public void updateShare(); + + public Object getBuffer(); +} diff --git a/src/api/java/mekanism/api/transmitters/INetworkDataHandler.java b/src/api/java/mekanism/api/transmitters/INetworkDataHandler.java new file mode 100644 index 0000000..38cd637 --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/INetworkDataHandler.java @@ -0,0 +1,10 @@ +package mekanism.api.transmitters; + +public interface INetworkDataHandler +{ + public String getNeededInfo(); + + public String getStoredInfo(); + + public String getFlowInfo(); +} diff --git a/src/api/java/mekanism/api/transmitters/ITransmitter.java b/src/api/java/mekanism/api/transmitters/ITransmitter.java new file mode 100644 index 0000000..cddc76a --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/ITransmitter.java @@ -0,0 +1,11 @@ +package mekanism.api.transmitters; + +public interface ITransmitter +{ + /** + * Get the transmitter's transmission type + * + * @return TransmissionType this transmitter uses + */ + public TransmissionType getTransmissionType(); +} diff --git a/src/api/java/mekanism/api/transmitters/ITransmitterTile.java b/src/api/java/mekanism/api/transmitters/ITransmitterTile.java new file mode 100644 index 0000000..3940b71 --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/ITransmitterTile.java @@ -0,0 +1,6 @@ +package mekanism.api.transmitters; + +public interface ITransmitterTile<A, N extends DynamicNetwork<A, N>> +{ + public IGridTransmitter<A, N> getTransmitter(); +} diff --git a/src/api/java/mekanism/api/transmitters/TransmissionType.java b/src/api/java/mekanism/api/transmitters/TransmissionType.java new file mode 100644 index 0000000..7b54e9c --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/TransmissionType.java @@ -0,0 +1,80 @@ +package mekanism.api.transmitters; + +import mekanism.api.gas.IGasTransmitter; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.StatCollector; + +public enum TransmissionType +{ + ENERGY("EnergyNetwork", "Energy"), + FLUID("FluidNetwork", "Fluids"), + GAS("GasNetwork", "Gases"), + ITEM("InventoryNetwork", "Items"), + HEAT("HeatNetwork", "Heat"); + + private String name; + private String transmission; + + private TransmissionType(String n, String t) + { + name = n; + transmission = t; + } + + public String getName() + { + return name; + } + + public String getTransmission() + { + return transmission; + } + + public String localize() + { + return StatCollector.translateToLocal("transmission." + getTransmission()); + } + + public static boolean checkTransmissionType(ITransmitter sideTile, TransmissionType type) + { + return type.checkTransmissionType(sideTile); + } + + public static boolean checkTransmissionType(TileEntity tile1, TransmissionType type) + { + return checkTransmissionType(tile1, type, null); + } + + public static boolean checkTransmissionType(TileEntity tile1, TransmissionType type, TileEntity tile2) + { + return type.checkTransmissionType(tile1, tile2); + } + + public boolean checkTransmissionType(ITransmitter transmitter) + { + return transmitter.getTransmissionType() == this; + } + + public boolean checkTransmissionType(TileEntity sideTile, TileEntity currentTile) + { + if(sideTile instanceof ITransmitter) + { + if(((ITransmitter)sideTile).getTransmissionType() == this) + { + return true; + } + } + + if(this == GAS && currentTile instanceof IGasTransmitter) + { + if(((IGasTransmitter)currentTile).canTransferGasToTube(sideTile)) + { + return true; + } + } + + return false; + } +}
\ No newline at end of file diff --git a/src/api/java/mekanism/api/transmitters/TransmitterNetworkRegistry.java b/src/api/java/mekanism/api/transmitters/TransmitterNetworkRegistry.java new file mode 100644 index 0000000..0f9c1c5 --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/TransmitterNetworkRegistry.java @@ -0,0 +1,289 @@ +package mekanism.api.transmitters; + +import java.util.HashMap; +import java.util.HashSet; + +import mekanism.api.Coord4D; +import mekanism.api.MekanismAPI; +import net.minecraftforge.common.util.ForgeDirection; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent.Phase; +import cpw.mods.fml.common.gameevent.TickEvent.ServerTickEvent; +import cpw.mods.fml.relauncher.Side; + +public class TransmitterNetworkRegistry +{ + private static TransmitterNetworkRegistry INSTANCE = new TransmitterNetworkRegistry(); + private static boolean loaderRegistered = false; + + private HashSet<DynamicNetwork> networks = Sets.newHashSet(); + private HashSet<DynamicNetwork> networksToChange = Sets.newHashSet(); + + private HashSet<IGridTransmitter> invalidTransmitters = Sets.newHashSet(); + private HashMap<Coord4D, IGridTransmitter> orphanTransmitters = Maps.newHashMap(); + + private Logger logger = LogManager.getLogger("MekanismTransmitters"); + + public static void initiate() + { + if(!loaderRegistered) + { + loaderRegistered = true; + + FMLCommonHandler.instance().bus().register(INSTANCE); + } + } + + public static void reset() + { + getInstance().networks.clear(); + getInstance().networksToChange.clear(); + getInstance().invalidTransmitters.clear(); + getInstance().orphanTransmitters.clear(); + } + + public static void invalidateTransmitter(IGridTransmitter transmitter) + { + getInstance().invalidTransmitters.add(transmitter); + } + + public static void registerOrphanTransmitter(IGridTransmitter transmitter) + { + getInstance().orphanTransmitters.put(transmitter.coord(), transmitter); + } + + public static void registerChangedNetwork(DynamicNetwork network) + { + getInstance().networksToChange.add(network); + } + + public static TransmitterNetworkRegistry getInstance() + { + return INSTANCE; + } + + public void registerNetwork(DynamicNetwork network) + { + networks.add(network); + } + + public void removeNetwork(DynamicNetwork network) + { + if(networks.contains(network)) + { + networks.remove(network); + } + } + + @SubscribeEvent + public void onTick(ServerTickEvent event) + { + if(event.phase == Phase.END && event.side == Side.SERVER) + { + tickEnd(); + } + } + + public void tickEnd() + { + removeInvalidTransmitters(); + + assignOrphans(); + + commitChanges(); + + for(DynamicNetwork net : networks) + { + net.tick(); + } + } + + public void removeInvalidTransmitters() + { + if(MekanismAPI.debug && !invalidTransmitters.isEmpty()) + { + logger.info("Dealing with " + invalidTransmitters.size() + " invalid Transmitters"); + } + + for(IGridTransmitter invalid : invalidTransmitters) + { + if(!(invalid.isOrphan() && invalid.isValid())) + { + DynamicNetwork n = invalid.getTransmitterNetwork(); + + if(n != null) + { + n.invalidate(); + } + } + } + + invalidTransmitters.clear(); + } + + public void assignOrphans() + { + if(MekanismAPI.debug && !orphanTransmitters.isEmpty()) + { + logger.info("Dealing with " + orphanTransmitters.size() + " orphan Transmitters"); + } + + for(IGridTransmitter orphanTransmitter : orphanTransmitters.values()) + { + DynamicNetwork network = getNetworkFromOrphan(orphanTransmitter); + + if(network != null) + { + networksToChange.add(network); + network.register(); + } + } + + orphanTransmitters.clear(); + } + + public <A, N extends DynamicNetwork<A, N>> DynamicNetwork<A, N> getNetworkFromOrphan(IGridTransmitter<A, N> startOrphan) + { + if(startOrphan.isValid() && startOrphan.isOrphan()) + { + OrphanPathFinder<A, N> finder = new OrphanPathFinder<A, N>(startOrphan); + finder.start(); + N network; + + switch(finder.networksFound.size()) + { + case 0: + if(MekanismAPI.debug) + { + logger.info("No networks found. Creating new network for " + finder.connectedTransmitters.size() + " transmitters"); + } + + network = startOrphan.createEmptyNetwork(); + + break; + case 1: + if(MekanismAPI.debug) + { + logger.info("Adding " + finder.connectedTransmitters.size() + " transmitters to single found network"); + } + + network = finder.networksFound.iterator().next(); + + break; + default: + if(MekanismAPI.debug) + { + logger.info("Merging " + finder.networksFound.size() + " networks with " + finder.connectedTransmitters.size() + " new transmitters"); + } + + network = startOrphan.mergeNetworks(finder.networksFound); + } + + network.addNewTransmitters(finder.connectedTransmitters); + + return network; + } + + return null; + } + + public void commitChanges() + { + for(DynamicNetwork network : networksToChange) + { + network.commit(); + } + + networksToChange.clear(); + } + + @Override + public String toString() + { + return "Network Registry:\n" + networks; + } + + public String[] toStrings() + { + String[] strings = new String[networks.size()]; + int i = 0; + + for(DynamicNetwork network : networks) + { + strings[i++] = network.toString(); + } + + return strings; + } + + public class OrphanPathFinder<A, N extends DynamicNetwork<A, N>> + { + public IGridTransmitter<A, N> startPoint; + + public HashSet<Coord4D> iterated = Sets.newHashSet(); + + public HashSet<IGridTransmitter<A, N>> connectedTransmitters = Sets.newHashSet(); + public HashSet<N> networksFound = Sets.newHashSet(); + + public OrphanPathFinder(IGridTransmitter<A, N> start) + { + startPoint = start; + } + + public void start() + { + iterate(startPoint.coord(), ForgeDirection.UNKNOWN); + } + + public void iterate(Coord4D from, ForgeDirection fromDirection) + { + if(iterated.contains(from)) + { + return; + } + + iterated.add(from); + + if(orphanTransmitters.containsKey(from)) + { + IGridTransmitter<A, N> transmitter = orphanTransmitters.get(from); + + if(transmitter.isValid() && transmitter.isOrphan()) + { + connectedTransmitters.add(transmitter); + transmitter.setOrphan(false); + + for(ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) + { + if(direction != fromDirection) + { + Coord4D directionCoord = transmitter.getAdjacentConnectableTransmitterCoord(direction); + + if(!(directionCoord == null || iterated.contains(directionCoord))) + { + iterate(directionCoord, direction.getOpposite()); + } + } + } + } + } + else { + addNetworkToIterated(from); + } + } + + public void addNetworkToIterated(Coord4D from) + { + N net = startPoint.getExternalNetwork(from); + if(net != null) networksFound.add(net); + } + } +} diff --git a/src/api/java/mekanism/api/transmitters/package-info.java b/src/api/java/mekanism/api/transmitters/package-info.java new file mode 100644 index 0000000..06819e7 --- /dev/null +++ b/src/api/java/mekanism/api/transmitters/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|transmitter") +package mekanism.api.transmitters; +import cpw.mods.fml.common.API;
\ No newline at end of file diff --git a/src/api/java/mekanism/api/util/BlockInfo.java b/src/api/java/mekanism/api/util/BlockInfo.java new file mode 100644 index 0000000..2cb40d7 --- /dev/null +++ b/src/api/java/mekanism/api/util/BlockInfo.java @@ -0,0 +1,38 @@ +package mekanism.api.util; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; + +public class BlockInfo +{ + public Block block; + public int meta; + + public BlockInfo(Block b, int j) + { + block = b; + meta = j; + } + + public static BlockInfo get(ItemStack stack) + { + return new BlockInfo(Block.getBlockFromItem(stack.getItem()), stack.getItemDamage()); + } + + @Override + public boolean equals(Object obj) + { + return obj instanceof BlockInfo && + ((BlockInfo)obj).block == block && + ((BlockInfo)obj).meta == meta; + } + + @Override + public int hashCode() + { + int code = 1; + code = 31 * code + block.getUnlocalizedName().hashCode(); + code = 31 * code + meta; + return code; + } +}
\ No newline at end of file diff --git a/src/api/java/mekanism/api/util/ItemInfo.java b/src/api/java/mekanism/api/util/ItemInfo.java new file mode 100644 index 0000000..f27065b --- /dev/null +++ b/src/api/java/mekanism/api/util/ItemInfo.java @@ -0,0 +1,38 @@ +package mekanism.api.util; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public class ItemInfo +{ + public Item item; + public int meta; + + public ItemInfo(Item i, int j) + { + item = i; + meta = j; + } + + public static ItemInfo get(ItemStack stack) + { + return new ItemInfo(stack.getItem(), stack.getItemDamage()); + } + + @Override + public boolean equals(Object obj) + { + return obj instanceof ItemInfo && + ((ItemInfo)obj).item == item && + ((ItemInfo)obj).meta == meta; + } + + @Override + public int hashCode() + { + int code = 1; + code = 31 * code + System.identityHashCode(item); + code = 7 * code + meta; + return code; + } +} diff --git a/src/api/java/mekanism/api/util/ListUtils.java b/src/api/java/mekanism/api/util/ListUtils.java new file mode 100644 index 0000000..e20807c --- /dev/null +++ b/src/api/java/mekanism/api/util/ListUtils.java @@ -0,0 +1,282 @@ +package mekanism.api.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +public class ListUtils +{ + public static <V> List<V> inverse(List<V> list) + { + List<V> toReturn = new ArrayList<V>(); + + for(int i = list.size() - 1; i >= 0; i--) + { + toReturn.add(list.get(i)); + } + + return toReturn; + } + + public static <V> List<V> cap(List<V> list, int cap) + { + List<V> toReturn = new ArrayList<V>(); + + if(list.size() <= cap) + { + toReturn = copy(list); + } + else { + int count = 0; + + for(V obj : list) + { + count++; + + toReturn.add(obj); + + if(count == cap) + { + break; + } + } + } + + return toReturn; + } + + public static <V> List<V> copy(List<V> list) + { + List<V> toReturn = new ArrayList<V>(); + + for(V obj : list) + { + toReturn.add(obj); + } + + return toReturn; + } + + public static <V> List<V> merge(List<V> listOne, List<V> listTwo) + { + List<V> newList = new ArrayList<V>(); + + for(V obj : listOne) + { + newList.add(obj); + } + + for(V obj : listTwo) + { + newList.add(obj); + } + + return newList; + } + + public static <V> List<V> capRemains(List<V> list, int cap) + { + List<V> toReturn = new ArrayList<V>(); + + if(list.size() <= cap) + { + return toReturn; + } + else { + List<V> inverse = inverse(list); + + int iterNeeded = list.size() - cap; + int count = 0; + + for(V obj : list) + { + count++; + + toReturn.add(obj); + + if(count == iterNeeded) + { + break; + } + } + + return toReturn; + } + } + + public static <V> ArrayList<List<V>> split(List<V> list, int divide) + { + int remain = list.size() % divide; + int size = (list.size() - remain) / divide; + + ArrayList<List<V>> toReturn = new ArrayList<List<V>>(); + + for(int i = 0; i < divide; i++) + { + toReturn.add(i, new ArrayList<V>()); + } + + for(List<V> iterSet : toReturn) + { + List<V> removed = new ArrayList<V>(); + + int toAdd = size; + + if(remain > 0) + { + remain--; + toAdd++; + } + + for(V obj : list) + { + if(toAdd == 0) + { + break; + } + + iterSet.add(obj); + removed.add(obj); + toAdd--; + } + + for(V obj : removed) + { + list.remove(obj); + } + } + + return toReturn; + } + + public static <V> V getTop(List<V> list) + { + for(V obj : list) + { + return obj; + } + + return null; + } + + public static <V> List<V> asList(Set<V> set) + { + return (List<V>)Arrays.asList(set.toArray()); + } + + public static <V> List<V> asList(V... values) + { + return (List<V>)Arrays.asList(values); + } + + public static double[] splitDouble(int size, double num) + { + double[] split = new double[size]; + + for(int i = 0; i < size; i++) + { + double remain = num%size; + double ret = (num-remain)/size; + ret += remain; + + split[i] = ret; + num -= remain; + } + + return split; + } + + public static double[] percent(double[] values) + { + double[] ret = new double[values.length]; + double total = 0; + + for(double d : values) total += d; + + for(int i = 0; i < values.length; i++) + { + ret[i] = values[i]/total; + } + + return ret; + } + + public static int[] calcPercentInt(double[] percent, int val) + { + int[] ret = new int[percent.length]; + + for(int i = 0; i < percent.length; i++) + { + ret[i] = (int)Math.round(val*percent[i]); + } + + int newTotal = 0; + for(int i : ret) newTotal += i; + + int diff = val-newTotal; + + if(diff != val) + { + for(int i = 0; i < ret.length; i++) + { + int num = ret[i]; + + if(diff < 0 && num == 0) + { + continue; + } + + if(diff > 0) + { + ret[i]++; + diff--; + } + else if(diff < 0) + { + ret[i]--; + diff++; + } + + if(diff == 0) + { + return ret; + } + } + } + + return ret; + } + + public static int[] splitInt(int size, int num) + { + int[] split = new int[size]; + + for(int i = 0; i < size; i++) + { + int remain = num%size; + int ret = (num-remain)/size; + ret += remain; + + split[i] = ret; + num -= remain; + } + + return split; + } + + public static double[] percent(int[] values) + { + double[] ret = new double[values.length]; + double total = 0; + + for(double d : values) total += d; + + for(int i = 0; i < values.length; i++) + { + ret[i] = values[i]/total; + } + + return ret; + } +} diff --git a/src/api/java/mekanism/api/util/StackUtils.java b/src/api/java/mekanism/api/util/StackUtils.java new file mode 100644 index 0000000..7363c75 --- /dev/null +++ b/src/api/java/mekanism/api/util/StackUtils.java @@ -0,0 +1,254 @@ +package mekanism.api.util; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; + +public final class StackUtils +{ + public static List<ItemStack> split(ItemStack stack) + { + if(stack == null || stack.stackSize == 0) + { + return null; + } + + List<ItemStack> ret = new ArrayList<ItemStack>(); + + if(stack.stackSize == 1) + { + ret.add(stack); + return ret; + } + + int remain = stack.stackSize % 2; + int split = (int)((float)(stack.stackSize)/2F); + + ret.add(size(stack, split+remain)); + ret.add(size(stack, split)); + + return ret; + } + + public static Item getItem(ItemStack stack) + { + if(stack == null) + { + return null; + } + + return stack.getItem(); + } + + public static boolean diffIgnoreNull(ItemStack stack1, ItemStack stack2) + { + if(stack1 == null || stack2 == null) + { + return false; + } + + return stack1.getItem() != stack2.getItem() || stack1.getItemDamage() != stack2.getItemDamage(); + } + + public static boolean equalsWildcard(ItemStack wild, ItemStack check) + { + if(wild == null || check == null) + { + return check == wild; + } + + return wild.getItem() == check.getItem() && (wild.getItemDamage() == OreDictionary.WILDCARD_VALUE || wild.getItemDamage() == check.getItemDamage()); + } + + public static boolean equalsWildcardWithNBT(ItemStack wild, ItemStack check) + { + return equalsWildcard(wild, check) && (wild.stackTagCompound == null ? check.stackTagCompound == null : (wild.stackTagCompound == check.stackTagCompound || wild.stackTagCompound.equals(check.stackTagCompound))); + } + + public static List<ItemStack> even(ItemStack stack1, ItemStack stack2) + { + ArrayList<ItemStack> ret = new ArrayList<ItemStack>(); + + if(getSize(stack1) == getSize(stack2) || Math.abs(getSize(stack1)-getSize(stack2)) == 1) + { + ret.add(stack1); + ret.add(stack2); + + return ret; + } + + if(getSize(stack1) > getSize(stack2)) + { + int diff = getSize(stack1)-getSize(stack2); + + List<ItemStack> split = split(size(stack1, diff)); + + ret.add(subtract(stack1, split.get(0))); + ret.add(add(stack2, split.get(0))); + } + else if(getSize(stack2) > getSize(stack1)) + { + int diff = getSize(stack2)-getSize(stack1); + + List<ItemStack> split = split(size(stack2, diff)); + + ret.add(subtract(stack2, split.get(0))); + ret.add(add(stack1, split.get(0))); + } + + return ret; + } + + public static ItemStack add(ItemStack stack1, ItemStack stack2) + { + if(stack1 == null) + { + return stack2; + } + else if(stack2 == null) + { + return stack1; + } + + return size(stack1, getSize(stack1)+getSize(stack2)); + } + + public static ItemStack subtract(ItemStack stack1, ItemStack stack2) + { + if(stack1 == null) + { + return null; + } + else if(stack2 == null) + { + return stack1; + } + + return size(stack1, getSize(stack1)-getSize(stack2)); + } + + public static ItemStack size(ItemStack stack, int size) + { + if(size <= 0 || stack == null) + { + return null; + } + + ItemStack ret = stack.copy(); + ret.stackSize = size; + return ret; + } + + public static ItemStack copy(ItemStack stack) + { + if(stack == null) + { + return null; + } + + return stack.copy(); + } + + public static int getSize(ItemStack stack) + { + return stack != null ? stack.stackSize : 0; + } + + public static List<ItemStack> getMergeRejects(ItemStack[] orig, ItemStack[] toAdd) + { + List<ItemStack> ret = new ArrayList<ItemStack>(); + + for(int i = 0; i < toAdd.length; i++) + { + if(toAdd[i] != null) + { + ItemStack reject = getMergeReject(orig[i], toAdd[i]); + + if(reject != null) + { + ret.add(reject); + } + } + } + + return ret; + } + + public static void merge(ItemStack[] orig, ItemStack[] toAdd) + { + for(int i = 0; i < toAdd.length; i++) + { + if(toAdd[i] != null) + { + orig[i] = merge(orig[i], toAdd[i]); + } + } + } + + public static ItemStack merge(ItemStack orig, ItemStack toAdd) + { + if(orig == null) + { + return toAdd; + } + + if(toAdd == null) + { + return orig; + } + + if(!orig.isItemEqual(toAdd) || !ItemStack.areItemStackTagsEqual(orig, toAdd)) + { + return orig; + } + + return StackUtils.size(orig, Math.min(orig.getMaxStackSize(), orig.stackSize+toAdd.stackSize)); + } + + public static ItemStack getMergeReject(ItemStack orig, ItemStack toAdd) + { + if(orig == null) + { + return null; + } + + if(toAdd == null) + { + return orig; + } + + if(!orig.isItemEqual(toAdd) || !ItemStack.areItemStackTagsEqual(orig, toAdd)) + { + return orig; + } + + int newSize = orig.stackSize+toAdd.stackSize; + + if(newSize > orig.getMaxStackSize()) + { + return StackUtils.size(orig, newSize-orig.getMaxStackSize()); + } + else { + return StackUtils.size(orig, newSize); + } + } + + public static boolean contains(ItemStack container, ItemStack contained) + { + return equalsWildcardWithNBT(contained, container) && container.stackSize >= contained.stackSize; + } + + public static int hashItemStack(ItemStack stack) + { + if(stack == null || stack.getItem() == null) + { + return -1; + } + + String name = stack.getItemDamage() == OreDictionary.WILDCARD_VALUE ? stack.getItem().getUnlocalizedName() : stack.getItem().getUnlocalizedName(stack); + return name.hashCode() << 8 | stack.getItemDamage(); + } +} diff --git a/src/api/java/mekanism/api/util/UnitDisplayUtils.java b/src/api/java/mekanism/api/util/UnitDisplayUtils.java new file mode 100644 index 0000000..9dd3e28 --- /dev/null +++ b/src/api/java/mekanism/api/util/UnitDisplayUtils.java @@ -0,0 +1,295 @@ +package mekanism.api.util; + +/** + * Code taken from UE and modified to fit Mekanism. + */ +public class UnitDisplayUtils +{ + public static enum ElectricUnit + { + JOULES("Joule", "J"), + REDSTONE_FLUX("Redstone Flux", "RF"), + MINECRAFT_JOULES("Minecraft Joule", "MJ"), + ELECTRICAL_UNITS("Electrical Unit", "EU"); + + public String name; + public String symbol; + + private ElectricUnit(String s, String s1) + { + name = s; + symbol = s1; + } + + public String getPlural() + { + return this == REDSTONE_FLUX ? name : name + "s"; + } + } + + public static enum TemperatureUnit + { + KELVIN("Kelvin", "K", 0, 1), + CELSIUS("Celsius", "°C", 273.15, 1), + RANKINE("Rankine", "R", 0, 9D/5D), + FAHRENHEIT("Fahrenheit", "°F", 459.67, 9D/5D), + AMBIENT("Ambient", "+STP", 300, 1); + + public String name; + public String symbol; + double zeroOffset; + double intervalSize; + + private TemperatureUnit(String s, String s1, double offset, double size) + { + name = s; + symbol = s1; + zeroOffset = offset; + intervalSize = size; + } + + public double convertFromK(double T) + { + return (T * intervalSize) - zeroOffset; + } + + public double convertToK(double T) + { + return (T + zeroOffset) / intervalSize; + } + } + + /** Metric system of measurement. */ + public static enum MeasurementUnit + { + FEMTO("Femto", "f", 0.000000000000001D), + PICO("Pico", "p", 0.000000000001D), + NANO("Nano", "n", 0.000000001D), + MICRO("Micro", "u", 0.000001D), + MILLI("Milli", "m", 0.001D), + BASE("", "", 1), + KILO("Kilo", "k", 1000D), + MEGA("Mega", "M", 1000000D), + GIGA("Giga", "G", 1000000000D), + TERA("Tera", "T", 1000000000000D), + PETA("Peta", "P", 1000000000000000D), + EXA("Exa", "E", 1000000000000000000D), + ZETTA("Zetta", "Z", 1000000000000000000000D), + YOTTA("Yotta", "Y", 1000000000000000000000000D); + + /** long name for the unit */ + public String name; + + /** short unit version of the unit */ + public String symbol; + + /** Point by which a number is consider to be of this unit */ + public double value; + + private MeasurementUnit(String s, String s1, double v) + { + name = s; + symbol = s1; + value = v; + } + + public String getName(boolean getShort) + { + if(getShort) + { + return symbol; + } + else { + return name; + } + } + + public double process(double d) + { + return d / value; + } + + public boolean above(double d) + { + return d > value; + } + + public boolean below(double d) + { + return d < value; + } + } + + /** + * Displays the unit as text. Does handle negative numbers, and will place a negative sign in + * front of the output string showing this. Use string.replace to remove the negative sign if + * unwanted + */ + public static String getDisplay(double value, ElectricUnit unit, int decimalPlaces, boolean isShort) + { + String unitName = unit.name; + String prefix = ""; + + if(value < 0) + { + value = Math.abs(value); + prefix = "-"; + } + + if(isShort) + { + unitName = unit.symbol; + } + else if(value > 1) + { + unitName = unit.getPlural(); + } + + if(value == 0) + { + return value + " " + unitName; + } + else { + for(int i = 0; i < MeasurementUnit.values().length; i++) + { + MeasurementUnit lowerMeasure = MeasurementUnit.values()[i]; + + if(lowerMeasure.below(value) && lowerMeasure.ordinal() == 0) + { + return prefix + roundDecimals(lowerMeasure.process(value), decimalPlaces) + " " + lowerMeasure.getName(isShort) + unitName; + } + + if(lowerMeasure.ordinal() + 1 >= MeasurementUnit.values().length) + { + return prefix + roundDecimals(lowerMeasure.process(value), decimalPlaces) + " " + lowerMeasure.getName(isShort) + unitName; + } + + MeasurementUnit upperMeasure = MeasurementUnit.values()[i + 1]; + + if((lowerMeasure.above(value) && upperMeasure.below(value)) || lowerMeasure.value == value) + { + return prefix + roundDecimals(lowerMeasure.process(value), decimalPlaces) + " " + lowerMeasure.getName(isShort) + unitName; + } + } + } + + return prefix + roundDecimals(value, decimalPlaces) + " " + unitName; + } + + public static String getDisplayShort(double value, ElectricUnit unit) + { + return getDisplay(value, unit, 2, true); + } + + public static String getDisplayShort(double value, ElectricUnit unit, int decimalPlaces) + { + return getDisplay(value, unit, decimalPlaces, true); + } + + public static String getDisplaySimple(double 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; + } + + public static String getDisplay(double T, TemperatureUnit unit, int decimalPlaces, boolean isShort) + { + String unitName = unit.name; + String prefix = ""; + + double value = unit.convertFromK(T); + + if(value < 0) + { + value = Math.abs(value); + prefix = "-"; + } + + if(isShort) + { + unitName = unit.symbol; + } + + if(value == 0) + { + return value + (isShort ? "" : " ") + unitName; + } + else { + for(int i = 0; i < MeasurementUnit.values().length; i++) + { + MeasurementUnit lowerMeasure = MeasurementUnit.values()[i]; + + if(lowerMeasure.below(value) && lowerMeasure.ordinal() == 0) + { + return prefix + roundDecimals(lowerMeasure.process(value), decimalPlaces) + (isShort ? "" : " ") + lowerMeasure.getName(isShort) + unitName; + } + + if(lowerMeasure.ordinal() + 1 >= MeasurementUnit.values().length) + { + return prefix + roundDecimals(lowerMeasure.process(value), decimalPlaces) + (isShort ? "" : " ") + lowerMeasure.getName(isShort) + unitName; + } + + MeasurementUnit upperMeasure = MeasurementUnit.values()[i + 1]; + + if((lowerMeasure.above(value) && upperMeasure.below(value)) || lowerMeasure.value == value) + { + return prefix + roundDecimals(lowerMeasure.process(value), decimalPlaces) + (isShort ? "" : " ") + lowerMeasure.getName(isShort) + unitName; + } + } + } + + return prefix + roundDecimals(value, decimalPlaces) + (isShort ? "" : " ") + unitName; + } + + public static String getDisplayShort(double value, TemperatureUnit unit) + { + return getDisplay(value, unit, 2, true); + } + + public static String getDisplayShort(double value, TemperatureUnit unit, int decimalPlaces) + { + return getDisplay(value, unit, decimalPlaces, true); + } + + 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); + } + + public static enum EnergyType + { + J, + RF, + EU, + MJ + } + + public static enum TempType + { + K, + C, + R, + F, + STP + } +} diff --git a/src/api/java/mekanism/api/util/package-info.java b/src/api/java/mekanism/api/util/package-info.java new file mode 100644 index 0000000..e5253bc --- /dev/null +++ b/src/api/java/mekanism/api/util/package-info.java @@ -0,0 +1,3 @@ +@API(apiVersion = "8.0.0", owner = "Mekanism", provides = "MekanismAPI|util") +package mekanism.api.util; +import cpw.mods.fml.common.API;
\ No newline at end of file |
