diff options
Diffstat (limited to 'src/main/java')
18 files changed, 1392 insertions, 5 deletions
diff --git a/src/main/java/gregtech/api/GregTech_API.java b/src/main/java/gregtech/api/GregTech_API.java index 7617b2c195..043cd0b763 100644 --- a/src/main/java/gregtech/api/GregTech_API.java +++ b/src/main/java/gregtech/api/GregTech_API.java @@ -297,6 +297,7 @@ public class GregTech_API { public static Block sBlockCasings1, sBlockCasings2, sBlockCasings3, sBlockCasings4, sBlockCasings5, sBlockCasings6, sBlockCasings8, sBlockCasings9, sSolenoidCoilCasings; public static Block sBlockLongDistancePipes; + public static Block sDroneRender; /** * Getting assigned by the Config */ diff --git a/src/main/java/gregtech/api/enums/GT_Values.java b/src/main/java/gregtech/api/enums/GT_Values.java index 418bf2d14c..78475455b1 100644 --- a/src/main/java/gregtech/api/enums/GT_Values.java +++ b/src/main/java/gregtech/api/enums/GT_Values.java @@ -613,6 +613,7 @@ public class GT_Values { + "minecraft7771"; public static final String AuthorQuerns = "Author: " + EnumChatFormatting.RED + "Querns"; + public static final String AuthorSilverMoon = "Author: " + EnumChatFormatting.AQUA + "SilverMoon"; public static final String AuthorTheEpicGamer274 = "Author: " + "TheEpicGamer274"; // 7.5F comes from GT_Tool_Turbine_Large#getBaseDamage() given huge turbines are the most efficient now. diff --git a/src/main/java/gregtech/api/enums/ItemList.java b/src/main/java/gregtech/api/enums/ItemList.java index ac1aeeb7b2..c6149f20b9 100644 --- a/src/main/java/gregtech/api/enums/ItemList.java +++ b/src/main/java/gregtech/api/enums/ItemList.java @@ -2023,7 +2023,12 @@ public enum ItemList implements IItemContainer { InfinityCooledCasing, Machine_Multi_TranscendentPlasmaMixer, Cover_Metrics_Transmitter, - NC_AdvancedSensorCard; + NC_AdvancedSensorCard, + Machine_Multi_DroneCentre, + TierdDrone0, + TierdDrone1, + TierdDrone2, + Hatch_DroneDownLink; public static final ItemList[] DYE_ONLY_ITEMS = { Color_00, Color_01, Color_02, Color_03, Color_04, Color_05, Color_06, Color_07, Color_08, Color_09, Color_10, Color_11, Color_12, Color_13, Color_14, Color_15 }, diff --git a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java index 3994a02085..d32cb781e2 100644 --- a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java +++ b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java @@ -676,7 +676,9 @@ public enum MetaTileEntityIDs { RECIPE_FILTER_ZPM(9337), RECIPE_FILTER_UV(9338), RECIPE_FILTER_UHV(9339), - INDUSTRIAL_APIARY(9399); + INDUSTRIAL_APIARY(9399), + Drone_Centre(9400), + DroneDownLink(9401); public final int ID; diff --git a/src/main/java/gregtech/common/GT_Client.java b/src/main/java/gregtech/common/GT_Client.java index ebce87fdb5..a4d41366d4 100644 --- a/src/main/java/gregtech/common/GT_Client.java +++ b/src/main/java/gregtech/common/GT_Client.java @@ -96,6 +96,7 @@ import gregtech.common.render.GT_FluidDisplayStackRenderer; import gregtech.common.render.GT_MetaGenerated_Tool_Renderer; import gregtech.common.render.GT_MultiTile_Renderer; import gregtech.common.render.GT_PollutionRenderer; +import gregtech.common.render.GT_RenderDrone; import gregtech.common.render.GT_Renderer_Block; import gregtech.common.render.GT_Renderer_Entity_Arrow; import gregtech.common.render.items.GT_MetaGenerated_Item_Renderer; @@ -623,6 +624,7 @@ public class GT_Client extends GT_Proxy implements Runnable { super.onLoad(); new GT_Renderer_Block(); new GT_MultiTile_Renderer(); + new GT_RenderDrone(); metaGeneratedItemRenderer = new GT_MetaGenerated_Item_Renderer(); for (GT_MetaGenerated_Item item : GT_MetaGenerated_Item.sInstances.values()) { metaGeneratedItemRenderer.registerItem(item); diff --git a/src/main/java/gregtech/common/GT_Proxy.java b/src/main/java/gregtech/common/GT_Proxy.java index 978b0caf9a..13f5939e38 100644 --- a/src/main/java/gregtech/common/GT_Proxy.java +++ b/src/main/java/gregtech/common/GT_Proxy.java @@ -175,6 +175,7 @@ import gregtech.common.items.GT_MetaGenerated_Tool_01; import gregtech.common.misc.GlobalEnergyWorldSavedData; import gregtech.common.misc.GlobalMetricsCoverDatabase; import gregtech.common.misc.spaceprojects.SpaceProjectWorldSavedData; +import gregtech.common.tileentities.machines.multi.drone.GT_MetaTileEntity_DroneCentre; public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler { @@ -1397,6 +1398,8 @@ public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler { public void onServerStarted() { GregTech_API.sWirelessRedstone.clear(); + GT_MetaTileEntity_DroneCentre.getCentreMap() + .clear(); GT_Log.out.println( "GT_Mod: Cleaning up all OreDict Crafting Recipes, which have an empty List in them, since they are never meeting any Condition."); List<IRecipe> tList = CraftingManager.getInstance() diff --git a/src/main/java/gregtech/common/blocks/GT_Block_Drone.java b/src/main/java/gregtech/common/blocks/GT_Block_Drone.java new file mode 100644 index 0000000000..81d1acc228 --- /dev/null +++ b/src/main/java/gregtech/common/blocks/GT_Block_Drone.java @@ -0,0 +1,65 @@ +package gregtech.common.blocks; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +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.common.tileentities.render.TileDrone; + +public class GT_Block_Drone extends Block { + + public GT_Block_Drone() { + super(Material.iron); + this.setResistance(20f); + this.setHardness(-1.0f); + this.setCreativeTab(GregTech_API.TAB_GREGTECH); + this.setBlockName("gt.dronerender"); + this.setLightLevel(100.0f); + GameRegistry.registerBlock(this, getUnlocalizedName()); + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister iconRegister) { + blockIcon = iconRegister.registerIcon("gregtech:iconsets/TRANSPARENT"); + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean canRenderInPass(int a) { + return true; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + + @Override + public boolean hasTileEntity(int metadata) { + return true; + } + + @Override + public TileEntity createTileEntity(World world, int metadata) { + return new TileDrone(); + } + + @Override + public ArrayList<ItemStack> getDrops(World world, int x, int y, int z, int meta, int fortune) { + return new ArrayList<>(); + } +} diff --git a/src/main/java/gregtech/common/items/GT_TierDrone.java b/src/main/java/gregtech/common/items/GT_TierDrone.java new file mode 100644 index 0000000000..58da852d0e --- /dev/null +++ b/src/main/java/gregtech/common/items/GT_TierDrone.java @@ -0,0 +1,18 @@ +package gregtech.common.items; + +import gregtech.api.items.GT_Generic_Item; + +public class GT_TierDrone extends GT_Generic_Item { + + private final int level; + + public GT_TierDrone(String aUnlocalized, String aEnglish, String aEnglishTooltip, int level) { + super(aUnlocalized, aEnglish, aEnglishTooltip); + this.level = level; + this.setMaxStackSize(64); + } + + public int getLevel() { + return level; + } +} diff --git a/src/main/java/gregtech/common/render/GT_RenderDrone.java b/src/main/java/gregtech/common/render/GT_RenderDrone.java new file mode 100644 index 0000000000..af1336a219 --- /dev/null +++ b/src/main/java/gregtech/common/render/GT_RenderDrone.java @@ -0,0 +1,93 @@ +package gregtech.common.render; + +import static gregtech.api.enums.Mods.GregTech; + +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.AdvancedModelLoader; +import net.minecraftforge.client.model.IModelCustom; + +import org.lwjgl.opengl.GL11; + +import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.common.tileentities.render.TileDrone; + +@SideOnly(Side.CLIENT) +public class GT_RenderDrone extends TileEntitySpecialRenderer { + + private static final ResourceLocation DroneTexture = new ResourceLocation(GregTech.ID, "textures/model/drone.png"); + private static final IModelCustom Drone = AdvancedModelLoader + .loadModel(new ResourceLocation(GregTech.ID, "textures/model/drone.obj")); + + public GT_RenderDrone() { + ClientRegistry.bindTileEntitySpecialRenderer(TileDrone.class, this); + } + + @Override + public void renderTileEntityAt(TileEntity tile, double x, double y, double z, float timeSinceLastTick) { + if (!(tile instanceof TileDrone drone)) return; + final float size = 1.0f; + GL11.glPushMatrix(); + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5); + renderDrone(size); + renderBlade(drone, size); + GL11.glPopMatrix(); + } + + private void renderDrone(double size) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + this.bindTexture(DroneTexture); + GL11.glScaled(size, size, size); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + Drone.renderOnly("drone", "box", "main"); + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_LIGHTING); + } + + private void renderBlade(TileDrone drone, double size) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + this.bindTexture(DroneTexture); + GL11.glScaled(size, size, size); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + GL11.glPushMatrix(); + GL11.glTranslated(-0.7d * size, -1 * size, -0.7 * size); + GL11.glRotated(drone.rotation, 0, 1, 0); + GL11.glTranslated(0.7d * size, 1 * size, 0.7 * size); + Drone.renderOnly("blade2"); + GL11.glPopMatrix(); + GL11.glPushMatrix(); + GL11.glTranslated(-0.7d * size, -1 * size, 0.7 * size); + GL11.glRotated(drone.rotation, 0, 1, 0); + GL11.glTranslated(0.7d * size, 1 * size, -0.7 * size); + Drone.renderOnly("blade3"); + GL11.glPopMatrix(); + GL11.glPushMatrix(); + GL11.glTranslated(0.7d * size, -1 * size, -0.7 * size); + GL11.glRotated(drone.rotation, 0, 1, 0); + GL11.glTranslated(-0.7d * size, 1 * size, 0.7 * size); + Drone.renderOnly("blade1"); + GL11.glPopMatrix(); + GL11.glPushMatrix(); + GL11.glTranslated(0.7d * size, -1 * size, 0.7 * size); + GL11.glRotated(drone.rotation, 0, 1, 0); + GL11.glTranslated(-0.7d * size, 1 * size, -0.7 * size); + Drone.renderOnly("blade4"); + GL11.glPopMatrix(); + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_LIGHTING); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/drone/DroneConnection.java b/src/main/java/gregtech/common/tileentities/machines/multi/drone/DroneConnection.java new file mode 100644 index 0000000000..57a8bea352 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/drone/DroneConnection.java @@ -0,0 +1,123 @@ +package gregtech.common.tileentities.machines.multi.drone; + +import static gregtech.GT_Mod.gregtechproxy; + +import java.util.Optional; + +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; +import net.minecraftforge.common.DimensionManager; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.util.GT_Util; + +public class DroneConnection { + + String customName; + GT_MetaTileEntity_MultiBlockBase machine; + ItemStack machineItem; + ChunkCoordinates machineCoord; + GT_MetaTileEntity_DroneCentre centre; + ChunkCoordinates centreCoord; + World world; + + public DroneConnection(GT_MetaTileEntity_MultiBlockBase machine, GT_MetaTileEntity_DroneCentre centre) { + this.machine = machine; + this.machineItem = machine.getStackForm(1); + machineCoord = machine.getBaseMetaTileEntity() + .getCoords(); + this.centre = centre; + centreCoord = centre.getBaseMetaTileEntity() + .getCoords(); + this.world = centre.getBaseMetaTileEntity() + .getWorld(); + customName = Optional.ofNullable(centre.tempNameList.remove(machineCoord.toString())) + .orElse(machine.getLocalName()); + } + + public DroneConnection(NBTTagCompound aNBT) { + NBTTagCompound machineTag = aNBT.getCompoundTag("machine"); + NBTTagCompound centreTag = aNBT.getCompoundTag("centre"); + if (!gregtechproxy.isClientSide()) { + this.world = DimensionManager.getWorld(aNBT.getInteger("worldID")); + } else { + this.world = Minecraft.getMinecraft().thePlayer.worldObj; + } + machineItem = ItemStack.loadItemStackFromNBT(aNBT.getCompoundTag("item")); + machineCoord = new ChunkCoordinates( + machineTag.getInteger("x"), + machineTag.getInteger("y"), + machineTag.getInteger("z")); + this.machine = getLoadedGT_BaseMachineAt(machineCoord, world, true); + centreCoord = new ChunkCoordinates( + centreTag.getInteger("x"), + centreTag.getInteger("y"), + centreTag.getInteger("z")); + this.centre = (GT_MetaTileEntity_DroneCentre) getLoadedGT_BaseMachineAt(centreCoord, world, true); + this.customName = aNBT.getString("name"); + } + + public GT_MetaTileEntity_MultiBlockBase getMachine() { + return machine; + } + + public boolean reCheckConnection() { + if (machine == null) this.machine = getLoadedGT_BaseMachineAt(machineCoord, world, true); + if (centre == null) + this.centre = (GT_MetaTileEntity_DroneCentre) getLoadedGT_BaseMachineAt(centreCoord, world, true); + if (machine != null && centre != null + && !centre.getConnectionList() + .contains(this)) + centre.getConnectionList() + .add(this); + return isValid(); + } + + public String getCustomName() { + return customName; + } + + public void setCustomName(String name) { + customName = name; + } + + public NBTTagCompound transConnectionToNBT() { + NBTTagCompound aNBT = new NBTTagCompound(); + if (!this.isValid()) return aNBT; + aNBT.setTag("machine", transGT_BaseMachineToNBT(machine)); + aNBT.setTag("centre", transGT_BaseMachineToNBT(centre)); + aNBT.setTag("item", machineItem.writeToNBT(new NBTTagCompound())); + aNBT.setInteger( + "worldID", + machine.getBaseMetaTileEntity() + .getWorld().provider.dimensionId); + aNBT.setString("name", getCustomName()); + return aNBT; + } + + public GT_MetaTileEntity_MultiBlockBase getLoadedGT_BaseMachineAt(ChunkCoordinates coords, World world, + boolean isLoaded) { + TileEntity te = GT_Util.getTileEntity(world, coords, isLoaded); + if (te == null) return null; + return (GT_MetaTileEntity_MultiBlockBase) ((IGregTechTileEntity) te).getMetaTileEntity(); + } + + private NBTTagCompound transGT_BaseMachineToNBT(GT_MetaTileEntity_MultiBlockBase machine) { + IHasWorldObjectAndCoords baseCoord = machine.getBaseMetaTileEntity(); + NBTTagCompound tag = new NBTTagCompound(); + tag.setInteger("x", baseCoord.getXCoord()); + tag.setInteger("y", baseCoord.getYCoord()); + tag.setInteger("z", baseCoord.getZCoord()); + return tag; + } + + public boolean isValid() { + return machine != null && machine.isValid() && centre != null && centre.isValid(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_DroneCentre.java b/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_DroneCentre.java new file mode 100644 index 0000000000..ee4ea4978d --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_DroneCentre.java @@ -0,0 +1,666 @@ +package gregtech.common.tileentities.machines.multi.drone; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_Values.AuthorSilverMoon; +import static gregtech.api.multitileentity.multiblock.casing.Glasses.chainAllGlasses; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.HashMultimap; +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.util.Vec3Impl; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.math.MainAxisAlignment; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedRow; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.Scrollable; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.TextFieldWidget; + +import appeng.api.util.DimensionalCoord; +import appeng.api.util.WorldCoord; +import appeng.client.render.BlockPosHighlighter; +import gregtech.api.GregTech_API; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IIconContainer; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; +import gregtech.common.items.GT_TierDrone; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_DroneCentre extends + GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GT_MetaTileEntity_DroneCentre> implements ISurvivalConstructable { + + private static final IIconContainer ACTIVE = new Textures.BlockIcons.CustomIcon("iconsets/DRONE_CENTRE_ACTIVE"); + private static final IIconContainer FACE = new Textures.BlockIcons.CustomIcon("iconsets/DRONE_CENTRE_FACE"); + private static final IIconContainer INACTIVE = new Textures.BlockIcons.CustomIcon("iconsets/DRONE_CENTRE_INACTIVE"); + private Vec3Impl centreCoord; + private int droneLevel = 0; + private int buttonID; + private final List<DroneConnection> connectionList = new ArrayList<>(); + public HashMap<String, String> tempNameList = new HashMap<>(); + // Save centre by dimID + private static final HashMultimap<Integer, GT_MetaTileEntity_DroneCentre> droneMap = HashMultimap.create(); + // spotless off + private static final IStructureDefinition<GT_MetaTileEntity_DroneCentre> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_DroneCentre>builder() + .addShape( + "main", + transpose( + new String[][] { { " ", " ", " ", " ", "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC" }, + { "CE~EC", "C C", "C C", "C C", "CAAAC", "CCCCC", "CAAAC", "C C", "CCCCC" }, + { "CEEEC", "CBBBC", "CBDBC", "CBBBC", "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC" }, + { "C C", " ", " ", " ", " ", " ", " ", " ", "C C" }, + { "C C", " ", " ", " ", " ", " ", " ", " ", "C C" }, + { "C C", " ", " ", " ", " ", " ", " ", " ", "C C" } })) + .addElement( + 'E', + buildHatchAdder(GT_MetaTileEntity_DroneCentre.class).atLeast(InputBus) + .casingIndex(59) + .dot(1) + .buildAndChain(ofBlock(GregTech_API.sBlockCasings4, 2))) + .addElement('C', ofBlock(GregTech_API.sBlockCasings4, 2)) + .addElement('A', chainAllGlasses()) + .addElement('B', ofBlock(GregTech_API.sBlockCasings1, 11)) + .addElement('D', ofBlock(GregTech_API.sBlockCasings4, 0)) + .build(); + + // spotless on + public GT_MetaTileEntity_DroneCentre(String name) { + super(name); + } + + public GT_MetaTileEntity_DroneCentre(int ID, String Name, String NameRegional) { + super(ID, Name, NameRegional); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_DroneCentre(super.mName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (getBaseMetaTileEntity().isActive()) { + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(59), TextureFactory.builder() + .addIcon(ACTIVE) + .extFacing() + .build() }; + } else { + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(59), TextureFactory.builder() + .addIcon(INACTIVE) + .extFacing() + .build() }; + } + } else if (side == aFacing.getOpposite()) { + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(59), TextureFactory.builder() + .addIcon(FACE) + .extFacing() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(59) }; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_DroneCentre> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Drone Centre") + .addInfo("Drone Center Controller") + .addInfo(EnumChatFormatting.AQUA + "Drone #10032, cleared for takeoff!") + .addInfo("Monitors multiblock machines in range.") + .addInfo("Replace maintenance hatch on other multi with drone downlink module.") + .addInfo("Provides maintenance, power control, monitoring and etc.") + .addInfo("Range is determined by drone tier: T1-32, T2-128, T3-512") + .addInfo("Place drones in input bus; only one needed to operate.") + .addInfo("Automatically upgrade based on the drone level in the input bus.") + .addInfo("There is a chance per second that the drone will crash.") + .addInfo("Chance is determined by drone tier: T1-1/28800, T2-1/172800, T3-0") + .addInfo("If machine is too far, remote control would not available") + .addInfo(AuthorSilverMoon) + .addSeparator() + .beginStructureBlock(5, 6, 9, false) + .addStructureInfo("Do not need maintenance hatch") + .addSeparator() + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece("main", stackSize, hintsOnly, 2, 1, 0); + } + + @Override + public int survivalConstruct(ItemStack stack, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece("main", stack, 2, 1, 0, elementBudget, env, false, true); + } + + @Override + protected IAlignmentLimits getInitialAlignmentLimits() { + // I don't think a drone can take off HORIZONTALLY! + return (d, r, f) -> (d.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0 && r.isNotRotated() + && !f.isVerticallyFliped(); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + return checkPiece("main", 2, 1, 0); + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + fixAll(); + if (aTick % 200 == 0) { + if (switch (droneLevel) { + case 1 -> getBaseMetaTileEntity().getRandomNumber(28800); + case 2 -> getBaseMetaTileEntity().getRandomNumber(172800); + default -> 1; + } == 0) { + droneLevel = 0; + if (!tryConsumeDrone()) criticalStopMachine(); + } + } + // Clean invalid connections every 4 seconds + if (aTick % 80 == 0) connectionList.removeIf(v -> !v.isValid()); + } + if (mMaxProgresstime > 0 && mMaxProgresstime - mProgresstime == 1) destroyRenderBlock(); + super.onPostTick(aBaseMetaTileEntity, aTick); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + droneLevel = aNBT.getInteger("drone"); + NBTTagCompound nameList = aNBT.getCompoundTag("conList"); + for (String s : nameList.func_150296_c()) { + tempNameList.put(s, nameList.getString(s)); + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("drone", droneLevel); + NBTTagCompound conList = new NBTTagCompound(); + for (DroneConnection con : connectionList) { + if (!Objects.equals(con.customName, con.machine.getLocalName())) + conList.setString(con.machineCoord.toString(), con.customName); + } + aNBT.setTag("conList", conList); + } + + @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); + tag.setInteger("connectionCount", connectionList.size()); + if (droneLevel != 0) tag.setInteger("droneLevel", droneLevel); + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + currenttip.add( + EnumChatFormatting.AQUA + StatCollector.translateToLocal("GT5U.waila.drone_downlink.droneLevel") + + tag.getInteger("droneLevel")); + currenttip.add( + StatCollector.translateToLocal("GT5U.waila.drone_downlink.connectionCount") + + tag.getInteger("connectionCount")); + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + if (droneLevel == 0) { + if (!tryConsumeDrone()) return SimpleCheckRecipeResult.ofFailure("drone_noDrone"); + } + if (droneLevel == 1 || droneLevel == 2) tryUpdateDrone(); + mMaxProgresstime = 200 * droneLevel; + createRenderBlock(); + return SimpleCheckRecipeResult.ofSuccess("drone_operating"); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + if (aBaseMetaTileEntity.isServerSide()) { + if (droneMap.containsValue(this)) return; + centreCoord = new Vec3Impl( + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord()); + droneMap.put(getBaseMetaTileEntity().getWorld().provider.dimensionId, this); + } + } + + @Override + public void onRemoval() { + droneMap.remove(getBaseMetaTileEntity().getWorld().provider.dimensionId, this); + } + + public List<DroneConnection> getConnectionList() { + return connectionList; + } + + public int getRange() { + return switch (droneLevel) { + case 1 -> 32; + case 2 -> 128; + case 3 -> 512; + default -> 0; + }; + } + + public Vec3Impl getCoords() { + return centreCoord; + } + + private boolean tryConsumeDrone() { + List<ItemStack> inputs = getStoredInputs(); + if (inputs.isEmpty()) return false; + for (ItemStack item : inputs) { + if (item != null && item.getItem() instanceof GT_TierDrone drone) { + this.droneLevel = drone.getLevel(); + item.stackSize--; + updateSlots(); + return true; + } + } + return false; + } + + private void tryUpdateDrone() { + List<ItemStack> inputs = getStoredInputs(); + if (inputs.isEmpty()) return; + for (ItemStack item : inputs) { + if (item != null && item.getItem() instanceof GT_TierDrone drone) { + if (drone.getLevel() <= this.droneLevel) continue; + this.droneLevel = drone.getLevel(); + item.stackSize--; + updateSlots(); + return; + } + } + } + + private void createRenderBlock() { + int x = getBaseMetaTileEntity().getXCoord(); + int y = getBaseMetaTileEntity().getYCoord(); + int z = getBaseMetaTileEntity().getZCoord(); + + double xOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetX; + double zOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetZ; + double yOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetY; + + this.getBaseMetaTileEntity() + .getWorld() + .setBlock((int) (x + xOffset), (int) (y + yOffset), (int) (z + zOffset), Blocks.air); + this.getBaseMetaTileEntity() + .getWorld() + .setBlock((int) (x + xOffset), (int) (y + yOffset), (int) (z + zOffset), GregTech_API.sDroneRender); + } + + private void destroyRenderBlock() { + int x = getBaseMetaTileEntity().getXCoord(); + int y = getBaseMetaTileEntity().getYCoord(); + int z = getBaseMetaTileEntity().getZCoord(); + + double xOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetX; + double zOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetZ; + double yOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetY; + + this.getBaseMetaTileEntity() + .getWorld() + .setBlock((int) (x + xOffset), (int) (y + yOffset), (int) (z + zOffset), Blocks.air); + } + + private void fixAll() { + this.mWrench = this.mScrewdriver = this.mSoftHammer = this.mHardHammer = this.mCrowbar = this.mSolderingTool = true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + buildContext.addSyncedWindow(10, this::createMachineListWindow); + buildContext.addSyncedWindow(11, this::createCustomNameWindow); + builder.widget(// Machine List + new ButtonWidget().setOnClick( + (clickData, widget) -> { + if (!widget.isClient()) widget.getContext() + .openSyncedWindow(10); + }) + .setSize(16, 16) + .setBackground(() -> { + List<UITexture> UI = new ArrayList<>(); + UI.add(GT_UITextures.BUTTON_STANDARD); + UI.add(GT_UITextures.OVERLAY_BUTTON_WHITELIST); + return UI.toArray(new IDrawable[0]); + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_open_list")) + .setPos(94, 91) + .setEnabled(getBaseMetaTileEntity().isActive())) + .widget(// Turn on ALL machines + new ButtonWidget().setOnClick((clickData, widget) -> { + if (!widget.isClient()) { + if (!getBaseMetaTileEntity().isActive()) { + GT_Utility.sendChatToPlayer( + widget.getContext() + .getPlayer(), + GT_Utility.trans("350", "You cannot control machine when drone centre shut down!")); + return; + } + for (DroneConnection mte : connectionList) { + mte.machine.getBaseMetaTileEntity() + .enableWorking(); + } + GT_Utility.sendChatToPlayer( + widget.getContext() + .getPlayer(), + GT_Utility.trans("351", "Successfully turn on all machines!")); + widget.getContext() + .getPlayer() + .closeScreen(); + } + }) + .setSize(16, 16) + .setBackground(() -> { + List<UITexture> UI = new ArrayList<>(); + UI.add(GT_UITextures.BUTTON_STANDARD); + UI.add(GT_UITextures.OVERLAY_BUTTON_POWER_SWITCH_ON); + return UI.toArray(new IDrawable[0]); + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_poweron_all")) + .setPos(146, 91) + .setEnabled(getBaseMetaTileEntity().isActive())) + .widget(// Turn off ALL machines + new ButtonWidget().setOnClick((clickData, widget) -> { + if (!widget.isClient()) { + if (!getBaseMetaTileEntity().isActive()) { + GT_Utility.sendChatToPlayer( + widget.getContext() + .getPlayer(), + GT_Utility.trans("350", "You cannot control machine when drone centre shut down!")); + return; + } + for (DroneConnection mte : connectionList) { + mte.machine.getBaseMetaTileEntity() + .disableWorking(); + } + GT_Utility.sendChatToPlayer( + widget.getContext() + .getPlayer(), + GT_Utility.trans("352", "Successfully turn off all machines!")); + widget.getContext() + .getPlayer() + .closeScreen(); + } + }) + .setSize(16, 16) + .setBackground(() -> { + List<UITexture> UI = new ArrayList<>(); + UI.add(GT_UITextures.BUTTON_STANDARD); + UI.add(GT_UITextures.OVERLAY_BUTTON_POWER_SWITCH_OFF); + return UI.toArray(new IDrawable[0]); + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_poweroff_all")) + .setPos(120, 91) + .setEnabled(getBaseMetaTileEntity().isActive())) + .widget(new FakeSyncWidget.ListSyncer<>(() -> connectionList, var1 -> { + connectionList.clear(); + connectionList.addAll(var1); + }, (buffer, j) -> { + try { + buffer.writeNBTTagCompoundToBuffer(j.transConnectionToNBT()); + } catch (IOException e) { + GT_Log.err.println(e.getCause()); + } + }, buffer -> { + try { + return new DroneConnection(buffer.readNBTTagCompoundFromBuffer()); + } catch (IOException e) { + GT_Log.err.println(e.getCause()); + } + return null; + })); + } + + protected ModularWindow createMachineListWindow(final EntityPlayer player) { + ModularWindow.Builder builder = ModularWindow.builder(260, 215); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + builder.widget( + ButtonWidget.closeWindowButton(true) + .setPos(245, 3)); + builder.widget( + new TextWidget(EnumChatFormatting.BOLD + StatCollector.translateToLocal("GT5U.gui.text.drone_title")) + .setScale(2) + .setTextAlignment(Alignment.Center) + .setPos(0, 10) + .setSize(260, 8)); + Scrollable MachineContainer = new Scrollable().setVerticalScroll(); + for (int i = 0; i < connectionList.size(); i++) { + DroneConnection connection = connectionList.get(i); + ItemStackHandler drawitem = new ItemStackHandler(1); + drawitem.setStackInSlot(0, connection.machineItem); + DynamicPositionedRow row = new DynamicPositionedRow().setSynced(false); + GT_MetaTileEntity_MultiBlockBase coreMachine = connection.machine; + int finalI = i; + row.widget( + SlotWidget.phantom(drawitem, 0) + .disableInteraction() + .setPos(0, 0)) + .widget(new ButtonWidget().setOnClick((clickData, widget) -> { + buttonID = finalI; + if (!widget.isClient()) widget.getContext() + .openSyncedWindow(11); + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_setname")) + .setBackground( + () -> new IDrawable[] { GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_PRINT }) + .setSize(16, 16)); + // Client can't handle unloaded machines + row.widget( + new ButtonWidget().setOnClick( + (clickData, widget) -> Optional.ofNullable(coreMachine) + .ifPresent(machine -> { + if (!getBaseMetaTileEntity().isActive()) { + GT_Utility.sendChatToPlayer( + player, + GT_Utility.trans("350", "You cannot control machine when drone centre shut down!")); + return; + } + if (machine.isAllowedToWork()) { + machine.disableWorking(); + } else { + machine.enableWorking(); + } + })) + .setPlayClickSoundResource( + () -> Optional.ofNullable(coreMachine) + .filter(GT_MetaTileEntity_MultiBlockBase::isAllowedToWork) + .map(var -> SoundResource.GUI_BUTTON_UP.resourceLocation) + .orElse(SoundResource.GUI_BUTTON_DOWN.resourceLocation)) + .setBackground( + () -> Optional.ofNullable(coreMachine) + .map( + machine -> machine.isAllowedToWork() + ? new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_POWER_SWITCH_ON } + : new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_POWER_SWITCH_OFF }) + .orElse(new IDrawable[] { GT_UITextures.PICTURE_STALLED_ELECTRICITY })) + .attachSyncer( + new FakeSyncWidget.BooleanSyncer( + () -> Optional.ofNullable(coreMachine) + .map(GT_MetaTileEntity_MultiBlockBase::isAllowedToWork) + .orElse(false), + var -> Optional.ofNullable(coreMachine) + .ifPresent(machine -> { + if (var) machine.enableWorking(); + else machine.disableWorking(); + })), + builder) + .addTooltip( + coreMachine != null ? StatCollector.translateToLocal("GT5U.gui.button.power_switch") + : StatCollector.translateToLocal("GT5U.gui.button.drone_outofrange")) + .setSize(16, 16)) + .widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (widget.isClient()) { + Optional.ofNullable(coreMachine) + .ifPresent(machine -> { + highlightMachine(player, machine); + player.closeScreen(); + }); + } + }) + .addTooltip( + coreMachine != null ? StatCollector.translateToLocal("GT5U.gui.button.drone_highlight") + : StatCollector.translateToLocal("GT5U.gui.button.drone_outofrange")) + .setBackground( + () -> Optional.ofNullable(coreMachine) + .map( + machine -> new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_INVERT_REDSTONE }) + .orElse(new IDrawable[] { GT_UITextures.OVERLAY_BUTTON_REDSTONE_OFF })) + .setSize(16, 16)); + row.widget( + new TextWidget( + connectionList.get(i) + .getCustomName()).setTextAlignment(Alignment.CenterLeft) + .setPos(0, 4)); + MachineContainer.widget( + row.setAlignment(MainAxisAlignment.SPACE_BETWEEN) + .setSpace(4) + .setPos(0, i * 20)); + } + return builder.widget( + MachineContainer.setPos(10, 30) + .setSize(240, 160)) + .setDraggable(false) + .build(); + } + + protected ModularWindow createCustomNameWindow(final EntityPlayer player) { + ModularWindow.Builder builder = ModularWindow.builder(150, 40); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + return builder.widget( + ButtonWidget.closeWindowButton(true) + .setPos(135, 3)) + .widget( + new TextWidget("Custom Machine Name").setTextAlignment(Alignment.Center) + .setPos(0, 5) + .setSize(150, 8)) + .widget( + new TextFieldWidget().setGetter( + () -> connectionList.get(buttonID) + .getCustomName()) + .setSetter( + var -> connectionList.get(buttonID) + .setCustomName(var)) + .setTextAlignment(Alignment.CenterLeft) + .setTextColor(Color.WHITE.dark(1)) + .setFocusOnGuiOpen(true) + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD_LIGHT_GRAY.withOffset(-1, -1, 2, 2)) + .setPos(10, 16) + .setSize(130, 16)) + .build(); + } + + // Just like HIGHLIGHT_INTERFACE (and exactly from it) + private void highlightMachine(EntityPlayer player, GT_MetaTileEntity_MultiBlockBase machine) { + DimensionalCoord blockPos = new DimensionalCoord( + machine.getBaseMetaTileEntity() + .getXCoord(), + machine.getBaseMetaTileEntity() + .getYCoord(), + machine.getBaseMetaTileEntity() + .getZCoord(), + machine.getBaseMetaTileEntity() + .getWorld().provider.dimensionId); + WorldCoord blockPos2 = new WorldCoord((int) player.posX, (int) player.posY, (int) player.posZ); + BlockPosHighlighter.highlightBlock( + blockPos, + System.currentTimeMillis() + 500 * WorldCoord.getTaxicabDistance(blockPos, blockPos2)); + } + + public static HashMultimap<Integer, GT_MetaTileEntity_DroneCentre> getCentreMap() { + return droneMap; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_Hatch_DroneDownLink.java b/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_Hatch_DroneDownLink.java new file mode 100644 index 0000000000..6e65033980 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_Hatch_DroneDownLink.java @@ -0,0 +1,269 @@ +package gregtech.common.tileentities.machines.multi.drone; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.stream.Collectors; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.util.Vec3Impl; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.IIconContainer; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IMachineBlockUpdateable; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Maintenance; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.render.TextureFactory; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_Hatch_DroneDownLink extends GT_MetaTileEntity_Hatch_Maintenance { + + private Vec3Impl downlinkCoord; + private DroneConnection connection; + // This has to be existed for doing random damage. + private GT_MetaTileEntity_MultiBlockBase machine; + private static final IIconContainer moduleActive = new Textures.BlockIcons.CustomIcon( + "iconsets/OVERLAY_DRONE_MODULE_ACTIVE"); + + public GT_MetaTileEntity_Hatch_DroneDownLink(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier); + } + + public GT_MetaTileEntity_Hatch_DroneDownLink(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures, false); + } + + @Override + public String[] getDescription() { + return new String[] { "Built-in powerful navigation beacon!" }; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister aBlockIconRegister) { + super.registerIcons(aBlockIconRegister); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(moduleActive) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(moduleActive) }; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_DroneDownLink( + this.mName, + this.mTier, + this.mDescriptionArray, + this.mTextures); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + downlinkCoord = new Vec3Impl( + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord()); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + if (hasConnection()) { + if (connection.centre.getBaseMetaTileEntity() + .isActive()) { + doNormalMaintain(); + } else { + // Centre offline? ...do nothing. + // doRandomIssue(); + } + } else { + // If the connection invalid, set it to null. + // Find connection every 10 second + if (aTick % 200 == 0) { + connection = null; + tryFindConnection(); + // Let's have some "surprise". Sorry, surprise party is over. + // if (this.machine != null && this.machine.isValid()) { + // doRandomIssue(); + } + } + } + } + + private void doNormalMaintain() { + this.mWrench = this.mScrewdriver = this.mSoftHammer = this.mHardHammer = this.mCrowbar = this.mSolderingTool = true; + connection.machine.mWrench = connection.machine.mScrewdriver = connection.machine.mSoftHammer = connection.machine.mHardHammer = connection.machine.mCrowbar = connection.machine.mSolderingTool = true; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + return false; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public void onRemoval() { + if (hasConnection()) connection.machine = null; + } + + private boolean hasConnection() { + if (connection == null) return false; + if (connection.isValid()) return true; + return connection.reCheckConnection(); + } + + /** + * Find a drone connection. This will search for all DC in the same dimension, then find one in range. + */ + private void tryFindConnection() { + if (GT_MetaTileEntity_DroneCentre.getCentreMap() + .containsKey(getBaseMetaTileEntity().getWorld().provider.dimensionId)) { + List<GT_MetaTileEntity_DroneCentre> target = GT_MetaTileEntity_DroneCentre.getCentreMap() + .get(getBaseMetaTileEntity().getWorld().provider.dimensionId) + .stream() + .collect(Collectors.toList()); + for (GT_MetaTileEntity_DroneCentre centre : target) { + if (centre.getCoords() + .withinDistance(this.downlinkCoord, centre.getRange()) + && centre.getBaseMetaTileEntity() + .isActive()) { + GT_MetaTileEntity_MultiBlockBase machine = tryFindCoreGTMultiBlock(); + if (machine != null && machine.isValid()) { + this.machine = machine; + connection = new DroneConnection(machine, centre); + connection.centre.getConnectionList() + .add(connection); + } + } + } + } + } + + private void doRandomIssue() { + switch (getBaseMetaTileEntity().getRandomNumber(6)) { + case 0 -> machine.mWrench = !machine.mWrench; + case 1 -> machine.mScrewdriver = !machine.mScrewdriver; + case 2 -> machine.mSoftHammer = !machine.mSoftHammer; + case 3 -> machine.mCrowbar = !machine.mCrowbar; + case 4 -> machine.mSolderingTool = !connection.machine.mSolderingTool; + case 5 -> machine.mHardHammer = !connection.machine.mHardHammer; + } + } + + // Find mainframe. Mainly from a method in GT_API——This will cause performance issue! Do not call it frequently. + private GT_MetaTileEntity_MultiBlockBase tryFindCoreGTMultiBlock() { + Queue<ChunkCoordinates> tQueue = new LinkedList<>(); + Set<ChunkCoordinates> visited = new HashSet<>(80); + tQueue.add( + this.getBaseMetaTileEntity() + .getCoords()); + World world = this.getBaseMetaTileEntity() + .getWorld(); + while (!tQueue.isEmpty()) { + final ChunkCoordinates aCoords = tQueue.poll(); + final TileEntity tTileEntity; + final boolean isMachineBlock; + tTileEntity = world.getTileEntity(aCoords.posX, aCoords.posY, aCoords.posZ); + isMachineBlock = GregTech_API.isMachineBlock( + world.getBlock(aCoords.posX, aCoords.posY, aCoords.posZ), + world.getBlockMetadata(aCoords.posX, aCoords.posY, aCoords.posZ)); + + // See if the block itself is MultiBlock, also the one we need. + if (tTileEntity instanceof IGregTechTileEntity te + && te.getMetaTileEntity() instanceof GT_MetaTileEntity_MultiBlockBase mte) + if (mte.mMaintenanceHatches.contains(this)) return mte; + + // Now see if we should add the nearby blocks to the queue: + // 1) If we've visited less than 5 blocks, then yes + // 2) If the tile says we should recursively update (pipes don't, machine blocks do) + // 3) If the block at the coordinates is marked as a machine block + if (visited.size() < 5 + || (tTileEntity instanceof IMachineBlockUpdateable + && ((IMachineBlockUpdateable) tTileEntity).isMachineBlockUpdateRecursive()) + || isMachineBlock) { + ChunkCoordinates tCoords; + + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX + 1, aCoords.posY, aCoords.posZ))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX - 1, aCoords.posY, aCoords.posZ))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY + 1, aCoords.posZ))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY - 1, aCoords.posZ))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY, aCoords.posZ + 1))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY, aCoords.posZ - 1))) + tQueue.add(tCoords); + } + } + return null; + } + + @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); + tag.setBoolean("connection", connection == null); + if (connection != null) { + tag.setInteger("x", connection.centreCoord.posX); + tag.setInteger("y", connection.centreCoord.posY); + tag.setInteger("z", connection.centreCoord.posZ); + } + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + currenttip.add( + tag.getBoolean("connection") + ? EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.waila.drone_downlink.noConnection") + : EnumChatFormatting.AQUA + StatCollector.translateToLocal("GT5U.waila.drone_downlink.connection") + + tag.getInteger("x") + + " " + + tag.getInteger("y") + + " " + + tag.getInteger("z")); + super.getWailaBody(itemStack, currenttip, accessor, config); + } +} diff --git a/src/main/java/gregtech/common/tileentities/render/TileDrone.java b/src/main/java/gregtech/common/tileentities/render/TileDrone.java new file mode 100644 index 0000000000..625157ff37 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/render/TileDrone.java @@ -0,0 +1,24 @@ +package gregtech.common.tileentities.render; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; + +public class TileDrone extends TileEntity { + + public double rotation = 0; + + @Override + public AxisAlignedBB getRenderBoundingBox() { + return INFINITE_EXTENT_AABB; + } + + @Override + public double getMaxRenderDistanceSquared() { + return 65536; + } + + @Override + public void updateEntity() { + rotation = (rotation + 50) % 360d; + } +} diff --git a/src/main/java/gregtech/loaders/load/GT_Loader_MetaTileEntities_Recipes.java b/src/main/java/gregtech/loaders/load/GT_Loader_MetaTileEntities_Recipes.java index 8ee6b07714..6fe3d273f6 100644 --- a/src/main/java/gregtech/loaders/load/GT_Loader_MetaTileEntities_Recipes.java +++ b/src/main/java/gregtech/loaders/load/GT_Loader_MetaTileEntities_Recipes.java @@ -221,6 +221,7 @@ import static gregtech.api.enums.MetaTileEntityIDs.WIREMILL_LV; import static gregtech.api.enums.MetaTileEntityIDs.WIREMILL_MV; import static gregtech.api.enums.Mods.BuildCraftFactory; import static gregtech.api.enums.Mods.Forestry; +import static gregtech.api.enums.Mods.GalacticraftCore; import static gregtech.api.enums.Mods.Gendustry; import static gregtech.api.enums.Mods.IndustrialCraft2; import static gregtech.api.enums.Mods.NotEnoughItems; @@ -6485,6 +6486,31 @@ public class GT_Loader_MetaTileEntities_Recipes implements Runnable { OrePrefixes.rotor.get(Materials.StainlessSteel), 'P', OrePrefixes.pipeLarge.get(Materials.Polytetrafluoroethylene), 'M', ItemList.Electric_Motor_HV, 'B', ItemList.Hull_HV }); + + // Add Drone down link hatch + GT_ModHandler.addCraftingRecipe( + ItemList.Hatch_DroneDownLink.get(1L), + bits, + new Object[] { " S ", "CMC", "RRR", 'M', ItemList.Hatch_Maintenance, 'S', ItemList.Sensor_IV, 'R', + new ItemStack(GregTech_API.sBlockReinforced, 1, 9), 'C', ItemList.Conveyor_Module_EV }); + + // And Drone Centre + GT_Values.RA.stdBuilder() + .itemInputs( + ItemList.Casing_Assembler.get(1), + ItemList.Cover_SolarPanel_HV.get(4), + ItemList.Conveyor_Module_IV.get(2), + ItemList.Robot_Arm_IV.get(2), + ItemList.Sensor_IV.get(2), + ItemList.Energy_LapotronicOrb.get(4), + ItemList.Cover_WirelessNeedsMaintainance.get(1), + GalacticraftCore.isModLoaded() ? GT_ModHandler.getModItem(GalacticraftCore.ID, "item.basicItem", 1, 19) + : ItemList.Sensor_EV.get(4)) + .itemOutputs(ItemList.Machine_Multi_DroneCentre.get(1L)) + .fluidInputs(Materials.AdvancedGlue.getFluid(8000L)) + .duration(30 * SECONDS) + .eut(TierEU.RECIPE_IV) + .addTo(assemblerRecipes); } private static void registerShapelessCraftingRecipes() { diff --git a/src/main/java/gregtech/loaders/postload/recipes/AssemblerRecipes.java b/src/main/java/gregtech/loaders/postload/recipes/AssemblerRecipes.java index 0f5023e854..c5dd0473a3 100644 --- a/src/main/java/gregtech/loaders/postload/recipes/AssemblerRecipes.java +++ b/src/main/java/gregtech/loaders/postload/recipes/AssemblerRecipes.java @@ -99,6 +99,21 @@ public class AssemblerRecipes implements Runnable { .eut(48) .addTo(assemblerRecipes); + GT_Values.RA.stdBuilder() + .itemInputs( + GT_OreDictUnificator.get(OrePrefixes.plateDense, Materials.TungstenSteel, 16), + GT_OreDictUnificator.get(OrePrefixes.circuit.get(Materials.Data), 4), + ItemList.Electric_Motor_IV.get(16), + ItemList.Emitter_EV.get(4), + ItemList.Duct_Tape.get(64), + ItemList.Energy_LapotronicOrb.get(1), + GT_Utility.getIntegratedCircuit(4)) + .itemOutputs(ItemList.TierdDrone0.get(4)) + .fluidInputs(Materials.AdvancedGlue.getFluid(144)) + .duration(10 * SECONDS) + .eut(48) + .addTo(assemblerRecipes); + for (byte i = 0; i < 16; i = (byte) (i + 1)) { for (int j = 0; j < Dyes.VALUES[i].getSizeOfFluidList(); j++) { diff --git a/src/main/java/gregtech/loaders/postload/recipes/AssemblyLineRecipes.java b/src/main/java/gregtech/loaders/postload/recipes/AssemblyLineRecipes.java index 474e0575ac..8748c96654 100644 --- a/src/main/java/gregtech/loaders/postload/recipes/AssemblyLineRecipes.java +++ b/src/main/java/gregtech/loaders/postload/recipes/AssemblyLineRecipes.java @@ -1,6 +1,9 @@ package gregtech.loaders.postload.recipes; import static gregtech.api.enums.Mods.GTPlusPlus; +import static gregtech.api.enums.Mods.GregTech; +import static gregtech.api.enums.Mods.NewHorizonsCoreMod; +import static gregtech.api.enums.Mods.TecTech; import static gregtech.api.util.GT_RecipeBuilder.HOURS; import static gregtech.api.util.GT_RecipeBuilder.MINUTES; import static gregtech.api.util.GT_RecipeBuilder.SECONDS; @@ -19,6 +22,7 @@ import gregtech.api.enums.Materials; import gregtech.api.enums.OrePrefixes; import gregtech.api.enums.TierEU; import gregtech.api.util.ExternalMaterials; +import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_OreDictUnificator; public class AssemblyLineRecipes implements Runnable { @@ -840,5 +844,51 @@ public class AssemblyLineRecipes implements Runnable { .duration(60 * SECONDS) .eut(TierEU.RECIPE_UV) .addTo(AssemblyLine); + + // Drone T2 + GT_Values.RA.stdBuilder() + .metadata(RESEARCH_ITEM, ItemList.TierdDrone0.get(1)) + .metadata(RESEARCH_TIME, 2 * HOURS) + .itemInputs( + GT_OreDictUnificator.get(OrePrefixes.plateDense, Materials.NaquadahAlloy, 16), + new Object[] { OrePrefixes.circuit.get(Materials.SuperconductorUHV), 4 }, + NewHorizonsCoreMod.isModLoaded() + ? GT_ModHandler.getModItem(NewHorizonsCoreMod.ID, "item.HeavyDutyRocketEngineTier3", 4) + : ItemList.Casing_Firebox_TungstenSteel.get(16), + ItemList.Large_Fluid_Cell_Osmium.get(1), + GT_OreDictUnificator.get(OrePrefixes.pipeQuadruple, Materials.MysteriousCrystal, 1), + ItemList.Emitter_ZPM.get(4), + ItemList.Energy_Module.get(1), + ItemList.Cover_WirelessNeedsMaintainance.get(1)) + .itemOutputs(ItemList.TierdDrone1.get(4)) + .fluidInputs( + new FluidStack(solderIndalloy, 576), + FluidRegistry.getFluidStack(GTPlusPlus.isModLoaded() ? "fluid.rocketfuelmixc" : "nitrofuel", 4000)) + .duration(60 * SECONDS) + .eut(TierEU.RECIPE_UV) + .addTo(AssemblyLine); + + // Drone T3 + GT_Values.RA.stdBuilder() + .metadata(RESEARCH_ITEM, ItemList.TierdDrone1.get(1)) + .metadata(RESEARCH_TIME, 8 * HOURS) + .itemInputs( + GT_OreDictUnificator.get(OrePrefixes.plateDense, Materials.Infinity, 16), + new Object[] { OrePrefixes.circuit.get(Materials.Bio), 4 }, + ItemList.Field_Generator_UV.get(16), + ItemList.Gravistar.get(8), + ItemList.Emitter_UV.get(4), + TecTech.isModLoaded() ? GT_ModHandler.getModItem(GregTech.ID, "gt.blockmachines", 16, 15497) + : ItemList.Hatch_AutoMaintenance.get(64), + ItemList.Energy_Cluster.get(8), + ItemList.Cover_WirelessNeedsMaintainance.get(1)) + .itemOutputs(ItemList.TierdDrone2.get(1)) + .fluidInputs( + new FluidStack(solderIndalloy, 144000), + GTPlusPlus.isModLoaded() ? FluidRegistry.getFluidStack("molten.ethylcyanoacrylatesuperglue", 2000) + : Materials.AdvancedGlue.getFluid(256000)) + .duration(60 * SECONDS) + .eut(TierEU.RECIPE_UHV) + .addTo(AssemblyLine); } } diff --git a/src/main/java/gregtech/loaders/preload/GT_Loader_Item_Block_And_Fluid.java b/src/main/java/gregtech/loaders/preload/GT_Loader_Item_Block_And_Fluid.java index 0d1257350d..9373e4b12f 100644 --- a/src/main/java/gregtech/loaders/preload/GT_Loader_Item_Block_And_Fluid.java +++ b/src/main/java/gregtech/loaders/preload/GT_Loader_Item_Block_And_Fluid.java @@ -60,6 +60,7 @@ import gregtech.common.blocks.GT_Block_Casings6; import gregtech.common.blocks.GT_Block_Casings8; import gregtech.common.blocks.GT_Block_Casings9; import gregtech.common.blocks.GT_Block_Concretes; +import gregtech.common.blocks.GT_Block_Drone; import gregtech.common.blocks.GT_Block_Granites; import gregtech.common.blocks.GT_Block_Machines; import gregtech.common.blocks.GT_Block_Metal; @@ -78,7 +79,9 @@ import gregtech.common.items.GT_MetaGenerated_Item_98; import gregtech.common.items.GT_MetaGenerated_Item_99; import gregtech.common.items.GT_MetaGenerated_Tool_01; import gregtech.common.items.GT_NeutronReflector_Item; +import gregtech.common.items.GT_TierDrone; import gregtech.common.items.GT_VolumetricFlask; +import gregtech.common.tileentities.render.TileDrone; public class GT_Loader_Item_Block_And_Fluid implements Runnable { @@ -540,7 +543,7 @@ public class GT_Loader_Item_Block_And_Fluid implements Runnable { GregTech_API.sBlockConcretes = new GT_Block_Concretes(); GregTech_API.sBlockStones = new GT_Block_Stones(); GregTech_API.sBlockOres1 = new GT_Block_Ores(); - + GregTech_API.sDroneRender = new GT_Block_Drone(); // meta ID order, DO NOT CHANGE ORDER GregTech_API.sBlockMetal1 = new GT_Block_Metal( @@ -664,6 +667,9 @@ public class GT_Loader_Item_Block_And_Fluid implements Runnable { tBaseMetaTileEntity.getClass() .getName()); + GT_Log.out.println("GT_Mod: Registering the DroneRender."); + GameRegistry.registerTileEntity(TileDrone.class, "DroneRender"); + GT_Log.out.println("GT_Mod: Registering the BaseMetaPipeEntity."); GameRegistry.registerTileEntity(BaseMetaPipeEntity.class, "BaseMetaPipeEntity"); FMLInterModComms.sendMessage(AppliedEnergistics2.ID, "whitelist-spatial", BaseMetaPipeEntity.class.getName()); @@ -2208,5 +2214,12 @@ public class GT_Loader_Item_Block_And_Fluid implements Runnable { .registerMachineBlock(GT_Utility.getBlockFromStack(GT_ModHandler.getIC2Item("reinforcedGlass", 0)), 0); GregTech_API.sSolenoidCoilCasings = new GT_Cyclotron_Coils(); + ItemList.TierdDrone0 + .set(new GT_TierDrone("tierdDrone0", "Drone (Level 1)", "Quadcopter Stable Small Aircraft", 1)); + ItemList.TierdDrone1 + .set(new GT_TierDrone("tierdDrone1", "Drone (Level 2)", "Dual Turbo High-Ejection Medium Aircraft", 2)); + ItemList.TierdDrone2 + .set(new GT_TierDrone("tierdDrone2", "Drone (Level 3)", "Single Engine Anti-Gravity Large Aircraft", 3)); + } } diff --git a/src/main/java/gregtech/loaders/preload/GT_Loader_MetaTileEntities.java b/src/main/java/gregtech/loaders/preload/GT_Loader_MetaTileEntities.java index 9977af29f8..d1196552c6 100644 --- a/src/main/java/gregtech/loaders/preload/GT_Loader_MetaTileEntities.java +++ b/src/main/java/gregtech/loaders/preload/GT_Loader_MetaTileEntities.java @@ -99,6 +99,8 @@ import static gregtech.api.enums.MetaTileEntityIDs.DYNAMO_HATCH_UHV; import static gregtech.api.enums.MetaTileEntityIDs.DYNAMO_HATCH_ULV; import static gregtech.api.enums.MetaTileEntityIDs.DYNAMO_HATCH_UV; import static gregtech.api.enums.MetaTileEntityIDs.DYNAMO_HATCH_ZPM; +import static gregtech.api.enums.MetaTileEntityIDs.DroneDownLink; +import static gregtech.api.enums.MetaTileEntityIDs.Drone_Centre; import static gregtech.api.enums.MetaTileEntityIDs.EBF_CONTROLLER; import static gregtech.api.enums.MetaTileEntityIDs.ENERGY_HATCH_EV; import static gregtech.api.enums.MetaTileEntityIDs.ENERGY_HATCH_HV; @@ -577,6 +579,8 @@ import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_ProcessingA import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_PyrolyseOven; import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_TranscendentPlasmaMixer; import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_VacuumFreezer; +import gregtech.common.tileentities.machines.multi.drone.GT_MetaTileEntity_DroneCentre; +import gregtech.common.tileentities.machines.multi.drone.GT_MetaTileEntity_Hatch_DroneDownLink; import gregtech.common.tileentities.machines.steam.GT_MetaTileEntity_AlloySmelter_Bronze; import gregtech.common.tileentities.machines.steam.GT_MetaTileEntity_AlloySmelter_Steel; import gregtech.common.tileentities.machines.steam.GT_MetaTileEntity_Compressor_Bronze; @@ -859,7 +863,6 @@ public class GT_Loader_MetaTileEntities implements Runnable { // TODO CHECK CIRC LARGE_TUNGSTENSTEEL_BOILER_CONTROLLER.ID, "multimachine.boiler.tungstensteel", "Large Tungstensteel Boiler").getStackForm(1L)); - ItemList.FusionComputer_LuV.set( new GT_MetaTileEntity_FusionComputer1( FUSION_CONTROLLER_MKI.ID, @@ -1029,7 +1032,9 @@ public class GT_Loader_MetaTileEntities implements Runnable { // TODO CHECK CIRC ItemList.NanoForge.set( new GT_MetaTileEntity_NanoForge(NANO_FORGE_CONTROLLER.ID, "multimachine.nanoforge", "Nano Forge") .getStackForm(1)); - + ItemList.Machine_Multi_DroneCentre.set( + new GT_MetaTileEntity_DroneCentre(Drone_Centre.ID, "multimachine_DroneCentre", "Drone Centre") + .getStackForm(1)); } private static void registerSteamMachines() { @@ -4091,6 +4096,12 @@ public class GT_Loader_MetaTileEntities implements Runnable { // TODO CHECK CIRC "Auto Maintenance Hatch", 6, true).getStackForm(1L)); + ItemList.Hatch_DroneDownLink.set( + new GT_MetaTileEntity_Hatch_DroneDownLink( + DroneDownLink.ID, + "hatch.dronedownlink", + "Drone DownLink Module", + 5).getStackForm(1)); ItemList.Hatch_DataAccess_EV.set( new GT_MetaTileEntity_Hatch_DataAccess(DATA_ACCESS_HATCH.ID, "hatch.dataaccess", "Data Access Hatch", 4) .getStackForm(1L)); |