aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gtPlusPlus/api/objects/minecraft
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gtPlusPlus/api/objects/minecraft')
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/AABB.java65
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/BTF_FluidTank.java188
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/BTF_Inventory.java228
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/BlockPos.java250
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/CubicObject.java62
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/DimChunkPos.java52
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/FakeBlockPos.java253
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/FakeWorld.java173
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/FluidGT6.java31
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/FormattedTooltipString.java25
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/GenericStack.java42
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/ItemPackage.java58
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/ItemStackData.java35
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/NoConflictGTRecipeMap.java123
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/SafeTexture.java64
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/ShapedRecipe.java250
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/TexturePackage.java55
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/ThreadPooCollector.java111
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoEUBonusMultiBehaviour.java27
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoOutputBonusMultiBehaviour.java27
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoSpeedBonusMultiBehaviour.java27
-rw-r--r--src/main/java/gtPlusPlus/api/objects/minecraft/multi/SpecialMultiBehaviour.java44
22 files changed, 2190 insertions, 0 deletions
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/AABB.java b/src/main/java/gtPlusPlus/api/objects/minecraft/AABB.java
new file mode 100644
index 0000000000..722ac00b64
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/AABB.java
@@ -0,0 +1,65 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import gtPlusPlus.core.util.minecraft.EntityUtils;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.world.World;
+
+/**
+ * Generates an AABB around an entity.
+ * @author Alkalus
+ *
+ */
+public class AABB {
+
+ private final AxisAlignedBB mAabb;
+ private final World mWorld;
+
+ /**
+ * Creates a AxisAlignedBB based around an Entity.
+ * @param aEntity - The Entity to work with.
+ * @param x - Maximum X from origin.
+ * @param y - Maximum Y from origin.
+ * @param z - Maximum Z from origin.
+ */
+ public AABB(Entity aEntity, int x, int y, int z) {
+ if (aEntity == null) {
+ mAabb = null;
+ mWorld = null;
+ }
+ else {
+ mWorld = aEntity.worldObj;
+ BlockPos aEntityLocation = EntityUtils.findBlockPosUnderEntity(aEntity);
+ int xMin, xMax, yMin, yMax, zMin, zMax;
+ xMin = aEntityLocation.xPos;
+ yMin = aEntityLocation.yPos;
+ zMin = aEntityLocation.zPos;
+ xMax = aEntityLocation.xPos + x;
+ yMax = aEntityLocation.yPos + y;
+ zMax = aEntityLocation.zPos + z;
+ mAabb = AxisAlignedBB.getBoundingBox(xMin, yMin, zMin, xMax, yMax, zMax);
+ }
+
+ }
+
+ /**
+ * Used to get the AxisAlignedBB from this class.
+ * @return
+ */
+ public AxisAlignedBB get() {
+ return mAabb;
+ }
+
+ /**
+ * Used to determine if this object is valid or not.
+ * @return
+ */
+ public boolean valid() {
+ return mAabb != null && mWorld != null;
+ }
+
+ public World world() {
+ return mWorld;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_FluidTank.java b/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_FluidTank.java
new file mode 100644
index 0000000000..0b8f97b378
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_FluidTank.java
@@ -0,0 +1,188 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import gtPlusPlus.core.util.minecraft.FluidUtils;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.FluidTank;
+import net.minecraftforge.fluids.FluidTankInfo;
+
+public class BTF_FluidTank extends FluidTank {
+
+ public FluidStack mFluid;
+
+ public BTF_FluidTank(int capacity) {
+ super(capacity);
+ }
+
+ /**
+ * Let's replace the Default handling with GT's own handling code, because it's probably better, right?
+ * @author Alkalus/GregoriusT
+ */
+
+
+ public FluidStack getFluid() {
+ return this.getDrainableStack();
+ }
+
+ public int getFluidAmount() {
+ return this.getDrainableStack() != null ? this.getDrainableStack().amount : 0;
+ }
+
+ public NBTTagCompound writeToNBT(NBTTagCompound aNBT) {
+ super.writeToNBT(aNBT);
+ if (this.mFluid != null) {
+ aNBT.setTag("mFluid", this.mFluid.writeToNBT(new NBTTagCompound()));
+ }
+ return aNBT;
+ }
+
+ public FluidTank readFromNBT(NBTTagCompound aNBT) {
+ this.mFluid = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mFluid"));
+ return this;
+ }
+
+/* public abstract boolean isLiquidInput(byte arg0);
+
+ public abstract boolean isLiquidOutput(byte arg0);
+
+ public abstract boolean doesFillContainers();
+
+ public abstract boolean doesEmptyContainers();*/
+
+ public boolean canTankBeFilled() {
+ return true;
+ }
+
+ public boolean canTankBeEmptied() {
+ return true;
+ }
+
+
+ public boolean isFluidInputAllowed(FluidStack aFluid) {
+ return true;
+ }
+
+ public FluidStack getFillableStack() {
+ return this.mFluid;
+ }
+
+ public FluidStack setFillableStack(FluidStack aFluid) {
+ this.mFluid = aFluid;
+ return this.mFluid;
+ }
+
+ public FluidStack getDrainableStack() {
+ return this.mFluid;
+ }
+
+ public FluidStack setDrainableStack(FluidStack aFluid) {
+ this.mFluid = aFluid;
+ return this.mFluid;
+ }
+
+ public FluidStack getDisplayedFluid() {
+ return this.getDrainableStack();
+ }
+
+ public boolean isFluidChangingAllowed() {
+ return true;
+ }
+
+ public int fill(FluidStack aFluid, boolean doFill) {
+ if (aFluid != null && aFluid.getFluid().getID() > 0 && aFluid.amount > 0 && this.canTankBeFilled()
+ && this.isFluidInputAllowed(aFluid)) {
+ if (this.getFillableStack() != null && this.getFillableStack().getFluid().getID() > 0) {
+ if (!this.getFillableStack().isFluidEqual(aFluid)) {
+ return 0;
+ } else {
+ int space = this.getCapacity() - this.getFillableStack().amount;
+ if (aFluid.amount <= space) {
+ if (doFill) {
+ FluidStack arg9999 = this.getFillableStack();
+ arg9999.amount += aFluid.amount;
+ }
+
+ return aFluid.amount;
+ } else {
+ if (doFill) {
+ this.getFillableStack().amount = this.getCapacity();
+ }
+
+ return space;
+ }
+ }
+ } else if (aFluid.amount <= this.getCapacity()) {
+ if (doFill) {
+ this.setFillableStack(aFluid.copy());
+ }
+
+ return aFluid.amount;
+ } else {
+ if (doFill) {
+ this.setFillableStack(aFluid.copy());
+ this.getFillableStack().amount = this.getCapacity();
+ }
+
+ return this.getCapacity();
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ public FluidStack drain(int maxDrain, boolean doDrain) {
+ if (this.getDrainableStack() != null && this.canTankBeEmptied()) {
+ if (this.getDrainableStack().amount <= 0 && this.isFluidChangingAllowed()) {
+ this.setDrainableStack((FluidStack) null);
+ return null;
+ } else {
+ int used = maxDrain;
+ if (this.getDrainableStack().amount < maxDrain) {
+ used = this.getDrainableStack().amount;
+ }
+
+ if (doDrain) {
+ FluidStack arg9999 = this.getDrainableStack();
+ arg9999.amount -= used;
+ }
+
+ FluidStack drained = this.getDrainableStack().copy();
+ drained.amount = used;
+ if (this.getDrainableStack().amount <= 0 && this.isFluidChangingAllowed()) {
+ this.setDrainableStack((FluidStack) null);
+ }
+
+ return drained;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int getCapacity() {
+ return super.getCapacity();
+ }
+
+ @Override
+ public FluidTankInfo getInfo() {
+ return new FluidTankInfo(this);
+ }
+
+ @Override
+ public void setFluid(FluidStack fluid) {
+ setFillableStack(fluid);
+ }
+
+ @Override
+ public void setCapacity(int capacity) {
+ super.setCapacity(capacity);
+ }
+
+ public FluidStack drain(FluidStack aFluid, boolean doDrain) {
+ return drain(aFluid.amount, doDrain);
+ }
+
+
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_Inventory.java b/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_Inventory.java
new file mode 100644
index 0000000000..04ce0dff19
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/BTF_Inventory.java
@@ -0,0 +1,228 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.ArrayList;
+
+import gregtech.api.util.GT_Utility;
+import gtPlusPlus.core.tileentities.base.TileEntityBase;
+import gtPlusPlus.core.util.data.ArrayUtils;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.inventory.ISidedInventory;
+import net.minecraft.item.ItemStack;
+
+public class BTF_Inventory implements ISidedInventory{
+
+ public final ItemStack[] mInventory;
+ public final TileEntityBase mTile;
+
+ public BTF_Inventory(int aSlots, TileEntityBase tile) {
+ this.mInventory = new ItemStack[aSlots];
+ this.mTile = tile;
+ }
+
+ public ItemStack[] getRealInventory() {
+ purgeNulls();
+ return this.mInventory;
+ }
+
+ public int getSizeInventory() {
+ return this.mInventory.length;
+ }
+
+ public ItemStack getStackInSlot(int aIndex) {
+ return aIndex >= 0 && aIndex < this.mInventory.length ? this.mInventory[aIndex] : null;
+ }
+
+ public void setInventorySlotContents(int aIndex, ItemStack aStack) {
+ if (aIndex >= 0 && aIndex < this.mInventory.length) {
+ this.mInventory[aIndex] = aStack;
+ }
+ }
+
+ public boolean isAccessAllowed(EntityPlayer aPlayer) {
+ return true;
+ }
+
+ public boolean isValidSlot(int aIndex) {
+ return true;
+ }
+
+ public int getInventoryStackLimit() {
+ return 64;
+ }
+
+
+ public boolean setStackToZeroInsteadOfNull(int aIndex) {
+ return false;
+}
+
+ public boolean isItemValidForSlot(int aIndex, ItemStack aStack) {
+ return isValidSlot(aIndex);
+ }
+
+ public ItemStack decrStackSize(int aIndex, int aAmount) {
+ ItemStack tStack = this.getStackInSlot(aIndex);
+ ItemStack rStack = GT_Utility.copy(new Object[]{tStack});
+ if (tStack != null) {
+ if (tStack.stackSize <= aAmount) {
+ if (this.setStackToZeroInsteadOfNull(aIndex)) {
+ tStack.stackSize = 0;
+ } else {
+ this.setInventorySlotContents(aIndex, (ItemStack) null);
+ }
+ } else {
+ rStack = tStack.splitStack(aAmount);
+ if (tStack.stackSize == 0 && !this.setStackToZeroInsteadOfNull(aIndex)) {
+ this.setInventorySlotContents(aIndex, (ItemStack) null);
+ }
+ }
+ }
+
+ return rStack;
+ }
+
+ public int[] getAccessibleSlotsFromSide(int aSide) {
+ ArrayList<Integer> tList = new ArrayList<Integer>();
+ TileEntityBase tTileEntity = this.mTile;
+ boolean tSkip = tTileEntity.getCoverBehaviorAtSide((byte) aSide).letsItemsIn((byte) aSide,
+ tTileEntity.getCoverIDAtSide((byte) aSide), tTileEntity.getCoverDataAtSide((byte) aSide), -2,
+ tTileEntity)
+ || tTileEntity.getCoverBehaviorAtSide((byte) aSide).letsItemsOut((byte) aSide,
+ tTileEntity.getCoverIDAtSide((byte) aSide), tTileEntity.getCoverDataAtSide((byte) aSide), -2,
+ tTileEntity);
+
+ for (int rArray = 0; rArray < this.getSizeInventory(); ++rArray) {
+ if (this.isValidSlot(rArray) && (tSkip
+ || tTileEntity.getCoverBehaviorAtSide((byte) aSide).letsItemsOut((byte) aSide,
+ tTileEntity.getCoverIDAtSide((byte) aSide), tTileEntity.getCoverDataAtSide((byte) aSide),
+ rArray, tTileEntity)
+ || tTileEntity.getCoverBehaviorAtSide((byte) aSide).letsItemsIn((byte) aSide,
+ tTileEntity.getCoverIDAtSide((byte) aSide), tTileEntity.getCoverDataAtSide((byte) aSide),
+ rArray, tTileEntity))) {
+ tList.add(Integer.valueOf(rArray));
+ }
+ }
+
+ int[] arg6 = new int[tList.size()];
+
+ for (int i = 0; i < arg6.length; ++i) {
+ arg6[i] = ((Integer) tList.get(i)).intValue();
+ }
+
+ return arg6;
+ }
+
+ public boolean canInsertItem(int aIndex, ItemStack aStack, int aSide) {
+ return this.isValidSlot(aIndex) && aStack != null && aIndex < this.mInventory.length
+ && (this.mInventory[aIndex] == null || GT_Utility.areStacksEqual(aStack, this.mInventory[aIndex]))
+ && this.allowPutStack(this.mTile, aIndex, (byte) aSide, aStack);
+ }
+
+ public boolean canExtractItem(int aIndex, ItemStack aStack, int aSide) {
+ return this.isValidSlot(aIndex) && aStack != null && aIndex < this.mInventory.length
+ && this.allowPullStack(this.mTile, aIndex, (byte) aSide, aStack);
+ }
+
+ public boolean allowPullStack(TileEntityBase mTile2, int aIndex, byte aSide, ItemStack aStack) {
+ return aIndex >= 0 && aIndex < this.getSizeInventory();
+ }
+
+ public boolean allowPutStack(TileEntityBase aBaseMetaTileEntity, int aIndex, byte aSide, ItemStack aStack) {
+ return (aIndex >= 0 && aIndex < this.getSizeInventory()) && (this.mInventory[aIndex] == null || GT_Utility.areStacksEqual(this.mInventory[aIndex], aStack));
+ }
+
+ public ItemStack getStackInSlotOnClosing(int i) {
+ return null;
+ }
+
+ public final boolean hasCustomInventoryName() {
+ return mTile != null ? mTile.hasCustomInventoryName() : false;
+ }
+
+
+ public void markDirty() {
+ if (mTile != null) {
+ purgeNulls();
+ mTile.markDirty();
+ }
+ }
+
+ public boolean isUseableByPlayer(EntityPlayer entityplayer) {
+ return true;
+ }
+
+ public void openInventory() {
+
+ }
+
+ public void closeInventory() {
+
+ }
+
+ @Override
+ public final String getInventoryName() {
+ return this.mTile != null ? mTile.getInventoryName() : "";
+ }
+
+ public boolean isFull() {
+ for (int s=0;s<this.getSizeInventory();s++) {
+ ItemStack slot = mInventory[s];
+ if (slot == null || slot.stackSize != slot.getMaxStackSize()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isEmpty() {
+ for (int s=0;s<this.getSizeInventory();s++) {
+ ItemStack slot = mInventory[s];
+ if (slot == null) {
+ continue;
+ }
+ else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean addItemStack(ItemStack aInput) {
+ if (aInput != null & (isEmpty() || !isFull())) {
+ for (int s = 0; s < this.getSizeInventory(); s++) {
+ if (mInventory != null && mInventory[s] != null) {
+ ItemStack slot = mInventory[s];
+ if (slot == null || (slot != null && GT_Utility.areStacksEqual(aInput, slot) && slot.stackSize != slot.getItem().getItemStackLimit(slot))) {
+ if (slot == null) {
+ slot = aInput.copy();
+ } else {
+ slot.stackSize++;
+ }
+ this.setInventorySlotContents(s, slot);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public final void purgeNulls() {
+ ItemStack[] aTemp = ArrayUtils.removeNulls(this.mInventory);
+ for (int g=0;g<this.getSizeInventory();g++) {
+ if (aTemp.length < this.getSizeInventory()) {
+ if (g <= aTemp.length-1) {
+ this.mInventory[g] = aTemp[g];
+ }
+ else {
+ this.mInventory[g] = null;
+ }
+ }
+ else {
+ this.mInventory[g] = aTemp[g];
+ }
+ }
+
+ }
+
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/BlockPos.java b/src/main/java/gtPlusPlus/api/objects/minecraft/BlockPos.java
new file mode 100644
index 0000000000..ab359c3853
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/BlockPos.java
@@ -0,0 +1,250 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import net.minecraft.block.Block;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.world.World;
+
+import gtPlusPlus.api.objects.data.AutoMap;
+import net.minecraftforge.common.DimensionManager;
+
+public class BlockPos implements Serializable{
+
+ private static final long serialVersionUID = -7271947491316682006L;
+ public final int xPos;
+ public final int yPos;
+ public final int zPos;
+ public final int dim;
+ public final transient World world;
+
+ public static BlockPos generateBlockPos(String sUUID) {
+ String[] s2 = sUUID.split("@");
+ return new BlockPos(s2);
+ }
+
+ public BlockPos(String[] s){
+ this(Integer.parseInt(s[1]), Integer.parseInt(s[2]), Integer.parseInt(s[3]), Integer.parseInt(s[0]));
+ }
+
+ public BlockPos(int x, int y, int z){
+ this(x, y, z, 0);
+ }
+
+ public BlockPos(int x, int y, int z, int dim){
+ this(x, y, z, DimensionManager.getWorld(dim));
+ }
+
+ public BlockPos(int x, int y, int z, World dim){
+ this.xPos = x;
+ this.yPos = y;
+ this.zPos = z;
+
+ if (dim != null) {
+ this.dim = dim.provider.dimensionId;
+ this.world = dim;
+ }
+ else {
+ this.dim = 0;
+ this.world = null;
+ }
+
+ }
+
+ public BlockPos(IGregTechTileEntity b) {
+ this (b.getXCoord(), b.getYCoord(), b.getZCoord(), b.getWorld());
+ }
+
+ public BlockPos(TileEntity b) {
+ this (b.xCoord, b.yCoord, b.zCoord, b.getWorldObj());
+ }
+
+ public String getLocationString() {
+ return "[X: "+this.xPos+"][Y: "+this.yPos+"][Z: "+this.zPos+"][Dim: "+this.dim+"]";
+ }
+
+ public String getUniqueIdentifier() {
+ String S = ""+this.dim+"@"+this.xPos+"@"+this.yPos+"@"+this.zPos;
+ return S;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash += (13 * this.xPos);
+ hash += (19 * this.yPos);
+ hash += (31 * this.zPos);
+ hash += (17 * this.dim);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+ if (other == this) {
+ return true;
+ }
+ if(!(other instanceof BlockPos)) {
+ return false;
+ }
+ BlockPos otherPoint = (BlockPos)other;
+ return this.xPos == otherPoint.xPos && this.yPos == otherPoint.yPos && this.zPos == otherPoint.zPos && this.dim == otherPoint.dim;
+ }
+
+ public int distanceFrom(BlockPos target) {
+ if (target.dim != this.dim) {
+ return Short.MIN_VALUE;
+ }
+ return distanceFrom(target.xPos, target.yPos, target.zPos);
+ }
+
+ /**
+ *
+ * @param x X coordinate of target.
+ * @param y Y coordinate of target.
+ * @param z Z coordinate of target.
+ * @return square of distance
+ */
+ public int distanceFrom(int x, int y, int z) {
+ int distanceX = this.xPos - x;
+ int distanceY = this.yPos - y;
+ int distanceZ = this.zPos - z;
+ return distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ;
+ }
+
+ public boolean isWithinRange(BlockPos target, int range) {
+ if (target.dim != this.dim) {
+ return false;
+ }
+ return isWithinRange(target.xPos, target.yPos, target.zPos, range);
+ }
+
+ public boolean isWithinRange(int x, int y, int z, int range) {
+ return distanceFrom(x, y, z) <= (range * range);
+ }
+
+
+ public BlockPos getUp() {
+ return new BlockPos(this.xPos, this.yPos+1, this.zPos, this.dim);
+ }
+
+ public BlockPos getDown() {
+ return new BlockPos(this.xPos, this.yPos-1, this.zPos, this.dim);
+ }
+
+ public BlockPos getXPos() {
+ return new BlockPos(this.xPos+1, this.yPos, this.zPos, this.dim);
+ }
+
+ public BlockPos getXNeg() {
+ return new BlockPos(this.xPos-1, this.yPos, this.zPos, this.dim);
+ }
+
+ public BlockPos getZPos() {
+ return new BlockPos(this.xPos, this.yPos, this.zPos+1, this.dim);
+ }
+
+ public BlockPos getZNeg() {
+ return new BlockPos(this.xPos, this.yPos, this.zPos-1, this.dim);
+ }
+
+ public AutoMap<BlockPos> getSurroundingBlocks(){
+ AutoMap<BlockPos> sides = new AutoMap<BlockPos>();
+ sides.put(getUp());
+ sides.put(getDown());
+ sides.put(getXPos());
+ sides.put(getXNeg());
+ sides.put(getZPos());
+ sides.put(getZNeg());
+ return sides;
+ }
+
+ public Block getBlockAtPos() {
+ return getBlockAtPos(this);
+ }
+
+ public Block getBlockAtPos(BlockPos pos) {
+ return getBlockAtPos(world, pos);
+ }
+
+ public Block getBlockAtPos(World world, BlockPos pos) {
+ return world.getBlock(pos.xPos, pos.yPos, pos.zPos);
+ }
+
+ public int getMetaAtPos() {
+ return getMetaAtPos(this);
+ }
+
+ public int getMetaAtPos(BlockPos pos) {
+ return getMetaAtPos(world, pos);
+ }
+
+ public int getMetaAtPos(World world, BlockPos pos) {
+ return world.getBlockMetadata(pos.xPos, pos.yPos, pos.zPos);
+ }
+
+ public boolean hasSimilarNeighbour() {
+ return hasSimilarNeighbour(false);
+ }
+
+ /**
+ * @param strict - Does this check Meta Data?
+ * @return - Does this block have a neighbour that is the same?
+ */
+ public boolean hasSimilarNeighbour(boolean strict) {
+ for (BlockPos g : getSurroundingBlocks().values()) {
+ if (getBlockAtPos(g) == getBlockAtPos()) {
+ if (!strict) {
+ return true;
+ }
+ else {
+ if (getMetaAtPos() == getMetaAtPos(g)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public AutoMap<BlockPos> getSimilarNeighbour() {
+ return getSimilarNeighbour(false);
+ }
+
+ /**
+ * @param strict - Does this check Meta Data?
+ * @return - Does this block have a neighbour that is the same?
+ */
+ public AutoMap<BlockPos> getSimilarNeighbour(boolean strict) {
+ AutoMap<BlockPos> sides = new AutoMap<BlockPos>();
+ for (BlockPos g : getSurroundingBlocks().values()) {
+ if (getBlockAtPos(g) == getBlockAtPos()) {
+ if (!strict) {
+ sides.put(g);
+ }
+ else {
+ if (getMetaAtPos() == getMetaAtPos(g)) {
+ sides.put(g);
+ }
+ }
+ }
+ }
+ return sides;
+ }
+
+ public Set<BlockPos> getValidNeighboursAndSelf(){
+ AutoMap<BlockPos> h = getSimilarNeighbour(true);
+ h.put(this);
+ Set<BlockPos> result = new HashSet<BlockPos>();
+ for (BlockPos f : h.values()) {
+ result.add(f);
+ }
+ return result;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/CubicObject.java b/src/main/java/gtPlusPlus/api/objects/minecraft/CubicObject.java
new file mode 100644
index 0000000000..8c76513d09
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/CubicObject.java
@@ -0,0 +1,62 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import gtPlusPlus.api.objects.data.AutoMap;
+import net.minecraftforge.common.util.ForgeDirection;
+
+public class CubicObject<T> {
+
+ public final T NORTH;
+ public final T SOUTH;
+
+ public final T WEST;
+ public final T EAST;
+
+ public final T UP;
+ public final T DOWN;
+
+ public CubicObject(AutoMap<T> aDataSet) {
+ this(aDataSet.get(0), aDataSet.get(1), aDataSet.get(2), aDataSet.get(3), aDataSet.get(4), aDataSet.get(5));
+ }
+
+ public CubicObject(T[] aDataSet) {
+ this(aDataSet[0], aDataSet[1], aDataSet[2], aDataSet[3], aDataSet[4], aDataSet[5]);
+ }
+
+ public CubicObject(T aDOWN, T aUP, T aNORTH, T aSOUTH, T aWEST, T aEAST) {
+ DOWN = aDOWN;
+ UP = aUP;
+ NORTH = aNORTH;
+ SOUTH = aSOUTH;
+ WEST = aWEST;
+ EAST = aEAST;
+ }
+
+ public T get(int aSide) {
+ return get(ForgeDirection.getOrientation(aSide));
+ }
+
+ public T get(ForgeDirection aSide) {
+ if (aSide == ForgeDirection.DOWN) {
+ return DOWN;
+ }
+ else if (aSide == ForgeDirection.UP) {
+ return UP;
+ }
+ else if (aSide == ForgeDirection.NORTH) {
+ return NORTH;
+ }
+ else if (aSide == ForgeDirection.SOUTH) {
+ return SOUTH;
+ }
+ else if (aSide == ForgeDirection.WEST) {
+ return WEST;
+ }
+ else if (aSide == ForgeDirection.EAST) {
+ return EAST;
+ }
+ else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/DimChunkPos.java b/src/main/java/gtPlusPlus/api/objects/minecraft/DimChunkPos.java
new file mode 100644
index 0000000000..010e522a14
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/DimChunkPos.java
@@ -0,0 +1,52 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.world.World;
+import net.minecraft.world.chunk.Chunk;
+
+public class DimChunkPos {
+
+ public final int dimension;
+ public final int xPos;
+ public final int zPos;
+ public final Chunk mainChunk;
+
+
+ public DimChunkPos(World world, BlockPos block){
+ this.dimension = world.provider.dimensionId;
+ this.mainChunk = world.getChunkFromBlockCoords(block.xPos, block.zPos);
+ this.xPos = this.mainChunk.xPosition;
+ this.zPos = this.mainChunk.zPosition;
+ }
+
+
+ public DimChunkPos(TileEntity tile){
+ this.dimension = tile.getWorldObj().provider.dimensionId;
+ this.mainChunk = tile.getWorldObj().getChunkFromBlockCoords(tile.xCoord, tile.zCoord);
+ this.xPos = this.mainChunk.xPosition;
+ this.zPos = this.mainChunk.zPosition;
+ }
+
+ public DimChunkPos(int dim, int x, int z){
+ this.dimension = dim;
+ this.xPos = x;
+ this.zPos = z;
+ Chunk h = Minecraft.getMinecraft().getIntegratedServer().worldServerForDimension(dim).getChunkFromChunkCoords(xPos, zPos);
+ if (h == null) {
+ this.mainChunk = null;
+ }
+ else {
+ this.mainChunk = h;
+ }
+ }
+
+ public Chunk getChunk() {
+ if (this.mainChunk != null) {
+ return this.mainChunk;
+ }
+ Chunk h = Minecraft.getMinecraft().getIntegratedServer().worldServerForDimension(this.dimension).getChunkFromChunkCoords(xPos, zPos);
+ return h;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/FakeBlockPos.java b/src/main/java/gtPlusPlus/api/objects/minecraft/FakeBlockPos.java
new file mode 100644
index 0000000000..d5db8081dc
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/FakeBlockPos.java
@@ -0,0 +1,253 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import gtPlusPlus.api.objects.data.AutoMap;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.world.World;
+import net.minecraftforge.common.DimensionManager;
+
+public class FakeBlockPos extends BlockPos {
+
+ private static final long serialVersionUID = -6442245826092414593L;
+ private transient Block aBlockAtPos;
+ private int aBlockMetaAtPos = 0;
+
+ public static FakeBlockPos generateBlockPos(String sUUID) {
+ String[] s2 = sUUID.split("@");
+ return new FakeBlockPos(s2);
+ }
+
+ public FakeBlockPos(String[] s){
+ this(Integer.parseInt(s[1]), Integer.parseInt(s[2]), Integer.parseInt(s[3]), Integer.parseInt(s[0]));
+ }
+
+ public FakeBlockPos(int x, int y, int z, Block aBlock, int aMeta){
+ this(x, y, z, 0);
+ aBlockAtPos = aBlock;
+ aBlockMetaAtPos = aMeta;
+ }
+
+ private FakeBlockPos(int x, int y, int z, int dim){
+ this(x, y, z, DimensionManager.getWorld(dim));
+ }
+
+ private FakeBlockPos(int x, int y, int z, World dim){
+ super(x, y, z, null);
+ }
+
+ public String getLocationString() {
+ String S = ""+this.xPos+"@"+this.yPos+"@"+this.zPos;
+ return S;
+ }
+
+ public String getUniqueIdentifier() {
+ String S = ""+this.xPos+"@"+this.yPos+"@"+this.zPos+this.aBlockAtPos.getLocalizedName()+"@"+this.aBlockMetaAtPos;
+ return S;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash += (13 * this.xPos);
+ hash += (19 * this.yPos);
+ hash += (31 * this.zPos);
+ hash += (17 * this.dim);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+ if (other == this) {
+ return true;
+ }
+ if(!(other instanceof FakeBlockPos)) {
+ return false;
+ }
+ FakeBlockPos otherPoint = (FakeBlockPos) other;
+ return this.xPos == otherPoint.xPos && this.yPos == otherPoint.yPos && this.zPos == otherPoint.zPos;
+ }
+
+ public int distanceFrom(FakeBlockPos target) {
+ if (target.dim != this.dim) {
+ return Short.MIN_VALUE;
+ }
+ return distanceFrom(target.xPos, target.yPos, target.zPos);
+ }
+
+ /**
+ *
+ * @param x X coordinate of target.
+ * @param y Y coordinate of target.
+ * @param z Z coordinate of target.
+ * @return square of distance
+ */
+ public int distanceFrom(int x, int y, int z) {
+ int distanceX = this.xPos - x;
+ int distanceY = this.yPos - y;
+ int distanceZ = this.zPos - z;
+ return distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ;
+ }
+
+ public boolean isWithinRange(FakeBlockPos target, int range) {
+ if (target.dim != this.dim) {
+ return false;
+ }
+ return isWithinRange(target.xPos, target.yPos, target.zPos, range);
+ }
+
+ public boolean isWithinRange(int x, int y, int z, int range) {
+ return distanceFrom(x, y, z) <= (range * range);
+ }
+
+
+ public FakeBlockPos getUp() {
+ return new FakeBlockPos(this.xPos, this.yPos+1, this.zPos, this.dim);
+ }
+
+ public FakeBlockPos getDown() {
+ return new FakeBlockPos(this.xPos, this.yPos-1, this.zPos, this.dim);
+ }
+
+ public FakeBlockPos getXPos() {
+ return new FakeBlockPos(this.xPos+1, this.yPos, this.zPos, this.dim);
+ }
+
+ public FakeBlockPos getXNeg() {
+ return new FakeBlockPos(this.xPos-1, this.yPos, this.zPos, this.dim);
+ }
+
+ public FakeBlockPos getZPos() {
+ return new FakeBlockPos(this.xPos, this.yPos, this.zPos+1, this.dim);
+ }
+
+ public FakeBlockPos getZNeg() {
+ return new FakeBlockPos(this.xPos, this.yPos, this.zPos-1, this.dim);
+ }
+
+ public AutoMap<BlockPos> getSurroundingBlocks(){
+ AutoMap<BlockPos> sides = new AutoMap<BlockPos>();
+ sides.put(getUp());
+ sides.put(getDown());
+ sides.put(getXPos());
+ sides.put(getXNeg());
+ sides.put(getZPos());
+ sides.put(getZNeg());
+ return sides;
+ }
+
+ public Block getBlockAtPos() {
+ return getBlockAtPos(this);
+ }
+
+ public Block getBlockAtPos(FakeBlockPos pos) {
+ return getBlockAtPos(world, pos);
+ }
+
+ public Block getBlockAtPos(World world, FakeBlockPos pos) {
+ return aBlockAtPos;
+ }
+
+ public int getMetaAtPos() {
+ return getMetaAtPos(this);
+ }
+
+ public int getMetaAtPos(FakeBlockPos pos) {
+ return getMetaAtPos(world, pos);
+ }
+
+ public int getMetaAtPos(World world, FakeBlockPos pos) {
+ return aBlockMetaAtPos;
+ }
+
+ public boolean hasSimilarNeighbour() {
+ return hasSimilarNeighbour(false);
+ }
+
+ /**
+ * @param strict - Does this check Meta Data?
+ * @return - Does this block have a neighbour that is the same?
+ */
+ public boolean hasSimilarNeighbour(boolean strict) {
+ for (BlockPos g : getSurroundingBlocks().values()) {
+ if (getBlockAtPos(g) == getBlockAtPos()) {
+ if (!strict) {
+ return true;
+ }
+ else {
+ if (getMetaAtPos() == getMetaAtPos(g)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public AutoMap<BlockPos> getSimilarNeighbour() {
+ return getSimilarNeighbour(false);
+ }
+
+ /**
+ * @param strict - Does this check Meta Data?
+ * @return - Does this block have a neighbour that is the same?
+ */
+ public AutoMap<BlockPos> getSimilarNeighbour(boolean strict) {
+ AutoMap<BlockPos> sides = new AutoMap<BlockPos>();
+ for (BlockPos g : getSurroundingBlocks().values()) {
+ if (getBlockAtPos(g) == getBlockAtPos()) {
+ if (!strict) {
+ sides.put(g);
+ }
+ else {
+ if (getMetaAtPos() == getMetaAtPos(g)) {
+ sides.put(g);
+ }
+ }
+ }
+ }
+ return sides;
+ }
+
+ public Set<BlockPos> getValidNeighboursAndSelf(){
+ AutoMap<BlockPos> h = getSimilarNeighbour(true);
+ h.put(this);
+ Set<BlockPos> result = new HashSet<BlockPos>();
+ for (BlockPos f : h.values()) {
+ result.add(f);
+ }
+ return result;
+ }
+
+ /**
+ * Called when a plant grows on this block, only implemented for saplings using the WorldGen*Trees classes right now.
+ * Modder may implement this for custom plants.
+ * This does not use ForgeDirection, because large/huge trees can be located in non-representable direction,
+ * so the source location is specified.
+ * Currently this just changes the block to dirt if it was grass.
+ *
+ * Note: This happens DURING the generation, the generation may not be complete when this is called.
+ *
+ * @param world Current world
+ * @param x Soil X
+ * @param y Soil Y
+ * @param z Soil Z
+ * @param sourceX Plant growth location X
+ * @param sourceY Plant growth location Y
+ * @param sourceZ Plant growth location Z
+ */
+ public void onPlantGrow(FakeWorld world, int x, int y, int z, int sourceX, int sourceY, int sourceZ)
+ {
+ if (getBlockAtPos() == Blocks.grass || getBlockAtPos() == Blocks.farmland)
+ {
+ this.aBlockAtPos = Blocks.dirt;
+ this.aBlockMetaAtPos = 0;
+ }
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/FakeWorld.java b/src/main/java/gtPlusPlus/api/objects/minecraft/FakeWorld.java
new file mode 100644
index 0000000000..8ee033a341
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/FakeWorld.java
@@ -0,0 +1,173 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.HashMap;
+
+import gregtech.api.enums.Materials;
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.objects.data.AutoMap;
+import gtPlusPlus.core.util.math.MathUtils;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import net.minecraft.block.Block;
+import net.minecraft.block.material.Material;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.world.IBlockAccess;
+import net.minecraft.world.biome.BiomeGenBase;
+import net.minecraftforge.common.util.ForgeDirection;
+
+public class FakeWorld implements IBlockAccess {
+
+ public static HashMap<String, FakeBlockPos> mStaticFakeWorldData;
+
+ public HashMap<String, FakeBlockPos> mFakeWorldData = new HashMap<String, FakeBlockPos>();
+
+ /**
+ * Must be an odd number
+ */
+ private int aWorldSize = 99;
+ private final int aDistanceFromOrigin;
+ private final int aWorldHeight;
+
+ public FakeWorld() {
+ this(99);
+ }
+
+ public FakeWorld(int aSize) {
+ if (MathUtils.isNumberEven(aSize)) {
+ aSize++;
+ }
+ aWorldSize = aSize;
+ aDistanceFromOrigin = ((aWorldSize-1)/2);
+ aWorldHeight = aDistanceFromOrigin >= 255 ? 255 : aDistanceFromOrigin;
+ Logger.WARNING("Created a Fake World with data:");
+ Logger.WARNING("World Size: "+aWorldSize);
+ Logger.WARNING("Distance from Origin in each dir: "+aDistanceFromOrigin);
+ Logger.WARNING("World Height: "+aWorldHeight);
+ init();
+ }
+
+ public void init() {
+
+ /*if (mStaticFakeWorldData == null) {
+ Logger.WARNING("Setting all Blocks in Fake World to Air.");
+ mStaticFakeWorldData = new HashMap<String, FakeBlockPos>();
+ for (int y=0;y<=aWorldHeight;y++) {
+ for (int x=-aDistanceFromOrigin;x<=aDistanceFromOrigin;x++) {
+ for (int z=-aDistanceFromOrigin;z<=aDistanceFromOrigin;z++) {
+ FakeBlockPos aTempPos = new FakeBlockPos(x, y, z, Blocks.air, 0);
+ mStaticFakeWorldData.put(aTempPos.getLocationString(), aTempPos);
+ }
+ }
+ }
+ }*/
+ //if (mStaticFakeWorldData != null) {
+ //Logger.WARNING(" Instancing static air world.");
+ mFakeWorldData = new HashMap<String, FakeBlockPos>();
+ //mFakeWorldData = (HashMap<String, FakeBlockPos>) mStaticFakeWorldData.clone();
+ //}
+
+
+ //Logger.WARNING("Initialisation of FakeWorld is now complete.");
+ }
+
+ public FakeBlockPos getBlockAtCoords(int x, int y, int z) {
+ String S = ""+x+"@"+y+"@"+z;
+ FakeBlockPos aBlock = mFakeWorldData.get(S);
+ if (aBlock == null) {
+ return new FakeBlockPos(x, y, z, Blocks.air, 0);
+ }
+ return aBlock;
+ }
+
+ public void setBlockAtCoords(int x, int y, int z, Block aBlock, int aMeta) {
+ FakeBlockPos aTempPos = new FakeBlockPos(x, y, z, aBlock, aMeta);
+ Logger.WARNING("Setting "+x+", "+y+", "+z+" to "+aBlock.getLocalizedName()+":"+aMeta);
+ mFakeWorldData.put(aTempPos.getLocationString(), aTempPos);
+ }
+
+ public AutoMap<ItemStack> getAllBlocksStoredInFakeWorld(){
+ AutoMap<ItemStack> aOutput = new AutoMap<ItemStack>();
+ for (FakeBlockPos aPos : mFakeWorldData.values()) {
+ if (aPos == null || aPos.getBlockAtPos() == Blocks.air) {
+ continue;
+ }
+ else {
+ ItemStack aTempStack = ItemUtils.simpleMetaStack(aPos.getBlockAtPos(), aPos.getMetaAtPos(), 1);
+ if (ItemUtils.checkForInvalidItems(aTempStack)) {
+ //Logger.WARNING("Output: "+aTempStack.getDisplayName());
+ aOutput.put(aTempStack);
+ }
+ }
+ }
+ return aOutput;
+ }
+
+ public Block getBlock(int x, int y, int z) {
+ FakeBlockPos aPos = getBlockAtCoords(x, y, z);
+ return aPos.getBlockAtPos();
+ }
+
+ public boolean isAirBlock(int x, int y, int z) {
+ Block aBlock = getBlock(x, y, z);
+ return aBlock == Blocks.air || aBlock.getMaterial() == Material.air;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Override
+ public TileEntity getTileEntity(int p_147438_1_, int p_147438_2_, int p_147438_3_) {
+ return null;
+ }
+
+ @Override
+ public int getLightBrightnessForSkyBlocks(int p_72802_1_, int p_72802_2_, int p_72802_3_, int p_72802_4_) {
+ return 0;
+ }
+
+ @Override
+ public int getBlockMetadata(int x, int y, int z) {
+ return getBlockAtCoords(x, y, z).getMetaAtPos();
+ }
+
+ @Override
+ public int isBlockProvidingPowerTo(int p_72879_1_, int p_72879_2_, int p_72879_3_, int p_72879_4_) {
+ return 0;
+ }
+
+ @Override
+ public BiomeGenBase getBiomeGenForCoords(int p_72807_1_, int p_72807_2_) {
+ return BiomeGenBase.plains;
+ }
+
+ @Override
+ public int getHeight() {
+ return aWorldHeight;
+ }
+
+ @Override
+ public boolean extendedLevelsInChunkCache() {
+ return false;
+ }
+
+ @Override
+ public boolean isSideSolid(int x, int y, int z, ForgeDirection side, boolean _default) {
+ if (!isAirBlock(x, y, z)) {
+ return true;
+ }
+ return false;
+ }
+
+
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/FluidGT6.java b/src/main/java/gtPlusPlus/api/objects/minecraft/FluidGT6.java
new file mode 100644
index 0000000000..2535046792
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/FluidGT6.java
@@ -0,0 +1,31 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import gregtech.api.GregTech_API;
+
+import gtPlusPlus.core.lib.CORE;
+import net.minecraftforge.fluids.Fluid;
+
+public class FluidGT6 extends Fluid implements Runnable
+{
+ private final short[] mRGBa;
+ public final String mTextureName;
+
+ public FluidGT6(final String aName, final String aTextureName, final short[] aRGBa) {
+ super(aName);
+ this.mRGBa = aRGBa;
+ this.mTextureName = aTextureName;
+ if (GregTech_API.sGTBlockIconload != null) {
+ GregTech_API.sGTBlockIconload.add(this);
+ }
+ }
+
+ @Override
+ public int getColor() {
+ return (Math.max(0, Math.min(255, this.mRGBa[0])) << 16) | (Math.max(0, Math.min(255, this.mRGBa[1])) << 8) | Math.max(0, Math.min(255, this.mRGBa[2]));
+ }
+
+ @Override
+ public void run() {
+ this.setIcons(GregTech_API.sBlockIcons.registerIcon(CORE.MODID+ ":" + "fluids/fluid." + this.mTextureName));
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/FormattedTooltipString.java b/src/main/java/gtPlusPlus/api/objects/minecraft/FormattedTooltipString.java
new file mode 100644
index 0000000000..ec13c82ea0
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/FormattedTooltipString.java
@@ -0,0 +1,25 @@
+package gtPlusPlus.api.objects.minecraft;
+
+public class FormattedTooltipString {
+
+ public final String mText;
+ public final boolean mPrefix;
+
+ public FormattedTooltipString(String aText, boolean aPrefix) {
+ mText = aText;
+ mPrefix = aPrefix;
+ }
+
+ public String getTooltip(Object aTagValue) {
+ String aTip;
+
+ if (mPrefix) {
+ aTip = mText+": "+aTagValue.toString();
+ }
+ else {
+ aTip = ""+aTagValue.toString()+": "+mText;
+ }
+ return aTip;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/GenericStack.java b/src/main/java/gtPlusPlus/api/objects/minecraft/GenericStack.java
new file mode 100644
index 0000000000..9c1b231961
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/GenericStack.java
@@ -0,0 +1,42 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import net.minecraft.item.ItemStack;
+
+import net.minecraftforge.fluids.FluidStack;
+
+public class GenericStack {
+
+ private ItemStack mItemStack;
+ private FluidStack mFluidStack;
+
+ public GenericStack(ItemStack s){
+ this.mItemStack = s;
+ this.mFluidStack = null;
+ }
+
+ public GenericStack(FluidStack f){
+ this.mItemStack = null;
+ this.mFluidStack = f;
+ }
+
+ public GenericStack() {
+ this.mItemStack = null;
+ this.mFluidStack = null;
+ }
+
+ public synchronized final FluidStack getFluidStack() {
+ return mFluidStack;
+ }
+
+ public synchronized final ItemStack getItemStack() {
+ return mItemStack;
+ }
+
+ public synchronized final void setItemStack(ItemStack mItemStack) {
+ this.mItemStack = mItemStack;
+ }
+
+ public synchronized final void setFluidStack(FluidStack mFluidStack) {
+ this.mFluidStack = mFluidStack;
+ }
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/ItemPackage.java b/src/main/java/gtPlusPlus/api/objects/minecraft/ItemPackage.java
new file mode 100644
index 0000000000..fa85f23cf3
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/ItemPackage.java
@@ -0,0 +1,58 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
+import gtPlusPlus.api.interfaces.RunnableWithInfo;
+import gtPlusPlus.core.handler.COMPAT_HANDLER;
+
+public abstract class ItemPackage implements RunnableWithInfo<String> {
+
+ public ItemPackage() {
+ this(false);
+ }
+
+ public ItemPackage(boolean hasExtraLateRun) {
+ // Register for late run
+ COMPAT_HANDLER.mObjectsToRunInPostInit.put(this);
+ if (hasExtraLateRun) {
+ COMPAT_HANDLER.mObjectsToRunInOnLoadComplete.put(this);
+ }
+ init();
+ }
+
+ @Override
+ public final void run() {
+ generateRecipes();
+ }
+
+ @Override
+ public final String getInfoData() {
+ return errorMessage();
+ }
+
+ public abstract String errorMessage();
+
+ public abstract boolean generateRecipes();
+
+ private final void init() {
+ items();
+ blocks();
+ fluids();
+ }
+
+ public abstract void items();
+
+ public abstract void blocks();
+
+ public abstract void fluids();
+
+ /**
+ * Override this to handle GT Recipe map manipulation after they're Baked.
+ * @param event - the {@link FMLLoadCompleteEvent}.
+ * @return - Did we do anything?
+ */
+ public boolean onLoadComplete(FMLLoadCompleteEvent event) {
+ return false;
+ };
+
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/ItemStackData.java b/src/main/java/gtPlusPlus/api/objects/minecraft/ItemStackData.java
new file mode 100644
index 0000000000..476926826b
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/ItemStackData.java
@@ -0,0 +1,35 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+
+public class ItemStackData {
+
+ protected final Item mItem;
+ protected final int mDamage;
+ protected final int mStackSize;
+ protected final NBTTagCompound mNBT;
+ protected final String mUniqueDataTag;
+
+ public ItemStackData (ItemStack aStack) {
+ mItem = aStack.getItem();
+ mDamage = aStack.getItemDamage();
+ mStackSize = aStack.stackSize;
+ mNBT = (aStack.getTagCompound() != null ? aStack.getTagCompound() : new NBTTagCompound());
+ mUniqueDataTag = ""+Item.getIdFromItem(mItem)+""+mDamage+""+mStackSize+""+mNBT.getId();
+ }
+
+ public String getUniqueDataIdentifier() {
+ return this.mUniqueDataTag;
+ }
+
+ public ItemStack getStack() {
+ ItemStack aTemp = ItemUtils.simpleMetaStack(mItem, mDamage, mStackSize);
+ aTemp.setTagCompound(mNBT);
+ return aTemp;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/NoConflictGTRecipeMap.java b/src/main/java/gtPlusPlus/api/objects/minecraft/NoConflictGTRecipeMap.java
new file mode 100644
index 0000000000..78e925fe04
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/NoConflictGTRecipeMap.java
@@ -0,0 +1,123 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.util.GT_Recipe;
+
+import gtPlusPlus.api.objects.data.AutoMap;
+
+public class NoConflictGTRecipeMap implements Collection<GT_Recipe> {
+
+ private AutoMap<GT_Recipe> mRecipeCache = new AutoMap<GT_Recipe>();
+ private final IGregTechTileEntity mMachineType;
+
+ public NoConflictGTRecipeMap () {
+ this(null);
+ }
+
+ public NoConflictGTRecipeMap (IGregTechTileEntity tile0) {
+ this.mMachineType = tile0;
+ }
+ public boolean put(GT_Recipe recipe) {
+ return add(recipe);
+ }
+
+ public boolean add(GT_Recipe recipe) {
+ return mRecipeCache.setValue(recipe);
+ }
+
+ public Collection<GT_Recipe> getRecipeMap() {
+ return mRecipeCache.values();
+ }
+
+ public boolean isMapValidForMachine(IGregTechTileEntity tile) {
+ return tile == mMachineType;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends GT_Recipe> arg0) {
+ int a = 0;
+ for (Object v : arg0) {
+ if (!this.mRecipeCache.containsValue((GT_Recipe) v)) {
+ this.mRecipeCache.put((GT_Recipe) v);
+ a++;
+ }
+ }
+ return a > 0;
+ }
+
+ @Override
+ public void clear() {
+ mRecipeCache.clear();
+ }
+
+ @Override
+ public boolean contains(Object arg0) {
+ return mRecipeCache.containsValue((GT_Recipe) arg0);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> arg0) {
+ int a = 0;
+ for (Object v : arg0) {
+ if (this.mRecipeCache.containsValue((GT_Recipe) v)) {
+ a++;
+ }
+ }
+ return a == arg0.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return mRecipeCache.isEmpty();
+ }
+
+ @Override
+ public Iterator<GT_Recipe> iterator() {
+ return mRecipeCache.iterator();
+ }
+
+ @Override
+ public boolean remove(Object arg0) {
+ return mRecipeCache.remove((GT_Recipe) arg0);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> arg0) {
+ int a = 0;
+ for (Object v : arg0) {
+ if (this.mRecipeCache.containsValue((GT_Recipe) v)) {
+ this.mRecipeCache.remove((GT_Recipe) v);
+ a++;
+ }
+ }
+ return a > 0;
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> arg0) {
+ int mStartSize = this.mRecipeCache.size();
+ this.mRecipeCache = (AutoMap<GT_Recipe>) arg0;
+ int mEndsize = this.mRecipeCache.size();
+ return mStartSize != mEndsize;
+ }
+
+ @Override
+ public int size() {
+ return this.mRecipeCache.size();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return this.mRecipeCache.toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] arg0) {
+ return (T[]) this.mRecipeCache.toArray();
+ }
+
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/SafeTexture.java b/src/main/java/gtPlusPlus/api/objects/minecraft/SafeTexture.java
new file mode 100644
index 0000000000..7c418b5a77
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/SafeTexture.java
@@ -0,0 +1,64 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.HashMap;
+
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import gregtech.api.GregTech_API;
+import gtPlusPlus.core.util.Utils;
+import net.minecraft.util.IIcon;
+
+/**
+ * A Server Side safe object that can hold {@link IIcon}s.
+ * @author Alkalus
+ *
+ */
+public class SafeTexture implements Runnable {
+
+ @SideOnly(Side.CLIENT)
+ private static final HashMap<Integer, IIcon> mHashToIconCache = new HashMap<Integer, IIcon>();
+
+ @SideOnly(Side.CLIENT)
+ private static final HashMap<String, Integer> mPathToHashCash = new HashMap<String, Integer>();
+
+ private static final HashMap<String, SafeTexture> mTextureObjectCache = new HashMap<String, SafeTexture>();
+
+ private final int mHash;
+
+ private final String mTextureName;
+
+ private final static String getKey(String aTexPath) {
+ String aNameKey = Utils.sanitizeString(aTexPath);
+ aNameKey = aNameKey.replace('/', ' ');
+ aNameKey = aNameKey.toLowerCase();
+ return aNameKey;
+ }
+
+ public static SafeTexture register(String aTexturePath) {
+ String aNameKey = getKey(aTexturePath);
+ SafeTexture g = mTextureObjectCache.get(aNameKey);
+ if (g == null) {
+ g = new SafeTexture(aTexturePath);
+ mTextureObjectCache.put(aNameKey, g);
+ mPathToHashCash.put(aTexturePath, aTexturePath.hashCode());
+ }
+ return g;
+ }
+
+ private SafeTexture(String aTexturePath) {
+ mTextureName = aTexturePath;
+ mHash = getKey(aTexturePath).hashCode();
+ GregTech_API.sGTBlockIconload.add(this);
+ }
+
+ @SideOnly(Side.CLIENT)
+ public IIcon getIcon() {
+ return mHashToIconCache.get(mHash);
+ }
+
+ @Override
+ public void run() {
+ mHashToIconCache.put(getKey(mTextureName).hashCode(), GregTech_API.sBlockIcons.registerIcon(mTextureName));
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/ShapedRecipe.java b/src/main/java/gtPlusPlus/api/objects/minecraft/ShapedRecipe.java
new file mode 100644
index 0000000000..c0e9b20c54
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/ShapedRecipe.java
@@ -0,0 +1,250 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import gtPlusPlus.api.objects.Logger;
+import gtPlusPlus.api.objects.data.AutoMap;
+import gtPlusPlus.api.objects.data.Pair;
+import gtPlusPlus.core.util.minecraft.ItemUtils;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.oredict.ShapedOreRecipe;
+
+public class ShapedRecipe {
+
+ private final static String CHARS = "abcdefghijklmnop";
+ public ShapedOreRecipe mRecipe;
+
+ ItemStack[] mBlackList = null;
+
+ public ShapedRecipe(
+ Object aInput1, Object aInput2, Object aInput3,
+ Object aInput4, Object aInput5, Object aInput6,
+ Object aInput7, Object aInput8, Object aInput9,
+ ItemStack aOutput) {
+
+ this(new Object[] {aInput1, aInput2, aInput3, aInput4, aInput5, aInput6, aInput7, aInput8, aInput9}, aOutput);
+
+ }
+
+ public ShapedRecipe(Object[] aInputs, ItemStack aOutput) {
+ String aGridWhole = "";
+ String aGrid[] = new String[3];
+ char[] aChar = new char[9];
+ String[] aLoggingInfo = new String[9];
+
+ if (mBlackList == null) {
+ mBlackList = new ItemStack[] {};
+ }
+
+ //Just to be safe
+ try {
+ int xSlot = 0;
+ int xNull = 0;
+ for (Object u : aInputs) {
+ String mInfo = "";
+ if (u instanceof String) {
+ mInfo = (String) u;
+ Logger.RECIPE("Input slot "+xSlot+++" contains "+mInfo);
+ }
+ else if (u instanceof ItemStack || u instanceof Item) {
+ if (u instanceof Item) {
+ u = ItemUtils.getSimpleStack((Item) u);
+ }
+ mInfo = ((ItemStack) u).getDisplayName();
+ Logger.RECIPE("Input slot "+xSlot+++" contains "+mInfo);
+ }
+ else if (u == null) {
+ xNull++;
+ }
+ }
+ Logger.RECIPE("Found "+xNull+" null inputs.");
+ //Check if the output is invalid
+ if (aOutput != null && xNull < 9) {
+
+ for (ItemStack q : mBlackList) {
+ if (q != null) {
+ if (q.isItemEqual(aOutput)) {
+ Logger.RECIPE("Found recipe Alkalus is Debugging.");
+ }
+ }
+ }
+
+ Object[] mVarags2 = null;
+ Logger.RECIPE("Generating Shaped Crafting Recipe for "+aOutput.getDisplayName());
+
+ if (aInputs.length < 9 || aInputs.length > 9) {
+ Logger.RECIPE("[Fix] Recipe for "+aOutput.getDisplayName()+" has incorrect number of inputs. Size: "+aInputs.length+".");
+ //Logger.RECIPE("[1234abcd] Reciped exists at location: "+ReflectionUtils.getMethodName(1));
+ //Logger.RECIPE("[1234abcd] Reciped exists at location: "+ReflectionUtils.getMethodName(2));
+ //Logger.RECIPE("[1234abcd] Reciped exists at location: "+ReflectionUtils.getMethodName(3));
+ //Logger.RECIPE("[1234abcd] Reciped exists at location: "+ReflectionUtils.getMethodName(4));
+ //Logger.RECIPE("Reciped exists at location: "+ReflectionUtils.getMethodName(1));
+ }
+
+
+ //Build a Pair for each slot
+ AutoMap<Pair<Character, Object>> aRecipePairs = new AutoMap<Pair<Character, Object>>();
+ int aCharSlot = 0;
+ int aMemSlot = 0;
+ int aInfoSlot = 0;
+ for (Object stack : aInputs) {
+ if (stack != null) {
+ String mInfo = "";
+ if (stack instanceof String) {
+ mInfo = (String) stack;
+ }
+ else if (stack instanceof ItemStack || stack instanceof Item) {
+ if (stack instanceof Item) {
+ stack = ItemUtils.getSimpleStack((Item) stack);
+ }
+ mInfo = ((ItemStack) stack).getDisplayName();
+ }
+ aRecipePairs.put(new Pair<Character, Object>(CHARS.charAt(aCharSlot), stack));
+ Logger.RECIPE("Storing '"+CHARS.charAt(aCharSlot)+"' with an object of type "+stack.getClass().getSimpleName()+" and a value of "+mInfo);
+ aChar[aMemSlot++] = CHARS.charAt(aCharSlot);
+ aCharSlot++;
+ aLoggingInfo[aInfoSlot++] = mInfo;
+ }
+ else {
+ aRecipePairs.put(new Pair<Character, Object>(' ', (ItemStack) null));
+ Logger.RECIPE("Storing ' ' with an object of type null");
+ aChar[aMemSlot++] = ' ';
+ aLoggingInfo[aInfoSlot++] = "Empty";
+ }
+ }
+
+ Logger.RECIPE(aRecipePairs.size()+" Char|Object pairs registered for recipe.");
+ //If we have enough valid slots, iterate them and build a String which represents the entire grid.
+ //If this String is the correct length, we will split it into thirds and build the grid String array.
+ if (aRecipePairs.size() == 9) {
+
+ for (Pair<Character, Object> h : aRecipePairs) {
+ if (h.getKey() != null) {
+ aGridWhole += String.valueOf(h.getKey());
+ Logger.RECIPE("Adding '"+String.valueOf(h.getKey())+"' to aGridWhole.");
+ }
+ }
+
+ Logger.RECIPE("aGridWhole: "+aGridWhole+" | size: "+aGridWhole.length());
+
+ //Build crafting grid
+ if (aGridWhole.length() == 9) {
+ Logger.RECIPE("aGridWhole size == 9");
+ aGrid[0] = ""+aGridWhole.charAt(0)+aGridWhole.charAt(1)+aGridWhole.charAt(2);
+ aGrid[1] = ""+aGridWhole.charAt(3)+aGridWhole.charAt(4)+aGridWhole.charAt(5);
+ aGrid[2] = ""+aGridWhole.charAt(6)+aGridWhole.charAt(7)+aGridWhole.charAt(8);
+ }
+ else {
+ Logger.RECIPE("[Fix] Grid length for recipe outputting "+aOutput.getDisplayName()+" is not 9.");
+ }
+
+ //Rebuild the Map without spaces
+ aRecipePairs.clear();
+ aCharSlot = 0;
+
+ //The amount of spaces in the Varags that the Shape strings takes.
+ //Currently they are inserted as a single array into index 0.
+ final int KEY_COUNTER = 1;
+
+ int counter = KEY_COUNTER;
+ for (Object stack : aInputs) {
+ if (stack != null) {
+ String mInfo = "";
+ if (stack instanceof String) {
+ mInfo = (String) stack;
+ }
+ else if (stack instanceof ItemStack || stack instanceof Item) {
+ if (stack instanceof Item) {
+ stack = ItemUtils.getSimpleStack((Item) stack);
+ }
+ mInfo = ((ItemStack) stack).getDisplayName();
+ }
+ aRecipePairs.put(new Pair<Character, Object>(CHARS.charAt(aCharSlot), stack));
+ Logger.RECIPE("Registering Pair of '"+CHARS.charAt(aCharSlot)+"' and a "+stack.getClass().getSimpleName()+" object. Object has a value of "+mInfo);
+ aCharSlot++;
+ counter++;
+ }
+ }
+
+ Logger.RECIPE("Counter started at "+KEY_COUNTER+", counter is now at "+counter+". Trying to create Varag array with a size of "+(KEY_COUNTER+(counter-KEY_COUNTER)*2));
+ //Counter started at 3, counter is now at 4. Trying to create Varag array with a size of 2
+
+ //Register the shaped grid straight to the varags
+ mVarags2 = new Object[(KEY_COUNTER+(counter-KEY_COUNTER)*2)];
+ /*mVarags2[0] = aGrid[0];
+ mVarags2[1] = aGrid[1];
+ mVarags2[2] = aGrid[2];*/
+ mVarags2[0] = aGrid;
+
+ //Add Each Char, then Item to the varags, sequentially.
+ int counter2 = KEY_COUNTER;
+ for (Pair<Character, Object> r : aRecipePairs) {
+ char c = r.getKey();
+ Object o = r.getValue();
+
+ if (o instanceof ItemStack || o instanceof Item) {
+ if (o instanceof Item) {
+ o = ItemUtils.getSimpleStack((Item) o);
+ }
+ o = ((ItemStack) o).copy();
+ }
+
+ mVarags2[counter2] = (char) c;
+ mVarags2[counter2+1] = o;
+ counter2 += 2;
+ }
+
+ Logger.RECIPE("Recipe Summary");
+ Logger.RECIPE("+ = + = + = +");
+ Logger.RECIPE("= "+aChar[0]+" = "+aChar[1]+" = "+aChar[2]+" =");
+ Logger.RECIPE("+ = + = + = +");
+ Logger.RECIPE("= "+aChar[3]+" = "+aChar[4]+" = "+aChar[5]+" =");
+ Logger.RECIPE("+ = + = + = +");
+ Logger.RECIPE("= "+aChar[6]+" = "+aChar[7]+" = "+aChar[8]+" =");
+ Logger.RECIPE("+ = + = + = +");
+ for (int r=0;r<9;r++) {
+ if (aChar[r] != ' ') {
+ Logger.RECIPE(""+aChar[r]+" : "+aLoggingInfo[r]);
+ }
+ }
+
+ }
+ else {
+ Logger.RECIPE("[Fix] Recipe for "+aOutput.getDisplayName()+" contains a strange number of inputs.");
+ }
+
+ //Try set the recipe for this object.
+ ShapedOreRecipe testRecipe = null;
+ try {
+ testRecipe = new ShapedOreRecipe(aOutput, mVarags2);
+ }
+ catch (Throwable t) {
+ Logger.RECIPE("[Fix][0] Error thrown when making a ShapedOreRecipe object.");
+ t.printStackTrace();
+ }
+ if (testRecipe == null) {
+ this.mRecipe = null;
+ Logger.RECIPE("[Fix] Failed to generate a shaped recipe.");
+ }
+ else {
+ this.mRecipe = testRecipe;
+ Logger.RECIPE("Generated a shaped recipe successfully.");
+ }
+ }
+
+ //Output was not valid
+ else {
+ this.mRecipe = null;
+ Logger.RECIPE("[Fix] Failed to generate a shaped recipe. Output was not valid.");
+ }
+
+
+ }
+ catch(Throwable t) {
+ this.mRecipe = null;
+ Logger.RECIPE("[Fix][1] Error thrown when making a ShapedOreRecipe object.");
+ t.printStackTrace();
+ }
+
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/TexturePackage.java b/src/main/java/gtPlusPlus/api/objects/minecraft/TexturePackage.java
new file mode 100644
index 0000000000..e610f8fdf0
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/TexturePackage.java
@@ -0,0 +1,55 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.LinkedHashMap;
+import java.util.Set;
+
+import gtPlusPlus.api.objects.data.AutoMap;
+import net.minecraft.util.IIcon;
+
+public class TexturePackage {
+
+ private AutoMap<IIcon> mAnimationArray = new AutoMap<IIcon>();
+
+ public IIcon getFrame(int aFrame) {
+ if (aFrame < 0 || aFrame >= mAnimationArray.size()) {
+ return mAnimationArray.get(0);
+ }
+ return mAnimationArray.get(aFrame);
+ }
+
+ public boolean addFrame(IIcon aFrame) {
+ if (aFrame != null) {
+ return mAnimationArray.add(aFrame);
+ }
+ return false;
+ }
+
+ public boolean addFrames(AutoMap<IIcon> aFrames) {
+ for (IIcon h : aFrames) {
+ if (!addFrame(h)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean addFrames(LinkedHashMap<?, IIcon> aFrames) {
+ for (IIcon h : aFrames.values()) {
+ if (!addFrame(h)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean addFrames(Set<IIcon> aFrames) {
+ for (IIcon h : aFrames) {
+ if (!addFrame(h)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/ThreadPooCollector.java b/src/main/java/gtPlusPlus/api/objects/minecraft/ThreadPooCollector.java
new file mode 100644
index 0000000000..0ff6e112ac
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/ThreadPooCollector.java
@@ -0,0 +1,111 @@
+package gtPlusPlus.api.objects.minecraft;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import gtPlusPlus.GTplusplus;
+import gtPlusPlus.GTplusplus.INIT_PHASE;
+import gtPlusPlus.api.objects.data.Pair;
+import gtPlusPlus.core.tileentities.machines.TileEntityPooCollector;
+import gtPlusPlus.core.util.Utils;
+import net.minecraft.entity.passive.EntityAnimal;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.world.World;
+import net.minecraft.world.chunk.Chunk;
+
+public class ThreadPooCollector extends Thread {
+
+ public boolean canRun = true;
+ public boolean isRunning = false;
+
+ private static final long INIT_TIME;
+ private static long internalTickCounter = 0;
+
+ private static final ThreadPooCollector mThread;
+ private static final HashMap<String, Pair<BlockPos, TileEntityPooCollector>> mPooCollectors = new LinkedHashMap<String, Pair<BlockPos, TileEntityPooCollector>>();
+
+
+ static {
+ mThread = new ThreadPooCollector();
+ INIT_TIME = (System.currentTimeMillis());
+ }
+
+ public ThreadPooCollector() {
+ setName("gtpp.handler.poop");
+ start();
+ }
+
+ public static ThreadPooCollector getInstance() {
+ return mThread;
+ }
+
+ public static void addTask(TileEntityPooCollector aTile) {
+ BlockPos aTempPos = new BlockPos(aTile);
+ mPooCollectors.put(aTempPos.getUniqueIdentifier(), new Pair<BlockPos, TileEntityPooCollector>(aTempPos, aTile));
+ }
+
+ public static void stopThread() {
+ mThread.canRun = false;
+ }
+
+
+ @Override
+ public void run() {
+
+ if (!isRunning) {
+ isRunning = true;
+ }
+ else {
+ return;
+ }
+
+ while (canRun) {
+ if (mPooCollectors.isEmpty() || GTplusplus.CURRENT_LOAD_PHASE != INIT_PHASE.STARTED) {
+ continue;
+ } else {
+ internalTickCounter = Utils.getTicksFromSeconds(
+ Utils.getSecondsFromMillis(Utils.getMillisSince(INIT_TIME, System.currentTimeMillis())));
+ if (internalTickCounter % 100 == 0) {
+ for (Pair<BlockPos, TileEntityPooCollector> pair : mPooCollectors.values()) {
+ if (pair != null) {
+ BlockPos p = pair.getKey();
+ if (p != null) {
+ if (p.world != null) {
+ World w = p.world;
+ if (w == null) {
+ continue;
+ }
+ Chunk c = w.getChunkFromBlockCoords(p.xPos, p.zPos);
+ if (c != null) {
+ if (c.isChunkLoaded) {
+ int startX = p.xPos - 2;
+ int startY = p.yPos;
+ int startZ = p.zPos - 2;
+ int endX = p.xPos + 3;
+ int endY = p.yPos + 5;
+ int endZ = p.zPos + 3;
+ AxisAlignedBB box = AxisAlignedBB.getBoundingBox(startX, startY, startZ,
+ endX, endY, endZ);
+ if (box != null) {
+ @SuppressWarnings("unchecked")
+ List<EntityAnimal> animals = w.getEntitiesWithinAABB(EntityAnimal.class, box);
+ if (animals != null && !animals.isEmpty()) {
+ pair.getValue().onPostTick(animals);
+ }
+ } else {
+ continue;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoEUBonusMultiBehaviour.java b/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoEUBonusMultiBehaviour.java
new file mode 100644
index 0000000000..78341db7a1
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoEUBonusMultiBehaviour.java
@@ -0,0 +1,27 @@
+package gtPlusPlus.api.objects.minecraft.multi;
+
+import gtPlusPlus.xmod.gregtech.api.enums.GregtechItemList;
+import net.minecraft.item.ItemStack;
+
+public class NoEUBonusMultiBehaviour extends SpecialMultiBehaviour {
+
+ public NoEUBonusMultiBehaviour() {
+ // Used by other mods which may wish to not obtain bonus outputs on their Sifting or Maceration recipes.
+ }
+
+ @Override
+ public ItemStack getTriggerItem() {
+ return GregtechItemList.Chip_MultiNerf_NoEuBonus.get(1);
+ }
+
+ @Override
+ public String getTriggerItemTooltip() {
+ return "Prevents EU discounts on GT++ multiblocks when used";
+ }
+
+ @Override
+ public int getEUPercent() {
+ return 0;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoOutputBonusMultiBehaviour.java b/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoOutputBonusMultiBehaviour.java
new file mode 100644
index 0000000000..8137f2573d
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoOutputBonusMultiBehaviour.java
@@ -0,0 +1,27 @@
+package gtPlusPlus.api.objects.minecraft.multi;
+
+import gtPlusPlus.xmod.gregtech.api.enums.GregtechItemList;
+import net.minecraft.item.ItemStack;
+
+public class NoOutputBonusMultiBehaviour extends SpecialMultiBehaviour {
+
+ public NoOutputBonusMultiBehaviour() {
+ // Used by other mods which may wish to not obtain bonus outputs on their Sifting or Maceration recipes.
+ }
+
+ @Override
+ public ItemStack getTriggerItem() {
+ return GregtechItemList.Chip_MultiNerf_NoOutputBonus.get(1);
+ }
+
+ @Override
+ public String getTriggerItemTooltip() {
+ return "Prevents bonus output % on GT++ multiblocks when used";
+ }
+
+ @Override
+ public int getOutputChanceRoll() {
+ return 10000;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoSpeedBonusMultiBehaviour.java b/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoSpeedBonusMultiBehaviour.java
new file mode 100644
index 0000000000..fe7a90960d
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/multi/NoSpeedBonusMultiBehaviour.java
@@ -0,0 +1,27 @@
+package gtPlusPlus.api.objects.minecraft.multi;
+
+import gtPlusPlus.xmod.gregtech.api.enums.GregtechItemList;
+import net.minecraft.item.ItemStack;
+
+public class NoSpeedBonusMultiBehaviour extends SpecialMultiBehaviour {
+
+ public NoSpeedBonusMultiBehaviour() {
+ // Used by other mods which may wish to not obtain bonus outputs on their Sifting or Maceration recipes.
+ }
+
+ @Override
+ public ItemStack getTriggerItem() {
+ return GregtechItemList.Chip_MultiNerf_NoSpeedBonus.get(1);
+ }
+
+ @Override
+ public String getTriggerItemTooltip() {
+ return "Prevents speed bonuses on GT++ multiblocks when used";
+ }
+
+ @Override
+ public int getSpeedBonusPercent() {
+ return 0;
+ }
+
+}
diff --git a/src/main/java/gtPlusPlus/api/objects/minecraft/multi/SpecialMultiBehaviour.java b/src/main/java/gtPlusPlus/api/objects/minecraft/multi/SpecialMultiBehaviour.java
new file mode 100644
index 0000000000..e562ccc40b
--- /dev/null
+++ b/src/main/java/gtPlusPlus/api/objects/minecraft/multi/SpecialMultiBehaviour.java
@@ -0,0 +1,44 @@
+package gtPlusPlus.api.objects.minecraft.multi;
+
+import gregtech.api.util.GT_Utility;
+import net.minecraft.item.ItemStack;
+
+/**
+ * Extend this class to implement custom behaviour for multiblocks.
+ * The Trigger item when in a special slot or input bus, will cause the multiblock to behave as specified.
+ * Not overriding a method here will cause the default values to be used.
+ * @author Alkalus
+ *
+ */
+public abstract class SpecialMultiBehaviour {
+
+ private final int mMaxParallelRecipes = Short.MIN_VALUE;
+ private final int mEUPercent = Short.MIN_VALUE;
+ private final int mSpeedBonusPercent = Short.MIN_VALUE;
+ private final int mOutputChanceRoll = Short.MIN_VALUE;
+
+ public abstract ItemStack getTriggerItem();
+
+ public abstract String getTriggerItemTooltip();
+
+ public int getMaxParallelRecipes() {
+ return this.mMaxParallelRecipes;
+ }
+
+ public int getEUPercent() {
+ return this.mEUPercent;
+ }
+
+ public int getSpeedBonusPercent() {
+ return this.mSpeedBonusPercent;
+ }
+
+ public int getOutputChanceRoll() {
+ return this.mOutputChanceRoll;
+ }
+
+ public final boolean isTriggerItem(ItemStack aToMatch) {
+ return GT_Utility.areStacksEqual(getTriggerItem(), aToMatch, false);
+ }
+
+}