From 8c4dd7de80e06875b942b1343f2ca4895ce2d758 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 17 Jul 2022 12:57:04 -0700 Subject: MultiTileEntity --- .../api/multitileentity/MultiTileEntityBlock.java | 603 +++++++++++ .../MultiTileEntityBlockInternal.java | 134 +++ .../MultiTileEntityClassContainer.java | 35 + .../multitileentity/MultiTileEntityContainer.java | 27 + .../MultiTileEntityItemInternal.java | 303 ++++++ .../multitileentity/MultiTileEntityRegistry.java | 230 +++++ .../multitileentity/base/BaseMultiTileEntity.java | 1047 ++++++++++++++++++++ .../base/BaseNontickableMultiTileEntity.java | 55 + .../base/BaseTickableMultiTileEntity.java | 113 +++ .../multitileentity/interfaces/IItemUpdatable.java | 15 + .../interfaces/IMultiTileEntity.java | 227 +++++ .../machine/MultiTileBasicMachine.java | 283 ++++++ 12 files changed, 3072 insertions(+) create mode 100644 src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java create mode 100644 src/main/java/gregtech/api/multitileentity/MultiTileEntityBlockInternal.java create mode 100644 src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java create mode 100644 src/main/java/gregtech/api/multitileentity/MultiTileEntityContainer.java create mode 100644 src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java create mode 100644 src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java create mode 100644 src/main/java/gregtech/api/multitileentity/base/BaseMultiTileEntity.java create mode 100644 src/main/java/gregtech/api/multitileentity/base/BaseNontickableMultiTileEntity.java create mode 100644 src/main/java/gregtech/api/multitileentity/base/BaseTickableMultiTileEntity.java create mode 100644 src/main/java/gregtech/api/multitileentity/interfaces/IItemUpdatable.java create mode 100644 src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java create mode 100644 src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java (limited to 'src/main/java/gregtech/api/multitileentity') 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 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 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) Collections.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 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 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 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 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 NAMED_REGISTRIES = new HashMap<>(); + private static final ItemStackMap REGISTRIES = new ItemStackMap<>(); + private static final HashSet> sRegisteredTileEntities = new HashSet<>(); + + public HashMap mCreativeTabs = new HashMap<>(); + public Map mRegistry = new HashMap<>(); + public List mRegistrations = new ArrayList<>(); + + public final String mNameInternal; + public final MultiTileEntityBlockInternal mBlock; + + private static MultiTileEntityBlockInternal regblock(String aNameInternal, MultiTileEntityBlockInternal aBlock, Class 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 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 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) ((IMultiTileEnti