diff options
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 |