aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech
diff options
context:
space:
mode:
authorJason Mitchell <mitchej@gmail.com>2022-07-17 12:57:04 -0700
committerJason Mitchell <mitchej+github@gmail.com>2022-07-22 12:57:20 -0700
commit8c4dd7de80e06875b942b1343f2ca4895ce2d758 (patch)
tree82f9185d76899d581950cc71f2406b9bc702bcbf /src/main/java/gregtech
parent48e6a5fde81f33d3ff4cb2ef610c39abd33a5821 (diff)
downloadGT5-Unofficial-8c4dd7de80e06875b942b1343f2ca4895ce2d758.tar.gz
GT5-Unofficial-8c4dd7de80e06875b942b1343f2ca4895ce2d758.tar.bz2
GT5-Unofficial-8c4dd7de80e06875b942b1343f2ca4895ce2d758.zip
MultiTileEntity
Diffstat (limited to 'src/main/java/gregtech')
-rw-r--r--src/main/java/gregtech/GT_Mod.java1
-rw-r--r--src/main/java/gregtech/api/enums/GT_Values.java8
-rw-r--r--src/main/java/gregtech/api/fluid/FluidTankGT.java444
-rw-r--r--src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java603
-rw-r--r--src/main/java/gregtech/api/multitileentity/MultiTileEntityBlockInternal.java134
-rw-r--r--src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java35
-rw-r--r--src/main/java/gregtech/api/multitileentity/MultiTileEntityContainer.java27
-rw-r--r--src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java303
-rw-r--r--src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java230
-rw-r--r--src/main/java/gregtech/api/multitileentity/base/BaseMultiTileEntity.java1047
-rw-r--r--src/main/java/gregtech/api/multitileentity/base/BaseNontickableMultiTileEntity.java55
-rw-r--r--src/main/java/gregtech/api/multitileentity/base/BaseTickableMultiTileEntity.java113
-rw-r--r--src/main/java/gregtech/api/multitileentity/interfaces/IItemUpdatable.java15
-rw-r--r--src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java227
-rw-r--r--src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java283
-rw-r--r--src/main/java/gregtech/api/net/GT_Packet_TileEntity.java60
-rw-r--r--src/main/java/gregtech/api/util/GT_Util.java152
-rw-r--r--src/main/java/gregtech/common/GT_Proxy.java83
-rw-r--r--src/main/java/gregtech/common/render/GT_Renderer_Block.java134
-rw-r--r--src/main/java/gregtech/common/render/IRenderedBlock.java72
-rw-r--r--src/main/java/gregtech/common/render/IRenderedBlockSideCheck.java12
-rw-r--r--src/main/java/gregtech/crossmod/Waila.java8
-rw-r--r--src/main/java/gregtech/loaders/preload/GT_Loader_MultiTileEntities.java38
23 files changed, 4016 insertions, 68 deletions
diff --git a/src/main/java/gregtech/GT_Mod.java b/src/main/java/gregtech/GT_Mod.java
index 4aebc96c03..13c3dfd390 100644
--- a/src/main/java/gregtech/GT_Mod.java
+++ b/src/main/java/gregtech/GT_Mod.java
@@ -205,6 +205,7 @@ public class GT_Mod implements IGT_Mod {
new GT_Loader_ItemData().run();
new GT_Loader_Item_Block_And_Fluid().run();
new GT_Loader_MetaTileEntities().run();
+ new GT_Loader_MultiTileEntities().run();
new GT_Loader_CircuitBehaviors().run();
new GT_CoverBehaviorLoader().run();
diff --git a/src/main/java/gregtech/api/enums/GT_Values.java b/src/main/java/gregtech/api/enums/GT_Values.java
index ed22331360..5765fc42c2 100644
--- a/src/main/java/gregtech/api/enums/GT_Values.java
+++ b/src/main/java/gregtech/api/enums/GT_Values.java
@@ -1,5 +1,6 @@
package gregtech.api.enums;
+import gregtech.api.fluid.FluidTankGT;
import gregtech.api.interfaces.internal.IGT_Mod;
import gregtech.api.interfaces.internal.IGT_RecipeAdder;
import gregtech.api.net.IGT_NetworkHandler;
@@ -7,6 +8,8 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.FluidTankInfo;
+import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.oredict.OreDictionary;
import java.util.HashSet;
@@ -445,4 +448,9 @@ public class GT_Values {
public static boolean worldTickHappened = false;
public static final int[] emptyIntArray = new int[0];
+ public static final IFluidTank[] emptyFluidTank = new IFluidTank[0];
+ public static final FluidTankGT[] emptyFluidTankGT = new FluidTankGT[0];
+ public static final FluidTankInfo[] emptyFluidTankInfo = new FluidTankInfo[0];
+ public static final FluidStack[] emptyFluidStack = new FluidStack[0];
+ public static final ItemStack[] emptyItemStackArray = new ItemStack[0];
}
diff --git a/src/main/java/gregtech/api/fluid/FluidTankGT.java b/src/main/java/gregtech/api/fluid/FluidTankGT.java
new file mode 100644
index 0000000000..5df9e2638a
--- /dev/null
+++ b/src/main/java/gregtech/api/fluid/FluidTankGT.java
@@ -0,0 +1,444 @@
+package gregtech.api.fluid;
+
+import gregtech.api.util.GT_Utility;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.FluidTankInfo;
+import net.minecraftforge.fluids.IFluidTank;
+
+import java.util.Map;
+
+import static com.google.common.primitives.Ints.saturatedCast;
+
+public class FluidTankGT implements IFluidTank {
+ public final FluidTankGT[] AS_ARRAY = new FluidTankGT[] {this};
+ private FluidStack mFluid;
+ private long mCapacity = 0, mAmount = 0;
+ private boolean mPreventDraining = false, mVoidExcess = false, mChangedFluids = false;
+ /** HashMap of adjustable Tank Sizes based on Fluids if needed. */
+ private Map<String, Long> mAdjustableCapacity = null;
+ private long mAdjustableMultiplier = 1;
+ /** Gives you a Tank Index in case there is multiple Tanks on a TileEntity that cares. */
+ public int mIndex = 0;
+
+ public FluidTankGT() {
+ mCapacity = Long.MAX_VALUE;
+ }
+
+ public FluidTankGT(long aCapacity) {
+ mCapacity = aCapacity;
+ }
+
+ public FluidTankGT(FluidStack aFluid) {
+ mFluid = aFluid;
+ if (aFluid != null) {
+ mCapacity = aFluid.amount;
+ mAmount = aFluid.amount;
+ }
+ }
+
+ public FluidTankGT(FluidStack aFluid, long aCapacity) {
+ mFluid = aFluid;
+ mCapacity = aCapacity;
+ mAmount = (aFluid == null ? 0 : aFluid.amount);
+ }
+
+ public FluidTankGT(FluidStack aFluid, long aAmount, long aCapacity) {
+ mFluid = aFluid;
+ mCapacity = aCapacity;
+ mAmount = (aFluid == null ? 0 : aAmount);
+ }
+
+ public FluidTankGT(Fluid aFluid, long aAmount) {
+ this(new FluidStack(aFluid, saturatedCast(aAmount)));
+ mAmount = aAmount;
+ }
+
+ public FluidTankGT(Fluid aFluid, long aAmount, long aCapacity) {
+ this(new FluidStack(aFluid, saturatedCast(aAmount)), aCapacity);
+ mAmount = aAmount;
+ }
+
+ public FluidTankGT(NBTTagCompound aNBT, String aKey, long aCapacity) {
+ this(aNBT.hasKey(aKey) ? aNBT.getCompoundTag(aKey) : null, aCapacity);
+ }
+
+ public FluidTankGT(NBTTagCompound aNBT, long aCapacity) {
+ mCapacity = aCapacity;
+ if (aNBT != null && !aNBT.hasNoTags()) {
+ mFluid = FluidStack.loadFluidStackFromNBT(aNBT);
+ mAmount = (isEmpty() ? 0 : aNBT.hasKey("LAmount") ? aNBT.getLong("LAmount") : mFluid.amount);
+ }
+ }
+
+ public FluidTankGT readFromNBT(NBTTagCompound aNBT, String aKey) {
+ if (aNBT.hasKey(aKey)) {
+ aNBT = aNBT.getCompoundTag(aKey);
+ if (aNBT != null && !aNBT.hasNoTags()) {
+ mFluid = FluidStack.loadFluidStackFromNBT(aNBT);
+ mAmount = (isEmpty() ? 0 : aNBT.hasKey("LAmount") ? aNBT.getLong("LAmount") : mFluid.amount);
+ }
+ }
+ return this;
+ }
+
+ public NBTTagCompound writeToNBT(NBTTagCompound aNBT, String aKey) {
+ if (mFluid != null && (mPreventDraining || mAmount > 0)) {
+ final NBTTagCompound tNBT = new NBTTagCompound();
+ mFluid.amount = (int) mAmount;
+ aNBT.setTag(aKey, mFluid.writeToNBT(tNBT));
+ if (mAmount > Integer.MAX_VALUE) tNBT.setLong("LAmount", mAmount);
+ } else {
+ aNBT.removeTag(aKey);
+ }
+ return aNBT;
+ }
+
+ public FluidStack drain(int aDrained) {
+ return drain(aDrained, true);
+ }
+
+ @Override
+ public FluidStack drain(int aDrained, boolean aDoDrain) {
+ if (isEmpty() || aDrained <= 0) return null;
+ if (mAmount < aDrained) aDrained = (int)mAmount;
+ final FluidStack rFluid = new FluidStack(mFluid, aDrained);
+ if (aDoDrain) {
+ mAmount -= aDrained;
+ if (mAmount <= 0) {
+ if (mPreventDraining) {
+ mAmount = 0;
+ } else {
+ setEmpty();
+ }
+ }
+ }
+ return rFluid;
+ }
+
+ public boolean drainAll(long aDrained) {
+ if (isEmpty() || mAmount < aDrained) return false;
+ mAmount -= aDrained;
+ if (mAmount <= 0) {
+ if (mPreventDraining) {
+ mAmount = 0;
+ } else {
+ setEmpty();
+ }
+ }
+ return true;
+ }
+
+ public long remove(long aDrained) {
+ if (isEmpty() || mAmount <= 0 || aDrained <= 0) return 0;
+ if (mAmount < aDrained) aDrained = mAmount;
+ mAmount -= aDrained;
+ if (mAmount <= 0) {
+ if (mPreventDraining) {
+ mAmount = 0;
+ } else {
+ setEmpty();
+ }
+ }
+ return aDrained;
+ }
+
+ public long add(long aFilled) {
+ if (isEmpty() || aFilled <= 0) return 0;
+ final long tCapacity = capacity();
+ if (mAmount + aFilled > tCapacity) {
+ if (!mVoidExcess) aFilled = tCapacity - mAmount;
+ mAmount = tCapacity;
+ return aFilled;
+ }
+ mAmount += aFilled;
+ return aFilled;
+ }
+
+ public long add(long aFilled, FluidStack aFluid) {
+ if (aFluid == null || aFilled <= 0) return 0;
+ if (isEmpty()) {
+ mFluid = aFluid.copy();
+ mChangedFluids = true;
+ mAmount = Math.min(capacity(aFluid), aFilled);
+ return mVoidExcess ? aFilled : mAmount;
+ }
+ return contains(aFluid) ? add(aFilled) : 0;
+ }
+
+ public int fill(FluidStack aFluid) {
+ return fill(aFluid, true);
+ }
+
+ @Override
+ public int fill(FluidStack aFluid, boolean aDoFill) {
+ if (aFluid == null) return 0;
+ if (aDoFill) {
+ if (isEmpty()) {
+ mFluid = aFluid.copy();
+ mChangedFluids = true;
+ mAmount = Math.min(capacity(aFluid), aFluid.amount);
+ return mVoidExcess ? aFluid.amount : (int) mAmount;
+ }
+ if (!contains(aFluid)) return 0;
+ final long tCapacity = capacity(aFluid);
+ long tFilled = tCapacity - mAmount;
+ if (aFluid.amount < tFilled) {
+ mAmount += aFluid.amount;
+ tFilled = aFluid.amount;
+ } else mAmount = tCapacity;
+ return mVoidExcess ? aFluid.amount : (int) tFilled;
+ }
+ return saturatedCast(isEmpty() ? mVoidExcess ? aFluid.amount : Math.min(capacity(aFluid), aFluid.amount) : contains(aFluid) ? mVoidExcess ? aFluid.amount : Math.min(capacity(aFluid) - mAmount, aFluid.amount) : 0);
+ }
+
+ public boolean canFillAll(FluidStack aFluid) {
+ return aFluid == null || aFluid.amount <= 0 || (isEmpty() ? mVoidExcess || aFluid.amount <= capacity(aFluid) : contains(aFluid) && (mVoidExcess || mAmount + aFluid.amount <= capacity(aFluid)));
+ }
+
+ public boolean canFillAll(long aAmount) {
+ return aAmount <= 0 || mVoidExcess || mAmount + aAmount <= capacity();
+ }
+
+ public boolean fillAll(FluidStack aFluid) {
+ if (aFluid == null || aFluid.amount <= 0) return true;
+ if (isEmpty()) {
+ final long tCapacity = capacity(aFluid);
+ if (aFluid.amount <= tCapacity || mVoidExcess) {
+ mFluid = aFluid.copy();
+ mChangedFluids = true;
+ mAmount = aFluid.amount;
+ if (mAmount > tCapacity) mAmount = tCapacity;
+ return true;
+ }
+ return false;
+ }
+ if (contains(aFluid)) {
+ if (mAmount + aFluid.amount <= capacity()) {
+ mAmount += aFluid.amount;
+ return true;
+ }
+ if (mVoidExcess) {
+ mAmount = capacity();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean fillAll(FluidStack aFluid, long aMultiplier) {
+ if (aMultiplier <= 0) return true;
+ if (aMultiplier == 1) return fillAll(aFluid);
+ if (aFluid == null || aFluid.amount <= 0) return true;
+ if (isEmpty()) {
+ final long tCapacity = capacity(aFluid);
+ if (aFluid.amount * aMultiplier <= tCapacity || mVoidExcess) {
+ mFluid = aFluid.copy();
+ mChangedFluids = true;
+ mAmount = aFluid.amount * aMultiplier;
+ if (mAmount > tCapacity) mAmount = tCapacity;
+ return true;
+ }
+ return false;
+ }
+ if (contains(aFluid)) {
+ if (mAmount + aFluid.amount * aMultiplier <= capacity()) {
+ mAmount += aFluid.amount * aMultiplier;
+ return true;
+ }
+ if (mVoidExcess) {
+ mAmount = capacity();
+ return true;
+ }
+ }
+ return false;
+ }
+ /** Resets Tank Contents entirely */
+ public FluidTankGT setEmpty() {
+ mFluid = null;
+ mChangedFluids = true;
+ mAmount = 0;
+ return this;
+ }
+
+ /** Sets Fluid Content, taking Amount from the Fluid Parameter */
+ public FluidTankGT setFluid(FluidStack aFluid) {
+ mFluid = aFluid;
+ mChangedFluids = true;
+ mAmount = (aFluid == null ? 0 : aFluid.amount);
+ return this;
+ }
+
+ /** Sets Fluid Content and Amount */
+ public FluidTankGT setFluid(FluidStack aFluid, long aAmount) {
+ mFluid = aFluid;
+ mChangedFluids = true;
+ mAmount = (aFluid == null ? 0 : aAmount);
+ return this;
+ }
+
+ /** Sets Fluid Content, taking Amount from the Tank Parameter */
+ public FluidTankGT setFluid(FluidTankGT aTank) {
+ mFluid = new FluidStack(aTank.mFluid, saturatedCast(aTank.mAmount));
+ mChangedFluids = true;
+ mAmount = aTank.mAmount;
+ return this;
+ }
+
+ /** Sets the Tank Index for easier Reverse Mapping. */
+ public FluidTankGT setIndex(int aIndex) {
+ mIndex = aIndex;
+ return this;
+ }
+
+ /** Sets the Capacity */
+ public FluidTankGT setCapacity(long aCapacity) {
+ if (aCapacity >= 0) mCapacity = aCapacity;
+ return this;
+ }
+ /** Sets the Capacity Multiplier */
+ public FluidTankGT setCapacityMultiplier(long aCapacityMultiplier) {
+ if (aCapacityMultiplier >= 0) mAdjustableMultiplier = aCapacityMultiplier;
+ return this;
+ }
+
+ /** Sets Tank capacity Map, should it be needed. */
+ public FluidTankGT setCapacity(Map<String, Long> aMap, long aCapacityMultiplier) {
+ mAdjustableCapacity = aMap;
+ mAdjustableMultiplier = aCapacityMultiplier;
+ return this;
+ }
+
+ /** Always keeps at least 0 Liters of Fluid instead of setting it to null */
+ public FluidTankGT setPreventDraining() {
+ return setPreventDraining(true);
+ }
+
+ /** Always keeps at least 0 Liters of Fluid instead of setting it to null */
+ public FluidTankGT setPreventDraining(boolean aPrevent) {
+ mPreventDraining = aPrevent;
+ return this;
+ }
+
+ /** Voids any Overlow */
+ public FluidTankGT setVoidExcess() {
+ return setVoidExcess(true);
+ }
+
+ /** Voids any Overlow */
+ public FluidTankGT setVoidExcess(boolean aVoidExcess) {
+ mVoidExcess = aVoidExcess;
+ return this;
+ }
+
+ public boolean isFull() {
+ return mFluid != null && mAmount >= capacity();
+ }
+
+ public long capacity() {
+ return capacity(mFluid);
+ }
+
+ public long capacity(FluidStack aFluid) {
+ if(mAdjustableCapacity == null || aFluid == null)
+ return mCapacity;
+ return capacity(aFluid.getFluid());
+ }
+
+ public long capacity(Fluid aFluid) {
+ if(mAdjustableCapacity == null || aFluid == null)
+ return mCapacity;
+ return capacity(aFluid.getName());
+ }
+
+ public long capacity(String aFluid) {
+ if( mAdjustableCapacity == null || aFluid == null)
+ return mCapacity;
+
+ final Long tSize = mAdjustableCapacity.get(aFluid);
+ return tSize == null ? Math.max(mAmount, mCapacity) : Math.max(tSize * mAdjustableMultiplier, Math.max(mAmount, mCapacity));
+ }
+
+ public boolean isHalf() {
+ return mFluid != null && mAmount * 2 >= capacity();
+ }
+
+ public boolean contains(Fluid aFluid) {
+ return mFluid != null && mFluid.getFluid() == aFluid;
+ }
+
+ public boolean contains(FluidStack aFluid) {
+ return GT_Utility.areFluidsEqual(mFluid, aFluid);
+ }
+
+ public boolean has(long aAmount) {
+ return mAmount >= aAmount;
+ }
+
+ public boolean has() {
+ return mAmount > 0;
+ }
+
+ public boolean check() {
+ if (mChangedFluids) {
+ mChangedFluids = false;
+ return true;
+ }
+ return false;
+ }
+
+ public boolean update() {
+ return mChangedFluids = true;
+ }
+
+ public boolean changed() {
+ return mChangedFluids;
+ }
+
+ public long amount() {
+ return isEmpty() ? 0 : mAmount;
+ }
+
+ public boolean isEmpty() {
+ return mFluid == null;
+ }
+
+ public long amount(long aMax) {
+ return isEmpty() || aMax <= 0 ? 0 : Math.min(mAmount, aMax);
+ }
+
+ public String name() {
+ return mFluid == null ? null : mFluid.getFluid().getName();
+ }
+
+ public FluidStack get() {
+ return mFluid;
+ }
+
+ public FluidStack get(long aMax) {
+ return isEmpty() || aMax <= 0 ? null : new FluidStack(mFluid, saturatedCast(Math.min(mAmount, aMax)));
+ }
+
+ @Override
+ public FluidStack getFluid() {
+ if (mFluid != null) mFluid.amount = saturatedCast(mAmount);
+ return mFluid;
+ }
+
+ @Override
+ public int getFluidAmount() {
+ return saturatedCast(mAmount);
+ }
+
+ @Override
+ public int getCapacity() {
+ return saturatedCast(capacity());
+ }
+
+ @Override
+ public FluidTankInfo getInfo() {
+ return new FluidTankInfo(isEmpty() ? null : mFluid.copy(), saturatedCast(capacity()));
+ }
+
+}
diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java
new file mode 100644
index 0000000000..13d2385381
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java
@@ -0,0 +1,603 @@
+package gregtech.api.multitileentity;
+
+import com.cricketcraft.chisel.api.IFacade;
+import cpw.mods.fml.common.registry.GameRegistry;
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.ItemList;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.IDebugableBlock;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.tileentity.IDebugableTileEntity;
+import gregtech.api.metatileentity.BaseTileEntity;
+import gregtech.api.metatileentity.CoverableTileEntity;
+import gregtech.api.metatileentity.GregTechTileClientEvents;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_BreakBlock;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_GetBlockHardness;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_GetComparatorInputOverride;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_GetWeakChanges;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_HasMultiBlockMachineRelevantData;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_IsProvidingStrongPower;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_IsProvidingWeakPower;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_OnNeighborBlockChange;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_ShouldCheckWeakPower;
+import gregtech.api.objects.XSTR;
+import gregtech.api.util.GT_Log;
+import gregtech.api.util.GT_Util;
+import gregtech.api.util.GT_Utility;
+import gregtech.common.render.GT_Renderer_Block;
+import gregtech.common.render.IRenderedBlock;
+import net.minecraft.block.Block;
+import net.minecraft.block.ITileEntityProvider;
+import net.minecraft.block.material.Material;
+import net.minecraft.client.renderer.texture.IIconRegister;
+import net.minecraft.creativetab.CreativeTabs;
+import net.minecraft.enchantment.EnchantmentHelper;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EnumCreatureType;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemBlock;
+import net.minecraft.item.ItemStack;
+import net.minecraft.stats.StatList;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.IIcon;
+import net.minecraft.util.MovingObjectPosition;
+import net.minecraft.util.StatCollector;
+import net.minecraft.world.Explosion;
+import net.minecraft.world.IBlockAccess;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.event.ForgeEventFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static gregtech.api.enums.GT_Values.OFFX;
+import static gregtech.api.enums.GT_Values.OFFY;
+import static gregtech.api.enums.GT_Values.OFFZ;
+import static gregtech.api.util.GT_Util.LAST_BROKEN_TILEENTITY;
+import static gregtech.api.util.GT_Util.getTileEntity;
+import static gregtech.api.util.GT_Util.setTileEntity;
+
+/*
+ * MultiTileEntityBlock ported from GT6
+ */
+public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITileEntityProvider, IRenderedBlock, IFacade {
+ protected static final Map<String, MultiTileEntityBlock> MULTI_BLOCK_MAP = new HashMap<>();
+ private static boolean LOCK = false;
+
+ protected final String mNameInternal, mTool;
+ protected final int mHarvestLevelOffset, mHarvestLevelMinimum, mHarvestLevelMaximum;
+ protected final boolean mOpaque, mNormalCube;
+
+ public static String getName(String aMaterialName, SoundType aSoundType, String aTool, int aHarvestLevelOffset, int aHarvestLevelMinimum, int aHarvestLevelMaximum, boolean aOpaque, boolean aNormalCube) {
+ return "gt.block.multiblock." + aMaterialName + "." + aSoundType.soundName + "." + aTool + "." + aHarvestLevelOffset + "." + aHarvestLevelMinimum + "." + aHarvestLevelMaximum + "." + aOpaque + "." + aNormalCube;
+
+ }
+ /**
+ * @param aMaterialName the Name of the vanilla Material Field. In case this is not a vanilla Material, insert the Name you want to give your own Material instead.
+ * @param aMaterial the Material used to determine the Block.
+ * @param aSoundType the Sound Type of the Block.
+ * @param aTool the Tool used to harvest this Block.
+ * @param aHarvestLevelOffset obvious
+ * @param aHarvestLevelMinimum obvious
+ * @param aHarvestLevelMaximum obvious
+ * @param aOpaque if this Block is Opaque.
+ * @param aNormalCube if this Block is a normal Cube (for Redstone Stuff).
+ */
+ public static MultiTileEntityBlock getOrCreate(
+ String aModID, String aMaterialName, Material aMaterial, SoundType aSoundType, String aTool, int aHarvestLevelOffset, int aHarvestLevelMinimum,
+ int aHarvestLevelMaximum, boolean aOpaque, boolean aNormalCube
+ ) {
+ final MultiTileEntityBlock rBlock = MULTI_BLOCK_MAP.get(aModID + ":" + getName(aMaterialName, aSoundType, aTool = aTool.toLowerCase(), aHarvestLevelOffset, aHarvestLevelMinimum, aHarvestLevelMaximum, aOpaque, aNormalCube));
+ return rBlock == null ? new MultiTileEntityBlock(aModID, aMaterialName, aMaterial, aSoundType, aTool, aHarvestLevelOffset, aHarvestLevelMinimum, aHarvestLevelMaximum, aOpaque, aNormalCube) : rBlock;
+ }
+ protected MultiTileEntityBlock(String aModID, String aMaterialName, Material aMaterial, SoundType aSoundType, String aTool, int aHarvestLevelOffset, int aHarvestLevelMinimum, int aHarvestLevelMaximum, boolean aOpaque, boolean aNormalCube) {
+ super(aMaterial);
+ if(GregTech_API.sPreloadFinished) throw new IllegalStateException("Blocks can only be initialized within preInit!");
+
+ mNameInternal = getName(aMaterialName, aSoundType, aTool, aHarvestLevelOffset, aHarvestLevelMinimum, aHarvestLevelMaximum, aOpaque, aNormalCube);
+ GameRegistry.registerBlock(this, ItemBlock.class, mNameInternal);
+
+ MULTI_BLOCK_MAP.put(aModID + ":" + mNameInternal, this);
+
+ setStepSound(aSoundType);
+ mOpaque = aOpaque;
+ mNormalCube = aNormalCube;
+
+ mTool = aTool.toLowerCase();
+ mHarvestLevelOffset = aHarvestLevelOffset;
+ mHarvestLevelMinimum = Math.max(0, aHarvestLevelMinimum);
+ mHarvestLevelMaximum = Math.max(aHarvestLevelMinimum, aHarvestLevelMaximum);
+
+ opaque = isOpaqueCube();
+ lightOpacity = isOpaqueCube() ? 255 : 0;
+
+ }
+
+ @Override
+ public final void breakBlock(World aWorld, int aX, int aY, int aZ, Block aBlock, int aMetaData) {
+ final TileEntity aTileEntity = getTileEntity(aWorld, aX, aY, aZ, true);
+ if (aTileEntity != null) LAST_BROKEN_TILEENTITY.set(aTileEntity);
+ if (aTileEntity == null || !aTileEntity.shouldRefresh(this, aBlock, aMetaData, aMetaData, aWorld, aX, aY, aZ)) return;
+ if (aTileEntity instanceof IMTE_BreakBlock && ((IMTE_BreakBlock)aTileEntity).breakBlock()) return;
+ if (aTileEntity instanceof IMTE_HasMultiBlockMachineRelevantData && ((IMTE_HasMultiBlockMachineRelevantData)aTileEntity).hasMultiBlockMachineRelevantData())
+ GregTech_API.causeMachineUpdate(aWorld, aX, aY, aZ);
+
+ aWorld.removeTileEntity(aX, aY, aZ);
+ }
+
+ @Override
+ public ArrayList<String> getDebugInfo(EntityPlayer aPlayer, int aX, int aY, int aZ, int aLogLevel) {
+ final TileEntity aTileEntity = aPlayer.worldObj.getTileEntity(aX, aY, aZ);
+ if (aTileEntity instanceof IDebugableTileEntity) {
+ return ((IDebugableTileEntity) aTileEntity).getDebugInfo(aPlayer, aLogLevel);
+ }
+ return (ArrayList<String>) Collections.<String>emptyList();
+ }
+
+ @Override
+ public final boolean func_149730_j/*isFullBlock*/() {
+ return mOpaque;
+ }
+
+ @Override
+ public final boolean isNormalCube() {
+ return mNormalCube;
+ }
+
+ @Override
+ public final boolean renderAsNormalBlock() {
+ return mOpaque || mNormalCube;
+ }
+
+ @Override
+ public int getRenderType() {
+ return GT_Renderer_Block.INSTANCE == null ? super.getRenderType() : GT_Renderer_Block.INSTANCE.mRenderID;
+ }
+
+ @Override
+ public final float getBlockHardness(World aWorld, int aX, int aY, int aZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMTE_GetBlockHardness ? ((IMTE_GetBlockHardness) aTileEntity).getBlockHardness() : 1.0F;
+ }
+
+ @SideOnly(Side.CLIENT)
+ @Override
+ public IIcon getIcon(IBlockAccess aIBlockAccess, int aX, int aY, int aZ, int aSide) {
+ return Textures.BlockIcons.MACHINE_LV_SIDE.getIcon();
+ }
+
+ @SideOnly(Side.CLIENT)
+ @Override
+ public IIcon getIcon(int aSide, int aMeta) {
+ return Textures.BlockIcons.MACHINE_LV_SIDE.getIcon();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public final void addCollisionBoxesToList(World aWorld, int aX, int aY, int aZ, AxisAlignedBB aAABB, List aList, Entity aEntity) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (aTileEntity instanceof IMultiTileEntity) ((IMultiTileEntity) aTileEntity).addCollisionBoxesToList(aAABB, aList, aEntity);
+ else super.addCollisionBoxesToList(aWorld, aX, aY, aZ, aAABB, aList, aEntity);
+ }
+
+ @Override
+ public final AxisAlignedBB getCollisionBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).getCollisionBoundingBoxFromPool()
+ : aTileEntity == null ? null : super.getCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ);
+ }
+
+ @Override
+ public final AxisAlignedBB getSelectedBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).getSelectedBoundingBoxFromPool()
+ : super.getSelectedBoundingBoxFromPool(aWorld, aX, aY, aZ);
+ }
+
+ @Override
+ public void setBlockBoundsBasedOnState(IBlockAccess blockAccess, int aX, int aY, int aZ) {
+ final TileEntity aTileEntity = blockAccess.getTileEntity(aX, aY, aZ);
+ if (aTileEntity instanceof IMultiTileEntity) {
+ ((IMultiTileEntity)aTileEntity).setBlockBoundsBasedOnState(this);
+ return;
+ }
+ super.setBlockBoundsBasedOnState(blockAccess, aX, aY, aZ);
+ }
+
+ @Override
+ public final boolean isOpaqueCube() {
+ return mOpaque;
+ }
+
+ @Override
+ public final void onNeighborChange(IBlockAccess aWorld, int aX, int aY, int aZ, int aTileX, int aTileY, int aTileZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (!LOCK) {
+ LOCK = true;
+ if (aTileEntity instanceof BaseTileEntity) ((BaseTileEntity) aTileEntity).onAdjacentBlockChange(aTileX, aTileY, aTileZ);
+ LOCK = false;
+ }
+ }
+
+ @Override
+ public void onNeighborBlockChange(World aWorld, int aX, int aY, int aZ, Block aBlock) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (!LOCK) {
+ LOCK = true;
+ if (aTileEntity instanceof BaseTileEntity) ((BaseTileEntity) aTileEntity).onAdjacentBlockChange(aX, aY, aZ);
+ LOCK = false;
+ }
+ if (aTileEntity instanceof IMTE_OnNeighborBlockChange) ((IMTE_OnNeighborBlockChange) aTileEntity).onNeighborBlockChange(aWorld, aBlock);
+ if (aTileEntity == null) aWorld.setBlockToAir(aX, aY, aZ);
+ }
+
+ @Override
+ public final void onBlockAdded(World aWorld, int aX, int aY, int aZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (aTileEntity instanceof IMultiTileEntity) ((IMultiTileEntity) aTileEntity).onBlockAdded();
+ }
+
+ @Override
+ public float getPlayerRelativeBlockHardness(EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMultiTileEntity && ((IMultiTileEntity) aTileEntity).privateAccess() && !((IMultiTileEntity) aTileEntity).playerOwnsThis(aPlayer, true) ? -1.0F
+ : super.getPlayerRelativeBlockHardness(aPlayer, aWorld, aX, aY, aZ);
+ }
+
+ @Override
+ public final void onBlockClicked(World aWorld, int aX, int aY, int aZ, EntityPlayer aPlayer) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (aTileEntity instanceof IMultiTileEntity) ((IMultiTileEntity) aTileEntity).onLeftClick(aPlayer);
+ else super.onBlockClicked(aWorld, aX, aY, aZ, aPlayer);
+ }
+
+ @Override
+ public boolean onBlockActivated(World aWorld, int aX, int aY, int aZ, EntityPlayer aPlayer, int aSide, float aHitX, float aHitY, float aHitZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (aPlayer != null && ItemList.TC_Thaumometer.isStackEqual(aPlayer.getHeldItem(), true, true)) return false;
+ return aTileEntity instanceof IMultiTileEntity && ((IMultiTileEntity) aTileEntity).onBlockActivated(aPlayer, (byte)aSide, aHitX, aHitY, aHitZ);
+ }
+
+ @Override
+ public final int isProvidingWeakPower(IBlockAccess aWorld, int aX, int aY, int aZ, int aSide) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMTE_IsProvidingWeakPower ? ((IMTE_IsProvidingWeakPower) aTileEntity).isProvidingWeakPower((byte)aSide) :
+ super.isProvidingWeakPower(aWorld, aX, aY, aZ, aSide);
+ }
+
+ @Override
+ public final int isProvidingStrongPower(IBlockAccess aWorld, int aX, int aY, int aZ, int aSide) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMTE_IsProvidingStrongPower ? ((IMTE_IsProvidingStrongPower) aTileEntity).isProvidingStrongPower((byte)aSide)
+ : super.isProvidingStrongPower(aWorld, aX, aY, aZ, aSide);
+ }
+
+
+ @Override
+ public final boolean shouldCheckWeakPower(IBlockAccess aWorld, int aX, int aY, int aZ, int aSide) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMTE_ShouldCheckWeakPower ? ((IMTE_ShouldCheckWeakPower) aTileEntity).shouldCheckWeakPower((byte)aSide)
+ : isNormalCube(aWorld, aX, aY, aZ);
+ }
+
+ @Override
+ public final boolean getWeakChanges(IBlockAccess aWorld, int aX, int aY, int aZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMTE_GetWeakChanges ? ((IMTE_GetWeakChanges) aTileEntity).getWeakChanges()
+ : super.getWeakChanges(aWorld, aX, aY, aZ);
+ }
+
+
+ @Override
+ public final void harvestBlock(World aWorld, EntityPlayer aPlayer, int aX, int aY, int aZ, int aMeta) {
+ if (aPlayer == null) aPlayer = harvesters.get();
+ aPlayer.addStat(StatList.mineBlockStatArray[getIdFromBlock(this)], 1);
+ aPlayer.addExhaustion(0.025F);
+ final boolean aSilkTouch = EnchantmentHelper.getSilkTouchModifier(aPlayer);
+ final int aFortune = EnchantmentHelper.getFortuneModifier(aPlayer);
+ float aChance = 1.0F;
+ final TileEntity aTileEntity = getTileEntity(aWorld, aX, aY, aZ, true);
+ if (aTileEntity instanceof IMultiTileEntity) {
+ final ArrayList<ItemStack> tList = ((IMultiTileEntity) aTileEntity).getDrops(aFortune, aSilkTouch);
+ aChance = ForgeEventFactory.fireBlockHarvesting(tList, aWorld, this, aX, aY, aZ, aMeta, aFortune, aChance, aSilkTouch, aPlayer);
+ for (ItemStack tStack : tList) if (XSTR.XSTR_INSTANCE.nextFloat() <= aChance) dropBlockAsItem(aWorld, aX, aY, aZ, tStack);
+ }
+ }
+
+ @Override
+ public ITexture[] getTexture(Block aBlock, byte aSide, int aRenderPass, boolean[] aShouldSideBeRendered) {
+ return null;
+ }
+
+ @Override
+ public ITexture[] getTexture(Block aBlock, byte aSide, boolean isActive, int aRenderPass) {
+ return null;
+ }
+
+ @Override
+ public int getRenderPasses(Block aBlock) {
+ return 0;
+ }
+
+ @Override
+ public boolean usesRenderPass(int aRenderPass) {
+ return true;
+ }
+
+ @Override
+ public boolean setBlockBounds(Block aBlock, int aRenderPass) {
+ return false;
+ }
+
+ @Override
+ public IRenderedBlock passRenderingToObject(ItemStack aStack) {
+ return null;
+ }
+
+ @Override
+ public IRenderedBlock passRenderingToObject(IBlockAccess aWorld, int aX, int aY, int aZ) {
+ final TileEntity tTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return tTileEntity instanceof IRenderedBlock ? (IRenderedBlock) tTileEntity : null;
+ }
+
+ @Override
+ public final boolean shouldSideBeRendered(IBlockAccess aWorld, int aX, int aY, int aZ, int aSide) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX - OFFX[aSide], aY - OFFY[aSide], aZ - OFFZ[aSide]);
+ return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).shouldSideBeRendered((byte)aSide) : super.shouldSideBeRendered(aWorld, aX, aY, aZ, aSide);
+ }
+
+ @Override
+ public Block getFacade(IBlockAccess aWorld, int aX, int aY, int aZ, int side) {
+ final TileEntity tTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (tTileEntity instanceof CoverableTileEntity) {
+ final byte aSide = (byte) side;
+ final CoverableTileEntity tile = (CoverableTileEntity) tTileEntity;
+ if (side != -1) {
+ final Block facadeBlock = tile.getCoverBehaviorAtSideNew(aSide).getFacadeBlock(aSide, tile.getCoverIDAtSide(aSide), tile.getComplexCoverDataAtSide(aSide), tile);
+ if (facadeBlock != null) return facadeBlock;
+ } else {
+ // we do not allow more than one type of facade per block, so no need to check every side
+ // see comment in gregtech.common.covers.GT_Cover_FacadeBase.isCoverPlaceable
+ for (byte i = 0; i < 6; i++) {
+ final Block facadeBlock = tile.getCoverBehaviorAtSideNew(i).getFacadeBlock(i, tile.getCoverIDAtSide(i), tile.getComplexCoverDataAtSide(i), tile);
+ if (facadeBlock != null) {
+ return facadeBlock;
+ }
+ }
+ }
+ }
+ return Blocks.air;
+ }
+
+ @Override
+ public int getFacadeMetadata(IBlockAccess aWorld, int aX, int aY, int aZ, int side) {
+ final TileEntity tTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (tTileEntity instanceof CoverableTileEntity) {
+ final byte aSide = (byte) side;
+ final CoverableTileEntity tile = (CoverableTileEntity) tTileEntity;
+ if (side != -1) {
+ final Block facadeBlock = tile.getCoverBehaviorAtSideNew(aSide).getFacadeBlock(aSide, tile.getCoverIDAtSide(aSide), tile.getComplexCoverDataAtSide(aSide), tile);
+ if (facadeBlock != null)
+ return tile.getCoverBehaviorAtSideNew(aSide).getFacadeMeta(aSide, tile.getCoverIDAtSide(aSide), tile.getComplexCoverDataAtSide(aSide), tile);
+ } else {
+ // we do not allow more than one type of facade per block, so no need to check every side
+ // see comment in gregtech.common.covers.GT_Cover_FacadeBase.isCoverPlaceable
+ for (byte i = 0; i < 6; i++) {
+ final Block facadeBlock = tile.getCoverBehaviorAtSideNew(i).getFacadeBlock(i, tile.getCoverIDAtSide(i), tile.getComplexCoverDataAtSide(i), tile);
+ if (facadeBlock != null) {
+ return tile.getCoverBehaviorAtSideNew(i).getFacadeMeta(i, tile.getCoverIDAtSide(i), tile.getComplexCoverDataAtSide(i), tile);
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ protected boolean canSilkHarvest() {
+ return false;
+ }
+
+ @Override
+ public final boolean canProvidePower() {
+ return !mNormalCube;
+ }
+
+ @Override
+ public final String getLocalizedName() {
+ return StatCollector.translateToLocal(mNameInternal + ".name");
+ }
+
+ @Override
+ public final String getUnlocalizedName() {
+ return mNameInternal;
+ }
+
+ @Override
+ public final boolean onBlockEventReceived(World aWorld, int aX, int aY, int aZ, int aID, int aData) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity == null || aTileEntity.receiveClientEvent(aID, aData);
+ }
+
+ @Override
+ public final void getSubBlocks(Item aItem, CreativeTabs aCreativeTab, List aList) {/**/}
+
+ @Override
+ public boolean hasComparatorInputOverride() {
+ return true;
+ }
+
+ @Override
+ public final int getComparatorInputOverride(World aWorld, int aX, int aY, int aZ, int aSide) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMTE_GetComparatorInputOverride ? ((IMTE_GetComparatorInputOverride) aTileEntity).getComparatorInputOverride((byte)aSide)
+ : aTileEntity instanceof IMTE_IsProvidingWeakPower ? ((IMTE_IsProvidingWeakPower) aTileEntity).isProvidingWeakPower(GT_Utility.getOppositeSide(aSide))
+ : super.getComparatorInputOverride(aWorld, aX, aY, aZ, aSide);
+ }
+
+ @Override
+ public final void registerBlockIcons(IIconRegister aIconRegister) {/**/}
+
+ @Override
+ public final boolean isNormalCube(IBlockAccess aWorld, int aX, int aY, int aZ) {
+ return mNormalCube;
+ }
+
+ @Override
+ public final boolean isSideSolid(IBlockAccess aWorld, int aX, int aY, int aZ, ForgeDirection aSide) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).isSideSolid((byte)(aSide != null ? aSide.ordinal() : GT_Values.SIDE_UNKNOWN)) : mOpaque;
+ }
+
+ @Override
+ public boolean removedByPlayer(World aWorld, EntityPlayer aPlayer, int aX, int aY, int aZ, boolean aWillHarvest) {
+ final TileEntity aTileEntity = GT_Util.getTileEntity(aWorld, aX, aY, aZ, true);
+ if (aTileEntity != null) LAST_BROKEN_TILEENTITY.set(aTileEntity);
+ return super.removedByPlayer(aWorld, aPlayer, aX, aY, aZ, aWillHarvest);
+ }
+
+ @Override
+ public int getFlammability(IBlockAccess aWorld, int aX, int aY, int aZ, ForgeDirection face) {
+ return 0;
+ }
+
+ @Override
+ public int getFireSpreadSpeed(IBlockAccess aWorld, int aX, int aY, int aZ, ForgeDirection face) {
+ return GregTech_API.sMachineFlammable && (aWorld.getBlockMetadata(aX, aY, aZ) == 0) ? 100 : 0;
+ }
+
+ @Override
+ public boolean hasTileEntity(int aMeta) {
+ return true;
+ }
+
+ @Override
+ public final ArrayList<ItemStack> getDrops(World aWorld, int aX, int aY, int aZ, int aUnusableMetaData, int aFortune) {
+ final TileEntity aTileEntity = getTileEntity(aWorld, aX, aY, aZ, true);
+ if (aTileEntity instanceof IMultiTileEntity) return ((IMultiTileEntity) aTileEntity).getDrops(aFortune, false);
+ return new ArrayList<>();
+ }
+
+ @Override
+ public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess aWorld, int aX, int aY, int aZ) {
+ return false;
+ }
+
+ @Override
+ public final float getExplosionResistance(Entity aExploder, World aWorld, int aX, int aY, int aZ, double aExplosionX, double aExplosionY, double aExplosionZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).getExplosionResistance(aExploder, aExplosionX, aExplosionY, aExplosionZ)
+ : 1.0F;
+ }
+
+ @Override
+ public final void onBlockExploded(World aWorld, int aX, int aY, int aZ, Explosion aExplosion) {
+ if (aWorld.isRemote) return;
+ final TileEntity aTileEntity = getTileEntity(aWorld, aX, aY, aZ, true);
+ if (aTileEntity != null) LAST_BROKEN_TILEENTITY.set(aTileEntity);
+ if (aTileEntity instanceof IMultiTileEntity) {
+ GT_Log.exp.printf("Explosion at : %d | %d | %d DIMID: %s due to near explosion!%n", aX, aY, aZ, aWorld.provider.dimensionId);
+ ((IMultiTileEntity) aTileEntity).onExploded(aExplosion);
+ }
+ else aWorld.setBlockToAir(aX, aY, aZ);
+ }
+
+ @Override
+ public final boolean canConnectRedstone(IBlockAccess aWorld, int aX, int aY, int aZ, int aSide) {
+ return true;
+ }
+
+ @Override
+ public final boolean recolourBlock(World aWorld, int aX, int aY, int aZ, ForgeDirection aSide, int aColor) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMultiTileEntity && ((IMultiTileEntity) aTileEntity).recolourBlock((byte)aSide.ordinal(), (byte) aColor);
+ }
+
+ @Override
+ public final String getHarvestTool(int aMeta) {
+ return mTool;
+ }
+
+ @Override
+ public final int getHarvestLevel(int aMeta) {
+ return Math.max(mHarvestLevelMinimum, Math.min(mHarvestLevelMaximum, mHarvestLevelOffset + aMeta));
+ }
+
+ @Override
+ public final boolean isToolEffective(String aType, int aMeta) {
+ return getHarvestTool(aMeta).equals(aType);
+ }
+
+
+ @Override
+ public final ItemStack getPickBlock(MovingObjectPosition aTarget, World aWorld, int aX, int aY, int aZ, EntityPlayer aPlayer) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).getPickBlock(aTarget) : null;
+ }
+
+ @Override
+ public final ItemStack getPickBlock(MovingObjectPosition aTarget, World aWorld, int aX, int aY, int aZ) {
+ final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).getPickBlock(aTarget) : null;
+ }
+
+
+ public final void receiveMultiTileEntityData(
+ IBlockAccess aWorld, int aX, short aY, int aZ, short aRID, short aID, int aCover0, int aCover1, int aCover2, int aCover3, int aCover4, int aCover5,
+ byte aTextureData, byte aTexturePage, byte aUpdateData, byte aRedstoneData, byte aColorData
+ ) {
+ if (!(aWorld instanceof World)) return;
+ final IMultiTileEntity te;
+
+ TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+
+ if (!(aTileEntity instanceof IMultiTileEntity) || ((IMultiTileEntity) aTileEntity).getMultiTileEntityRegistryID() != aRID || ((IMultiTileEntity) aTileEntity).getMultiTileEntityID() != aID) {
+ final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(aRID);
+ if (tRegistry == null) return;
+
+ aTileEntity = tRegistry.getNewTileEntity((World) aWorld, aX, aY, aZ, aID);
+ if (!(aTileEntity instanceof IMultiTileEntity)) return;
+ setTileEntity((World) aWorld, aX, aY, aZ, aTileEntity, false);
+ }
+ te = (IMultiTileEntity) aTileEntity;
+
+ boolean updated;
+ updated = te.setCoverIDAtSideNoUpdate((byte) 0, aCover0);
+ updated |= te.setCoverIDAtSideNoUpdate((byte) 1, aCover1);
+ updated |= te.setCoverIDAtSideNoUpdate((byte) 2, aCover2);
+ updated |= te.setCoverIDAtSideNoUpdate((byte) 3, aCover3);
+ updated |= te.setCoverIDAtSideNoUpdate((byte) 4, aCover4);
+ updated |= te.setCoverIDAtSideNoUpdate((byte) 5, aCover5);
+
+ if(updated) {
+ te.issueBlockUpdate();
+ }
+
+
+ te.receiveClientEvent(GregTechTileClientEvents.CHANGE_COMMON_DATA, aTextureData);
+ te.receiveClientEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, aUpdateData & 0x7F);
+ te.receiveClientEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, aTexturePage | 0x80);
+ te.receiveClientEvent(GregTechTileClientEvents.CHANGE_COLOR, aColorData);
+ te.receiveClientEvent(GregTechTileClientEvents.CHANGE_REDSTONE_OUTPUT, aRedstoneData);
+ }
+
+
+ @Override
+ public final TileEntity createTileEntity(World aWorld, int aMeta) {
+ return null;
+ }
+
+ @Override
+ public TileEntity createNewTileEntity(World world, int i) { return null; }
+}
diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlockInternal.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlockInternal.java
new file mode 100644
index 0000000000..feb2a0a0f5
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlockInternal.java
@@ -0,0 +1,134 @@
+package gregtech.api.multitileentity;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_HasMultiBlockMachineRelevantData;
+import gregtech.common.render.GT_Renderer_Block;
+import gregtech.common.render.IRenderedBlock;
+import net.minecraft.block.Block;
+import net.minecraft.block.material.Material;
+import net.minecraft.client.renderer.texture.IIconRegister;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.StatCollector;
+import net.minecraft.world.IBlockAccess;
+import net.minecraft.world.World;
+
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+import static gregtech.api.util.GT_Util.setTileEntity;
+
+public class MultiTileEntityBlockInternal extends Block implements IRenderedBlock {
+ public MultiTileEntityRegistry mMultiTileEntityRegistry;
+
+ public MultiTileEntityBlockInternal() {
+ super(Material.anvil);
+ }
+
+ @Override
+ public void registerBlockIcons(IIconRegister aIconRegister) { /* Do Nothing */ }
+
+ @Override
+ public int getRenderType() {
+ return GT_Renderer_Block.INSTANCE == null ? super.getRenderType() : GT_Renderer_Block.INSTANCE.mRenderID;
+ }
+ @Override public final String getUnlocalizedName() {return mMultiTileEntityRegistry.mNameInternal;}
+ @Override public final String getLocalizedName() {return StatCollector.translateToLocal(mMultiTileEntityRegistry.mNameInternal + ".name");}
+
+ public boolean placeBlock(World aWorld, int aX, int aY, int aZ, byte aSide, short aMetaData, NBTTagCompound aNBT, boolean aCauseBlockUpdates, boolean aForcePlacement) {
+ final MultiTileEntityContainer aMTEContainer = mMultiTileEntityRegistry.getNewTileEntityContainer(aWorld, aX, aY, aZ, aMetaData, aNBT);
+ if (aMTEContainer == null) return false;
+
+ final Block tReplacedBlock = aWorld.getBlock(aX, aY, aZ);
+
+
+ // This is some complicated bullshit Greg had to do to make his MTEs work right.
+ // Set Block with reverse MetaData first.
+ aWorld.setBlock(aX, aY, aZ, aMTEContainer.mBlock, 15-aMTEContainer.mBlockMetaData, 2);
+ // Make sure the Block has been set, yes I know setBlock has a true/false return value, but guess what, it is not reliable in 0.0001% of cases! -Greg
+ if (aWorld.getBlock(aX, aY, aZ) != aMTEContainer.mBlock) {aWorld.setBlock(aX, aY, aZ, Blocks.air, 0, 0); return false;}
+ // TileEntity should not refresh yet! -Greg
+ ((IMultiTileEntity)aMTEContainer.mTileEntity).setShouldRefresh(false);
+ // Fake-Set the TileEntity first, bypassing a lot of checks. -Greg
+ setTileEntity(aWorld, aX, aY, aZ, (TileEntity) aMTEContainer.mTileEntity, false);
+ // Now set the Block with the REAL MetaData. -Greg
+ setTileEntity(aWorld, aX, aY, aZ, aMTEContainer.mBlock, aMTEContainer.mBlockMetaData, 0, false);
+ // When the TileEntity is set now it SHOULD refresh! -Greg
+ ((IMultiTileEntity)aMTEContainer.mTileEntity).setShouldRefresh(true);
+ // But make sure again that the Block we have set was actually set properly, because 0.0001%! -Greg
+ if (aWorld.getBlock(aX, aY, aZ) != aMTEContainer.mBlock) {aWorld.setBlock(aX, aY, aZ, Blocks.air, 0, 0); return false;}
+ // And finally properly set the TileEntity for real! -Greg
+ setTileEntity(aWorld, aX, aY, aZ, (TileEntity) aMTEContainer.mTileEntity, aCauseBlockUpdates);
+ // Yep, all this just to set one Block and its TileEntity properly... -Greg
+
+
+ try {
+ if (aMTEContainer.mTileEntity instanceof IMTE_HasMultiBlockMachineRelevantData) {
+ if (((IMTE_HasMultiBlockMachineRelevantData)aMTEContainer.mTileEntity).hasMultiBlockMachineRelevantData()) GregTech_API.causeMachineUpdate(aWorld, aX, aY, aZ);
+ }
+ } catch(Throwable e) {
+ GT_FML_LOGGER.error("causeMachineUpdate", e);
+ }
+
+ try {
+ if (!aWorld.isRemote && aCauseBlockUpdates) {
+ aWorld.notifyBlockChange(aX, aY, aZ, tReplacedBlock);
+ aWorld.func_147453_f(aX, aY, aZ, aMTEContainer.mBlock);
+ }
+ } catch(Throwable e) {
+ GT_FML_LOGGER.error("aCauseBlockUpdates", e);
+ }
+
+ try {
+ ((IMultiTileEntity)aMTEContainer.mTileEntity).onTileEntityPlaced();
+ } catch(Throwable e) {
+ GT_FML_LOGGER.error("onTileEntityPlaced", e);
+ }
+
+
+ try {
+ aWorld.func_147451_t/*updateAllLightTypes*/(aX, aY, aZ);
+ } catch(Throwable e) {
+ GT_FML_LOGGER.error("updateAllLightTypes", e);
+ }
+ return true;
+ }
+
+ @Override
+ public ITexture[] getTexture(Block aBlock, byte aSide, int aRenderPass, boolean[] aShouldSideBeRendered) {
+ return null;
+ }
+
+ @Override
+ public ITexture[] getTexture(Block aBlock, byte aSide, boolean isActive, int aRenderPass) {
+ return null;
+ }
+
+ @Override
+ public int getRenderPasses(Block aBlock) {
+ return 0;
+ }
+
+ @Override
+ public boolean usesRenderPass(int aRenderPass) {
+ return true;
+ }
+
+ @Override
+ public boolean setBlockBounds(Block aBlock, int aRenderPass) {
+ return false;
+ }
+
+ @Override
+ public IRenderedBlock passRenderingToObject(ItemStack aStack) {
+ final TileEntity tTileEntity = mMultiTileEntityRegistry.getNewTileEntity(aStack);
+ return tTileEntity instanceof IRenderedBlock ? (IRenderedBlock)tTileEntity : null;
+ }
+
+ @Override
+ public IRenderedBlock passRenderingToObject(IBlockAccess aWorld, int aX, int aY, int aZ) {
+ return null;
+ }
+}
diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java
new file mode 100644
index 0000000000..3443ae52ca
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java
@@ -0,0 +1,35 @@
+package gregtech.api.multitileentity;
+
+import gregtech.api.enums.Materials;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import gregtech.api.util.GT_Util;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import static gregtech.api.enums.GT_Values.NBT;
+
+public class MultiTileEntityClassContainer {
+ public final Class<? extends TileEntity> mClass;
+ public final MultiTileEntityBlock mBlock;
+ public final TileEntity mCanonicalTileEntity;
+ public final NBTTagCompound mParameters;
+ public final byte mBlockMetaData, mStackSize;
+ public final short mID;
+ public final boolean mHidden;
+
+
+
+ public MultiTileEntityClassContainer(int aID, Class<? extends TileEntity> aClass, int aBlockMetaData, int aStackSize, MultiTileEntityBlock aBlock, NBTTagCompound aParameters) {
+ if (!IMultiTileEntity.class.isAssignableFrom(aClass)) throw new IllegalArgumentException("MultiTileEntities must implement the Interface IMultiTileEntity!");
+ mBlockMetaData = (byte) aBlockMetaData;
+ mStackSize = (byte) aStackSize;
+ mParameters = aParameters == null ? new NBTTagCompound() : aParameters;
+ mHidden = mParameters.getBoolean(NBT.HIDDEN);
+ mID = (short) aID;
+ mBlock = aBlock;
+ mClass = aClass;
+ if (mParameters.hasKey(NBT.MATERIAL) && !mParameters.hasKey(NBT.COLOR))
+ mParameters.setInteger(NBT.COLOR, GT_Util.getRGBInt(Materials.get(mParameters.getString(NBT.MATERIAL)).getRGBA()));
+ try {mCanonicalTileEntity = aClass.newInstance();} catch (Throwable e) {throw new IllegalArgumentException(e);}
+ if (mCanonicalTileEntity instanceof IMultiTileEntity) ((IMultiTileEntity) mCanonicalTileEntity).initFromNBT(mParameters, mID, (short) -1);
+ }
+}
diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityContainer.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityContainer.java
new file mode 100644
index 0000000000..1c037a45e1
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityContainer.java
@@ -0,0 +1,27 @@
+package gregtech.api.multitileentity;
+
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.world.World;
+
+import static gregtech.api.util.GT_Util.setTileEntity;
+
+public class MultiTileEntityContainer {
+ public final TileEntity mTileEntity;
+ public final MultiTileEntityBlock mBlock;
+ public final byte mBlockMetaData;
+
+ public MultiTileEntityContainer(TileEntity aTileEntity, MultiTileEntityBlock aBlock, byte aBlockMetaData) {
+ mBlockMetaData = aBlockMetaData;
+ mTileEntity = aTileEntity;
+ mBlock = aBlock;
+ }
+ public void setMultiTile(World aWorld, int aX, int aY, int aZ) {
+ // This is some complicated Bullshit Greg had to do to make his MTEs work right.
+ ((IMultiTileEntity)mTileEntity).setShouldRefresh(false);
+ setTileEntity(aWorld, aX, aY, aZ, mTileEntity, false);
+ setTileEntity(aWorld, aX, aY, aZ, mBlock, mBlockMetaData, 0, false);
+ ((IMultiTileEntity)mTileEntity).setShouldRefresh(true);
+ setTileEntity(aWorld, aX, aY, aZ, mTileEntity, true);
+ }
+}
diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java
new file mode 100644
index 0000000000..897dbf7991
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java
@@ -0,0 +1,303 @@
+package gregtech.api.multitileentity;
+
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.metatileentity.CoverableTileEntity;
+import gregtech.api.multitileentity.interfaces.IItemUpdatable;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_AddToolTips;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_GetMaxStackSize;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_HasMultiBlockMachineRelevantData;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_OnlyPlaceableWhenSneaking;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_IgnoreEntityCollisionWhenPlacing;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_CanPlace;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockSnow;
+import net.minecraft.client.renderer.texture.IIconRegister;
+import net.minecraft.creativetab.CreativeTabs;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemBlock;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.IIcon;
+import net.minecraft.world.World;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.IFluidContainerItem;
+
+import java.util.List;
+
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+import static gregtech.api.enums.GT_Values.SIDE_TOP;
+import static gregtech.api.util.GT_Util.setTileEntity;
+
+public class MultiTileEntityItemInternal extends ItemBlock implements IFluidContainerItem, IItemUpdatable {
+ public final MultiTileEntityBlockInternal mBlock;
+
+ public MultiTileEntityItemInternal(Block aBlock) {
+ super(aBlock);
+ setMaxDamage(0);
+ setHasSubtypes(true);
+ mBlock = (MultiTileEntityBlockInternal)aBlock;
+ }
+ @Override
+ @SuppressWarnings("unchecked")
+ public void addInformation(ItemStack aStack, EntityPlayer aPlayer, List aList, boolean aF3_H) {
+ final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aStack);
+ if (tTileEntityContainer == null) {
+ aList.add("INVALID ITEM!");
+ return;
+ }
+ if (tTileEntityContainer.mTileEntity instanceof IMTE_AddToolTips) {
+ try {
+ ((IMTE_AddToolTips) tTileEntityContainer.mTileEntity).addToolTips(aList, aStack, aF3_H);
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("addInformation", e);
+ }
+ }
+ final NBTTagCompound aNBT = aStack.getTagCompound();
+ CoverableTileEntity.addInstalledCoversInformation(aNBT, aList);
+ // TODO: Add anything else relevant
+ }
+
+
+ @Override
+ @SideOnly(Side.CLIENT)
+ @SuppressWarnings("unchecked")
+ public void getSubItems(Item aItem, CreativeTabs aTab, List aList) {
+ for (MultiTileEntityClassContainer tClass : mBlock.mMultiTileEntityRegistry.mRegistrations) {
+ if (!tClass.mHidden) {
+ if (((IMultiTileEntity) tClass.mCanonicalTileEntity).getSubItems(mBlock, aItem, aTab, aList, tClass.mID)) {
+ aList.add(mBlock.mMultiTileEntityRegistry.getItem(tClass.mID));
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onItemUse(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, int aSide, float aHitX, float aHitY, float aHitZ) {
+ if (aY < 0 || aY > aWorld.getHeight()) return false;
+ try {
+ final Block tClickedBlock = aWorld.getBlock(aX, aY, aZ);
+ if (tClickedBlock instanceof BlockSnow && (aWorld.getBlockMetadata(aX, aY, aZ) & 7) < 1) {
+ aSide = SIDE_TOP;
+ } else if (tClickedBlock != Blocks.vine && tClickedBlock != Blocks.tallgrass && tClickedBlock != Blocks.deadbush && !tClickedBlock.isReplaceable(aWorld, aX, aY, aZ)) {
+ aX += GT_Values.OFFX[aSide];
+ aY += GT_Values.OFFY[aSide];
+ aZ += GT_Values.OFFZ[aSide];
+ }
+ final Block tReplacedBlock = aWorld.getBlock(aX, aY, aZ);
+
+ if (!tReplacedBlock.isReplaceable(aWorld, aX, aY, aZ) || !mBlock.canReplace(aWorld, aX, aY, aZ, aSide, aStack)) return false;
+ if (aStack.stackSize == 0 || (aPlayer != null && !aPlayer.canPlayerEdit(aX, aY, aZ, aSide, aStack))) return false;
+
+ final MultiTileEntityContainer aMTEContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aWorld, aX, aY, aZ, aStack);
+
+ if (aMTEContainer != null
+ && (aPlayer == null || aPlayer.isSneaking() || !(aMTEContainer.mTileEntity instanceof IMTE_OnlyPlaceableWhenSneaking) || !((IMTE_OnlyPlaceableWhenSneaking) aMTEContainer.mTileEntity).onlyPlaceableWhenSneaking())
+ && (
+ aWorld.checkNoEntityCollision(AxisAlignedBB.getBoundingBox(aX, aY, aZ, aX+1, aY+1, aZ+1))
+ || (aMTEContainer.mTileEntity instanceof IMTE_IgnoreEntityCollisionWhenPlacing && ((IMTE_IgnoreEntityCollisionWhenPlacing)aMTEContainer.mTileEntity).ignoreEntityCollisionWhenPlacing(aStack, aPlayer, aWorld, aX, aY, aZ, (byte)aSide, aHitX, aHitY, aHitZ))
+ )
+ && (!(aMTEContainer.mTileEntity instanceof IMTE_CanPlace) || ((IMTE_CanPlace)aMTEContainer.mTileEntity).canPlace(aStack, aPlayer, aWorld, aX, aY, aZ, (byte)aSide, aHitX, aHitY, aHitZ))
+ && aWorld.setBlock(aX, aY, aZ, aMTEContainer.mBlock, 15 - aMTEContainer.mBlockMetaData, 2))
+ {
+ aMTEContainer.setMultiTile(aWorld, aX, aY, aZ);
+
+ try {
+ if (((IMultiTileEntity) aMTEContainer.mTileEntity).onPlaced(aStack, aPlayer, aWorld, aX, aY, aZ, (byte) aSide, aHitX, aHitY, aHitZ)) {
+ aWorld.playSoundEffect(
+ aX + 0.5, aY + 0.5, aZ + 0.5, aMTEContainer.mBlock.stepSound.func_150496_b(), (aMTEContainer.mBlock.stepSound.getVolume() + 1) / 2,
+ aMTEContainer.mBlock.stepSound.getPitch() * 0.8F
+ );
+ }
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("onPlaced", e);
+ }
+ try {
+ if (aMTEContainer.mTileEntity instanceof IMTE_HasMultiBlockMachineRelevantData && (((IMTE_HasMultiBlockMachineRelevantData) aMTEContainer.mTileEntity).hasMultiBlockMachineRelevantData())) {
+ GregTech_API.causeMachineUpdate(aWorld, aX, aY, aZ);
+ }
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("causeMachineUpdate", e);
+ }
+ try {
+ if (!aWorld.isRemote) {
+ aWorld.notifyBlockChange(aX, aY, aZ, tReplacedBlock);
+ aWorld.func_147453_f/*updateNeighborsAboutBlockChange*/(aX, aY, aZ, aMTEContainer.mBlock);
+ }
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("notifyBlockChange", e);
+ }
+ try {
+ ((IMultiTileEntity)aMTEContainer.mTileEntity).onTileEntityPlaced();
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("onTileEntityPlaced", e);
+ }
+ try {
+ aWorld.func_147451_t/*updateAllLightTypes*/(aX, aY, aZ);
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("updateAllLightTypes", e);
+ }
+
+ aStack.stackSize--;
+ return true;
+ }
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("onItemUse", e);
+ }
+ return false;
+ }
+
+ @Override
+ public void updateItemStack(ItemStack aStack) {
+ final MultiTileEntityClassContainer tContainer = mBlock.mMultiTileEntityRegistry.getClassContainer(aStack);
+ if (tContainer == null) return;
+ final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aStack);
+ if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IItemUpdatable) {
+ ((IItemUpdatable)tTileEntityContainer.mTileEntity).updateItemStack(aStack);
+ }
+ }
+ @Override
+ public void updateItemStack(ItemStack aStack, World aWorld, int aX, int aY, int aZ) {
+ final MultiTileEntityClassContainer tContainer = mBlock.mMultiTileEntityRegistry.getClassContainer(aStack);
+ if (tContainer == null) return;
+ final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aStack);
+ if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IItemUpdatable) {
+ ((IItemUpdatable)tTileEntityContainer.mTileEntity).updateItemStack(aStack, aWorld, aX, aY, aZ);
+ }
+ }
+
+ @Override
+ public int getItemStackLimit(ItemStack aStack) {
+ final MultiTileEntityClassContainer tContainer = mBlock.mMultiTileEntityRegistry.getClassContainer(aStack);
+ if (tContainer == null) return 1;
+ final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aStack);
+ if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IMTE_GetMaxStackSize) {
+ return ((IMTE_GetMaxStackSize)tTileEntityContainer.mTileEntity).getMaxStackSize(aStack, tContainer.mStackSize);
+ }
+ return tContainer.mStackSize;
+ }
+
+ @Override
+ public void onCreated(ItemStack aStack, World aWorld, EntityPlayer aPlayer) {
+ updateItemStack(aStack);
+ }
+
+ @Override
+ public FluidStack getFluid(ItemStack aStack) {
+ final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aStack);
+ if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IFluidContainerItem) {
+ final FluidStack rFluid = ((IFluidContainerItem)tTileEntityContainer.mTileEntity).getFluid(aStack);
+ updateItemStack(aStack);
+ return rFluid;
+ }
+ return null;
+ }
+
+ @Override
+ public int getCapacity(ItemStack aStack) {
+ final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aStack);
+ if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IFluidContainerItem) {
+ final int rCapacity = ((IFluidContainerItem)tTileEntityContainer.mTileEntity).getCapacity(aStack);
+ updateItemStack(aStack);
+ return rCapacity;
+ }
+ return 0;
+ }
+
+ @Override
+ public int fill(ItemStack aStack, FluidStack aFluid, boolean aDoFill) {
+ final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aStack);
+ if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IFluidContainerItem) {
+ final int tFilled = ((IFluidContainerItem)tTileEntityContainer.mTileEntity).fill(aStack, aFluid, aDoFill);
+ updateItemStack(aStack);
+ return tFilled;
+ }
+ return 0;
+ }
+
+ @Override
+ public FluidStack drain(ItemStack aStack, int aMaxDrain, boolean aDoDrain) {
+ final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry.getNewTileEntityContainer(aStack);
+ if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IFluidContainerItem) {
+ final FluidStack rFluid = ((IFluidContainerItem)tTileEntityContainer.mTileEntity).drain(aStack, aMaxDrain, aDoDrain);
+ updateItemStack(aStack);
+ return rFluid;
+ }
+ return null;
+ }
+
+ @Override
+ public boolean func_150936_a/*canPlaceAtSide*/(World aWorld, int aX, int aY, int aZ, int aSide, EntityPlayer aPlayer, ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public final String getUnlocalizedName() {
+ return mBlock.mMultiTileEntityRegistry.mNameInternal;
+ }
+
+ @Override
+ public final String getUnlocalizedName(ItemStack aStack) {
+ return mBlock.mMultiTileEntityRegistry.mNameInternal + "." + getDamage(aStack);
+ }
+
+ @Override
+ public int getSpriteNumber() {
+ return 0;
+ }
+
+ @Override
+ @SideOnly(Side.CLIENT)
+ public void registerIcons(IIconRegister aRegister) {
+ /* Empty */
+ }
+
+ @Override
+ @SideOnly(Side.CLIENT)
+ public IIcon getIconFromDamage(int aMeta) {
+ itemIcon = Items.bread.getIconFromDamage(0);
+ return itemIcon; /* Fixes Eating Animation Particles. */
+ }
+
+ @Override
+ public boolean doesContainerItemLeaveCraftingGrid(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public final boolean getShareTag() {
+ return true; // just to be sure
+ }
+
+ @Override
+ public int getItemEnchantability() {
+ return 0;
+ }
+
+ @Override
+ public boolean getIsRepairable(ItemStack aStack, ItemStack aMaterial) {
+ return false;
+ }
+
+ @Override
+ public ItemStack getContainerItem(ItemStack aStack) {
+ return null;
+ }
+
+ @Override
+ public final boolean hasContainerItem(ItemStack aStack) {
+ return getContainerItem(aStack) != null;
+ }
+
+ @Override
+ public boolean isBookEnchantable(ItemStack aStack, ItemStack aBook) {
+ return false;
+ }
+}
diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java
new file mode 100644
index 0000000000..732a0459b0
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java
@@ -0,0 +1,230 @@
+package gregtech.api.multitileentity;
+
+import appeng.core.CreativeTab;
+import com.mitchej123.hodgepodge.core.util.ItemStackMap;
+import cpw.mods.fml.common.registry.GameRegistry;
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import gregtech.api.util.GT_LanguageManager;
+import gregtech.api.util.GT_Util;
+import gregtech.api.util.GT_Utility;
+import net.minecraft.block.Block;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemBlock;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.StatCollector;
+import net.minecraft.world.World;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+
+public class MultiTileEntityRegistry {
+ private static final HashMap<String, MultiTileEntityRegistry> NAMED_REGISTRIES = new HashMap<>();
+ private static final ItemStackMap<MultiTileEntityRegistry> REGISTRIES = new ItemStackMap<>();
+ private static final HashSet<Class<?>> sRegisteredTileEntities = new HashSet<>();
+
+ public HashMap<Short, CreativeTab> mCreativeTabs = new HashMap<>();
+ public Map<Short, MultiTileEntityClassContainer> mRegistry = new HashMap<>();
+ public List<MultiTileEntityClassContainer> mRegistrations = new ArrayList<>();
+
+ public final String mNameInternal;
+ public final MultiTileEntityBlockInternal mBlock;
+
+ private static MultiTileEntityBlockInternal regblock(String aNameInternal, MultiTileEntityBlockInternal aBlock, Class<? extends ItemBlock> aItemClass) {
+ GameRegistry.registerBlock(aBlock, aItemClass == null ? ItemBlock.class : aItemClass, aNameInternal);
+ return aBlock;
+ }
+
+ /**
+ * @param aNameInternal the internal Name of the Item
+ */
+ public MultiTileEntityRegistry(String aNameInternal) {
+ this(aNameInternal, new MultiTileEntityBlockInternal(), MultiTileEntityItemInternal.class);
+ }
+
+ /**
+ * @param aNameInternal the internal Name of the Item
+ */
+ public MultiTileEntityRegistry(String aNameInternal, MultiTileEntityBlockInternal aBlock, Class<? extends ItemBlock> aItemClass) {
+ this(aNameInternal, regblock(aNameInternal, aBlock, aItemClass));
+ }
+
+ /**
+ * @param aNameInternal the internal Name of the Item
+ */
+ public MultiTileEntityRegistry(String aNameInternal, MultiTileEntityBlockInternal aBlock) {
+ if (!GregTech_API.sPreloadStarted || GregTech_API.sPreloadFinished) throw new IllegalStateException("The MultiTileEntity Registry must be initialised during Preload Phase and not before");
+ mNameInternal = aNameInternal;
+ mBlock = aBlock;
+ mBlock.mMultiTileEntityRegistry = this;
+ REGISTRIES.put(new ItemStack(Item.getItemFromBlock(aBlock), 1, GT_Values.W), this);
+ NAMED_REGISTRIES.put(mNameInternal, this);
+ }
+
+ public static TileEntity getCanonicalTileEntity(int aRegistryID, int aMultiTileEntityID) {
+ final MultiTileEntityRegistry tRegistry = getRegistry(aRegistryID);
+ if (tRegistry == null) return null;
+ final MultiTileEntityClassContainer tClassContainer = tRegistry.getClassContainer(aMultiTileEntityID);
+ if (tClassContainer == null) return null;
+ return tClassContainer.mCanonicalTileEntity;
+ }
+
+ public static MultiTileEntityRegistry getRegistry(int aRegistryID) {
+ return REGISTRIES.get(new ItemStack(Item.getItemById(aRegistryID), 1, GT_Values.W));
+ }
+ public static MultiTileEntityRegistry getRegistry(String aRegistryName) {
+ return NAMED_REGISTRIES.get(aRegistryName);
+ }
+
+
+ /** Adds a new MultiTileEntity. It is highly recommended to do this in either the PreInit or the Init Phase. PostInit might not work well.*/
+ public ItemStack add(
+ String aLocalised, String aCategoricalName, int aID, Class<? extends TileEntity> aClass, int aBlockMetaData, int aStackSize,
+ MultiTileEntityBlock aBlock, NBTTagCompound aParameters, Object... aRecipe
+ ) {
+ return add(aLocalised, aCategoricalName, new MultiTileEntityClassContainer(aID, aClass, aBlockMetaData, aStackSize, aBlock, aParameters), aRecipe);
+ }
+
+ /** Adds a new MultiTileEntity. It is highly recommended to do this in either the PreInit or the Init Phase. PostInit might not work well.*/
+ public ItemStack add(String aLocalised, String aCategoricalName, MultiTileEntityClassContainer aClassContainer, Object... aRecipe) {
+ boolean tFailed = false;
+ if (GT_Utility.isStringInvalid(aLocalised)) {
+ GT_FML_LOGGER.error("MULTI-TILE REGISTRY ERROR: Localisation Missing!");
+ tFailed = true;
+ }
+ if (aClassContainer == null) {
+ GT_FML_LOGGER.error("MULTI-TILE REGISTRY ERROR: Class Container is null!");
+ tFailed = true;
+ } else {
+ if (aClassContainer.mClass == null) {
+ GT_FML_LOGGER.error("MULTI-TILE REGISTRY ERROR: Class inside Class Container is null!");
+ tFailed = true;
+ }
+ if (aClassContainer.mID == GT_Values.W) {
+ GT_FML_LOGGER.error("MULTI-TILE REGISTRY ERROR: Class Container uses Wildcard MetaData!");
+ tFailed = true;
+ }
+ if (aClassContainer.mID < 0) {
+ GT_FML_LOGGER.error("MULTI-TILE REGISTRY ERROR: Class Container uses negative MetaData!");
+ tFailed = true;
+ }
+ if (mRegistry.containsKey(aClassContainer.mID)) {
+ GT_FML_LOGGER.error("MULTI-TILE REGISTRY ERROR: Class Container uses occupied MetaData!");
+ tFailed = true;
+ }
+ }
+ if (tFailed) {
+ GT_FML_LOGGER.error("MULTI-TILE REGISTRY ERROR: STACKTRACE START");
+ int i = 0; for (StackTraceElement tElement : new Exception().getStackTrace()) if (i++<5 && !tElement.getClassName().startsWith("sun")) GT_FML_LOGGER.error("\tat " + tElement); else break;
+ GT_FML_LOGGER.error("MULTI-TILE REGISTRY ERROR: STACKTRACE END");
+ return null;
+ }
+
+ GT_LanguageManager.addStringLocalization(mNameInternal+"."+aClassContainer.mID+".name", aLocalised, false);
+ mRegistry.put(aClassContainer.mID, aClassContainer);
+ mLastRegisteredID = aClassContainer.mID;
+ mRegistrations.add(aClassContainer);
+
+ if (sRegisteredTileEntities.add(aClassContainer.mCanonicalTileEntity.getClass())) {
+ if (aClassContainer.mCanonicalTileEntity instanceof IMultiTileEntity) ((IMultiTileEntity)aClassContainer.mCanonicalTileEntity).onRegistrationFirst(this, aClassContainer.mID);
+ }
+// // TODO: Recipe
+// if (aRecipe != null && aRecipe.length > 1) {
+// if (aRecipe[0] instanceof Object[]) aRecipe = (Object[])aRecipe[0];
+// if (aRecipe.length > 2) CR.shaped(getItem(aClassContainer.mID), CR.DEF_REV_NCC, aRecipe);
+// }
+// // A simple special case to make it easier to add a Machine to Recipe Lists without having to worry about anything.
+// String tRecipeMapName = aClassContainer.mParameters.getString(NBT_RECIPEMAP);
+// if (GT_Utility.isStringValid(tRecipeMapName)) {RecipeMap tMap = RecipeMap.RECIPE_MAPS.get(tRecipeMapName); if (tMap != null) tMap.mRecipeMachineList.add(getItem(aClassContainer.mID));}
+// tRecipeMapName = aClassContainer.mParameters.getString(NBT_FUELMAP);
+// if (GT_Utility.isStringValid(tRecipeMapName)) {RecipeMap tMap = RecipeMap.RECIPE_MAPS.get(tRecipeMapName); if (tMap != null) tMap.mRecipeMachineList.add(getItem(aClassContainer.mID));}
+//
+ return getItem(aClassContainer.mID);
+ }
+
+ public short mLastRegisteredID = GT_Values.W;
+
+
+ public ItemStack getItem() {return getItem(mLastRegisteredID, 1, null);}
+ public ItemStack getItem(int aID) {return getItem(aID, 1, null);}
+ public ItemStack getItem(int aID, NBTTagCompound aNBT) {return getItem(aID, 1, aNBT);}
+ public ItemStack getItem(int aID, long aAmount) {return getItem(aID, aAmount, null);}
+
+ public ItemStack getItem(int aID, long aAmount, NBTTagCompound aNBT) {
+ final ItemStack rStack = new ItemStack(mBlock, (int)aAmount, aID);
+ if (aNBT == null || aNBT.hasNoTags()) {
+ aNBT = new NBTTagCompound();
+ final MultiTileEntityContainer tTileEntityContainer = getNewTileEntityContainer(aID, aNBT);
+ if (tTileEntityContainer != null) ((IMultiTileEntity)tTileEntityContainer.mTileEntity).writeItemNBT(aNBT);
+ }
+ rStack.setTagCompound(aNBT);
+ return rStack;
+ }
+
+ public String getLocal(int aID) {
+ return StatCollector.translateToLocal(mNameInternal + "." + aID + ".name");
+ }
+
+ public MultiTileEntityClassContainer getClassContainer(int aID) {
+ return mRegistry.get((short) aID);
+ }
+
+ public MultiTileEntityClassContainer getClassContainer(ItemStack aStack) {
+ return mRegistry.get((short) Items.feather.getDamage(aStack));
+ }
+
+ public TileEntity getNewTileEntity(int aID) {
+ final MultiTileEntityContainer tContainer = getNewTileEntityContainer(null, 0, 0, 0, aID, null);
+ return tContainer == null ? null : (TileEntity) tContainer.mTileEntity;
+ }
+
+ public MultiTileEntityContainer getNewTileEntityContainer(World aWorld, int aX, int aY, int aZ, int aID, NBTTagCompound aNBT) {
+ final MultiTileEntityClassContainer tClass = mRegistry.get((short) aID);
+ if (tClass == null || tClass.mBlock == null) return null;
+ final MultiTileEntityContainer rContainer = new MultiTileEntityContainer((TileEntity) GT_Utility.callConstructor(tClass.mClass, -1, null, true), tClass.mBlock, tClass.mBlockMetaData);
+ if (rContainer.mTileEntity == null) return null;
+ rContainer.mTileEntity.setWorldObj(aWorld);
+ rContainer.mTileEntity.xCoord = aX;
+ rContainer.mTileEntity.yCoord = aY;
+ rContainer.mTileEntity.zCoord = aZ;
+ ((IMultiTileEntity) rContainer.mTileEntity).initFromNBT(aNBT == null || aNBT.hasNoTags() ? tClass.mParameters : GT_Util.fuseNBT(aNBT, tClass.mParameters), (short) aID, (short) Block.getIdFromBlock(mBlock));
+ return rContainer;
+ }
+
+ public TileEntity getNewTileEntity(World aWorld, int aX, int aY, int aZ, int aID) {
+ final MultiTileEntityContainer tContainer = getNewTileEntityContainer(aWorld, aX, aY, aZ, aID, null);
+ return tContainer == null ? null : tContainer.mTileEntity;
+ }
+
+ public TileEntity getNewTileEntity(ItemStack aStack) {
+ final MultiTileEntityContainer tContainer = getNewTileEntityContainer(null, 0, 0, 0, Items.feather.getDamage(aStack), aStack.getTagCompound());
+ return tContainer == null ? null : tContainer.mTileEntity;
+ }
+
+ public TileEntity getNewTileEntity(World aWorld, int aX, int aY, int aZ, ItemStack aStack) {
+ final MultiTileEntityContainer tContainer = getNewTileEntityContainer(aWorld, aX, aY, aZ, Items.feather.getDamage(aStack), aStack.getTagCompound());
+ return tContainer == null ? null : tContainer.mTileEntity;
+ }
+
+ public MultiTileEntityContainer getNewTileEntityContainer(ItemStack aStack) {
+ return getNewTileEntityContainer(null, 0, 0, 0, Items.feather.getDamage(aStack), aStack.getTagCompound());
+ }
+
+ public MultiTileEntityContainer getNewTileEntityContainer(World aWorld, int aX, int aY, int aZ, ItemStack aStack) {
+ return getNewTileEntityContainer(aWorld, aX, aY, aZ, Items.feather.getDamage(aStack), aStack.getTagCompound());
+ }
+
+ public MultiTileEntityContainer getNewTileEntityContainer(int aID, NBTTagCompound aNBT) {
+ return getNewTileEntityContainer(null, 0, 0, 0, aID, aNBT);
+ }
+
+}
diff --git a/src/main/java/gregtech/api/multitileentity/base/BaseMultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/base/BaseMultiTileEntity.java
new file mode 100644
index 0000000000..387b50d7c8
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/base/BaseMultiTileEntity.java
@@ -0,0 +1,1047 @@
+package gregtech.api.multitileentity.base;
+
+import cpw.mods.fml.common.registry.GameRegistry;
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.Materials;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.tileentity.IGregtechWailaProvider;
+import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords;
+import gregtech.api.metatileentity.CoverableTileEntity;
+import gregtech.api.metatileentity.GregTechTileClientEvents;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import gregtech.api.multitileentity.MultiTileEntityBlockInternal;
+import gregtech.api.multitileentity.MultiTileEntityClassContainer;
+import gregtech.api.multitileentity.MultiTileEntityRegistry;
+import gregtech.api.net.GT_Packet_New;
+import gregtech.api.net.GT_Packet_TileEntity;
+import gregtech.api.objects.GT_ItemStack;
+import gregtech.api.objects.XSTR;
+import gregtech.api.util.GT_Log;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Util;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.ISerializableObject;
+import gregtech.common.render.IRenderedBlock;
+import mcp.mobius.waila.api.IWailaConfigHandler;
+import mcp.mobius.waila.api.IWailaDataAccessor;
+import net.minecraft.block.Block;
+import net.minecraft.client.renderer.RenderBlocks;
+import net.minecraft.creativetab.CreativeTabs;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.network.Packet;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.MovingObjectPosition;
+import net.minecraft.world.Explosion;
+import net.minecraft.world.IBlockAccess;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.FluidTankInfo;
+import net.minecraftforge.fluids.IFluidTank;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+import static gregtech.api.enums.GT_Values.NBT;
+import static gregtech.api.enums.GT_Values.OPOS;
+import static gregtech.api.enums.GT_Values.SIDE_WEST;
+import static gregtech.api.enums.GT_Values.VALID_SIDES;
+
+public abstract class BaseMultiTileEntity extends CoverableTileEntity implements IMultiTileEntity, IHasWorldObjectAndCoords, IRenderedBlock, IGregtechWailaProvider {
+ // Makes a Bounding Box without having to constantly specify the Offset Coordinates.
+ protected static final float[] PX_BOX = {0, 0, 0, 1, 1, 1};
+
+ public Materials mMaterial = Materials._NULL;
+ protected final boolean mIsTicking; // If this TileEntity is ticking at all
+
+ protected boolean mShouldRefresh = true; // This Variable checks if this TileEntity should refresh when the Block is being set. That way you can turn this check off any time you need it.
+ protected boolean mDoesBlockUpdate = false; // This Variable is for a buffered Block Update.
+ protected boolean mForceFullSelectionBoxes = false; // This Variable is for forcing the Selection Box to be full.
+ protected boolean mNeedsUpdate = false;
+ protected boolean mInventoryChanged = false;
+ protected boolean mIsPainted = false;
+ protected byte mFacing = SIDE_WEST; // Default to WEST, so it renders facing Left in the inventory
+ protected byte mColor;
+ private short mMTEID = GT_Values.W, mMTERegistry = GT_Values.W;
+ private String mCustomName = null;
+ private String mOwnerName = "";
+ private UUID mOwnerUuid = GT_Utility.defaultUuid;
+ private boolean mLockUpgrade = false;
+
+ public BaseMultiTileEntity(boolean mIsTicking) {
+ this.mIsTicking = mIsTicking;
+ }
+
+ @Override
+ public short getMultiTileEntityID() {
+ return mMTEID;
+ }
+
+ @Override
+ public short getMultiTileEntityRegistryID() {
+ return mMTERegistry;
+ }
+
+ @Override
+ public void onRegistrationFirst(MultiTileEntityRegistry aRegistry, short aID) {
+ GameRegistry.registerTileEntity(getClass(), getTileEntityName());
+ }
+
+ @Override
+ public void initFromNBT(NBTTagCompound aNBT, short aMTEID, short aMTERegistry) {
+ // Set ID and Registry ID.
+ mMTEID = aMTEID;
+ mMTERegistry = aMTERegistry;
+ // Read the Default Parameters from NBT.
+ if (aNBT != null) readFromNBT(aNBT);
+ }
+
+ @Override
+ public void readFromNBT(NBTTagCompound aNBT) {
+ // Check if this is a World/Chunk Loading Process calling readFromNBT.
+ if (mMTEID == GT_Values.W || mMTERegistry == GT_Values.W) {
+ // Yes it is, so read the ID Tags first.
+ mMTEID = aNBT.getShort(NBT.MTE_ID);
+ mMTERegistry = aNBT.getShort(NBT.MTE_REG);
+ // And add additional Default Parameters, in case the Mod updated with new ones.
+ final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(mMTERegistry);
+ if (tRegistry != null) {
+ final MultiTileEntityClassContainer tClass = tRegistry.getClassContainer(mMTEID);
+ if (tClass != null) {
+ // Add the Default Parameters. Useful for things that differ between different tiers/types of the same machine
+ aNBT = GT_Util.fuseNBT(aNBT, tClass.mParameters);
+ }
+ }
+ }
+ // read the Coords if it has them.
+ if (aNBT.hasKey("x")) xCoord = aNBT.getInteger("x");
+ if (aNBT.hasKey("y")) yCoord = aNBT.getInteger("y");
+ if (aNBT.hasKey("z")) zCoord = aNBT.getInteger("z");
+ // read the custom Name.
+ if (aNBT.hasKey(NBT.DISPAY)) mCustomName = aNBT.getCompoundTag(NBT.DISPAY).getString(NBT.CUSTOM_NAME);
+
+ // And now everything else.
+ try {
+ if (aNBT.hasKey(NBT.MATERIAL)) mMaterial = Materials.get(aNBT.getString(NBT.MATERIAL));
+ mOwnerName = aNBT.getString(NBT.OWNER);
+ try {
+ mOwnerUuid = UUID.fromString(aNBT.getString(NBT.OWNER_UUID));
+ } catch (IllegalArgumentException e){
+ mOwnerUuid = null;
+ }
+ if (aNBT.hasKey(NBT.LOCK_UPGRADE)) mLockUpgrade = aNBT.getBoolean(NBT.LOCK_UPGRADE);
+ if (aNBT.hasKey(NBT.FACING)) mFacing = aNBT.getByte(NBT.FACING);
+
+ readCoverNBT(aNBT);
+ readMultiTileNBT(aNBT);
+
+ if (mCoverData == null || mCoverData.length != 6) mCoverData = new ISerializableObject[6];
+ if (mCoverSides.length != 6) mCoverSides = new int[]{0, 0, 0, 0, 0, 0};
+ if (mSidedRedstone.length != 6) mSidedRedstone = new byte[]{15, 15, 15, 15, 15, 15};
+
+ updateCoverBehavior();
+
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("readFromNBT", e);
+ }
+ }
+
+ public void readMultiTileNBT(NBTTagCompound aNBT) {
+ /* Do Nothing */
+ }
+
+ @Override
+ public final void writeToNBT(NBTTagCompound aNBT) {
+ super.writeToNBT(aNBT);
+ // write the IDs
+ aNBT.setShort(NBT.MTE_ID, mMTEID);
+ aNBT.setShort(NBT.MTE_REG, mMTERegistry);
+ // write the Custom Name
+ if (GT_Utility.isStringValid(mCustomName)) {
+ final NBTTagCompound displayNBT;
+ if (aNBT.hasKey(NBT.DISPAY)) {
+ displayNBT = aNBT.getCompoundTag(NBT.DISPAY);
+ } else {
+ displayNBT = new NBTTagCompound();
+ aNBT.setTag(NBT.DISPAY, displayNBT);
+ }
+ displayNBT.setString(NBT.CUSTOM_NAME, mCustomName);
+ }
+
+ // write the rest
+ try {
+ aNBT.setString(NBT.OWNER, mOwnerName);
+ aNBT.setString(NBT.OWNER_UUID, mOwnerUuid == null ? "" : mOwnerUuid.toString());
+ aNBT.setBoolean(NBT.LOCK_UPGRADE, mLockUpgrade);
+ aNBT.setByte(NBT.FACING, mFacing);
+
+ writeCoverNBT(aNBT, false);
+ writeMultiTileNBT(aNBT);
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("writeToNBT", e);
+ }
+ }
+
+ public void writeMultiTileNBT(NBTTagCompound aNBT) {
+ /* Do Nothing */
+ }
+
+ @Override
+ public NBTTagCompound writeItemNBT(NBTTagCompound aNBT) {
+ writeCoverNBT(aNBT, true);
+
+ return aNBT;
+ }
+
+
+ @Override
+ public long getTimer() {
+ return 0;
+ }
+
+ @Override
+ public int getRandomNumber(int aRange) {
+ return XSTR.XSTR_INSTANCE.nextInt(aRange);
+ }
+
+ @Override
+ public TileEntity getTileEntity(int aX, int aY, int aZ) {
+ if (worldObj == null || (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ))) return null;
+ return GT_Util.getTileEntity(worldObj, aX, aY, aZ, true);
+ }
+
+ @Override
+ public boolean canUpdate() {
+ return mIsTicking && mShouldRefresh;
+ }
+
+ @Override
+ public boolean shouldRefresh(Block aOldBlock, Block aNewBlock, int aOldMeta, int aNewMeta, World aWorld, int aX, int aY, int aZ) {
+ return mShouldRefresh || aOldBlock != aNewBlock;
+ }
+
+ @Override
+ public void updateEntity() {
+ super.updateEntity();
+ if (mDoesBlockUpdate) doBlockUpdate();
+ }
+
+ public void doBlockUpdate() {
+ final Block tBlock = getBlock(getCoords());
+ worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, tBlock);
+ if (this instanceof IMTE_IsProvidingStrongPower) for (byte tSide : GT_Values.ALL_VALID_SIDES) {
+ if (getBlockAtSide(tSide).isNormalCube(worldObj, xCoord + GT_Values.OFFX[tSide], yCoord + GT_Values.OFFY[tSide], zCoord + GT_Values.OFFZ[tSide])) {
+ worldObj.notifyBlocksOfNeighborChange(
+ xCoord + GT_Values.OFFX[tSide], yCoord + GT_Values.OFFY[tSide], zCoord + GT_Values.OFFZ[tSide], tBlock, OPOS[tSide]
+ );
+ }
+ }
+ mDoesBlockUpdate = false;
+ }
+
+ @Override
+ public boolean shouldSideBeRendered(byte aSide) {
+ final TileEntity tTileEntity = getTileEntityAtSideAndDistance(aSide, 1);
+ // TODO: check to an interface
+ // if (getBlockAtSide(aSide) == Blocks.glass) return false;
+ return tTileEntity instanceof IMultiTileEntity ? !((IMultiTileEntity) tTileEntity).isSurfaceOpaque(OPOS[aSide]) : !getBlockAtSide(aSide).isOpaqueCube();
+ }
+
+ @Override
+ public boolean isSurfaceOpaque(byte aSide) {
+ return true;
+ }
+
+ @Override
+ @SideOnly(Side.CLIENT)
+ public final IRenderedBlock passRenderingToObject(ItemStack aStack) {
+ return this;
+ }
+
+ @Override
+ @SideOnly(Side.CLIENT)
+ public final IRenderedBlock passRenderingToObject(IBlockAccess aWorld, int aX, int aY, int aZ) {
+ return this;
+ }
+
+ @Override public int getRenderPasses(Block aBlock) {return 1;}
+ @Override public boolean usesRenderPass(int aRenderPass) {return true;}
+ @Override public boolean setBlockBounds(Block aBlock, int aRenderPass) {return false;}
+ @Override public boolean renderItem(Block aBlock, RenderBlocks aRenderer) {return false;}
+ @Override public boolean renderBlock(Block aBlock, RenderBlocks aRenderer, IBlockAccess aWorld, int aX, int aY, int aZ) {return false;}
+
+ @Override
+ public ITexture[] getTexture(Block aBlock, byte aSide) {
+ return getTexture(aBlock, aSide, 1, VALID_SIDES);
+ }
+
+ @Override public final ITexture[] getTexture(Block aBlock, byte aSide, int aRenderPass, boolean[] aShouldSideBeRendered) {
+ if (!aShouldSideBeRendered[aSide]) return null;
+
+ final ITexture coverTexture = getCoverTexture(aSide);
+ final ITexture[] textureUncovered = getTexture(aBlock, aSide, true, aRenderPass);
+
+ if (coverTexture != null) {
+ final ITexture[] textureCovered = Arrays.copyOf(textureUncovered, textureUncovered.length + 1);
+ textureCovered[textureUncovered.length] = coverTexture;
+ return textureCovered;
+ } else {
+ return textureUncovered;
+ }
+ }
+
+ @Override
+ public void setCustomName(String aName) {
+ mCustomName = aName;
+ }
+
+ @Override
+ public String getCustomName() {
+ return GT_Utility.isStringValid(mCustomName) ? mCustomName : null;
+ }
+
+ @Override
+ public byte getColorization() {
+ // TODO
+ return 0;
+ }
+
+ @Override
+ public boolean unpaint() {
+ return false;
+ }
+
+ @Override
+ public byte setColorization(byte aColor) {
+ // TODO
+ return 0;
+ }
+
+ @Override
+ public boolean isPainted() {
+ return false;
+ }
+
+ @Override
+ public boolean paint(int aRGB) {
+ return false;
+ }
+
+ @Override
+ public boolean isFacingValid(byte aFacing) {
+ return false;
+ }
+
+ @Override
+ public byte getFrontFacing() {
+ return mFacing;
+ }
+
+ /**
+ * Sets the main facing to {aSide} and update as appropriately
+ * @return Whether the facing was changed
+ */
+ @Override
+ public boolean setMainFacing(byte aSide) {
+ if(!isValidFacing(aSide)) return false;
+ mFacing = aSide;
+
+ issueClientUpdate();
+ issueBlockUpdate();
+ onFacingChange();
+ checkDropCover();
+ doEnetUpdate();
+
+ if (shouldTriggerBlockUpdate()) {
+ // If we're triggering a block update this will call onMachineBlockUpdate()
+ GregTech_API.causeMachineUpdate(worldObj, xCoord, yCoord, zCoord);
+ } else {
+ // If we're not trigger a cascading one, call the update here.
+ onMachineBlockUpdate();
+ }
+ return true;
+ }
+
+ @Override
+ public int getPaint() {
+ return GT_Values.UNCOLORED;
+ }
+
+ @Override
+ public byte getBackFacing() {
+ return GT_Utility.getOppositeSide(mFacing);
+ }
+
+ @Override
+ public boolean isValidFacing(byte aSide) {
+ return aSide >= 0 && aSide <= 6 && getValidFacings()[aSide];
+ }
+
+ @Override
+ public boolean[] getValidFacings() {
+ return VALID_SIDES;
+ }
+
+ @Override
+ public void issueCoverUpdate(byte aSide) {
+ super.issueCoverUpdate(aSide);
+ issueClientUpdate();
+ }
+
+ public AxisAlignedBB box(double[] aBox) {
+ return AxisAlignedBB.getBoundingBox(
+ xCoord + aBox[0], yCoord + aBox[1], zCoord + aBox[2], xCoord + aBox[3], yCoord + aBox[4], zCoord + aBox[5]
+ );
+ }
+
+ public boolean box(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, double aMinX, double aMinY, double aMinZ, double aMaxX, double aMaxY, double aMaxZ) {
+ final AxisAlignedBB tBox = box(aMinX, aMinY, aMinZ, aMaxX, aMaxY, aMaxZ);
+ return tBox.intersectsWith(aAABB) && aList.add(tBox);
+ }
+
+ @Override
+ public void onFacingChange() {/*Do nothing*/}
+
+ public AxisAlignedBB box(double aMinX, double aMinY, double aMinZ, double aMaxX, double aMaxY, double aMaxZ) {
+ return AxisAlignedBB.getBoundingBox(xCoord + aMinX, yCoord + aMinY, zCoord + aMinZ, xCoord + aMaxX, yCoord + aMaxY, zCoord + aMaxZ);
+ }
+
+ @Override
+ public boolean shouldTriggerBlockUpdate() {
+ return false;
+ }
+
+ public boolean box(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, double[] aBox) {
+ final AxisAlignedBB tBox = box(aBox[0], aBox[1], aBox[2], aBox[3], aBox[4], aBox[5]);
+ return tBox.intersectsWith(aAABB) && aList.add(tBox);
+ }
+
+ @Override
+ public void onMachineBlockUpdate() {/*Do nothing*/}
+
+ public boolean box(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, float[] aBox) {
+ final AxisAlignedBB tBox = box(aBox[0], aBox[1], aBox[2], aBox[3], aBox[4], aBox[5]);
+ return tBox.intersectsWith(aAABB) && aList.add(tBox);
+ }
+
+ public boolean box(AxisAlignedBB aAABB, List<AxisAlignedBB> aList) {
+ final AxisAlignedBB tBox = box(PX_BOX);
+ return tBox.intersectsWith(aAABB) && aList.add(tBox);
+ }
+
+ public AxisAlignedBB box(float[] aBox) {
+ return AxisAlignedBB.getBoundingBox(xCoord + aBox[0], yCoord + aBox[1], zCoord + aBox[2], xCoord + aBox[3], yCoord + aBox[4], zCoord + aBox[5]);
+ }
+
+ public boolean box(Block aBlock) {
+ aBlock.setBlockBounds(0, 0, 0, 1, 1, 1);
+ return true;
+ }
+
+ /**
+ * Causes a general Texture update.
+ * <p/>
+ * Only used Client Side to mark Blocks dirty.
+ */
+ @Override
+ public void issueTextureUpdate() {
+ if (!mIsTicking) {
+ markBlockForUpdate();
+ } else {
+ mNeedsUpdate = true;
+ }
+ }
+
+ public boolean box(Block aBlock, double[] aBox) {
+ aBlock.setBlockBounds((float) aBox[0], (float) aBox[1], (float) aBox[2], (float) aBox[3], (float) aBox[4], (float) aBox[5]);
+ return true;
+ }
+
+
+ protected void markBlockForUpdate() {
+ worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
+ //worldObj.func_147479_m(xCoord, yCoord, zCoord);
+ mNeedsUpdate = false;
+
+ }
+
+ public boolean box(Block aBlock, float[] aBox) {
+ aBlock.setBlockBounds(aBox[0], aBox[1], aBox[2], aBox[3], aBox[4], aBox[5]);
+ return true;
+ }
+
+ @Override
+ public void onTileEntityPlaced() {
+ /* empty */
+ }
+
+ public boolean box(Block aBlock, double aMinX, double aMinY, double aMinZ, double aMaxX, double aMaxY, double aMaxZ) {
+ aBlock.setBlockBounds((float) aMinX, (float) aMinY, (float) aMinZ, (float) aMaxX, (float) aMaxY, (float) aMaxZ);
+ return true;
+ }
+
+ @Override
+ public void setShouldRefresh(boolean aShouldRefresh) {
+ mShouldRefresh = aShouldRefresh;
+ }
+
+ /**
+ * shouldJoinIc2Enet - defaults to false, override to change
+ */
+ @Override
+ public boolean shouldJoinIc2Enet() {
+ return false;
+ }
+
+ @Override
+ public final void addCollisionBoxesToList(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, Entity aEntity) {
+ box(getCollisionBoundingBoxFromPool(), aAABB, aList);
+ }
+
+ /**
+ * Simple Function to prevent Block Updates from happening multiple times within the same Tick.
+ */
+ @Override
+ public final void issueBlockUpdate() {
+ if (mIsTicking) mDoesBlockUpdate = true;
+ else doBlockUpdate();
+ }
+
+ @Override
+ public boolean isStillValid() {
+ return !isInvalid();
+ }
+
+ @Override
+ public boolean allowCoverOnSide(byte aSide, GT_ItemStack aCoverID) {
+ return true;
+ }
+
+ public AxisAlignedBB box() {
+ return AxisAlignedBB.getBoundingBox(xCoord, yCoord, zCoord, xCoord + 1, yCoord + 1, zCoord + 1);
+ }
+
+ public boolean box(AxisAlignedBB aBox, AxisAlignedBB aAABB, List<AxisAlignedBB> aList) {
+ return aBox != null && aBox.intersectsWith(aAABB) && aList.add(aBox);
+ }
+
+ public float[] shrunkBox() {
+ return PX_BOX;
+ }
+
+ @Override
+ public void setBlockBoundsBasedOnState(Block aBlock) {
+ box(aBlock);
+ }
+
+ @Override
+ public AxisAlignedBB getCollisionBoundingBoxFromPool() {
+ return box();
+ }
+
+ @Override
+ public AxisAlignedBB getSelectedBoundingBoxFromPool() {
+ if (mForceFullSelectionBoxes) return box();
+ return box(shrunkBox());
+ }
+
+ @Override
+ public ItemStack getPickBlock(MovingObjectPosition aTarget) {
+ final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(mMTERegistry);
+ return tRegistry == null ? null : tRegistry.getItem(mMTEID, writeItemNBT(new NBTTagCompound()));
+ }
+
+ @Override
+ public void onBlockAdded() {
+
+ }
+
+ @Override
+ public String getOwnerName() {
+ if (GT_Utility.isStringInvalid(mOwnerName)) return "Player";
+ return mOwnerName;
+ }
+
+ @Override
+ public String setOwnerName(String aName) {
+ if (GT_Utility.isStringInvalid(aName)) return mOwnerName = "Player";
+ return mOwnerName = aName;
+ }
+
+ @Override
+ public UUID getOwnerUuid() {
+ return mOwnerUuid;
+ }
+
+ @Override
+ public void setOwnerUuid(UUID uuid) {
+ mOwnerUuid = uuid;
+ }
+
+ @Override
+ public boolean onPlaced(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, byte aSide, float aHitX, float aHitY, float aHitZ) {
+ mFacing = getSideForPlayerPlacing(aPlayer, mFacing, getValidFacings());
+ onFacingChange();
+ return true;
+ }
+
+ @Override
+ public boolean allowInteraction(Entity aEntity) {
+ return true;
+ }
+
+ public boolean allowRightclick(Entity aEntity) {
+ return allowInteraction(aEntity);
+ }
+
+ @Override
+ public boolean onBlockActivated(EntityPlayer aPlayer, byte aSide, float aX, float aY, float aZ) {
+ try {
+ return allowRightclick(aPlayer) && onRightClick(aPlayer, aSide, aX, aY, aZ);
+ } catch(Throwable e) {
+ e.printStackTrace(GT_Log.err);
+ return true;
+ }
+ }
+ @Override
+ public boolean onRightClick(EntityPlayer aPlayer, byte aSide, float aX, float aY, float aZ) {
+ if (isClientSide()) {
+ //Configure Cover, sneak can also be: screwdriver, wrench, side cutter, soldering iron
+ if (aPlayer.isSneaking()) {
+ final byte tSide = (getCoverIDAtSide(aSide) == 0) ? GT_Utility.determineWrenchingSide(aSide, aX, aY, aZ) : aSide;
+ return (getCoverBehaviorAtSideNew(tSide).hasCoverGUI());
+ } else if (getCoverBehaviorAtSideNew(aSide).onCoverRightclickClient(aSide, this, aPlayer, aX, aY, aZ)) {
+ return true;
+ }
+
+ if (!getCoverBehaviorAtSideNew(aSide).isGUIClickable(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this))
+ return false;
+ }
+ if (isServerSide()) {
+ if (!privateAccess() || aPlayer.getDisplayName().equalsIgnoreCase(getOwnerName())) {
+ final ItemStack tCurrentItem = aPlayer.inventory.getCurrentItem();
+ final byte wrenchSide = GT_Utility.determineWrenchingSide(aSide, aX, aY, aZ);
+
+ if(tCurrentItem != null) {
+ if (getColorization() >= 0 && GT_Utility.areStacksEqual(new ItemStack(Items.water_bucket, 1), tCurrentItem)) {
+ // TODO (Colorization)
+ }
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sWrenchList)) return onWrenchRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sScrewdriverList)) return onScrewdriverRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sHardHammerList)) return onHammerRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sSoftHammerList)) return onMalletRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sSolderingToolList)) return onSolderingRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sWireCutterList)) return onWireCutterRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+
+ final byte coverSide = getCoverIDAtSide(aSide) == 0 ? wrenchSide : aSide;
+
+ if (getCoverIDAtSide(coverSide) == 0) {
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sCovers.keySet())) {
+ if (GregTech_API.getCoverBehaviorNew(tCurrentItem).isCoverPlaceable(coverSide, tCurrentItem, this) &&
+ allowCoverOnSide(coverSide, new GT_ItemStack(tCurrentItem)))
+ {
+ setCoverItemAtSide(coverSide, tCurrentItem);
+ if (!aPlayer.capabilities.isCreativeMode) tCurrentItem.stackSize--;
+ GT_Utility.sendSoundToPlayers(worldObj, GregTech_API.sSoundList.get(100), 1.0F, -1, xCoord, yCoord, zCoord);
+ issueClientUpdate();
+ }
+ sendCoverDataIfNeeded();
+ return true;
+ }
+ } else {
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sCrowbarList)) {
+ if (GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer)) {
+ GT_Utility.sendSoundToPlayers(worldObj, GregTech_API.sSoundList.get(0), 1.0F, -1, xCoord, yCoord, zCoord);
+ dropCover(coverSide, aSide, false);
+ }
+ sendCoverDataIfNeeded();
+ return true;
+ }
+ }
+ } else if (aPlayer.isSneaking()) { //Sneak click, no tool -> open cover config if possible.
+ aSide = (getCoverIDAtSide(aSide) == 0) ? GT_Utility.determineWrenchingSide(aSide, aX, aY, aZ) : aSide;
+ return getCoverIDAtSide(aSide) > 0 && getCoverBehaviorAtSideNew(aSide).onCoverShiftRightClick(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this, aPlayer);
+ }
+
+ if (getCoverBehaviorAtSideNew(aSide).onCoverRightClick(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this, aPlayer, aX, aY, aZ))
+ return true;
+
+ if (!getCoverBehaviorAtSideNew(aSide).isGUIClickable(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this))
+ return false;
+
+
+ }
+ }
+ return false;
+ }
+
+ public boolean onWrenchRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, byte wrenchSide, float aX, float aY, float aZ) {
+ if(setMainFacing(wrenchSide)) {
+ GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer);
+ GT_Utility.sendSoundToPlayers(worldObj, GregTech_API.sSoundList.get(100), 1.0F, -1, xCoord, yCoord, zCoord);
+ }
+ return true;
+ }
+
+ public boolean onScrewdriverRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, byte wrenchSide, float aX, float aY, float aZ) {
+ if (GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 200, aPlayer)) {
+ setCoverDataAtSide(wrenchSide, getCoverBehaviorAtSideNew(wrenchSide).onCoverScrewdriverClick(wrenchSide, getCoverIDAtSide(wrenchSide), getComplexCoverDataAtSide(wrenchSide), this, aPlayer, aX, aY, aZ));
+ // TODO: Update connections!
+ GT_Utility.sendSoundToPlayers(worldObj, GregTech_API.sSoundList.get(100), 1.0F, -1, xCoord, yCoord, zCoord);
+ }
+ return true;
+ }
+
+ public boolean onHammerRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, byte wrenchSide, float aX, float aY, float aZ) {
+
+ return true;
+ }
+
+ public boolean onMalletRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, byte wrenchSide, float aX, float aY, float aZ) {
+
+ return true;
+ }
+
+ public boolean onSolderingRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, byte wrenchSide, float aX, float aY, float aZ) {
+
+ return true;
+ }
+
+ public boolean onWireCutterRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, byte wrenchSide, float aX, float aY, float aZ) {
+
+ return true;
+ }
+
+ @Override
+ public float getExplosionResistance(Entity aExploder, double aExplosionX, double aExplosionY, double aExplosionZ) {
+ return getExplosionResistance();
+ }
+
+ @Override
+ public float getExplosionResistance() {
+ return 10.0F;
+ }
+
+ @Override
+ public void onExploded(Explosion aExplosion) {
+
+ }
+
+ @Override
+ public boolean isSideSolid(byte aSide) {
+ return true;
+ }
+
+ @Override
+ public ArrayList<ItemStack> getDrops(int aFortune, boolean aSilkTouch) {
+ final ArrayList<ItemStack> rList = new ArrayList<>();
+ final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(getMultiTileEntityRegistryID());
+ if (tRegistry != null) rList.add(tRegistry.getItem(getMultiTileEntityID(), writeItemNBT(new NBTTagCompound())));
+ return rList;
+ }
+
+
+ @Override
+ public boolean getSubItems(MultiTileEntityBlockInternal aBlock, Item aItem, CreativeTabs aTab, List<ItemStack> aList, short aID) {
+ return true;
+ }
+
+
+ @Override
+ public boolean recolourBlock(byte aSide, byte aColor) {
+// if (aColor > 15 || aColor < -1) aColor = -1;
+// if(paint((byte) (aColor + 1))) {
+//// updateClientData();
+//// causeBlockUpdate();
+// return true;
+// }
+// if (unpaint()) {updateClientData(); causeBlockUpdate(); return T;}
+// mColor = (byte) (aColor + 1);
+//// if (canAccessData()) mMetaTileEntity.onColorChangeServer(aColor);
+ return false;
+ }
+
+
+ @Override
+ public boolean playerOwnsThis(EntityPlayer aPlayer, boolean aCheckPrecicely) {
+ if (aCheckPrecicely || privateAccess() || (mOwnerName.length() == 0))
+ if ((mOwnerName.length() == 0) && isServerSide()) {
+ setOwnerName(aPlayer.getDisplayName());
+ setOwnerUuid(aPlayer.getUniqueID());
+ } else
+ return !privateAccess() || aPlayer.getDisplayName().equals("Player") || mOwnerName.equals("Player") || mOwnerName.equals(
+ aPlayer.getDisplayName());
+ return true;
+ }
+
+ @Override
+ public boolean privateAccess() {
+ return mLockUpgrade;
+ }
+
+ public byte getTextureData() {
+ return 0;
+ }
+
+ /**
+ * @return a Packet containing all Data which has to be synchronised to the Client - Override as needed
+ */
+ public GT_Packet_New getClientDataPacket() {
+ return new GT_Packet_TileEntity(
+ xCoord, (short) yCoord, zCoord,
+ getMultiTileEntityRegistryID(), getMultiTileEntityID(),
+ mCoverSides[0], mCoverSides[1], mCoverSides[2], mCoverSides[3], mCoverSides[4], mCoverSides[5],
+ (byte) ((mFacing & 7) | (mRedstone ? 16 : 0)),
+ (byte) getTextureData(), /*getTexturePage()*/
+ (byte) 0, /*getUpdateData()*/
+ (byte) (((mSidedRedstone[0] > 0) ? 1 : 0) | ((mSidedRedstone[1] > 0) ? 2 : 0) | ((mSidedRedstone[2] > 0) ? 4 : 0) | ((mSidedRedstone[3] > 0) ? 8 : 0) | ((mSidedRedstone[4] > 0) ? 16 : 0) | ((mSidedRedstone[5] > 0) ? 32 : 0)),
+ mColor
+ );
+ }
+
+ @Override
+ public Packet getDescriptionPacket() {
+ issueClientUpdate();
+ return null;
+ }
+
+ @Override
+ public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, IWailaConfigHandler config) {
+ super.getWailaBody(itemStack, currenttip, accessor, config);
+ currenttip.add(String.format("Facing: %s", ForgeDirection.getOrientation(getFrontFacing()).name()));
+ }
+
+ @Override
+ public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, int z) {
+ super.getWailaNBTData(player, tile, tag, world, x, y, z);
+ }
+
+
+ @Override
+ public void sendClientData( EntityPlayerMP aPlayer) {
+ if(worldObj == null || worldObj.isRemote) return;
+ final GT_Packet_New tPacket = getClientDataPacket();
+ if(aPlayer == null) {
+ GT_Values.NW.sendPacketToAllPlayersInRange(worldObj, tPacket, getXCoord(), getZCoord());
+ } else {
+ GT_Values.NW.sendToPlayer(tPacket, aPlayer);
+ }
+ sendCoverDataIfNeeded();
+ }
+ public void setTextureData(byte aValue) {/*Do nothing*/}
+
+ @Override
+ public boolean receiveClientEvent(int aEventID, int aValue) {
+ super.receiveClientEvent(aEventID, aValue);
+ if (isClientSide()) {
+ issueTextureUpdate();
+ switch (aEventID) {
+ case GregTechTileClientEvents.CHANGE_COMMON_DATA:
+ mFacing = (byte) (aValue & 7);
+ //mActive = ((aValue & 8) != 0);
+ mRedstone = ((aValue & 16) != 0);
+ //mLockUpgrade = ((aValue&32) != 0);
+ //mWorks = ((aValue & 64) != 0);
+ break;
+ case GregTechTileClientEvents.CHANGE_CUSTOM_DATA:
+ if ((aValue & 0x80) != 0) // Is texture index
+ setTextureData((byte) (aValue & 0x7F));
+ //else if (mMetaTileEntity instanceof GT_MetaTileEntity_Hatch)//is texture page and hatch
+ // ((GT_MetaTileEntity_Hatch) mMetaTileEntity).onTexturePageUpdate((byte) (aValue & 0x7F));
+ break;
+ case GregTechTileClientEvents.CHANGE_COLOR:
+ if (aValue > 16 || aValue < 0) aValue = 0;
+ mColor = (byte) aValue;
+ break;
+ case GregTechTileClientEvents.CHANGE_REDSTONE_OUTPUT:
+ mSidedRedstone[0] = (byte) ((aValue & 1) == 1 ? 15 : 0);
+ mSidedRedstone[1] = (byte) ((aValue & 2) == 2 ? 15 : 0);
+ mSidedRedstone[2] = (byte) ((aValue & 4) == 4 ? 15 : 0);
+ mSidedRedstone[3] = (byte) ((aValue & 8) == 8 ? 15 : 0);
+ mSidedRedstone[4] = (byte) ((aValue & 16) == 16 ? 15 : 0);
+ mSidedRedstone[5] = (byte) ((aValue & 32) == 32 ? 15 : 0);
+ break;
+// case GregTechTileClientEvents.DO_SOUND:
+// if (mTickTimer > 20)
+// doSound((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
+// break;
+// case GregTechTileClientEvents.START_SOUND_LOOP:
+// if (mTickTimer > 20)
+// startSoundLoop((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
+// break;
+// case GregTechTileClientEvents.STOP_SOUND_LOOP:
+// if (mTickTimer > 20)
+// stopSoundLoop((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
+// break;
+// case GregTechTileClientEvents.CHANGE_LIGHT:
+// mLightValue = (byte) aValue;
+// break;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean hasCustomInventoryName() {
+ return false;
+ }
+
+ @Override
+ public ArrayList<String> getDebugInfo(EntityPlayer aPlayer, int aLogLevel) {
+ final ArrayList<String> tList = new ArrayList<>();
+ if (aLogLevel > 2) {
+ tList.add("MultiTileRegistry-ID: " + EnumChatFormatting.BLUE + mMTERegistry + EnumChatFormatting.RESET + " MultiTile-ID: " + EnumChatFormatting.BLUE + mMTEID + EnumChatFormatting.RESET);
+ }
+ if(joinedIc2Enet)
+ tList.add("Joined IC2 ENet");
+
+ addDebugInfo(aPlayer, aLogLevel, tList);
+
+ return tList;
+ }
+
+ protected void addDebugInfo(EntityPlayer aPlayer, int aLogLevel, ArrayList<String> tList) {
+ /* Do nothing */
+ }
+
+ /**
+ * Fluid - A Default implementation of the Fluid Tank behaviour, so that every TileEntity can use this to simplify its Code.
+ */
+ protected IFluidTank getFluidTankFillable(byte aSide, FluidStack aFluidToFill) {return null;}
+ protected IFluidTank getFluidTankDrainable(byte aSide, FluidStack aFluidToDrain) {return null;}
+ protected IFluidTank[] getFluidTanks(byte aSide) { return GT_Values.emptyFluidTank; }
+
+ public boolean isLiquidInput(byte aSide) {return true;}
+
+ public boolean isLiquidOutput(byte aSide) {return true;}
+
+ @Override
+ public int fill(ForgeDirection aDirection, FluidStack aFluid, boolean aDoFill) {
+ if (aFluid == null || aFluid.amount <= 0) return 0;
+ final IFluidTank tTank = getFluidTankFillable((byte)aDirection.ordinal(), aFluid);
+ return (tTank == null) ? 0 : tTank.fill(aFluid, aDoFill);
+ }
+
+ @Override
+ public FluidStack drain(ForgeDirection aDirection, FluidStack aFluid, boolean aDoDrain) {
+ if (aFluid == null || aFluid.amount <= 0) return null;
+ final IFluidTank tTank = getFluidTankDrainable((byte)aDirection.ordinal(), aFluid);
+ if (tTank == null || tTank.getFluid() == null || tTank.getFluidAmount() == 0 || !tTank.getFluid().isFluidEqual(aFluid)) return null;
+ return tTank.drain(aFluid.amount, aDoDrain);
+ }
+
+ @Override
+ public FluidStack drain(ForgeDirection aDirection, int aAmountToDrain, boolean aDoDrain) {
+ if (aAmountToDrain <= 0) return null;
+ final IFluidTank tTank = getFluidTankDrainable((byte)aDirection.ordinal(), null);
+ if (tTank == null || tTank.getFluid() == null || tTank.getFluidAmount() == 0) return null;
+ return tTank.drain(aAmountToDrain, aDoDrain);
+ }
+
+ @Override
+ public boolean canFill(ForgeDirection aDirection, Fluid aFluid) {
+ if (aFluid == null) return false;
+ final IFluidTank tTank = getFluidTankFillable((byte)aDirection.ordinal(), new FluidStack(aFluid, 0));
+ return tTank != null && (tTank.getFluid() == null || tTank.getFluid().getFluid() == aFluid);
+ }
+
+ @Override
+ public boolean canDrain(ForgeDirection aDirection, Fluid aFluid) {
+ if (aFluid == null) return false;
+ final IFluidTank tTank = getFluidTankDrainable((byte)aDirection.ordinal(), new FluidStack(aFluid, 0));
+ return tTank != null && (tTank.getFluid() != null && tTank.getFluid().getFluid() == aFluid);
+ }
+
+ @Override
+ public FluidTankInfo[] getTankInfo(ForgeDirection aDirection) {
+ final IFluidTank[] tTanks = getFluidTanks((byte)aDirection.ordinal());
+ if (tTanks == null || tTanks.length <= 0) return GT_Values.emptyFluidTankInfo;
+ final FluidTankInfo[] rInfo = new FluidTankInfo[tTanks.length];
+ for (int i = 0; i < tTanks.length; i++) rInfo[i] = new FluidTankInfo(tTanks[i]);
+ return rInfo;
+ }
+
+ /**
+ * Energy - Do nothing by Default
+ */
+ @Override public boolean isUniversalEnergyStored(long aEnergyAmount) { return false; }
+ @Override public long getUniversalEnergyStored() { return 0; }
+ @Override public long getUniversalEnergyCapacity() { return 0; }
+ @Override public long getOutputAmperage() { return 0; }
+ @Override public long getOutputVoltage() { return 0; }
+ @Override public long getInputAmperage() { return 0; }
+ @Override public long getInputVoltage() { return 0; }
+ @Override public boolean decreaseStoredEnergyUnits(long aEnergy, boolean aIgnoreTooLessEnergy) { return false; }
+ @Override public boolean increaseStoredEnergyUnits(long aEnergy, boolean aIgnoreTooMuchEnergy) { return false; }
+ @Override public boolean drainEnergyUnits(byte aSide, long aVoltage, long aAmperage) { return false; }
+ @Override public long getAverageElectricInput() { return 0; }
+ @Override public long getAverageElectricOutput() { return 0; }
+ @Override public long getStoredEU() { return 0; }
+ @Override public long getEUCapacity() { return 0; }
+ @Override public long injectEnergyUnits(byte aSide, long aVoltage, long aAmperage) { return 0; }
+ @Override public boolean inputEnergyFrom(byte aSide) { return false; }
+ @Override public boolean outputsEnergyTo(byte aSide) { return false; }
+
+ /**
+ * Inventory - Do nothing by default
+ */
+ @Override public void openInventory() { /* Do nothing */ }
+ @Override public void closeInventory() { /* Do nothing */ }
+ @Override public boolean hasInventoryBeenModified() { return false; }
+ @Override public boolean isValidSlot(int aIndex) { return false; }
+ @Override public boolean addStackToSlot(int aIndex, ItemStack aStack) { return false; }
+ @Override public boolean addStackToSlot(int aIndex, ItemStack aStack, int aAmount) { return false; }
+ @Override public int[] getAccessibleSlotsFromSide(int aSide) { return GT_Values.emptyIntArray; }
+ @Override public boolean canInsertItem(int aSlot, ItemStack aStack, int aSide) { return false; }
+ @Override public boolean canExtractItem(int aSlot, ItemStack aStack, int aSide) { return false; }
+ @Override public int getSizeInventory() { return 0; }
+ @Override public ItemStack getStackInSlot(int aSlot) { return null; }
+ @Override public ItemStack decrStackSize(int aSlot, int aDecrement) { return null; }
+ @Override public ItemStack getStackInSlotOnClosing(int aSlot) { return null; }
+ @Override public void setInventorySlotContents(int aSlot, ItemStack aStack) { /* Do nothing */ }
+ @Override public int getInventoryStackLimit() { return 0; }
+ @Override public boolean isItemValidForSlot(int aSlot, ItemStack aStack) { return false; }
+ @Override public void markInventoryBeenModified() { mInventoryChanged = true; }
+
+
+ /*
+ * Cover Helpers
+ */
+
+ public boolean coverLetsFluidIn(byte aSide, Fluid aFluid) {
+ return getCoverBehaviorAtSideNew(aSide).letsFluidIn(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), aFluid, this);
+ }
+ public boolean coverLetsFluidOut(byte aSide, Fluid aFluid) {
+ return getCoverBehaviorAtSideNew(aSide).letsFluidOut(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), aFluid, this);
+ }
+
+ public boolean coverLetsEnergyIn(byte aSide) {
+ return getCoverBehaviorAtSideNew(aSide).letsEnergyIn(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this);
+ }
+ public boolean coverLetsEnergyOut(byte aSide) {
+ return getCoverBehaviorAtSideNew(aSide).letsEnergyOut(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this);
+ }
+
+ public boolean coverLetsItemsIn(byte aSide, int aSlot) {
+ return getCoverBehaviorAtSideNew(aSide).letsItemsIn(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), aSlot, this);
+ }
+ public boolean coverLetsItemsOut(byte aSide, int aSlot) {
+ return getCoverBehaviorAtSideNew(aSide).letsItemsOut(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), aSlot,this);
+ }
+
+}
diff --git a/src/main/java/gregtech/api/multitileentity/base/BaseNontickableMultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/base/BaseNontickableMultiTileEntity.java
new file mode 100644
index 0000000000..2e689a6bae
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/base/BaseNontickableMultiTileEntity.java
@@ -0,0 +1,55 @@
+package gregtech.api.multitileentity.base;
+import gregtech.api.net.GT_Packet_SendCoverData;
+import gregtech.api.util.ISerializableObject;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.Packet;
+
+import static gregtech.api.enums.GT_Values.NW;
+
+public abstract class BaseNontickableMultiTileEntity extends BaseMultiTileEntity {
+ boolean mConstructed = false; // Keeps track of whether this TE has been constructed and placed in the world
+ public BaseNontickableMultiTileEntity() {
+ super(false);
+ }
+
+ @Override
+ public void issueClientUpdate() {
+ if(worldObj != null && !worldObj.isRemote) sendClientData(null);
+ }
+
+ @Override
+ public Packet getDescriptionPacket() {
+ // We should have a world object and have been constructed by this point
+ mConstructed = true;
+
+ super.getDescriptionPacket();
+ // We don't get ticked, so if we have any cover data that needs to be sent, send it now
+ sendCoverDataIfNeeded();
+ return null;
+ }
+
+ @Override
+ public void issueCoverUpdate(byte aSide) {
+ if(!mConstructed) {
+ // Queue these up and send them with the description packet
+ super.issueCoverUpdate(aSide);
+ } else {
+ // Otherwise, send the data right away
+ NW.sendPacketToAllPlayersInRange(
+ worldObj,
+ new GT_Packet_SendCoverData(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this),
+ xCoord, zCoord
+ );
+ // Just in case
+ mCoverNeedUpdate[aSide] = false;
+ }
+ }
+
+ @Override
+ public void receiveCoverData(byte aCoverSide, int aCoverID, ISerializableObject aCoverData, EntityPlayerMP aPlayer) {
+ super.receiveCoverData(aCoverSide, aCoverID, aCoverData, aPlayer);
+ // We don't get ticked so issue the texture update right away
+ issueTextureUpdate();
+ }
+
+}
diff --git a/src/main/java/gregtech/api/multitileentity/base/BaseTickableMultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/base/BaseTickableMultiTileEntity.java
new file mode 100644
index 0000000000..c8bc04557f
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/base/BaseTickableMultiTileEntity.java
@@ -0,0 +1,113 @@
+package gregtech.api.multitileentity.base;
+
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_OnNeighborBlockChange;
+import gregtech.api.util.GT_Log;
+import gregtech.api.util.GT_Util;
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.world.World;
+
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+
+public abstract class BaseTickableMultiTileEntity extends BaseMultiTileEntity implements IMTE_OnNeighborBlockChange {
+ /** Variable for seeing if the Tick Function is called right now. */
+ public boolean mIsRunningTick = false;
+ /** Gets set to true when the Block received a Block Update. */
+ public boolean mBlockUpdated = false;
+ /** Timer Value */
+ protected long mTimer = 0;
+ /** Variable for updating Data to the Client */
+ private boolean mSendClientData = false;
+
+
+ public BaseTickableMultiTileEntity() {
+ super(true);
+ }
+
+ @Override
+ public final void updateEntity() {
+ mIsRunningTick = true;
+ final boolean isServerSide = isServerSide();
+ try {
+ if (mTimer++ == 0) {
+ markDirty();
+ GT_Util.markChunkDirty(this);
+ onFirstTick(isServerSide);
+ }
+ if (!isDead()) onPreTick(mTimer, isServerSide);
+ if (!isDead()) {
+ mTimer++;
+ super.updateEntity();
+ }
+ if (!isServerSide) {
+ if (mNeedsUpdate) {
+ worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
+ //worldObj.func_147479_m(xCoord, yCoord, zCoord);
+ mNeedsUpdate = false;
+ }
+ }
+ if (!isDead()) onTick(mTimer, isServerSide);
+ if (!isDead() && isServerSide && mTimer > 2 && mSendClientData) {
+ sendClientData(null);
+ }
+ if (!isDead()) onPostTick(mTimer, isServerSide);
+
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("UpdateEntity Failed", e);
+ e.printStackTrace(GT_Log.err);
+ try {
+ onTickFailed(mTimer, isServerSide);
+ } catch (Throwable e2) {
+ GT_FML_LOGGER.error("UpdateEntity:onTickFailed Failed", e);
+ }
+ }
+
+ mIsRunningTick = false;
+ }
+
+ @Override
+ public void sendClientData(EntityPlayerMP aPlayer) {
+ if (mSendClientData) {
+ GT_FML_LOGGER.info("Sending client data");
+ super.sendClientData(aPlayer);
+ mSendClientData = false;
+ }
+ }
+
+ /** The very first Tick happening to this TileEntity */
+ public void onFirstTick(boolean isServerSide) {
+ if (isServerSide) {
+ checkDropCover();
+ } else {
+ requestCoverDataIfNeeded();
+ }
+ }
+
+ /** The first part of the Tick. */
+ public void onPreTick(long aTick, boolean isServerSide) { /*Do nothing*/ }
+
+ /** The regular Tick. */
+ public void onTick(long aTimer, boolean isServerSide) { /*Do nothing*/ }
+
+ /** The absolute last part of the Tick. */
+ public void onPostTick(long aTick, boolean isServerSide) { /*Do nothing*/ }
+
+ /** Gets called when there is an Exception happening during one of the Tick Functions. */
+ public void onTickFailed(long aTimer, boolean isServerSide) { /*Do nothing*/ }
+
+ @Override
+ public void onNeighborBlockChange(World aWorld, Block aBlock) {
+ mBlockUpdated = true;
+ }
+
+ @Override
+ public void issueClientUpdate() {
+ mSendClientData = true;
+ }
+
+ @Override
+ public byte getComparatorValue(byte aSide) {
+ return 0;
+ }
+
+}
diff --git a/src/main/java/gregtech/api/multitileentity/interfaces/IItemUpdatable.java b/src/main/java/gregtech/api/multitileentity/interfaces/IItemUpdatable.java
new file mode 100644
index 0000000000..77def5e8fd
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/interfaces/IItemUpdatable.java
@@ -0,0 +1,15 @@
+package gregtech.api.multitileentity.interfaces;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.world.World;
+
+public interface IItemUpdatable {
+ /**
+ * Updates the Data of the ItemStack. Not called every tick but instead called whenever something important happens to the Stack.
+ */
+ void updateItemStack(ItemStack aStack);
+ /**
+ * Updates the Data of the ItemStack. Not called every tick but instead called whenever something important happens to the Stack.
+ */
+ void updateItemStack(ItemStack aStack, World aWorld, int aX, int aY, int aZ);
+}
diff --git a/src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java
new file mode 100644
index 0000000000..87d7892fba
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java
@@ -0,0 +1,227 @@
+package gregtech.api.multitileentity.interfaces;
+
+import cpw.mods.fml.common.Optional;
+import gregtech.api.interfaces.tileentity.IBasicEnergyContainer;
+import gregtech.api.interfaces.tileentity.ICoverable;
+import gregtech.api.interfaces.tileentity.IDebugableTileEntity;
+import gregtech.api.interfaces.tileentity.IEnergyConnected;
+import gregtech.api.interfaces.tileentity.IHasInventory;
+import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords;
+import gregtech.api.interfaces.tileentity.ITexturedTileEntity;
+import gregtech.api.interfaces.tileentity.ITurnable;
+import gregtech.api.multitileentity.MultiTileEntityBlockInternal;
+import gregtech.api.multitileentity.MultiTileEntityItemInternal;
+import gregtech.api.multitileentity.MultiTileEntityRegistry;
+import net.minecraft.block.Block;
+import net.minecraft.creativetab.CreativeTabs;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.MovingObjectPosition;
+import net.minecraft.world.Explosion;
+import net.minecraft.world.World;
+import net.minecraftforge.fluids.IFluidHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import static gregtech.api.enums.GT_Values.MOD_ID_APC;
+
+/*
+ * Heavily inspired by GT6
+ */
+public interface IMultiTileEntity extends IHasWorldObjectAndCoords, ICoverable, ITurnable, IHasInventory, IEnergyConnected, IBasicEnergyContainer, IFluidHandler, ITexturedTileEntity, IDebugableTileEntity {
+ /** Those two IDs HAVE to be saved inside the NBT of the TileEntity itself. They get set by the Registry itself, when the TileEntity is placed. */
+ short getMultiTileEntityID();
+ short getMultiTileEntityRegistryID();
+ /** Called by the Registry with the default NBT Parameters and the two IDs you have to save, when the TileEntity is created. aNBT may be null, take that into account if you decide to call the regular readFromNBT Function from here. */
+ void initFromNBT(NBTTagCompound aNBT, short aMTEID, short aMTERegistry);
+ /** Writes Item Data to the NBT. */
+ NBTTagCompound writeItemNBT(NBTTagCompound aNBT);
+ /** Sets the Item Display Name. Use null to reset it. */
+ void setCustomName(String aName);
+ String getCustomName();
+
+ /** return the internal Name of this TileEntity to be registered. */
+ String getTileEntityName();
+
+ /** Called when a TileEntity of this particular Class is being registered first at any MultiTileEntity Registry. So basically one call per Class. */
+ void onRegistrationFirst(MultiTileEntityRegistry aRegistry, short aID);
+
+ /** Called after the TileEntity has been placed and set up. */
+ void onTileEntityPlaced();
+
+ /** Checks if the TileEntity is Invalid or Unloaded, should bes required for every TileEntity. */
+ @Override
+ boolean isDead();
+
+ void issueClientUpdate();
+ void sendClientData( EntityPlayerMP aPlayer);
+ boolean receiveClientEvent(int aEventID, int aValue);
+
+ void setShouldRefresh(boolean aShouldRefresh);
+
+ void addCollisionBoxesToList(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, Entity aEntity);
+ AxisAlignedBB getCollisionBoundingBoxFromPool();
+ AxisAlignedBB getSelectedBoundingBoxFromPool();
+ void setBlockBoundsBasedOnState(Block aBlock);
+
+ void onBlockAdded();
+ boolean playerOwnsThis(EntityPlayer aPlayer, boolean aCheckPrecicely);
+ boolean privateAccess();
+
+ /** @return the amount of Time this TileEntity has been loaded. */
+ @Override
+ long getTimer();
+
+ /** Sets the Owner of the Machine. Returns the set Name. */
+ String setOwnerName(String aName);
+
+ /** gets the Name of the Machines Owner or "Player" if not set. */
+ String getOwnerName();
+
+ /** Gets the UniqueID of the Machines Owner. */
+ UUID getOwnerUuid();
+
+ /** Sets the UniqueID of the Machines Owner. */
+ void setOwnerUuid(UUID uuid);
+
+ /**
+ * Causes a general Texture update.
+ * Only used Client Side to mark Blocks dirty.
+ */
+ void issueTextureUpdate();
+
+ /**
+ * Paintable Support
+ */
+ boolean unpaint();
+ boolean isPainted();
+ boolean paint(int aRGB);
+ int getPaint();
+
+ /**
+ * Sets the main facing to {aSide} and update as appropriately
+ * @return Whether the facing was changed
+ */
+ boolean setMainFacing(byte aSide);
+ boolean isFacingValid(byte aFacing);
+ void onFacingChange();
+ @Override default void setFrontFacing(byte aSide) { setMainFacing(aSide); }
+
+
+
+ boolean shouldTriggerBlockUpdate();
+ void onMachineBlockUpdate();
+
+ boolean allowInteraction(Entity aEntity);
+ default void onLeftClick(EntityPlayer aPlayer) { /* do nothing */ }
+
+ boolean onBlockActivated(EntityPlayer aPlayer, byte aSide, float aX, float aY, float aZ);
+ boolean onRightClick(EntityPlayer aPlayer, byte aSide, float aX, float aY, float aZ);
+
+ ArrayList<ItemStack> getDrops(int aFortune, boolean aSilkTouch);
+
+ boolean isSideSolid(byte aSide);
+
+ float getExplosionResistance(Entity aExploder, double aExplosionX, double aExplosionY, double aExplosionZ);
+ float getExplosionResistance();
+ void onExploded(Explosion aExplosion);
+
+ boolean recolourBlock(byte aSide, byte aColor);
+
+ /** Adds to the Creative Tab. return false to prevent it from being added. */
+ boolean getSubItems(MultiTileEntityBlockInternal aBlock, Item aItem, CreativeTabs aTab, List<ItemStack> aList, short aID);
+
+ ItemStack getPickBlock(MovingObjectPosition aTarget);
+
+ boolean shouldSideBeRendered(byte aSide);
+
+ boolean isSurfaceOpaque(byte aSide);
+
+ boolean onPlaced(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, byte aSide, float aHitX, float aHitY, float aHitZ);
+
+// ItemStack getPickBlock(MovingObjectPosition aTarget);
+
+ /*
+ * Various Sub Interfaces from GT6
+ */
+
+ interface IMTE_OnNeighborBlockChange extends IMultiTileEntity {
+ void onNeighborBlockChange(World aWorld, Block aBlock);
+ }
+
+ interface IMTE_IsProvidingWeakPower extends IMultiTileEntity {
+ /** Remember that it passes the opposite Side due to the way vanilla works! */
+ int isProvidingWeakPower(byte aOppositeSide);
+ }
+
+ interface IMTE_IsProvidingStrongPower extends IMultiTileEntity {
+ /** Remember that it passes the opposite Side due to the way vanilla works! */
+ int isProvidingStrongPower(byte aOppositeSide);
+ }
+
+ interface IMTE_ShouldCheckWeakPower extends IMultiTileEntity {
+ boolean shouldCheckWeakPower(byte aSide);
+ }
+
+ interface IMTE_GetWeakChanges extends IMultiTileEntity {
+ boolean getWeakChanges();
+ }
+
+
+ interface IMTE_GetComparatorInputOverride extends IMultiTileEntity {
+ int getComparatorInputOverride(byte aSide);
+ }
+
+ interface IMTE_BreakBlock extends IMultiTileEntity {
+ /** return true to prevent the TileEntity from being removed. */
+ boolean breakBlock();
+ }
+
+ interface IMTE_HasMultiBlockMachineRelevantData extends IMultiTileEntity {
+ /** Return true to mark this Block as a Machine Block for Multiblocks. (Triggers machine update thread) */
+ boolean hasMultiBlockMachineRelevantData();
+ }
+
+ interface IMTE_GetBlockHardness extends IMultiTileEntity {
+ float getBlockHardness();
+ }
+
+ interface IMTE_GetFoodValues extends IMultiTileEntity {
+ @Optional.Method(modid = MOD_ID_APC)
+ squeek.applecore.api.food.FoodValues getFoodValues(MultiTileEntityItemInternal aItem, ItemStack aStack);
+ }
+
+ interface IMTE_OnlyPlaceableWhenSneaking extends IMultiTileEntity {
+ /** Return true to prevent placing this Block without Sneaking. */
+ boolean onlyPlaceableWhenSneaking();
+ }
+
+ interface IMTE_IgnoreEntityCollisionWhenPlacing extends IMultiTileEntity {
+ /** Return true to ignore the Player standing in the way of placing this Block; useful for things like pipes/wires. */
+ boolean ignoreEntityCollisionWhenPlacing(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, byte aSide, float aHitX, float aHitY, float aHitZ);
+ }
+
+ interface IMTE_CanPlace extends IMultiTileEntity {
+ /** Return false if this TileEntity cannot be placed at that Location. */
+ boolean canPlace(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, byte aSide, float aHitX, float aHitY, float aHitZ);
+ }
+
+
+ interface IMTE_GetMaxStackSize extends IMultiTileEntity {
+ /** Gets the Max Stacksize of this Item. */
+ byte getMaxStackSize(ItemStack aStack, byte aDefault);
+ }
+
+ interface IMTE_AddToolTips extends IMultiTileEntity {
+ /** Adds ToolTips to the Item. */
+ void addToolTips(List<String> aList, ItemStack aStack, boolean aF3_H);
+ }
+
+}
diff --git a/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java b/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java
new file mode 100644
index 0000000000..41b6a74aef
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java
@@ -0,0 +1,283 @@
+package gregtech.api.multitileentity.machine;
+
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.GT_Values.NBT;
+import gregtech.api.fluid.FluidTankGT;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.multitileentity.MultiTileEntityRegistry;
+import gregtech.api.multitileentity.base.BaseTickableMultiTileEntity;
+import gregtech.api.util.GT_Utility;
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.IFluidTank;
+
+import static com.google.common.primitives.Ints.saturatedCast;
+
+public class MultiTileBasicMachine extends BaseTickableMultiTileEntity {
+ protected int mParallel = 1;
+ protected long mStoredEnergy = 0;
+ protected FluidTankGT[] mTanksInput = GT_Values.emptyFluidTankGT, mTanksOutput = GT_Values.emptyFluidTankGT;
+ protected ItemStack[] mOutputItems = GT_Values.emptyItemStackArray;
+ protected FluidStack[] mOutputFluids = GT_Values.emptyFluidStack;
+
+ protected ItemStack[] mInventory = GT_Values.emptyItemStackArray;
+
+ @Override
+ public String getTileEntityName() {
+ return "gt.multitileentity.machine.basic";
+ }
+
+
+ @Override
+ public void writeMultiTileNBT(NBTTagCompound aNBT) {
+ super.writeMultiTileNBT(aNBT);
+
+ }
+
+ @Override
+ public void readMultiTileNBT(NBTTagCompound aNBT) {
+ super.readMultiTileNBT(aNBT);
+ if (aNBT.hasKey(NBT.PARALLEL)) mParallel = Math.max(1, aNBT.getInteger(NBT.PARALLEL));
+
+ mInventory = getDefaultInventory(aNBT);
+ if(mInventory != null) {
+ final NBTTagList tList = aNBT.getTagList(NBT.INV_LIST, 10);
+ for (int i = 0; i < tList.tagCount(); i++) {
+ final NBTTagCompound tNBT = tList.getCompoundTagAt(i);
+ final int tSlot = tNBT.getShort("s");
+ if (tSlot >= 0 && tSlot < mInventory.length) mInventory[tSlot] = GT_Utility.loadItem(tNBT);
+ }
+ }
+ /* Tanks */
+ long tCapacity = 1000;
+ if (aNBT.hasKey(NBT.TANK_CAPACITY)) tCapacity = saturatedCast(aNBT.getLong(NBT.TANK_CAPACITY));
+
+ mTanksInput = new FluidTankGT[getFluidInputCount()];
+ mTanksOutput = new FluidTankGT[getFluidOutputCount()];
+ mOutputFluids = new FluidStack[getFluidOutputCount()];
+ mOutputItems = new ItemStack[getItemOutputCount()];
+
+ // TODO: See if we need the adjustable map here `.setCapacity(mRecipes, mParallel * 2L)` in place of the `setCapacityMultiplier`
+ for (int i = 0; i < mTanksInput.length; i++) mTanksInput[i] = new FluidTankGT(tCapacity).setCapacityMultiplier(mParallel * 2L).readFromNBT(aNBT, NBT.TANK_IN + i);
+ for (int i = 0; i < mTanksOutput.length; i++) mTanksOutput[i] = new FluidTankGT().readFromNBT(aNBT, NBT.TANK_OUT + i);
+ for (int i = 0; i < mOutputFluids.length; i++) mOutputFluids[i] = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag(NBT.FLUID_OUT + "." + i));
+ for (int i = 0; i < mOutputItems.length; i++) mOutputItems[i] = ItemStack.loadItemStackFromNBT(aNBT.getCompoundTag(NBT.INV_OUT + "." + i));
+
+ }
+
+ /*
+ * Fluids
+ */
+
+
+ /**
+ * The number of fluid (input) slots available for this machine
+ */
+ public int getFluidInputCount() {
+ return 2;
+ }
+
+ /**
+ * The number of fluid (output) slots available for this machine
+ */
+ public int getFluidOutputCount() {
+ return 2;
+ }
+
+ public ItemStack[] getDefaultInventory(NBTTagCompound aNBT) {
+ final int tSize = Math.max(0, aNBT.getShort(NBT.INV_SIZE));
+ return tSize > 0 ? new ItemStack[tSize] : GT_Values.emptyItemStackArray;
+ }
+
+ @Override
+ public ITexture[] getTexture(Block aBlock, byte aSide, boolean isActive, int aRenderPass) {
+ return new ITexture[0];
+ }
+
+ @Override
+ public void setLightValue(byte aLightValue) {
+
+ }
+
+ @Override
+ public String getInventoryName() {
+ final String name = getCustomName();
+ if(name != null) return name;
+ final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(getMultiTileEntityRegistryID());
+ return tRegistry == null ? getClass().getName() : tRegistry.getLocal(getMultiTileEntityID());
+ }
+
+
+ @Override
+ public boolean isUseableByPlayer(EntityPlayer aPlayer) {
+ return playerOwnsThis(aPlayer, false) && mTickTimer > 40 &&
+ getTileEntityOffset(0, 0, 0) == this &&
+ aPlayer.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64 && allowInteraction(aPlayer);
+ }
+
+
+ @Override
+ public boolean isLiquidInput(byte aSide) {
+ return aSide != mFacing;
+ }
+
+ @Override
+ public boolean isLiquidOutput(byte aSide) {
+ return aSide != mFacing;
+ }
+
+
+ @Override
+ protected IFluidTank[] getFluidTanks(byte aSide) {
+ final boolean fluidInput = isLiquidInput(aSide);
+ final boolean fluidOutput = isLiquidOutput(aSide);
+
+ if(fluidInput && fluidOutput) {
+ final IFluidTank[] rTanks = new IFluidTank[ mTanksInput.length + mTanksOutput.length];
+ System.arraycopy(mTanksInput, 0, rTanks, 0, mTanksInput.length);
+ System.arraycopy(mTanksOutput, 0, rTanks, mTanksInput.length, mTanksOutput.length);
+ return rTanks;
+ } else if(fluidInput) {
+ return mTanksInput;
+ } else if(fluidOutput) {
+ return mTanksOutput;
+ }
+ return GT_Values.emptyFluidTank;
+ }
+
+ @Override
+ public IFluidTank getFluidTankFillable(byte aSide, FluidStack aFluidToFill) {
+ if(!isLiquidInput(aSide)) return null;
+ for (FluidTankGT tankGT : mTanksInput) if (tankGT.contains(aFluidToFill)) return tankGT;
+// if (!mRecipes.containsInput(aFluidToFill, this, slot(mRecipes.mInputItemsCount + mRecipes.mOutputItemsCount))) return null;
+ for (FluidTankGT fluidTankGT : mTanksInput) if (fluidTankGT.isEmpty()) return fluidTankGT;
+ return null;
+ }
+
+ @Override
+ protected IFluidTank getFluidTankDrainable(byte aSide, FluidStack aFluidToDrain) {
+ if(!isLiquidOutput(aSide)) return null;
+ for (FluidTankGT fluidTankGT : mTanksOutput)
+ if (aFluidToDrain == null ? fluidTankGT.has() : fluidTankGT.contains(aFluidToDrain))
+ return fluidTankGT;
+
+ return null;
+ }
+
+ /*
+ * Energy
+ */
+
+ @Override
+ public boolean isEnetInput() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnetOutput() {
+ return true;
+ }
+
+ @Override
+ public boolean isUniversalEnergyStored(long aEnergyAmount) {
+ return getUniversalEnergyStored() >= aEnergyAmount;
+ }
+
+ @Override
+ public long getUniversalEnergyStored() {
+ return mStoredEnergy;
+ }
+
+ @Override
+ public long getUniversalEnergyCapacity() {
+ return 0;
+ }
+
+ @Override
+ public long getOutputAmperage() {
+ return 1;
+ }
+
+ @Override
+ public long getOutputVoltage() {
+ return 1;
+ }
+
+ @Override
+ public long getInputAmperage() {
+ return 1;
+ }
+
+ @Override
+ public long getInputVoltage() {
+ return 1;
+ }
+
+
+ public boolean isEnergyInputSide(byte aSide) {
+ return true;
+ }
+
+ public boolean isEnergyOutputSide(byte aSide) {
+ return true;
+ }
+
+ @Override
+ public boolean inputEnergyFrom(byte aSide) {
+ if (aSide == GT_Values.SIDE_UNKNOWN) return true;
+ if (aSide >= 0 && aSide < 6) {
+ if(isInvalid()) return false;
+ if (!getCoverBehaviorAtSideNew(aSide).letsEnergyIn(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this)) return false;
+ if (isEnetInput()) return isEnergyInputSide(aSide);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean outputsEnergyTo(byte aSide) {
+ if (aSide == GT_Values.SIDE_UNKNOWN) return true;
+ if (aSide >= 0 && aSide < 6) {
+ if (isInvalid()) return false;
+ if (!getCoverBehaviorAtSideNew(aSide).letsEnergyOut(aSide, getCoverIDAtSide(aSide), getComplexCoverDataAtSide(aSide), this)) return false;
+ if (isEnetOutput()) return isEnergyOutputSide(aSide);
+ }
+ return false;
+ }
+
+ /*
+ * Inventory
+ */
+
+ @Override public boolean hasInventoryBeenModified() {
+ return mInventoryChanged;
+ }
+
+ @Override
+ public boolean isItemValidForSlot(int aSlot, ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public int getInventoryStackLimit() {
+ return 64;
+ }
+
+ /**
+ * The number of item (input) slots available for this machine
+ */
+ public int getItemInputCount() {
+ return 2;
+ }
+
+ /**
+ * The number of item (output) slots available for this machine
+ */
+ public int getItemOutputCount() {
+ return 2;
+ }
+
+}
diff --git a/src/main/java/gregtech/api/net/GT_Packet_TileEntity.java b/src/main/java/gregtech/api/net/GT_Packet_TileEntity.java
index 051be672ab..970b0ca156 100644
--- a/src/main/java/gregtech/api/net/GT_Packet_TileEntity.java
+++ b/src/main/java/gregtech/api/net/GT_Packet_TileEntity.java
@@ -3,21 +3,23 @@ package gregtech.api.net;
import com.google.common.io.ByteArrayDataInput;
import gregtech.api.metatileentity.BaseMetaPipeEntity;
import gregtech.api.metatileentity.BaseMetaTileEntity;
+import gregtech.api.multitileentity.MultiTileEntityBlock;
import io.netty.buffer.ByteBuf;
+import net.minecraft.block.Block;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
public class GT_Packet_TileEntity extends GT_Packet_New {
private int mX, mZ, mC0, mC1, mC2, mC3, mC4, mC5;
- private short mY, mID;
+ private short mY, mID, mRID;
private byte mTexture, mTexturePage, mUpdate, mRedstone, mColor;
public GT_Packet_TileEntity() {
super(true);
}
- //For tiles
- public GT_Packet_TileEntity(int aX, short aY, int aZ, short aID, int aC0, int aC1, int aC2, int aC3, int aC4, int aC5, byte aTexture, byte aTexturePage, byte aUpdate, byte aRedstone, byte aColor) {
+ // For multi tiles
+ public GT_Packet_TileEntity(int aX, short aY, int aZ, short aRID, short aID, int aC0, int aC1, int aC2, int aC3, int aC4, int aC5, byte aTexture, byte aTexturePage, byte aUpdate, byte aRedstone, byte aColor) {
super(false);
mX = aX;
mY = aY;
@@ -28,6 +30,7 @@ public class GT_Packet_TileEntity extends GT_Packet_New {
mC3 = aC3;
mC4 = aC4;
mC5 = aC5;
+ mRID = aRID;
mID = aID;
mTexture = aTexture;
mTexturePage=aTexturePage;
@@ -36,24 +39,14 @@ public class GT_Packet_TileEntity extends GT_Packet_New {
mColor = aColor;
}
- //For pipes
+ // For meta tiles
+ public GT_Packet_TileEntity(int aX, short aY, int aZ, short aID, int aC0, int aC1, int aC2, int aC3, int aC4, int aC5, byte aTexture, byte aTexturePage, byte aUpdate, byte aRedstone, byte aColor) {
+ this(aX, aY, aZ, (short) 0, aID, aC0, aC1, aC2, aC3, aC4, aC5, aTexture, aTexturePage, aUpdate, aRedstone, aColor);
+ }
+
+ // For pipes
public GT_Packet_TileEntity(int aX, short aY, int aZ, short aID, int aC0, int aC1, int aC2, int aC3, int aC4, int aC5, byte aTexture, byte aUpdate, byte aRedstone, byte aColor) {
- super(false);
- mX = aX;
- mY = aY;
- mZ = aZ;
- mC0 = aC0;
- mC1 = aC1;
- mC2 = aC2;
- mC3 = aC3;
- mC4 = aC4;
- mC5 = aC5;
- mID = aID;
- mTexture = aTexture;
- mTexturePage=0;
- mUpdate = aUpdate;
- mRedstone = aRedstone;
- mColor = aColor;
+ this(aX, aY, aZ, (short) 0, aID, aC0, aC1, aC2, aC3, aC4, aC5, aTexture, (byte) 0, aUpdate, aRedstone, aColor);
}
@Override
@@ -61,6 +54,8 @@ public class GT_Packet_TileEntity extends GT_Packet_New {
aOut.writeInt(mX);
aOut.writeShort(mY);
aOut.writeInt(mZ);
+
+ aOut.writeShort(mRID);
aOut.writeShort(mID);
aOut.writeInt(mC0);
@@ -79,18 +74,29 @@ public class GT_Packet_TileEntity extends GT_Packet_New {
@Override
public GT_Packet_New decode(ByteArrayDataInput aData) {
- return new GT_Packet_TileEntity(aData.readInt(), aData.readShort(), aData.readInt(), aData.readShort(), aData.readInt(), aData.readInt(), aData.readInt(), aData.readInt(), aData.readInt(), aData.readInt(), aData.readByte(), aData.readByte(), aData.readByte(), aData.readByte(), aData.readByte());
+ return new GT_Packet_TileEntity(
+ // Coords
+ aData.readInt(), aData.readShort(), aData.readInt(),
+ // Registry & ID
+ aData.readShort(), aData.readShort(),
+ // Covers
+ aData.readInt(), aData.readInt(), aData.readInt(), aData.readInt(), aData.readInt(), aData.readInt(),
+ // Everything else
+ aData.readByte(), aData.readByte(), aData.readByte(), aData.readByte(), aData.readByte()
+ );
}
@Override
public void process(IBlockAccess aWorld) {
if (aWorld != null) {
- TileEntity tTileEntity = aWorld.getTileEntity(mX, mY, mZ);
- if (tTileEntity != null) {
- if (tTileEntity instanceof BaseMetaTileEntity)
- ((BaseMetaTileEntity) tTileEntity).receiveMetaTileEntityData(mID, mC0, mC1, mC2, mC3, mC4, mC5, mTexture, mTexturePage, mUpdate, mRedstone, mColor);
- else if (tTileEntity instanceof BaseMetaPipeEntity)
- ((BaseMetaPipeEntity) tTileEntity).receiveMetaTileEntityData(mID, mC0, mC1, mC2, mC3, mC4, mC5, mTexture, mUpdate, mRedstone, mColor);
+ final TileEntity tTileEntity = aWorld.getTileEntity(mX, mY, mZ);
+ final Block tBlock;
+ if (tTileEntity instanceof BaseMetaTileEntity)
+ ((BaseMetaTileEntity) tTileEntity).receiveMetaTileEntityData(mID, mC0, mC1, mC2, mC3, mC4, mC5, mTexture, mTexturePage, mUpdate, mRedstone, mColor);
+ else if (tTileEntity instanceof BaseMetaPipeEntity)
+ ((BaseMetaPipeEntity) tTileEntity).receiveMetaTileEntityData(mID, mC0, mC1, mC2, mC3, mC4, mC5, mTexture, mUpdate, mRedstone, mColor);
+ else if ((tBlock = aWorld.getBlock(mX, mY, mZ)) instanceof MultiTileEntityBlock) {
+ ((MultiTileEntityBlock)tBlock).receiveMultiTileEntityData(aWorld, mX, mY, mZ, mRID, mID, mC0, mC1, mC2, mC3, mC4, mC5, mTexture, mTexturePage, mUpdate, mRedstone, mColor);
}
}
}
diff --git a/src/main/java/gregtech/api/util/GT_Util.java b/src/main/java/gregtech/api/util/GT_Util.java
new file mode 100644
index 0000000000..1079da6c26
--- /dev/null
+++ b/src/main/java/gregtech/api/util/GT_Util.java
@@ -0,0 +1,152 @@
+package gregtech.api.util;
+
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.ChunkCoordinates;
+import net.minecraft.util.Tuple;
+import net.minecraft.world.World;
+import net.minecraft.world.chunk.Chunk;
+
+public class GT_Util {
+ // Last broken tile entity
+ public static final ThreadLocal<TileEntity> LAST_BROKEN_TILEENTITY = new ThreadLocal<>();
+
+ public static Tuple tuple(String key, Object value) {
+ return new Tuple(key, value);
+ }
+
+ public static NBTTagCompound fuseNBT(NBTTagCompound aNBT1, NBTTagCompound aNBT2) {
+ if (aNBT1 == null) return aNBT2 == null ? new NBTTagCompound() : (NBTTagCompound)aNBT2.copy();
+ NBTTagCompound rNBT = (NBTTagCompound)aNBT1.copy();
+ if (aNBT2 == null) return rNBT;
+ for (Object tKey : aNBT2.func_150296_c/*getKeySet*/()) if (!rNBT.hasKey(tKey.toString())) rNBT.setTag(tKey.toString(), aNBT2.getTag(tKey.toString()));
+ return rNBT;
+ }
+
+ /**
+ * Construct a NBTTagCompound from a series of key, value pairs. Inspired from GT6.
+ */
+ public static NBTTagCompound makeNBT(Tuple... aTags) {
+ final NBTTagCompound rNBT = new NBTTagCompound();
+ for(Tuple t : aTags) {
+ if (t.getSecond() == null) continue;
+
+ if (t.getSecond() instanceof Boolean)
+ rNBT.setBoolean(t.getFirst().toString(), (Boolean) t.getSecond());
+ else if (t.getSecond() instanceof Byte)
+ rNBT.setByte(t.getFirst().toString(), (Byte) t.getSecond());
+ else if (t.getSecond() instanceof Short)
+ rNBT.setShort(t.getFirst().toString(), (Short) t.getSecond());
+ else if (t.getSecond() instanceof Integer)
+ rNBT.setInteger(t.getFirst().toString(), (Integer) t.getSecond());
+ else if (t.getSecond() instanceof Long)
+ rNBT.setLong(t.getFirst().toString(), (Long) t.getSecond());
+ else if (t.getSecond() instanceof Float)
+ rNBT.setFloat(t.getFirst().toString(), (Float) t.getSecond());
+ else if (t.getSecond() instanceof Double)
+ rNBT.setDouble(t.getFirst().toString(), (Double) t.getSecond());
+ else if (t.getSecond() instanceof String)
+ rNBT.setString(t.getFirst().toString(), (String) t.getSecond());
+ else if (t.getSecond() instanceof NBTBase)
+ rNBT.setTag(t.getFirst().toString(), (NBTBase) t.getSecond());
+ else
+ rNBT.setString(t.getFirst().toString(), t.getSecond().toString());
+ }
+
+ return rNBT;
+ }
+
+ /**
+ * Get a TileEntity
+ */
+ public static TileEntity getTileEntity(World aWorld, int aX, int aY, int aZ, boolean aLoadUnloadedChunks) {
+ if (aLoadUnloadedChunks || aWorld.blockExists(aX, aY, aZ)) {
+ TileEntity rTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (rTileEntity instanceof IMultiTileEntity && ((IMultiTileEntity)rTileEntity).isDead()) return null;
+ if (rTileEntity != null) return rTileEntity;
+ rTileEntity = LAST_BROKEN_TILEENTITY.get();
+ if (rTileEntity != null && rTileEntity.xCoord == aX && rTileEntity.yCoord == aY && rTileEntity.zCoord == aZ) return rTileEntity;
+ }
+ return null;
+ }
+
+ /** Sets the TileEntity at the passed position, with the option of turning adjacent TileEntity updates off. */
+ public static TileEntity setTileEntity(World aWorld, int aX, int aY, int aZ, TileEntity aTileEntity, boolean aCauseTileEntityUpdates) {
+ if (aCauseTileEntityUpdates) aWorld.setTileEntity(aX, aY, aZ, aTileEntity); else {
+ Chunk tChunk = aWorld.getChunkFromChunkCoords(aX >> 4, aZ >> 4);
+ if (tChunk != null) {
+ aWorld.addTileEntity(aTileEntity);
+ tChunk.func_150812_a/*setBlockTileEntityInChunk*/(aX & 15, aY, aZ & 15, aTileEntity);
+ tChunk.setChunkModified();
+ }
+ }
+ return aTileEntity;
+ }
+
+ public static boolean setTileEntity(World aWorld, int aX, int aY, int aZ, Block aBlock, short aMeta, long aFlags, boolean aRemoveGrassBelow) {
+ if (aRemoveGrassBelow) {
+ final Block tBlock = aWorld.getBlock(aX, aY-1, aZ);
+ if (tBlock == Blocks.grass || tBlock == Blocks.mycelium) aWorld.setBlock(aX, aY-1, aZ, Blocks.dirt, 0, (byte)aFlags);
+ }
+ return aWorld.setBlock(aX, aY, aZ, aBlock, aMeta, (byte)aFlags);
+ }
+
+
+ public static TileEntity getTileEntity (World aWorld, ChunkCoordinates aCoords, boolean aLoadUnloadedChunks) {
+ return getTileEntity(aWorld, aCoords.posX, aCoords.posY, aCoords.posZ, aLoadUnloadedChunks);
+ }
+
+ /** Marks a Chunk dirty so it is saved */
+ public static boolean markChunkDirty(World aWorld, int aX, int aZ) {
+ if (aWorld == null || aWorld.isRemote) return false;
+ Chunk aChunk = aWorld.getChunkFromBlockCoords(aX, aZ);
+ if (aChunk == null) {
+ aWorld.getBlockMetadata(aX, 0, aZ);
+ aChunk = aWorld.getChunkFromBlockCoords(aX, aZ);
+ if (aChunk == null) {
+ GT_Log.err.println("Some important Chunk does not exist for some reason at Coordinates X: " + aX + " and Z: " + aZ);
+ return false;
+ }
+ }
+ aChunk.setChunkModified();
+ return true;
+ }
+ /** Marks a Chunk dirty so it is saved */
+ public static boolean markChunkDirty(Object aTileEntity) {
+ return aTileEntity instanceof TileEntity && markChunkDirty(((TileEntity)aTileEntity).getWorldObj(), ((TileEntity)aTileEntity).xCoord, ((TileEntity)aTileEntity).zCoord);
+ }
+
+ public static int mixRGBInt(int aRGB1, int aRGB2) {
+ return getRGBInt(new short[] {(short)((getR(aRGB1) + getR(aRGB2)) >> 1), (short)((getG(aRGB1) + getG(aRGB2)) >> 1), (short)((getB(aRGB1) + getB(aRGB2)) >> 1)});
+ }
+
+ public static int getRGBInt(short[] aColors) {
+ return aColors == null ? 16777215 : (aColors[0] << 16) | (aColors[1] << 8) | aColors[2];
+ }
+
+ public static int getRGBaInt(short[] aColors) {
+ return aColors == null ? 16777215 : (aColors[0]) << 16 | (aColors[1] << 8) | aColors[2] | (aColors[3] << 24);
+ }
+
+ public static int getRGBInt(short aR, short aG, short aB) {
+ return (aR << 16) | (aG << 8) | aB;
+ }
+
+ public static int getRGBaInt(short aR, short aG, short aB, short aA) {
+ return (aR << 16) | (aG << 8) | aB | (aA << 24);
+ }
+
+ public static short[] getRGBaArray(int aColors) {
+ return new short[] {(short)((aColors >>> 16) & 255), (short)((aColors >>> 8) & 255), (short)(aColors & 255), (short)((aColors >>> 24) & 255)};
+ }
+
+ public static short getR(int aColors) {return (short)((aColors >>> 16) & 255);}
+ public static short getG(int aColors) {return (short)((aColors >>> 8) & 255);}
+ public static short getB(int aColors) {return (short) (aColors & 255);}
+ public static short getA(int aColors) {return (short)((aColors >>> 24) & 255);}
+
+}
diff --git a/src/main/java/gregtech/common/GT_Proxy.java b/src/main/java/gregtech/common/GT_Proxy.java
index e4f3051b02..e56697fae0 100644
--- a/src/main/java/gregtech/common/GT_Proxy.java
+++ b/src/main/java/gregtech/common/GT_Proxy.java
@@ -1,6 +1,10 @@
package gregtech.common;
-import cpw.mods.fml.common.*;
+import cpw.mods.fml.common.FMLCommonHandler;
+import cpw.mods.fml.common.IFuelHandler;
+import cpw.mods.fml.common.Loader;
+import cpw.mods.fml.common.ModContainer;
+import cpw.mods.fml.common.ProgressManager;
import cpw.mods.fml.common.eventhandler.Event.Result;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
@@ -11,8 +15,16 @@ import cpw.mods.fml.common.registry.GameRegistry;
import forestry.api.genetics.AlleleManager;
import gregtech.GT_Mod;
import gregtech.api.GregTech_API;
-import gregtech.api.enums.*;
+import gregtech.api.enums.ConfigCategories;
+import gregtech.api.enums.Dyes;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.ItemList;
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.OreDictNames;
+import gregtech.api.enums.OrePrefixes;
+import gregtech.api.enums.SubTag;
import gregtech.api.enums.TC_Aspects.TC_AspectStack;
+import gregtech.api.enums.ToolDictNames;
import gregtech.api.interfaces.IBlockOnWalkOver;
import gregtech.api.interfaces.IProjectileItem;
import gregtech.api.interfaces.internal.IGT_Mod;
@@ -21,8 +33,27 @@ import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
import gregtech.api.items.GT_MetaGenerated_Item;
import gregtech.api.items.GT_MetaGenerated_Tool;
-import gregtech.api.objects.*;
-import gregtech.api.util.*;
+import gregtech.api.objects.GT_ChunkManager;
+import gregtech.api.objects.GT_Fluid;
+import gregtech.api.objects.GT_FluidStack;
+import gregtech.api.objects.GT_ItemStack;
+import gregtech.api.objects.GT_UO_DimensionList;
+import gregtech.api.objects.ItemData;
+import gregtech.api.util.GT_BlockMap;
+import gregtech.api.util.GT_CLS_Compat;
+import gregtech.api.util.GT_ChunkAssociatedData;
+import gregtech.api.util.GT_ClientPreference;
+import gregtech.api.util.GT_CoverBehaviorBase;
+import gregtech.api.util.GT_LanguageManager;
+import gregtech.api.util.GT_Log;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_OreDictUnificator;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_RecipeRegistrator;
+import gregtech.api.util.GT_Shaped_Recipe;
+import gregtech.api.util.GT_Shapeless_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.api.util.WorldSpawnedEventBuilder;
import gregtech.common.entities.GT_Entity_Arrow;
import gregtech.common.gui.GT_ContainerVolumetricFlask;
import gregtech.common.gui.GT_GUIContainerVolumetricFlask;
@@ -54,16 +85,22 @@ import net.minecraft.util.MathHelper;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.World;
import net.minecraft.world.WorldSettings.GameType;
+import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.feature.WorldGenMinable;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.EnderTeleportEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
-import net.minecraftforge.event.entity.player.*;
+import net.minecraftforge.event.entity.player.ArrowLooseEvent;
+import net.minecraftforge.event.entity.player.ArrowNockEvent;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.event.entity.player.PlayerEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.terraingen.OreGenEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.ChunkDataEvent;
+import net.minecraftforge.event.world.ChunkWatchEvent;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
@@ -77,13 +114,33 @@ import org.apache.commons.lang3.text.WordUtils;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
-import static gregtech.api.enums.GT_Values.*;
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+import static gregtech.api.enums.GT_Values.MOD_ID_RC;
+import static gregtech.api.enums.GT_Values.MOD_ID_TC;
+import static gregtech.api.enums.GT_Values.MOD_ID_TE;
+import static gregtech.api.enums.GT_Values.MOD_ID_TF;
+import static gregtech.api.enums.GT_Values.W;
+import static gregtech.api.enums.GT_Values.debugEntityCramming;
+import static gregtech.api.util.GT_Util.LAST_BROKEN_TILEENTITY;
public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler {
@@ -1435,6 +1492,7 @@ public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler {
}
}
+ @SuppressWarnings("deprecated")
public static void stepMaterialsVanilla(Collection<GT_Proxy.OreDictEventContainer> mEvents, ProgressManager.ProgressBar progressBar){
int size = 5;
int sizeStep = mEvents.size() / 20 - 1;
@@ -1443,7 +1501,7 @@ public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler {
tEvent = i$.next();
sizeStep--;
if(sizeStep == 0) {
- GT_Mod.GT_FML_LOGGER.info("Baking : " + size + "%", new Object[0]);
+ GT_FML_LOGGER.info("Baking : " + size + "%", new Object[0]);
sizeStep = mEvents.size()/20-1;
size += 5;
}
@@ -1476,9 +1534,14 @@ public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler {
if (aEvent.side.isServer()) {
if (aEvent.phase == TickEvent.Phase.START) {
TICK_LOCK.lock();
+
} else {
TICK_LOCK.unlock();
}
+
+ // Making sure it is being freed up in order to prevent exploits or Garbage Collection mishaps.
+ LAST_BROKEN_TILEENTITY.set(null);
+
}
}
@@ -1491,7 +1554,7 @@ public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler {
for (Runnable runnable : GregTech_API.sFirstWorldTick)
runnable.run();
isFirstWorldTick = false;
- worldTickHappened = true;
+ GT_Values.worldTickHappened = true;
}
if (aEvent.side.isServer()) {
if (this.mUniverse == null) {
@@ -2084,7 +2147,7 @@ public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler {
try {
GT_CLS_Compat.stepMaterialsCLS(mEvents, progressBar);
} catch (IllegalAccessException | InvocationTargetException e) {
- GT_Mod.GT_FML_LOGGER.catching(e);
+ GT_FML_LOGGER.catching(e);
}
}
else
diff --git a/src/main/java/gregtech/common/render/GT_Renderer_Block.java b/src/main/java/gregtech/common/render/GT_Renderer_Block.java
index e09130acb4..ef8748064f 100644
--- a/src/main/java/gregtech/common/render/GT_Renderer_Block.java
+++ b/src/main/java/gregtech/common/render/GT_Renderer_Block.java
@@ -21,12 +21,20 @@ import net.minecraft.client.particle.EffectRenderer;
import net.minecraft.client.particle.EntityDiggingFX;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import org.lwjgl.opengl.GL11;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static gregtech.api.enums.GT_Values.ALL_VALID_SIDES;
+import static gregtech.api.enums.GT_Values.OFFX;
+import static gregtech.api.enums.GT_Values.OFFY;
+import static gregtech.api.enums.GT_Values.OFFZ;
import static gregtech.api.interfaces.metatileentity.IConnectable.CONNECTED_DOWN;
import static gregtech.api.interfaces.metatileentity.IConnectable.CONNECTED_EAST;
import static gregtech.api.interfaces.metatileentity.IConnectable.CONNECTED_NORTH;
@@ -60,7 +68,7 @@ public class GT_Renderer_Block implements ISimpleBlockRenderingHandler {
}
public static boolean renderStandardBlock(IBlockAccess aWorld, int aX, int aY, int aZ, Block aBlock, RenderBlocks aRenderer) {
- TileEntity tTileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ final TileEntity tTileEntity = aWorld.getTileEntity(aX, aY, aZ);
if ((tTileEntity instanceof IPipeRenderedTileEntity)) {
return renderStandardBlock(aWorld, aX, aY, aZ, aBlock, aRenderer, new ITexture[][]{
((IPipeRenderedTileEntity) tTileEntity).getTextureCovered((byte) DOWN.ordinal()),
@@ -77,7 +85,8 @@ public class GT_Renderer_Block implements ISimpleBlockRenderingHandler {
((ITexturedTileEntity) tTileEntity).getTexture(aBlock, (byte) NORTH.ordinal()),
((ITexturedTileEntity) tTileEntity).getTexture(aBlock, (byte) SOUTH.ordinal()),
((ITexturedTileEntity) tTileEntity).getTexture(aBlock, (byte) WEST.ordinal()),
- ((ITexturedTileEntity) tTileEntity).getTexture(aBlock, (byte) EAST.ordinal())});
+ ((ITexturedTileEntity) tTileEntity).getTexture(aBlock, (byte) EAST.ordinal())}
+ );
}
return false;
}
@@ -454,7 +463,7 @@ public class GT_Renderer_Block implements ISimpleBlockRenderingHandler {
return true;
}
-
+
@SideOnly(Side.CLIENT)
public static void addHitEffects(EffectRenderer effectRenderer, Block block, World world, int x, int y, int z, int side) {
double rX = x + XSTR.XSTR_INSTANCE.nextDouble() * 0.8 + 0.1;
@@ -481,9 +490,9 @@ public class GT_Renderer_Block implements ISimpleBlockRenderingHandler {
for (int iX = 0; iX < 4; ++iX) {
for (int iY = 0; iY < 4; ++iY) {
for (int iZ = 0; iZ < 4; ++iZ) {
- double bX = x + (iX + 0.5) / 4.0;
- double bY = y + (iY + 0.5) / 4.0;
- double bZ = z + (iZ + 0.5) / 4.0;
+ final double bX = x + (iX + 0.5) / 4.0;
+ final double bY = y + (iY + 0.5) / 4.0;
+ final double bZ = z + (iZ + 0.5) / 4.0;
effectRenderer.addEffect((new EntityDiggingFX(world, bX, bY, bZ, bX - x - 0.5, bY - y - 0.5, bZ - z - 0.5, block, block.getDamageValue(world, x, y, z))).applyColourMultiplier(x, y, z));
}
}
@@ -497,28 +506,58 @@ public class GT_Renderer_Block implements ISimpleBlockRenderingHandler {
GL11.glRotatef(90.0F, 0.0F, 1.0F, 0.0F);
GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
+ if(aBlock instanceof IRenderedBlock) {
+ boolean tNeedsToSetBounds = true;
+ final ItemStack aStack = new ItemStack(aBlock, 1, aMeta);
+ IRenderedBlock tRenderer = ((IRenderedBlock)aBlock).passRenderingToObject(aStack);
+ if (tRenderer != null) tRenderer = tRenderer.passRenderingToObject(aStack);
+ if (tRenderer == null)
+ tRenderer = IRenderedBlock.ErrorRenderer.INSTANCE;
+ for (int i = 0, j = tRenderer.getRenderPasses(aBlock); i < j; i++) {
+ if (tRenderer.usesRenderPass(i)) {
+ if (tRenderer.setBlockBounds(aBlock, i)) {
+ tNeedsToSetBounds = true;
+ aRenderer.setRenderBoundsFromBlock(aBlock);
+ } else {
+ if (tNeedsToSetBounds) aBlock.setBlockBoundsForItemRender();
+ aRenderer.setRenderBoundsFromBlock(aBlock);
+ tNeedsToSetBounds = false;
+ }
+
+ renderNegativeYFacing(null, aRenderer, aBlock, 0, 0, 0, tRenderer.getTexture(aBlock, (byte) DOWN.ordinal(), true, i), !tNeedsToSetBounds);
+ renderPositiveYFacing(null, aRenderer, aBlock, 0, 0, 0, tRenderer.getTexture(aBlock, (byte) UP.ordinal(), true, i), !tNeedsToSetBounds);
+ renderNegativeZFacing(null, aRenderer, aBlock, 0, 0, 0, tRenderer.getTexture(aBlock, (byte) NORTH.ordinal(), true, i), !tNeedsToSetBounds);
+ renderPositiveZFacing(null, aRenderer, aBlock, 0, 0, 0, tRenderer.getTexture(aBlock, (byte) SOUTH.ordinal(), true, i), !tNeedsToSetBounds);
+ renderNegativeXFacing(null, aRenderer, aBlock, 0, 0, 0, tRenderer.getTexture(aBlock, (byte) WEST.ordinal(), true, i), !tNeedsToSetBounds);
+ renderPositiveXFacing(null, aRenderer, aBlock, 0, 0, 0, tRenderer.getTexture(aBlock, (byte) EAST.ordinal(), true, i), !tNeedsToSetBounds);
+ }
+ }
+ if (tNeedsToSetBounds) aBlock.setBlockBounds(0, 0, 0, 1, 1, 1);
- if (aBlock instanceof GT_Block_Ores_Abstract) {
- GT_TileEntity_Ores tTileEntity = new GT_TileEntity_Ores();
- tTileEntity.mMetaData = ((short) aMeta);
+ } else {
+ if (aBlock instanceof GT_Block_Ores_Abstract) {
+ final GT_TileEntity_Ores tTileEntity = new GT_TileEntity_Ores();
+ tTileEntity.mMetaData = ((short) aMeta);
- aBlock.setBlockBoundsForItemRender();
- aRenderer.setRenderBoundsFromBlock(aBlock);
- renderNegativeYFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) DOWN.ordinal()), true);
- renderPositiveYFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) UP.ordinal()), true);
- renderNegativeZFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) NORTH.ordinal()), true);
- renderPositiveZFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) SOUTH.ordinal()), true);
- renderNegativeXFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) WEST.ordinal()), true);
- renderPositiveXFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) EAST.ordinal()), true);
-
- } else if (aMeta > 0
+ aBlock.setBlockBoundsForItemRender();
+ aRenderer.setRenderBoundsFromBlock(aBlock);
+ renderNegativeYFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) DOWN.ordinal()), true);
+ renderPositiveYFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) UP.ordinal()), true);
+ renderNegativeZFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) NORTH.ordinal()), true);
+ renderPositiveZFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) SOUTH.ordinal()), true);
+ renderNegativeXFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) WEST.ordinal()), true);
+ renderPositiveXFacing(null, aRenderer, aBlock, 0, 0, 0, tTileEntity.getTexture(aBlock, (byte) EAST.ordinal()), true);
+ } else if (aMeta > 0
&& (aMeta < GregTech_API.METATILEENTITIES.length)
&& aBlock instanceof GT_Block_Machines
&& (GregTech_API.METATILEENTITIES[aMeta] != null)
- && (!GregTech_API.METATILEENTITIES[aMeta].renderInInventory(aBlock, aMeta, aRenderer))) {
- renderNormalInventoryMetaTileEntity(aBlock, aMeta, aRenderer);
+ && (!GregTech_API.METATILEENTITIES[aMeta].renderInInventory(aBlock, aMeta, aRenderer)))
+ {
+ renderNormalInventoryMetaTileEntity(aBlock, aMeta, aRenderer);
+ }
+ aBlock.setBlockBounds(blockMin, blockMin, blockMin, blockMax, blockMax, blockMax);
}
- aBlock.setBlockBounds(blockMin, blockMin, blockMin, blockMax, blockMax, blockMax);
+
aRenderer.setRenderBoundsFromBlock(aBlock);
GL11.glTranslatef(0.5F, 0.5F, 0.5F);
@@ -529,7 +568,7 @@ public class GT_Renderer_Block implements ISimpleBlockRenderingHandler {
if ((aMeta <= 0) || (aMeta >= GregTech_API.METATILEENTITIES.length)) {
return;
}
- IMetaTileEntity tMetaTileEntity = GregTech_API.METATILEENTITIES[aMeta];
+ final IMetaTileEntity tMetaTileEntity = GregTech_API.METATILEENTITIES[aMeta];
if (tMetaTileEntity == null) {
return;
}
@@ -643,18 +682,55 @@ public class GT_Renderer_Block implements ISimpleBlockRenderingHandler {
public boolean renderWorldBlock(IBlockAccess aWorld, int aX, int aY, int aZ, Block aBlock, int aModelID, RenderBlocks aRenderer) {
aRenderer.enableAO = Minecraft.isAmbientOcclusionEnabled() && GT_Mod.gregtechproxy.mRenderTileAmbientOcclusion;
aRenderer.useInventoryTint = false;
- TileEntity tileEntity = aWorld.getTileEntity(aX, aY, aZ);
+ if (aBlock instanceof IRenderedBlock) {
+ IRenderedBlock tRenderer = ((IRenderedBlock)aBlock).passRenderingToObject(aWorld, aX, aY, aZ);
+ if (tRenderer != null) tRenderer = tRenderer.passRenderingToObject(aWorld, aX, aY, aZ);
+ if (tRenderer == null) tRenderer = IRenderedBlock.ErrorRenderer.INSTANCE;
+ boolean tNeedsToSetBounds = true;
+ boolean rReturn = false;
+ if (tRenderer.renderBlock(aBlock, aRenderer, aWorld, aX, aY, aZ)) {
+ rReturn = true;
+ } else {
+ final boolean[] tSides = new boolean[6];
+ if (tRenderer instanceof IRenderedBlockSideCheck) {
+ for (byte tSide : ALL_VALID_SIDES) rReturn |= (tSides[tSide] = ((IRenderedBlockSideCheck)tRenderer).renderFullBlockSide(aBlock, aRenderer, tSide));
+ } else {
+ for (byte tSide : ALL_VALID_SIDES) rReturn |= (tSides[tSide] = aBlock.shouldSideBeRendered(aWorld, aX+OFFX[tSide], aY+OFFY[tSide], aZ+OFFZ[tSide], tSide));
+ }
+ for (int i = 0, j = tRenderer.getRenderPasses(aBlock); i < j; i++) {
+ if (tRenderer.usesRenderPass(i)) {
+ if (tRenderer.setBlockBounds(aBlock, i)) {
+ tNeedsToSetBounds = true;
+ aRenderer.setRenderBoundsFromBlock(aBlock);
+ } else {
+ if (tNeedsToSetBounds) aBlock.setBlockBounds(0, 0, 0, 1, 1, 1);
+ aRenderer.setRenderBoundsFromBlock(aBlock);
+ tNeedsToSetBounds = false;
+ }
+ renderNegativeYFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, tRenderer.getTexture(aBlock, (byte) DOWN.ordinal(), i, tSides), tSides[DOWN.ordinal()]);
+ renderPositiveYFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, tRenderer.getTexture(aBlock, (byte) UP.ordinal(), i, tSides), tSides[UP.ordinal()]);
+ renderNegativeZFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, tRenderer.getTexture(aBlock, (byte) NORTH.ordinal(), i, tSides), tSides[NORTH.ordinal()]);
+ renderPositiveZFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, tRenderer.getTexture(aBlock, (byte) SOUTH.ordinal(), i, tSides), tSides[SOUTH.ordinal()]);
+ renderNegativeXFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, tRenderer.getTexture(aBlock, (byte) WEST.ordinal(), i, tSides), tSides[WEST.ordinal()]);
+ renderPositiveXFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, tRenderer.getTexture(aBlock, (byte) EAST.ordinal(), i, tSides), tSides[EAST.ordinal()]);
+ }
+ }
+ if (tNeedsToSetBounds) aBlock.setBlockBounds(0, 0, 0, 1, 1, 1);
+ }
+
+ return rReturn;
+ }
+
+ final TileEntity tileEntity = aWorld.getTileEntity(aX, aY, aZ);
if (tileEntity == null) return false;
if (tileEntity instanceof IGregTechTileEntity) {
- IMetaTileEntity metaTileEntity;
- if ((metaTileEntity = ((IGregTechTileEntity) tileEntity).getMetaTileEntity()) != null &&
- metaTileEntity.renderInWorld(aWorld, aX, aY, aZ, aBlock, aRenderer)) {
+ final IMetaTileEntity metaTileEntity;
+ if ((metaTileEntity = ((IGregTechTileEntity) tileEntity).getMetaTileEntity()) != null && metaTileEntity.renderInWorld(aWorld, aX, aY, aZ, aBlock, aRenderer)) {
aRenderer.enableAO = false;
return true;
}
}
- if (tileEntity instanceof IPipeRenderedTileEntity &&
- renderPipeBlock(aWorld, aX, aY, aZ, aBlock, (IPipeRenderedTileEntity) tileEntity, aRenderer)) {
+ if (tileEntity instanceof IPipeRenderedTileEntity && renderPipeBlock(aWorld, aX, aY, aZ, aBlock, (IPipeRenderedTileEntity) tileEntity, aRenderer)) {
aRenderer.enableAO = false;
return true;
}
diff --git a/src/main/java/gregtech/common/render/IRenderedBlock.java b/src/main/java/gregtech/common/render/IRenderedBlock.java
new file mode 100644
index 0000000000..6d2ba999d5
--- /dev/null
+++ b/src/main/java/gregtech/common/render/IRenderedBlock.java
@@ -0,0 +1,72 @@
+package gregtech.common.render;
+
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import gregtech.api.enums.Textures;
+import gregtech.api.interfaces.ITexture;
+import net.minecraft.block.Block;
+import net.minecraft.client.renderer.RenderBlocks;
+import net.minecraft.item.ItemStack;
+import net.minecraft.world.IBlockAccess;
+
+public interface IRenderedBlock {
+ /** @return the Textures to be rendered */
+ @SideOnly(Side.CLIENT)
+ ITexture[] getTexture(Block aBlock, byte aSide, int aRenderPass, boolean[] aShouldSideBeRendered);
+
+ @SideOnly(Side.CLIENT)
+ ITexture[] getTexture(Block aBlock, byte aSide, boolean isActive, int aRenderPass);
+
+ /** gets the Amount of Render Passes for this TileEntity or similar Handler. Only gets called once per Rendering. */
+ @SideOnly(Side.CLIENT)
+ int getRenderPasses(Block aBlock);
+
+ /** if this uses said Render Pass or if it can be skipped entirely. */
+ @SideOnly(Side.CLIENT)
+ boolean usesRenderPass(int aRenderPass);
+
+ /** sets the Block Size rendered; return false for letting it select the normal Block Bounds. */
+ @SideOnly(Side.CLIENT)
+ boolean setBlockBounds(Block aBlock, int aRenderPass);
+
+ /** returning true stops all the other Rendering from happening. */
+ @SideOnly(Side.CLIENT)
+ default boolean renderItem(Block aBlock, RenderBlocks aRenderer) { return false; }
+
+ /** returning true stops all the other Rendering from happening. */
+ @SideOnly(Side.CLIENT)
+ default boolean renderBlock(Block aBlock, RenderBlocks aRenderer, IBlockAccess aWorld, int aX, int aY, int aZ) { return false; }
+
+ /** if this Block lets the TileEntity or a similar Handler do all the Inventory Render work. */
+ @SideOnly(Side.CLIENT)
+ IRenderedBlock passRenderingToObject(ItemStack aStack);
+
+ /** if this Block lets the TileEntity or a similar Handler do all the World Render work. */
+ @SideOnly(Side.CLIENT)
+ IRenderedBlock passRenderingToObject(IBlockAccess aWorld, int aX, int aY, int aZ);
+
+ class ErrorRenderer implements IRenderedBlockSideCheck, IRenderedBlock {
+ public static final ErrorRenderer INSTANCE = new ErrorRenderer();
+ public ITexture[] mErrorTexture = Textures.BlockIcons.ERROR_RENDERING;
+ @Override public ITexture[] getTexture(Block aBlock, byte aSide, int aRenderPass, boolean[] aShouldSideBeRendered) {return mErrorTexture;}
+ @Override public ITexture[] getTexture(Block aBlock, byte aSide, boolean isActive, int aRenderPass) {return mErrorTexture;}
+ @Override public int getRenderPasses(Block aBlock) {return 1;}
+ @Override public boolean usesRenderPass(int aRenderPass) {return true;}
+ @Override public boolean setBlockBounds(Block aBlock, int aRenderPass) {aBlock.setBlockBounds(-0.25F, -0.25F, -0.25F, 1.25F, 1.25F, 1.25F); return true;}
+ @Override public boolean renderFullBlockSide(Block aBlock, RenderBlocks aRenderer, byte aSide) {return true;}
+ @Override public IRenderedBlock passRenderingToObject(ItemStack aStack) {return this;}
+ @Override public IRenderedBlock passRenderingToObject(IBlockAccess aWorld, int aX, int aY, int aZ) {return this;}
+
+ @Override
+ public boolean renderBlock(Block aBlock, RenderBlocks aRenderer, IBlockAccess aWorld, int aX, int aY, int aZ) {
+ aBlock.setBlockBounds(-0.25F, -0.25F, -0.25F, 1.25F, 1.25F, 1.25F);
+ GT_Renderer_Block.renderNegativeYFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, mErrorTexture, false);
+ GT_Renderer_Block.renderPositiveYFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, mErrorTexture, false);
+ GT_Renderer_Block.renderNegativeZFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, mErrorTexture, false);
+ GT_Renderer_Block.renderPositiveZFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, mErrorTexture, false);
+ GT_Renderer_Block.renderNegativeXFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, mErrorTexture, false);
+ GT_Renderer_Block.renderPositiveXFacing(aWorld, aRenderer, aBlock, aX, aY, aZ, mErrorTexture, false);
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/gregtech/common/render/IRenderedBlockSideCheck.java b/src/main/java/gregtech/common/render/IRenderedBlockSideCheck.java
new file mode 100644
index 0000000000..ef0c469f04
--- /dev/null
+++ b/src/main/java/gregtech/common/render/IRenderedBlockSideCheck.java
@@ -0,0 +1,12 @@
+package gregtech.common.render;
+
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import net.minecraft.block.Block;
+import net.minecraft.client.renderer.RenderBlocks;
+
+public interface IRenderedBlockSideCheck {
+ /** returning false stops all the other Rendering from happening on that Side. */
+ @SideOnly(Side.CLIENT)
+ boolean renderFullBlockSide(Block aBlock, RenderBlocks aRenderer, byte aSide);
+}
diff --git a/src/main/java/gregtech/crossmod/Waila.java b/src/main/java/gregtech/crossmod/Waila.java
index c8bdb1b275..2fb2c1c61b 100644
--- a/src/main/java/gregtech/crossmod/Waila.java
+++ b/src/main/java/gregtech/crossmod/Waila.java
@@ -3,6 +3,7 @@ package gregtech.crossmod;
import cpw.mods.fml.common.event.FMLInterModComms;
import gregtech.api.metatileentity.BaseMetaPipeEntity;
import gregtech.api.metatileentity.BaseMetaTileEntity;
+import gregtech.api.multitileentity.base.BaseMultiTileEntity;
import mcp.mobius.waila.api.IWailaDataProvider;
import mcp.mobius.waila.api.IWailaRegistrar;
@@ -12,12 +13,15 @@ public class Waila {
register.registerBodyProvider(multiBlockProvider, BaseMetaTileEntity.class);
register.registerBodyProvider(multiBlockProvider, BaseMetaPipeEntity.class);
-
+ register.registerBodyProvider(multiBlockProvider, BaseMultiTileEntity.class);
+
register.registerNBTProvider(multiBlockProvider, BaseMetaTileEntity.class);
register.registerNBTProvider(multiBlockProvider, BaseMetaPipeEntity.class);
-
+ register.registerNBTProvider(multiBlockProvider, BaseMultiTileEntity.class);
+
register.registerTailProvider(multiBlockProvider, BaseMetaTileEntity.class);
register.registerTailProvider(multiBlockProvider, BaseMetaPipeEntity.class);
+ register.registerTailProvider(multiBlockProvider, BaseMultiTileEntity.class);
}
public static void init() {
diff --git a/src/main/java/gregtech/loaders/preload/GT_Loader_MultiTileEntities.java b/src/main/java/gregtech/loaders/preload/GT_Loader_MultiTileEntities.java
new file mode 100644
index 0000000000..eea1cab11f
--- /dev/null
+++ b/src/main/java/gregtech/loaders/preload/GT_Loader_MultiTileEntities.java
@@ -0,0 +1,38 @@
+package gregtech.loaders.preload;
+
+import gregtech.api.multitileentity.MultiTileEntityBlock;
+import gregtech.api.multitileentity.MultiTileEntityRegistry;
+import gregtech.api.util.GT_Util;
+import net.minecraft.block.Block;
+import net.minecraft.block.material.Material;
+import net.minecraft.tileentity.TileEntity;
+
+
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+import static gregtech.api.enums.GT_Values.NBT;
+import static gregtech.api.util.GT_Util.tuple;
+
+public class GT_Loader_MultiTileEntities implements Runnable {
+ @Override
+ public void run() {
+ GT_FML_LOGGER.info("GT_Mod: Regisering MultiTileEntities");
+ final MultiTileEntityRegistry aRegistry = new MultiTileEntityRegistry("gt.multitileentity");
+ final MultiTileEntityBlock aMachine = MultiTileEntityBlock.getOrCreate("GregTech", "machine", Material.iron, Block.soundTypeMetal, "wrench", 0, 0, 15, true, true);
+
+ Class<? extends TileEntity> aClass;
+
+ /*
+ * Placeholder, implemented in MTEMultiBlock branch
+ */
+// aClass = MultiBlock_Macerator.class; aRegistry.add(
+// "Large Macerator", "Multiblock Controller", 1000, aClass, 1, 64, aMachine,
+// GT_Util.makeNBT(tuple(NBT.MATERIAL, Material.iron), tuple(NBT.TEXTURE, "metalwall"), tuple(NBT.TANK_CAPACITY, 128000L))
+// );
+
+// aClass = MultiBlockPart.class; aRegistry.add(
+// "Test Casing", "Multiblock Casing", 18000, aClass, 1, 64, aMachine,
+// GT_Util.makeNBT(tuple(NBT.MATERIAL, Material.iron), tuple(NBT.TEXTURE, "metalwall"))
+// );
+
+ }
+}