aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/gregtech/api/GregTech_API.java1
-rw-r--r--src/main/java/gregtech/api/enums/ItemList.java3
-rw-r--r--src/main/java/gregtech/api/enums/MetaTileEntityIDs.java3
-rw-r--r--src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java1
-rw-r--r--src/main/java/gregtech/api/recipe/check/ResultMissingItem.java60
-rw-r--r--src/main/java/gregtech/api/util/GT_Utility.java16
-rw-r--r--src/main/java/gregtech/common/GT_Client.java2
-rw-r--r--src/main/java/gregtech/common/blocks/GT_WormholeRenderBlock.java75
-rw-r--r--src/main/java/gregtech/common/render/GT_WormholeRenderer.java79
-rw-r--r--src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_WormholeGenerator.java1119
-rw-r--r--src/main/java/gregtech/common/tileentities/render/TileWormhole.java98
-rw-r--r--src/main/java/gregtech/loaders/preload/GT_Loader_Item_Block_And_Fluid.java5
-rw-r--r--src/main/java/gregtech/loaders/preload/GT_Loader_MetaTileEntities.java7
-rw-r--r--src/main/resources/assets/gregtech/lang/en_US.lang1
14 files changed, 1468 insertions, 2 deletions
diff --git a/src/main/java/gregtech/api/GregTech_API.java b/src/main/java/gregtech/api/GregTech_API.java
index a65f9eedb5..cdcc3b4a0f 100644
--- a/src/main/java/gregtech/api/GregTech_API.java
+++ b/src/main/java/gregtech/api/GregTech_API.java
@@ -301,6 +301,7 @@ public class GregTech_API {
public static Block sBlockGlass1;
public static Block sBlockTintedGlass;
public static Block sLaserRender;
+ public static Block sWormholeRender;
/**
* Getting assigned by the Config
*/
diff --git a/src/main/java/gregtech/api/enums/ItemList.java b/src/main/java/gregtech/api/enums/ItemList.java
index 1f5d223a6b..57a44373b6 100644
--- a/src/main/java/gregtech/api/enums/ItemList.java
+++ b/src/main/java/gregtech/api/enums/ItemList.java
@@ -2040,6 +2040,8 @@ public enum ItemList implements IItemContainer {
TierdDrone1,
TierdDrone2,
Hatch_DroneDownLink,
+ Casing_Shielded_Accelerator,
+ WormholeGenerator,
Hatch_pHSensor,
Hatch_LensHousing,
Hatch_LensIndicator,
@@ -2069,7 +2071,6 @@ public enum ItemList implements IItemContainer {
Quark_Creation_Catalyst_Bottom,
Quark_Creation_Catalyst_Top,
Quark_Creation_Catalyst_Unaligned,
- Casing_Shielded_Accelerator,
GlassOmniPurposeInfinityFused,
GlassQuarkContainment,
BlockQuarkPipe,
diff --git a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java
index 78bc31ec57..de74b51806 100644
--- a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java
+++ b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java
@@ -701,7 +701,8 @@ public enum MetaTileEntityIDs {
sofc2(13102),
tfft(13104),
lsc(13106),
- tfftHatch(13109);
+ tfftHatch(13109),
+ WORMHOLE_GENERATOR_CONTROLLER(13115);
public final int ID;
diff --git a/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java b/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java
index 41ea858fec..5844a49180 100644
--- a/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java
+++ b/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java
@@ -155,5 +155,6 @@ public final class CheckRecipeResultRegistry {
register(new ResultInsufficientMachineTier(0));
register(new ResultInsufficientStartupPower(0));
register(new ResultInsufficientStartupPowerBigInt(BigInteger.ZERO));
+ register(new ResultMissingItem());
}
}
diff --git a/src/main/java/gregtech/api/recipe/check/ResultMissingItem.java b/src/main/java/gregtech/api/recipe/check/ResultMissingItem.java
new file mode 100644
index 0000000000..868d664109
--- /dev/null
+++ b/src/main/java/gregtech/api/recipe/check/ResultMissingItem.java
@@ -0,0 +1,60 @@
+package gregtech.api.recipe.check;
+
+import java.util.Objects;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.client.resources.I18n;
+import net.minecraft.item.ItemStack;
+import net.minecraft.network.PacketBuffer;
+
+import cpw.mods.fml.common.network.ByteBufUtils;
+
+public class ResultMissingItem implements CheckRecipeResult {
+
+ @Nullable
+ public ItemStack itemStack;
+
+ public ResultMissingItem() {
+
+ }
+
+ public ResultMissingItem(@Nullable ItemStack itemStack) {
+ this.itemStack = itemStack;
+ }
+
+ @Override
+ @Nonnull
+ public String getID() {
+ return "missing_item";
+ }
+
+ @Override
+ public boolean wasSuccessful() {
+ return false;
+ }
+
+ @Override
+ @Nonnull
+ public String getDisplayString() {
+ return Objects.requireNonNull(
+ I18n.format("GT5U.gui.text.missing_item", itemStack != null ? itemStack.getDisplayName() : "null"));
+ }
+
+ @Override
+ @Nonnull
+ public CheckRecipeResult newInstance() {
+ return new ResultMissingItem(itemStack != null ? itemStack.copy() : null);
+ }
+
+ @Override
+ public void encode(@Nonnull PacketBuffer buffer) {
+ ByteBufUtils.writeItemStack(buffer, itemStack);
+ }
+
+ @Override
+ public void decode(PacketBuffer buffer) {
+ this.itemStack = ByteBufUtils.readItemStack(buffer);
+ }
+}
diff --git a/src/main/java/gregtech/api/util/GT_Utility.java b/src/main/java/gregtech/api/util/GT_Utility.java
index c0f7413995..581c22852e 100644
--- a/src/main/java/gregtech/api/util/GT_Utility.java
+++ b/src/main/java/gregtech/api/util/GT_Utility.java
@@ -3489,6 +3489,7 @@ public class GT_Utility {
EnumChatFormatting.GOLD + GT_Utility.trans("166", "Is valid Beacon Pyramid Material")
+ EnumChatFormatting.RESET);
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this block's info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
}
@@ -3517,6 +3518,7 @@ public class GT_Utility {
}
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this tile's fluid tank info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3532,6 +3534,7 @@ public class GT_Utility {
if (temp != null) tList.addAll(temp);
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this block's debug info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3585,6 +3588,7 @@ public class GT_Utility {
}
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this leaves' info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3636,6 +3640,7 @@ public class GT_Utility {
}
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this crop's info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3647,6 +3652,7 @@ public class GT_Utility {
tList.addAll(Arrays.asList(info.getInfoData()));
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
}
@@ -3660,6 +3666,7 @@ public class GT_Utility {
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's owner.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
}
@@ -3702,6 +3709,7 @@ public class GT_Utility {
+ " EU");
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's energy info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
}
@@ -3716,6 +3724,7 @@ public class GT_Utility {
if (tString != null && !tString.equals(E)) tList.add(tString);
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's covers.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3747,6 +3756,7 @@ public class GT_Utility {
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's progress.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3762,6 +3772,7 @@ public class GT_Utility {
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's upgrades.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3783,6 +3794,7 @@ public class GT_Utility {
+ " EU");
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's IC2 energy info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3799,6 +3811,7 @@ public class GT_Utility {
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's EU conduction info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3826,6 +3839,7 @@ public class GT_Utility {
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's IC@ wrenchability.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3845,6 +3859,7 @@ public class GT_Utility {
}
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this device's alignment info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
@@ -3869,6 +3884,7 @@ public class GT_Utility {
+ EnumChatFormatting.RESET);
}
} catch (Throwable e) {
+ tList.add(String.format("§cAn exception was thrown while fetching this reactor's info.§r"));
if (D1) e.printStackTrace(GT_Log.err);
}
return rEUAmount;
diff --git a/src/main/java/gregtech/common/GT_Client.java b/src/main/java/gregtech/common/GT_Client.java
index 69fc98212f..9de59e8661 100644
--- a/src/main/java/gregtech/common/GT_Client.java
+++ b/src/main/java/gregtech/common/GT_Client.java
@@ -97,6 +97,7 @@ 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_WormholeRenderer;
import gregtech.common.render.items.GT_MetaGenerated_Item_Renderer;
import gregtech.common.tileentities.debug.GT_MetaTileEntity_AdvDebugStructureWriter;
import gregtech.loaders.ExtraIcons;
@@ -624,6 +625,7 @@ public class GT_Client extends GT_Proxy implements Runnable {
new GT_MultiTile_Renderer();
new GT_RenderDrone();
new GT_LaserRenderer();
+ new GT_WormholeRenderer();
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/blocks/GT_WormholeRenderBlock.java b/src/main/java/gregtech/common/blocks/GT_WormholeRenderBlock.java
new file mode 100644
index 0000000000..1c6e434477
--- /dev/null
+++ b/src/main/java/gregtech/common/blocks/GT_WormholeRenderBlock.java
@@ -0,0 +1,75 @@
+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.common.tileentities.render.TileWormhole;
+
+public class GT_WormholeRenderBlock extends Block {
+
+ public GT_WormholeRenderBlock() {
+ super(Material.iron);
+ this.setResistance(20f);
+ this.setHardness(-1.0f);
+ // this.setCreativeTab(TecTech.creativeTabTecTech);
+ this.setBlockName("WormholeRenderer");
+ 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 String getUnlocalizedName() {
+ return "gt.wormholerenderer";
+ }
+
+ @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 TileWormhole();
+ }
+
+ @Override
+ public ArrayList<ItemStack> getDrops(World world, int x, int y, int z, int meta, int fortune) {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public boolean isCollidable() {
+ return true;
+ }
+
+}
diff --git a/src/main/java/gregtech/common/render/GT_WormholeRenderer.java b/src/main/java/gregtech/common/render/GT_WormholeRenderer.java
new file mode 100644
index 0000000000..43385eb861
--- /dev/null
+++ b/src/main/java/gregtech/common/render/GT_WormholeRenderer.java
@@ -0,0 +1,79 @@
+package gregtech.common.render;
+
+import static com.github.technus.tectech.rendering.EOH.EOH_RenderingUtils.addRenderedBlockInWorld;
+
+import net.minecraft.block.Block;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.texture.TextureMap;
+import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
+import net.minecraft.init.Blocks;
+import net.minecraft.tileentity.TileEntity;
+
+import org.lwjgl.opengl.GL11;
+
+import cpw.mods.fml.client.registry.ClientRegistry;
+import gregtech.common.tileentities.render.TileWormhole;
+
+public class GT_WormholeRenderer extends TileEntitySpecialRenderer {
+
+ public GT_WormholeRenderer() {
+ ClientRegistry.bindTileEntitySpecialRenderer(TileWormhole.class, this);
+ }
+
+ private static final double trimPercentage = .95;
+ private static final double corePercentage = trimPercentage / Math.sqrt(3);
+
+ private static void render(Block coreBlock, double rotation) {
+
+ GL11.glPushMatrix();
+ GL11.glRotated(rotation, 2, 1, 0);
+ GL11.glScaled(-1, -1, -1);
+
+ Tessellator.instance.startDrawingQuads();
+ Tessellator.instance.setColorOpaque_F(1f, 1f, 1f);
+ addRenderedBlockInWorld(Blocks.quartz_block, 0, 0, 0, 0);
+ Tessellator.instance.draw();
+
+ GL11.glScaled(trimPercentage, trimPercentage, trimPercentage);
+
+ Tessellator.instance.startDrawingQuads();
+ Tessellator.instance.setColorOpaque_F(0.1f, 0.1f, 0.1f);
+ addRenderedBlockInWorld(Blocks.coal_block, 0, 0, 0, 0);
+ Tessellator.instance.draw();
+ GL11.glPopMatrix();
+
+ if (coreBlock != null) {
+ GL11.glPushMatrix();
+ GL11.glScaled(corePercentage, corePercentage, corePercentage);
+ GL11.glRotated(rotation, 0, -2, .1);
+ Tessellator.instance.startDrawingQuads();
+ Tessellator.instance.setColorOpaque_F(1f, 1f, 1f);
+ addRenderedBlockInWorld(coreBlock, 0, 0, 0, 0);
+ Tessellator.instance.draw();
+ GL11.glPopMatrix();
+ }
+
+ }
+
+ @Override
+ public void renderTileEntityAt(TileEntity tile, double x, double y, double z, float timeSinceLastTick) {
+
+ if (tile instanceof TileWormhole wTile) {
+ GL11.glPushMatrix();
+ GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5);
+ GL11.glScaled(wTile.targetRadius, wTile.targetRadius, wTile.targetRadius);
+ GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
+ GL11.glDisable(GL11.GL_LIGHTING);
+
+ double rotationTimer = wTile.getWorldObj()
+ .getWorldInfo()
+ .getWorldTotalTime() + timeSinceLastTick;
+
+ this.bindTexture(TextureMap.locationBlocksTexture);
+ render(wTile.getBlock(), rotationTimer);
+
+ GL11.glPopAttrib();
+ GL11.glPopMatrix();
+ }
+ }
+}
diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_WormholeGenerator.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_WormholeGenerator.java
new file mode 100644
index 0000000000..d0c356e4fe
--- /dev/null
+++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_WormholeGenerator.java
@@ -0,0 +1,1119 @@
+package gregtech.common.tileentities.machines.multi;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.withChannel;
+import static goodgenerator.util.DescTextLocalization.BLUE_PRINT_INFO;
+import static gregtech.api.enums.GT_HatchElement.InputBus;
+import static gregtech.api.enums.GT_HatchElement.Maintenance;
+import static gregtech.api.enums.GT_Values.V;
+import static gregtech.api.enums.GT_Values.VN;
+import static gregtech.api.enums.Textures.BlockIcons.getCasingTextureForId;
+import static gregtech.api.util.GT_StructureUtility.buildHatchAdder;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.github.bartimaeusnek.bartworks.API.BorosilicateGlass;
+import com.github.technus.tectech.thing.casing.GT_Block_CasingsTT;
+import com.github.technus.tectech.thing.casing.TT_Container_Casings;
+import com.github.technus.tectech.thing.metaTileEntity.hatch.GT_MetaTileEntity_Hatch_DynamoMulti;
+import com.github.technus.tectech.thing.metaTileEntity.hatch.GT_MetaTileEntity_Hatch_EnergyMulti;
+import com.google.common.collect.MapMaker;
+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.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn;
+import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget;
+import com.gtnewhorizons.modularui.common.widget.SlotWidget;
+import com.gtnewhorizons.modularui.common.widget.TextWidget;
+
+import appeng.api.AEApi;
+import gregtech.GT_Mod;
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.TierEU;
+import gregtech.api.interfaces.IHatchElement;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords;
+import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.ResultMissingItem;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
+import gregtech.api.util.IGT_HatchAdder;
+import gregtech.common.tileentities.render.TileWormhole;
+import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock;
+
+public class GT_MetaTileEntity_WormholeGenerator extends
+ GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_WormholeGenerator> implements ISurvivalConstructable {
+
+ /**
+ * Number of seconds to average the wormhole energy over.
+ */
+ public static int WH_ENERGY_AVG_WINDOW = 90;
+
+ /**
+ * The amount of EU received per EU sent.
+ */
+ public static double TRANSFER_EFFICIENCY = (1.0 - 0.00_0004 * 64);
+
+ /**
+ * The amount of EU to lose every second the wormhole decays.
+ */
+ public static double DECAY_RATE = 0.25;
+
+ /**
+ * The amount of EU that the wormhole collapses at.
+ */
+ public static double COLLAPSE_THRESHOLD = 32;
+
+ /**
+ * The wormhole render radius percent of the max size when specified wormhole power is reached (purely aesthetical)
+ */
+ public static double RENDER_PERCENT_TARGET = .1;
+
+ /**
+ * Wormhole energy to specify reach the specified size percentage (purely aesthetical)
+ */
+ public static double RENDER_TARGET_ENERGY = TierEU.IV * 256;
+
+ /**
+ * Maximum wormhole radius (purely aesthetical)
+ */
+ public static double RENDER_MAX_RADIUS = 2.999 / Math.sqrt(3);
+
+ private static final String STRUCTURE_PIECE_MAIN = "main";
+ private static final byte GLASS_TIER_UNSET = -2;
+
+ private static final int TT_CASING_INDEX = GT_Block_CasingsTT.textureOffset;
+
+ private static final int TOP_HATCH = 0, BOTTOM_HATCH = 1, LEFT_HATCH = 2, RIGHT_HATCH = 3, BACK_HATCH = 4,
+ FRONT_HATCH = 5, MAX_HATCHES = 6;
+
+ private static final int[] OPPOSITES = { BOTTOM_HATCH, TOP_HATCH, RIGHT_HATCH, LEFT_HATCH, FRONT_HATCH,
+ BACK_HATCH, };
+
+ private static final String[] HATCH_NAMES = { "Top", "Bottom", "Left", "Right", "Back", "Front" };
+ private static final boolean[] HATCH_MASK = { true, true, true, true, false, false };
+
+ private byte mGlassTier = -2;
+ private boolean mStructureBadGlassTier = false;
+
+ private final GT_MetaTileEntity_Hatch_EnergyMulti[] mSendHatches = new GT_MetaTileEntity_Hatch_EnergyMulti[MAX_HATCHES];
+ private final GT_MetaTileEntity_Hatch_DynamoMulti[] mReceiveHatches = new GT_MetaTileEntity_Hatch_DynamoMulti[MAX_HATCHES];
+
+ private final ItemStack singularity = AEApi.instance()
+ .definitions()
+ .materials()
+ .singularity()
+ .maybeStack(1)
+ .get();
+ private final ItemStack qeSingularity = AEApi.instance()
+ .definitions()
+ .materials()
+ .qESingularity()
+ .maybeStack(1)
+ .get();
+
+ private WormholeLink mLink;
+ private final WeakReference<GT_MetaTileEntity_WormholeGenerator> mSelfReference = new WeakReference<>(this);
+
+ private double mWormholeEnergy_UI = 0;
+
+ private boolean mIsUnloading = false;
+
+ public GT_MetaTileEntity_WormholeGenerator(int aID, String aName, String aNameRegional) {
+ super(aID, aName, aNameRegional);
+ }
+
+ public GT_MetaTileEntity_WormholeGenerator(String aName) {
+ super(aName);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new GT_MetaTileEntity_WormholeGenerator(mName);
+ }
+
+ @Override
+ public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection side, ForgeDirection facing,
+ int colorIndex, boolean active, boolean redstoneLevel) {
+ if (side == facing) {
+ if (active) {
+ return new ITexture[] { getCasingTextureForId(TT_CASING_INDEX), TextureFactory.builder()
+ .addIcon(TexturesGtBlock.Overlay_Machine_Controller_Advanced_Active)
+ .extFacing()
+ .build() };
+ } else {
+ return new ITexture[] { getCasingTextureForId(TT_CASING_INDEX), TextureFactory.builder()
+ .addIcon(TexturesGtBlock.Overlay_Machine_Controller_Advanced)
+ .extFacing()
+ .build() };
+ }
+ }
+ return new ITexture[] { getCasingTextureForId(TT_CASING_INDEX) };
+ }
+
+ // #region Structure
+
+ // spotless:off
+ private static final IStructureDefinition<GT_MetaTileEntity_WormholeGenerator> STRUCTURE_DEFINITION = StructureDefinition
+ .<GT_MetaTileEntity_WormholeGenerator>builder()
+ .addShape(
+ STRUCTURE_PIECE_MAIN,
+ transpose(
+ new String[][]{
+ {" "," F "," EEE "," FEtEF "," EEE "," F "," "},
+ {" F "," AADAA "," A B A ","FDBBBDF"," A B A "," AADAA "," F "},
+ {" EEE "," A B A ","E E","EB BE","E E"," A B A "," EEE "},
+ {" FE~EF ","FA B AF","E E","lB Br","E E","FA B AF"," FEEEF "},
+ {" EEE "," A B A ","E E","EB BE","E E"," A B A "," EEE "},
+ {" F "," AADAA "," A B A ","FDBBBDF"," A B A "," AADAA "," F "},
+ {" "," F "," EEE "," FEbEF "," EEE "," F "," "}
+ }))
+ .addElement('E',
+ buildHatchAdder(GT_MetaTileEntity_WormholeGenerator.class)
+ .atLeast(Maintenance, InputBus)
+ .casingIndex(TT_CASING_INDEX) // High Power Casing
+ .dot(1)
+ .buildAndChain(lazy(() -> ofBlock(TT_Container_Casings.sBlockCasingsTT, 0))) // High Power Casing
+ )
+ .addElement(
+ 'A',
+ withChannel(
+ "glass",
+ BorosilicateGlass.ofBoroGlass(GLASS_TIER_UNSET, (te, t) -> te.mGlassTier = t, te -> te.mGlassTier))
+ )
+ .addElement('D', ofBlock(GregTech_API.sBlockCasings8, 5)) // Europium Reinforced Radiation Proof Machine Casing
+ .addElement('B', ofBlock(GregTech_API.sBlockCasings4, 7)) // Fusion Coil Block
+ .addElement('F', lazy(() -> ofBlock(TT_Container_Casings.sBlockCasingsTT, 4))) // Molecular Casing
+ .addElement('t',
+ buildHatchAdder(GT_MetaTileEntity_WormholeGenerator.class)
+ .anyOf(new TransferHatch(TOP_HATCH))
+ .casingIndex(TT_CASING_INDEX) // High Power Casing
+ .dot(2)
+ .buildAndChain(lazy(() -> ofBlock(TT_Container_Casings.sBlockCasingsTT, 0))) // High Power Casing
+ )
+ .addElement('b',
+ buildHatchAdder(GT_MetaTileEntity_WormholeGenerator.class)
+ .anyOf(new TransferHatch(BOTTOM_HATCH))
+ .casingIndex(TT_CASING_INDEX) // High Power Casing
+ .dot(2)
+ .buildAndChain(lazy(() -> ofBlock(TT_Container_Casings.sBlockCasingsTT, 0))) // High Power Casing
+ )
+ .addElement('l',
+ buildHatchAdder(GT_MetaTileEntity_WormholeGenerator.class)
+ .anyOf(new TransferHatch(LEFT_HATCH))
+ .casingIndex(TT_CASING_INDEX) // High Power Casing
+ .dot(2)
+ .buildAndChain(lazy(() -> ofBlock(TT_Container_Casings.sBlockCasingsTT, 0))) // High Power Casing
+ )
+ .addElement('r',
+ buildHatchAdder(GT_MetaTileEntity_WormholeGenerator.class)
+ .anyOf(new TransferHatch(RIGHT_HATCH))
+ .casingIndex(TT_CASING_INDEX) // High Power Casing
+ .dot(2)
+ .buildAndChain(lazy(() -> ofBlock(TT_Container_Casings.sBlockCasingsTT, 0))) // High Power Casing
+ )
+ .build();
+ // spotless:on
+
+ private static class TransferHatch implements IHatchElement<GT_MetaTileEntity_WormholeGenerator> {
+
+ public final int mIndex;
+
+ public TransferHatch(int index) {
+ this.mIndex = index;
+ }
+
+ @Override
+ public List<? extends Class<? extends IMetaTileEntity>> mteClasses() {
+ return Arrays.asList(GT_MetaTileEntity_Hatch_EnergyMulti.class, GT_MetaTileEntity_Hatch_DynamoMulti.class);
+ }
+
+ @Override
+ public IGT_HatchAdder<? super GT_MetaTileEntity_WormholeGenerator> adder() {
+ return (tile, aTileEntity, aBaseCasingIndex) -> {
+ if (aTileEntity == null) return false;
+
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+
+ if (aMetaTileEntity == null) return false;
+
+ if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_EnergyMulti input) {
+ input.updateTexture(aBaseCasingIndex);
+ input.updateCraftingIcon(tile.getMachineCraftingIcon());
+ tile.mSendHatches[mIndex] = input;
+ return true;
+ } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_DynamoMulti output) {
+ output.updateTexture(aBaseCasingIndex);
+ output.updateCraftingIcon(tile.getMachineCraftingIcon());
+ tile.mReceiveHatches[mIndex] = output;
+ return true;
+ }
+
+ return false;
+ };
+ }
+
+ @Override
+ public String name() {
+ return "TransferHatch";
+ }
+
+ @Override
+ public long count(GT_MetaTileEntity_WormholeGenerator t) {
+ return t.mExoticEnergyHatches.size();
+ }
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ protected SoundResource getProcessStartSound() {
+ return SoundResource.GT_MACHINES_FUSION_LOOP;
+ }
+
+ @Override
+ public IStructureDefinition<GT_MetaTileEntity_WormholeGenerator> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ if (!checkPiece(STRUCTURE_PIECE_MAIN, 3, 3, 0)) return false;
+
+ mStructureBadGlassTier = false;
+
+ for (var energyHatch : mExoticEnergyHatches) {
+ if (energyHatch.getBaseMetaTileEntity() == null) {
+ continue;
+ }
+
+ if (energyHatch.getTierForStructure() > mGlassTier) {
+ mStructureBadGlassTier = true;
+ }
+ }
+
+ return !mStructureBadGlassTier;
+ }
+
+ @Override
+ public void clearHatches() {
+ super.clearHatches();
+
+ Arrays.fill(mSendHatches, null);
+ Arrays.fill(mReceiveHatches, null);
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 3, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 3, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ // #endregion
+ @Override
+ public void onBlockDestroyed() {
+ super.onBlockDestroyed();
+ destroyRenderBlock();
+ }
+
+ @Override
+ public void onDisableWorking() {
+ super.onDisableWorking();
+ // destroyRenderBlock();
+ }
+
+ @Override
+ public void onStructureChange() {
+ super.onStructureChange();
+ if (!checkStructure(false, this.getBaseMetaTileEntity())) {
+ destroyRenderBlock();
+ }
+ }
+
+ private void destroyRenderBlock() {
+ IGregTechTileEntity gregTechTileEntity = this.getBaseMetaTileEntity();
+ if (gregTechTileEntity.getWorld() == null) {
+ return;
+ }
+
+ int x = gregTechTileEntity.getXCoord();
+ int y = gregTechTileEntity.getYCoord();
+ int z = gregTechTileEntity.getZCoord();
+
+ int xOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetX;
+ int yOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetY;
+ int zOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetZ;
+
+ int xTarget = x + xOffset;
+ int yTarget = y + yOffset;
+ int zTarget = z + zOffset;
+
+ Optional.of(gregTechTileEntity)
+ .map(IHasWorldObjectAndCoords::getWorld)
+ .ifPresent(w -> w.setBlock(xTarget, yTarget, zTarget, Blocks.air));
+ }
+
+ @Nullable
+ private TileWormhole createRenderBlock() {
+
+ IGregTechTileEntity gregTechTileEntity = this.getBaseMetaTileEntity();
+ World world = gregTechTileEntity.getWorld();
+
+ if (world == null) {
+ return null;
+ }
+
+ int x = gregTechTileEntity.getXCoord();
+ int y = gregTechTileEntity.getYCoord();
+ int z = gregTechTileEntity.getZCoord();
+
+ int xOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetX;
+ int yOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetY;
+ int zOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetZ;
+
+ int xTarget = x + xOffset;
+ int yTarget = y + yOffset;
+ int zTarget = z + zOffset;
+
+ world.setBlock(xTarget, yTarget, zTarget, Blocks.air);
+ world.setBlock(xTarget, yTarget, zTarget, GregTech_API.sWormholeRender);
+
+ TileWormhole wormhole = (TileWormhole) world.getTileEntity(xTarget, yTarget, zTarget);
+
+ if (wormhole == null) {
+ return null;
+ }
+ return wormhole;
+ }
+
+ @Nullable
+ private TileWormhole getRenderBlock() {
+ IGregTechTileEntity gregTechTileEntity = this.getBaseMetaTileEntity();
+
+ int x = gregTechTileEntity.getXCoord();
+ int y = gregTechTileEntity.getYCoord();
+ int z = gregTechTileEntity.getZCoord();
+
+ double xOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetX;
+ double zOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetZ;
+ double yOffset = 3 * getExtendedFacing().getRelativeBackInWorld().offsetY;
+
+ int wX = (int) (x + xOffset);
+ int wY = (int) (y + yOffset);
+ int wZ = (int) (z + zOffset);
+
+ TileEntity tile = Optional.ofNullable(gregTechTileEntity.getWorld())
+ .map(w -> w.getTileEntity(wX, wY, wZ))
+ .orElse(null);
+ if (tile instanceof TileWormhole wormhole) return wormhole;
+ return null;
+
+ }
+
+ public void updateRenderDim() {
+ TileWormhole temp = getRenderBlock();
+
+ World target = Optional.ofNullable(mLink)
+ .map(link -> link.getDest(mSelfReference))
+ .map(MetaTileEntity::getBaseMetaTileEntity)
+ .map(IHasWorldObjectAndCoords::getWorld)
+ .orElse(null);
+
+ TileWormhole hole = getRenderBlock();
+ if (hole == null) hole = createRenderBlock();
+
+ if (hole != null) {
+ hole.setDimFromWorld(target);
+ }
+ }
+
+ public void updateRenderRadius(double radius) {
+ TileWormhole hole = getRenderBlock();
+ if (hole == null) hole = createRenderBlock();
+
+ if (hole != null) {
+ hole.setRadius(radius);
+ }
+ }
+
+ private static double wormholeRadiusCalc(double energy) {
+ if (energy < COLLAPSE_THRESHOLD) return 0;
+
+ double offset = RENDER_TARGET_ENERGY + (COLLAPSE_THRESHOLD - RENDER_TARGET_ENERGY) / (RENDER_PERCENT_TARGET);
+ return RENDER_MAX_RADIUS * (COLLAPSE_THRESHOLD - energy) / (offset - energy);
+ }
+
+ // #region Logic
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public void onUnload() {
+ super.onUnload();
+ mIsUnloading = true;
+ if (mLink != null) {
+ mLink.disconnect(mSelfReference);
+ }
+ }
+
+ @Override
+ protected void runMachine(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
+ checkFrequency();
+
+ mMaxProgresstime = 20;
+ mEfficiency = Math.max(0, getMaxEfficiency(mInventory[1]) - ((getIdealStatus() - getRepairStatus()) * 1000));
+
+ if (doRandomMaintenanceDamage()) {
+ if (onRunningTick(mInventory[1])) {
+ markDirty();
+
+ if (++mProgresstime >= mMaxProgresstime) {
+ mProgresstime = 0;
+
+ if (mLink != null) {
+ mLink.update(mSelfReference);
+ }
+ checkRecipe();
+ }
+ }
+ }
+ }
+
+ @Override
+ @Nonnull
+ public CheckRecipeResult checkProcessing() {
+ if (mLink == null || !mLink.isConnected(mSelfReference)
+ || getBaseMetaTileEntity() == null
+ || !getBaseMetaTileEntity().isAllowedToWork()) {
+ return SimpleCheckRecipeResult.ofFailure("none");
+ }
+
+ if (mLink.isActive()) {
+ for (int i = 0; i < MAX_HATCHES; i++) {
+ if (!HATCH_MASK[i]) continue;
+
+ long optimal = mLink.mWormholeEnergy > Long.MAX_VALUE ? Long.MAX_VALUE : ((long) mLink.mWormholeEnergy);
+ if (getTransferable(i) > 0) {
+ if (mLink.mWormholeEnergy <= 0) {
+ var singularityStack = singularity.copy();
+
+ if (!depleteInput(singularityStack)) {
+ return new ResultMissingItem(singularityStack);
+ }
+ mLink.mWormholeEnergy = 1;
+ optimal = 1;
+ }
+ transferPower(optimal, i);
+ }
+ }
+ }
+
+ if (mLink.mWormholeEnergy > 0) {
+ return SimpleCheckRecipeResult.ofSuccess("none");
+ }
+ return SimpleCheckRecipeResult.ofFailure("none");
+ }
+
+ private void checkFrequency() {
+ if (mIsUnloading) {
+ return;
+ }
+
+ ItemStack link = null;
+
+ for (var slot : mInventory) {
+ if (slot != null && qeSingularity.getItem() == slot.getItem()
+ && qeSingularity.getItemDamage() == slot.getItemDamage()) {
+ link = slot;
+ break;
+ }
+ }
+
+ Long freq = link != null && link.getTagCompound() != null
+ && link.getTagCompound()
+ .hasKey("freq", 4 /* Long */) ? link.getTagCompound()
+ .getLong("freq") : null;
+
+ if (!Objects.equals(freq, mLink == null ? null : mLink.mFrequency)) {
+ if (mLink != null) {
+ mLink.disconnect(mSelfReference);
+ mLink = null;
+ }
+
+ if (freq != null) {
+ mLink = WormholeLink.get(freq);
+ mLink.connect(mSelfReference);
+ }
+ }
+ }
+
+ private long getTransferable(int index) {
+ var dest = mLink.getDest(mSelfReference);
+ if (dest == null || mMaxProgresstime == 0 || dest.mMaxProgresstime == 0) {
+ return 0;
+ }
+
+ var inputHatch = mSendHatches[index];
+ var outputHatch = dest.mReceiveHatches[OPPOSITES[index]];
+
+ if (inputHatch == null || outputHatch == null) {
+ return 0;
+ }
+
+ long available = inputHatch.getEUVar();
+ long empty = outputHatch.maxEUStore() - outputHatch.getEUVar();
+
+ return Math.min(available, empty);
+ }
+
+ private void transferPower(long optimal, int index) {
+ var dest = mLink.getDest(mSelfReference);
+ if (dest == null) {
+ return;
+ }
+
+ var inputHatch = mSendHatches[index];
+ var outputHatch = dest.mReceiveHatches[OPPOSITES[index]];
+
+ if (inputHatch == null || outputHatch == null) {
+ return;
+ }
+
+ long available = inputHatch.getEUVar();
+ long empty = outputHatch.maxEUStore() - outputHatch.getEUVar();
+ long maxSend = inputHatch.maxAmperesIn() * V[inputHatch.mTier] * 20;
+ long maxReceive = outputHatch.maxAmperesOut() * V[outputHatch.mTier] * 20;
+
+ // spotless:off
+ long toSend = (long)(Math.min(Math.min(Math.min(available, empty), maxSend), maxReceive) * (1.0 - (getIdealStatus() - getRepairStatus()) * 0.1));
+
+ double overclocks = Math.max(Math.log((double)toSend / (double)optimal) / Math.log(4.0), 0.0);
+
+ long toReceive = (long) (
+ toSend *
+ (1.0 / Math.pow(4.0, overclocks)) *
+ Math.pow(2.0, overclocks) *
+ (1.0 - (dest.getIdealStatus() - dest.getRepairStatus()) * 0.1) *
+ TRANSFER_EFFICIENCY
+ );
+ // spotless:on
+
+ inputHatch.setEUVar(inputHatch.getEUVar() - toSend);
+ outputHatch.setEUVar(outputHatch.getEUVar() + toReceive);
+
+ double size = wormholeRadiusCalc((double) optimal / 20);
+ this.updateRenderRadius(size);
+ dest.updateRenderRadius(size);
+
+ mLink.onEnergyTransferred(toSend);
+ mLink.mSendAmounts[index] += toSend;
+ mLink.mReceiveAmounts[OPPOSITES[index]] += toReceive;
+ }
+
+ @Override
+ public void saveNBTData(NBTTagCompound aNBT) {
+ super.saveNBTData(aNBT);
+
+ try {
+ if (mLink != null) {
+ mLink.tryPromote();
+
+ NBTTagCompound link = new NBTTagCompound();
+
+ link.setLong("mFrequency", mLink.mFrequency);
+ link.setDouble("mWormholeEnergy", mLink.mWormholeEnergy);
+
+ if (mLink.isMaster(mSelfReference)) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(baos);
+
+ dos.writeInt(mLink.mReceiveAmounts.length);
+ for (var x : mLink.mReceiveAmounts) {
+ dos.writeLong(x);
+ }
+
+ dos.writeInt(mLink.mSendAmounts.length);
+ for (var x : mLink.mSendAmounts) {
+ dos.writeLong(x);
+ }
+
+ link.setByteArray("data", baos.toByteArray());
+ }
+
+ aNBT.setTag("mLink", link);
+ }
+ } catch (Throwable t) {
+ GT_Mod.GT_FML_LOGGER.error("Could not save GT_MetaTileEntity_WormholeGenerator", t);
+ }
+
+ }
+
+ @Override
+ public void loadNBTData(NBTTagCompound aNBT) {
+ super.loadNBTData(aNBT);
+
+ checkFrequency();
+
+ if (aNBT.hasKey("mLink") && mLink != null) {
+ NBTTagCompound link = aNBT.getCompoundTag("mLink");
+
+ long freq = link.getLong("mFrequency");
+
+ try {
+ if (freq == mLink.mFrequency && mLink.isMaster(mSelfReference)) {
+ mLink.mWormholeEnergy = link.getDouble("mWormholeEnergy");
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(link.getByteArray("data"));
+ DataInputStream dis = new DataInputStream(bais);
+
+ long[] recv_amounts = new long[dis.readInt()];
+ for (int i = 0; i < recv_amounts.length; i++) {
+ recv_amounts[i] = dis.readLong();
+ }
+
+ System.arraycopy(
+ recv_amounts,
+ 0,
+ mLink.mReceiveAmounts,
+ 0,
+ Math.min(recv_amounts.length, mLink.mReceiveAmounts.length));
+
+ long[] send_amounts = new long[dis.readInt()];
+ for (int i = 0; i < send_amounts.length; i++) {
+ send_amounts[i] = dis.readLong();
+ }
+
+ System.arraycopy(
+ send_amounts,
+ 0,
+ mLink.mSendAmounts,
+ 0,
+ Math.min(send_amounts.length, mLink.mSendAmounts.length));
+ }
+ } catch (Throwable t) {
+ GT_Mod.GT_FML_LOGGER.error("Could not load GT_MetaTileEntity_WormholeGenerator", t);
+ }
+ }
+ }
+
+ private static class WormholeLink {
+
+ private final static Map<Long, WormholeLink> WORMHOLE_GENERATORS = new MapMaker().weakValues()
+ .makeMap();
+
+ public final long mFrequency;
+
+ public WeakReference<GT_MetaTileEntity_WormholeGenerator> mMaster, mSlave;
+
+ public final long[] mSendAmounts = new long[MAX_HATCHES];
+ public final long[] mReceiveAmounts = new long[MAX_HATCHES];
+
+ public double mWormholeEnergy;
+ private double mPendingEnergy;
+
+ private WormholeLink(long frequency) {
+ mFrequency = frequency;
+ }
+
+ public static WormholeLink get(long frequency) {
+ return WORMHOLE_GENERATORS.computeIfAbsent(frequency, WormholeLink::new);
+ }
+
+ public void update(WeakReference<GT_MetaTileEntity_WormholeGenerator> updater) {
+ tryPromote();
+
+ if (isMaster(updater)) {
+ if (isActive() && mPendingEnergy > 0) {
+ var delta = mPendingEnergy / WH_ENERGY_AVG_WINDOW;
+
+ if (mPendingEnergy < mWormholeEnergy) {
+ // if the wormhole is shrinking and the next tick would take it below the pending energy, just
+ // use the pending energy
+ if (mWormholeEnergy - delta < mPendingEnergy) {
+ mWormholeEnergy = mPendingEnergy;
+ } else {
+ mWormholeEnergy -= delta;
+ }
+ } else if (mPendingEnergy > mWormholeEnergy) {
+ // if the wormhole is growing and the next tick would take it above the pending energy, just use
+ // the pending energy
+ if (mWormholeEnergy + delta > mPendingEnergy) {
+ mWormholeEnergy = mPendingEnergy;
+ } else {
+ mWormholeEnergy += delta;
+ }
+ }
+
+ mPendingEnergy = 0;
+ } else {
+ mWormholeEnergy *= (1.0 - DECAY_RATE);
+
+ if (mWormholeEnergy < COLLAPSE_THRESHOLD) {
+ mWormholeEnergy = 0;
+
+ }
+ }
+ Arrays.fill(mSendAmounts, 0);
+ Arrays.fill(mReceiveAmounts, 0);
+ }
+ }
+
+ public void onEnergyTransferred(long amount) {
+ mPendingEnergy += amount;
+ }
+
+ public boolean isMaster(WeakReference<GT_MetaTileEntity_WormholeGenerator> tile) {
+ return mMaster == tile;
+ }
+
+ public boolean isConnected(WeakReference<GT_MetaTileEntity_WormholeGenerator> tile) {
+ return mMaster == tile || mSlave == tile;
+ }
+
+ public boolean isFormed() {
+ return mMaster != null && mSlave != null;
+ }
+
+ public boolean connect(WeakReference<GT_MetaTileEntity_WormholeGenerator> tile) {
+ tryPromote();
+
+ if (mMaster == null) {
+ mMaster = tile;
+ Optional.ofNullable(mMaster)
+ .map(Reference::get)
+ .ifPresent(GT_MetaTileEntity_WormholeGenerator::updateRenderDim);
+
+ Optional.ofNullable(mSlave)
+ .map(Reference::get)
+ .ifPresent(GT_MetaTileEntity_WormholeGenerator::updateRenderDim);
+ return true;
+ }
+ if (mSlave == null) {
+ mSlave = tile;
+
+ Optional.of(mMaster)
+ .map(Reference::get)
+ .ifPresent(GT_MetaTileEntity_WormholeGenerator::updateRenderDim);
+
+ Optional.ofNullable(mSlave)
+ .map(Reference::get)
+ .ifPresent(GT_MetaTileEntity_WormholeGenerator::updateRenderDim);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public void disconnect(WeakReference<GT_MetaTileEntity_WormholeGenerator> tile) {
+ Objects.requireNonNull(tile.get())
+ .destroyRenderBlock();
+
+ if (tile == mMaster) mMaster = null;
+ if (tile == mSlave) mSlave = null;
+
+ tryPromote();
+
+ if (mMaster == null && mSlave == null) {
+ WORMHOLE_GENERATORS.remove(mFrequency, this);
+ }
+ }
+
+ public void tryPromote() {
+ mMaster = tryClean(mMaster);
+ mSlave = tryClean(mSlave);
+
+ if (mMaster == null && mSlave != null) {
+ mMaster = mSlave;
+ mSlave = null;
+ }
+ }
+
+ private static WeakReference<GT_MetaTileEntity_WormholeGenerator> tryClean(
+ WeakReference<GT_MetaTileEntity_WormholeGenerator> tileReference) {
+ if (tileReference != null) {
+ var tile = tileReference.get();
+
+ if (tile == null) {
+ return null;
+ } else {
+ var base = tile.getBaseMetaTileEntity();
+
+ if (base == null || base.isDead()) {
+ return null;
+ }
+ }
+ }
+
+ return tileReference;
+ }
+
+ public GT_MetaTileEntity_WormholeGenerator getDest(WeakReference<GT_MetaTileEntity_WormholeGenerator> tile) {
+ if (tile == mMaster) {
+ return mSlave != null ? mSlave.get() : null;
+ }
+
+ if (tile == mSlave) {
+ return mMaster != null ? mMaster.get() : null;
+ }
+
+ return null;
+ }
+
+ public boolean isActive() {
+ boolean masterCanWork = Optional.ofNullable(mMaster)
+ .map(WeakReference::get)
+ .map(GT_MetaTileEntity_WormholeGenerator::getBaseMetaTileEntity)
+ .map(IGregTechTileEntity::isAllowedToWork)
+ .orElse(false);
+
+ boolean slaveCanWork = Optional.ofNullable(mSlave)
+ .map(WeakReference::get)
+ .map(GT_MetaTileEntity_WormholeGenerator::getBaseMetaTileEntity)
+ .map(IGregTechTileEntity::isAllowedToWork)
+ .orElse(false);
+
+ return masterCanWork && slaveCanWork;
+ }
+ }
+
+ // #endregion
+
+ // #region UI
+
+ @Override
+ protected GT_Multiblock_Tooltip_Builder createTooltip() {
+ final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder();
+
+ // spotless:off
+ tt.addMachineType("Wormhole Generator")
+ .addInfo("Controller for the Miniature Wormhole Generator.")
+ .addInfo("Transfers EU between two wormhole generators.")
+ .addInfo("Wormholes are linked by placing an AE2 Entangled Singularity in each controller slot.")
+ .addInfo("The transfer rate is limited by the wormhole size, and the wormhole size is governed by the transfer rate.")
+ .addInfo("If the transfer rate is completely stable, the transfer efficiency is " + String.format("%.3f", TRANSFER_EFFICIENCY * 100.0) + "%.")
+ .addInfo("EU will only be transferred if there is space in the laser source hatch.")
+ .addInfo("Each laser target must have a laser source on the §oother§7 controller, on the §oopposite§7 side.")
+ .addInfo("Consumes an AE2 Singularity from an input bus each time the wormhole is kick-started.")
+ .addInfo("The structure is too complex!")
+ .addInfo(BLUE_PRINT_INFO)
+ .beginStructureBlock(7, 9, 7, false)
+ .addSeparator()
+ .addCasingInfoExactly("Molecular Casing", 2 * 12, false)
+ .addCasingInfoExactly("Europium Reinforced Radiation Proof Machine Casing", 4, false)
+ .addCasingInfoExactly("Fusion Coil Block", 3 * 4 + 5 * 2, false)
+ .addCasingInfoRange("High Power Casing", 8 * 6 + 1, 8 * 6 + 1 + 4, false)
+ .addCasingInfoExactly("Borosilicate Glass (any)", 9 * 4, true)
+ .addMaintenanceHatch("§61§r (dot 1)")
+ .addInputBus("§61§r (dot 1)")
+ .addDynamoHatch("§60§r - §64§r (laser only, dot 2)")
+ .addEnergyHatch("§60§r - §64§r (laser only, dot 2)")
+ .addStructureInfo("§rThe glass tier limits the hatch tier.")
+ .addSubChannelUsage("glass", "Borosilicate Glass Tier")
+ .toolTipFinisher("Gregtech");
+ // spotless:on
+
+ return tt;
+ }
+
+ @Override
+ public String[] getInfoData() {
+ List<String> data = new ArrayList<>();
+
+ data.addAll(Arrays.asList(super.getInfoData()));
+
+ data.add("-----------------------");
+ data.add("Wormhole Generator Info");
+
+ if (mStructureBadGlassTier) {
+ data.add(String.format("§cStructure errors:§r"));
+
+ if (mStructureBadGlassTier) {
+ data.add(String.format("§cGlass tier must be greater than or equal to the energy hatch tiers.§r"));
+ }
+ }
+
+ if (mLink == null) {
+ data.add("An entangled singularity must be present in the controller slot");
+ } else {
+ if (!mLink.isFormed()) {
+ data.add("Wormhole status: §cNo destination§f");
+ } else {
+ if (mLink.mWormholeEnergy > 0) {
+ if (mLink.isActive()) {
+ data.add("Wormhole status: §bActive§f");
+ } else {
+ data.add("Wormhole status: §6Decaying§f");
+ }
+ } else {
+ boolean anyTransferable = false;
+
+ for (int i = 0; i < MAX_HATCHES; i++) {
+ if (!HATCH_MASK[i]) continue;
+
+ if (getTransferable(i) > 0) {
+ anyTransferable = true;
+ break;
+ }
+ }
+
+ if (anyTransferable) {
+ data.add("Wormhole status: §7Inactive§f");
+ } else {
+ data.add("Wormhole status: §7No energy in input hatches§f");
+ }
+ }
+
+ double radius = Math.sqrt(mLink.mWormholeEnergy / 20.0 / 32.0);
+ data.add(String.format("Wormhole diameter: §b%,d§r ångström", (long) (radius * 2)));
+
+ data.add(String.format("Optimal transfer speed: §b%,.0f§r EU/t", mLink.mWormholeEnergy / 20));
+ }
+ }
+
+ for (int i = 0; i < MAX_HATCHES; i++) {
+ if (!HATCH_MASK[i]) continue;
+
+ var inputHatch = mSendHatches[i];
+ var outputHatch = mReceiveHatches[i];
+
+ // spotless:off
+ if(inputHatch != null) {
+ data.add(String.format(
+ "%s hatch (%,dA/t %s) transferred §b%,d§f EU (equivalent to %,dA/t) with an efficiency of %.3f%% in the last second",
+ HATCH_NAMES[i],
+ inputHatch.Amperes,
+ VN[inputHatch.mTier],
+ mLink != null ? mLink.mSendAmounts[i] : 0,
+ mLink != null ? mLink.mSendAmounts[i] / 20 / V[inputHatch.mTier] : 0,
+ mLink != null && mLink.mSendAmounts[i] > 0 ? ((double)mLink.mReceiveAmounts[OPPOSITES[i]]) / ((double)mLink.mSendAmounts[i]) * 100 : 0
+ ));
+ } else if(outputHatch != null) {
+ data.add(String.format(
+ "%s hatch (%,dA/t %s) received §b%,d§f EU (equivalent to %,dA/t) with an efficiency of %.3f%% in the last second",
+ HATCH_NAMES[i],
+ outputHatch.Amperes,
+ VN[outputHatch.mTier],
+ mLink != null ? mLink.mReceiveAmounts[i] : 0,
+ mLink != null ? mLink.mReceiveAmounts[i] / 20 / V[outputHatch.mTier] : 0,
+ mLink != null && mLink.mSendAmounts[OPPOSITES[i]] > 0 ? ((double)mLink.mReceiveAmounts[i]) / ((double)mLink.mSendAmounts[OPPOSITES[i]]) * 100 : 0
+ ));
+ } else {
+ data.add(String.format("%s hatch is not present", HATCH_NAMES[i]));
+ }
+ // spotless:on
+ }
+
+ data.add("-----------------------");
+
+ return data.toArray(new String[data.size()]);
+ }
+
+ @Override
+ protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) {
+ super.drawTexts(screenElements, inventorySlot);
+
+ screenElements.widgets(TextWidget.dynamicString(() -> {
+ if (mLink == null) {
+ return String.format("§7Missing Entangled Singularity§f");
+ }
+
+ if (!mLink.isFormed()) {
+ return String.format("§7Wormhole status: §cNo destination§f");
+ }
+
+ if (mLink.mWormholeEnergy > 0 && !mLink.isActive()) {
+ return String.format("§7Wormhole status: §6Decaying§f");
+ }
+
+ if (mLink.mWormholeEnergy > 0) {
+ return String.format("§7Wormhole status: §bActive§f");
+ }
+
+ return String.format("§7Wormhole status: Inactive§f");
+ }),
+
+ TextWidget.dynamicString(() -> {
+ if (mLink == null) {
+ return "";
+ }
+
+ // LV power = 1 angstrom in diameter
+ double radius = Math.sqrt(mLink.mWormholeEnergy / 20.0 / 32.0);
+
+ return String.format("§7Wormhole diameter: §b%,d§7 ŧf", (long) (radius * 2));
+ })
+ .setEnabled(w -> mWormholeEnergy_UI > 0),
+
+ TextWidget.dynamicString(() -> {
+ if (mLink == null) {
+ return "";
+ }
+
+ if (mLink.mWormholeEnergy >= 1e10) {
+ return String.format("§7Max I/O per hatch: §b%3.3e§7 EU/t§f", mLink.mWormholeEnergy / 20);
+ } else {
+ return String.format("§7Max I/O per hatch: §b%,d§7 EU/t§f", (long) (mLink.mWormholeEnergy / 20));
+ }
+ })
+ .setEnabled(w -> mWormholeEnergy_UI > 0),
+
+ new FakeSyncWidget.DoubleSyncer(
+ () -> mLink != null ? mLink.mWormholeEnergy : 0,
+ val -> mWormholeEnergy_UI = val));
+ }
+
+ // #endregion
+
+}
diff --git a/src/main/java/gregtech/common/tileentities/render/TileWormhole.java b/src/main/java/gregtech/common/tileentities/render/TileWormhole.java
new file mode 100644
index 0000000000..f219cfe989
--- /dev/null
+++ b/src/main/java/gregtech/common/tileentities/render/TileWormhole.java
@@ -0,0 +1,98 @@
+package gregtech.common.tileentities.render;
+
+import java.util.List;
+import java.util.Optional;
+
+import net.minecraft.block.Block;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldProvider;
+
+import cpw.mods.fml.relauncher.Side;
+import micdoodle8.mods.galacticraft.core.tile.TileEntityAdvanced;
+import micdoodle8.mods.galacticraft.core.util.Annotations;
+import pers.gwyog.gtneioreplugin.plugin.block.ModBlocks;
+import pers.gwyog.gtneioreplugin.util.DimensionHelper;
+
+public class TileWormhole extends TileEntityAdvanced {
+
+ @Annotations.NetworkedField(targetSide = Side.CLIENT)
+ public boolean shouldRender = false;
+ @Annotations.NetworkedField(targetSide = Side.CLIENT)
+ public int dimID = 0;
+
+ @Annotations.NetworkedField(targetSide = Side.CLIENT)
+ public double targetRadius = 0;
+
+ @Override
+ public void addExtraNetworkedData(List<Object> networkedList) {
+ super.addExtraNetworkedData(networkedList);
+ }
+
+ @Override
+ public void writeToNBT(NBTTagCompound compound) {
+ super.writeToNBT(compound);
+ compound.setInteger("dimID", dimID);
+ }
+
+ @Override
+ public void readFromNBT(NBTTagCompound compound) {
+ super.readFromNBT(compound);
+ dimID = compound.getInteger("dimID");
+ }
+
+ public int getDimFromWorld(World target) {
+ if (target == null) return 0;
+ String dimName = Optional.ofNullable(target.provider)
+ .map(WorldProvider::getDimensionName)
+ .orElse(null);
+ if (dimName == null) return 0;
+ for (int i = 0; i < DimensionHelper.DimName.length; i++) {
+ if (dimName.equals(DimensionHelper.DimName[i])) return i;
+ }
+ return 0;
+ }
+
+ public void setDimFromWorld(World target) {
+ int newName = getDimFromWorld(target);
+ if (target != null & dimID != newName) {
+ dimID = newName;
+ }
+ }
+
+ public void setRadius(double target) {
+ targetRadius = target;
+ }
+
+ public Block getBlock() {
+ return ModBlocks.getBlock(DimensionHelper.DimNameDisplayed[dimID]);
+ }
+
+ @Override
+ public void updateEntity() {
+ super.updateEntity();
+ if (worldObj != null && worldObj.isRemote) {
+ worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
+ }
+ }
+
+ @Override
+ public double getMaxRenderDistanceSquared() {
+ return 65536;
+ }
+
+ @Override
+ public double getPacketRange() {
+ return 128;
+ }
+
+ @Override
+ public int getPacketCooldown() {
+ return 20;
+ }
+
+ @Override
+ public boolean isNetworkedTile() {
+ return true;
+ }
+}
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 00ccea451e..f4c7139c4f 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
@@ -74,6 +74,7 @@ import gregtech.common.blocks.GT_Block_Stones;
import gregtech.common.blocks.GT_Block_TintedIndustrialGlass;
import gregtech.common.blocks.GT_Cyclotron_Coils;
import gregtech.common.blocks.GT_TileEntity_Ores;
+import gregtech.common.blocks.GT_WormholeRenderBlock;
import gregtech.common.items.GT_DepletetCell_Item;
import gregtech.common.items.GT_FluidDisplayItem;
import gregtech.common.items.GT_IntegratedCircuit_Item;
@@ -88,6 +89,7 @@ import gregtech.common.items.GT_TierDrone;
import gregtech.common.items.GT_VolumetricFlask;
import gregtech.common.tileentities.render.TileDrone;
import gregtech.common.tileentities.render.TileLaser;
+import gregtech.common.tileentities.render.TileWormhole;
public class GT_Loader_Item_Block_And_Fluid implements Runnable {
@@ -553,6 +555,7 @@ public class GT_Loader_Item_Block_And_Fluid implements Runnable {
GregTech_API.sBlockGlass1 = new GT_Block_Glass1();
GregTech_API.sBlockTintedGlass = new GT_Block_TintedIndustrialGlass();
GregTech_API.sLaserRender = new GT_Block_Laser();
+ GregTech_API.sWormholeRender = new GT_WormholeRenderBlock();
// meta ID order, DO NOT CHANGE ORDER
GregTech_API.sBlockMetal1 = new GT_Block_Metal(
@@ -680,6 +683,8 @@ public class GT_Loader_Item_Block_And_Fluid implements Runnable {
GameRegistry.registerTileEntity(TileDrone.class, "DroneRender");
GT_Log.out.println("GT_Mod: Registering the LaserRender.");
GameRegistry.registerTileEntity(TileLaser.class, "LaserRenderer");
+ GT_Log.out.println("GT_Mod: Registering the WormholeRender.");
+ GameRegistry.registerTileEntity(TileWormhole.class, "WormholeRender");
GT_Log.out.println("GT_Mod: Registering the BaseMetaPipeEntity.");
GameRegistry.registerTileEntity(BaseMetaPipeEntity.class, "BaseMetaPipeEntity");
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 9929fbb1c2..e8222304a9 100644
--- a/src/main/java/gregtech/loaders/preload/GT_Loader_MetaTileEntities.java
+++ b/src/main/java/gregtech/loaders/preload/GT_Loader_MetaTileEntities.java
@@ -462,6 +462,7 @@ import static gregtech.api.enums.MetaTileEntityIDs.WIRELESS_HATCH_ENERGY_UMV;
import static gregtech.api.enums.MetaTileEntityIDs.WIRELESS_HATCH_ENERGY_UV;
import static gregtech.api.enums.MetaTileEntityIDs.WIRELESS_HATCH_ENERGY_UXV;
import static gregtech.api.enums.MetaTileEntityIDs.WIRELESS_HATCH_ENERGY_ZPM;
+import static gregtech.api.enums.MetaTileEntityIDs.WORMHOLE_GENERATOR_CONTROLLER;
import static gregtech.api.enums.MetaTileEntityIDs.transformer_EV_HV;
import static gregtech.api.enums.MetaTileEntityIDs.transformer_HV_MV;
import static gregtech.api.enums.MetaTileEntityIDs.transformer_IV_EV;
@@ -602,6 +603,7 @@ 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.GT_MetaTileEntity_WormholeGenerator;
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.multi.purification.GT_MetaTileEntity_Hatch_DegasifierControlHatch;
@@ -1130,6 +1132,11 @@ public class GT_Loader_MetaTileEntities implements Runnable { // TODO CHECK CIRC
new GT_MetaTileEntity_MultiCanner(MULTI_CANNER_CONTROLLER.ID, "multimachine.canner", "TurboCan Pro")
.getStackForm(1));
+ ItemList.WormholeGenerator.set(
+ new GT_MetaTileEntity_WormholeGenerator(
+ WORMHOLE_GENERATOR_CONTROLLER.ID,
+ "multimachine.wormhole",
+ "Miniature Wormhole Generator").getStackForm(1));
ItemList.Machine_Multi_IndustrialLaserEngraver.set(
new GT_MetaTileEntity_IndustrialLaserEngraver(
INDUSTRIAL_LASER_ENGRAVER_CONTROLLER.ID,
diff --git a/src/main/resources/assets/gregtech/lang/en_US.lang b/src/main/resources/assets/gregtech/lang/en_US.lang
index c24d8dd8a6..1c651fb2d5 100644
--- a/src/main/resources/assets/gregtech/lang/en_US.lang
+++ b/src/main/resources/assets/gregtech/lang/en_US.lang
@@ -554,6 +554,7 @@ GT5U.gui.text.pollution_fail=§4Failed to output the pollution.
GT5U.gui.text.structure_incomplete=§4Shut down due to incomplete structure.
GT5U.gui.text.no_repair=§4Shut down due to machine damage.
GT5U.gui.text.no_machine_part=No correct machine part in controller slot.
+GT5U.gui.text.missing_item=§7Missing required item: §b%s§f
GT5U.gui.text.ph_sensor=pH threshold
GT5U.item.programmed_circuit.select.header=Reprogram Circuit