aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gtnhlanth/common/tileentity
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gtnhlanth/common/tileentity')
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/MTEDigester.java240
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/MTEDissolutionTank.java264
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/MTELINAC.java749
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/MTESourceChamber.java409
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/MTESynchrotron.java1077
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/MTETargetChamber.java480
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/recipe/beamline/BeamlineRecipeAdder2.java165
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/recipe/beamline/BeamlineRecipeLoader.java193
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/recipe/beamline/RecipeSC.java52
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/recipe/beamline/RecipeTC.java71
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/recipe/beamline/SourceChamberFrontend.java24
-rw-r--r--src/main/java/gtnhlanth/common/tileentity/recipe/beamline/TargetChamberFrontend.java109
12 files changed, 3833 insertions, 0 deletions
diff --git a/src/main/java/gtnhlanth/common/tileentity/MTEDigester.java b/src/main/java/gtnhlanth/common/tileentity/MTEDigester.java
new file mode 100644
index 0000000000..9e1fc65c1b
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/MTEDigester.java
@@ -0,0 +1,240 @@
+package gtnhlanth.common.tileentity;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.HatchElement.Energy;
+import static gregtech.api.enums.HatchElement.InputBus;
+import static gregtech.api.enums.HatchElement.InputHatch;
+import static gregtech.api.enums.HatchElement.Maintenance;
+import static gregtech.api.enums.HatchElement.Muffler;
+import static gregtech.api.enums.HatchElement.OutputBus;
+import static gregtech.api.enums.HatchElement.OutputHatch;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages;
+import static gregtech.api.util.GTStructureUtility.buildHatchAdder;
+import static gregtech.api.util.GTStructureUtility.ofCoil;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.common.util.ForgeDirection;
+
+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 gregtech.api.GregTechAPI;
+import gregtech.api.enums.HeatingCoilLevel;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.MTEEnhancedMultiBlockBase;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GTRecipe;
+import gregtech.api.util.MultiblockTooltipBuilder;
+import gregtech.api.util.OverclockCalculator;
+import gtnhlanth.api.recipe.LanthanidesRecipeMaps;
+import gtnhlanth.util.DescTextLocalization;
+
+public class MTEDigester extends MTEEnhancedMultiBlockBase<MTEDigester> implements ISurvivalConstructable {
+
+ protected int casingAmount = 0;
+ protected int height = 0;
+
+ private HeatingCoilLevel heatLevel;
+
+ private final IStructureDefinition<MTEDigester> multiDefinition = StructureDefinition.<MTEDigester>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { " ", " ttttt ", " t---t ", " t---t ", " t---t ", " ttttt ", " " },
+ { " ttt ", " t---t ", "t-----t", "t-----t", "t-----t", " t---t ", " ttt " },
+ { " tccct ", "tc---ct", "c-----c", "c-----c", "c-----c", "tc---ct", " tccct " },
+ { " tt~tt ", "thhhhht", "thsssht", "thsssht", "thsssht", "thhhhht", " ttttt " }, }))
+
+ .addElement(
+ 't',
+ buildHatchAdder(MTEDigester.class)
+ .atLeast(InputHatch, OutputHatch, InputBus, OutputBus, Maintenance, Energy, Muffler)
+ .casingIndex(47)
+ .dot(1)
+ .buildAndChain(GregTechAPI.sBlockCasings4, 0))
+ .addElement('h', ofBlock(GregTechAPI.sBlockCasings1, 11))
+ .addElement('s', ofBlock(GregTechAPI.sBlockCasings4, 1))
+ .addElement('c', ofCoil(MTEDigester::setCoilLevel, MTEDigester::getCoilLevel))
+ .build();
+
+ public MTEDigester(String name) {
+ super(name);
+ }
+
+ public MTEDigester(int id, String name, String nameRegional) {
+ super(id, name, nameRegional);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ return checkPiece(mName, 3, 3, 0) && !mMufflerHatches.isEmpty() && mMaintenanceHatches.size() == 1;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ public HeatingCoilLevel getCoilLevel() {
+ return this.heatLevel;
+ }
+
+ public void setCoilLevel(HeatingCoilLevel level) {
+ this.heatLevel = level;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return LanthanidesRecipeMaps.digesterRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @Nonnull
+ @Override
+ protected OverclockCalculator createOverclockCalculator(@Nonnull GTRecipe recipe) {
+ return super.createOverclockCalculator(recipe).enablePerfectOC();
+ }
+
+ @Override
+ protected @Nonnull CheckRecipeResult validateRecipe(@Nonnull GTRecipe recipe) {
+ return recipe.mSpecialValue <= MTEDigester.this.getCoilLevel()
+ .getHeat() ? CheckRecipeResultRegistry.SUCCESSFUL
+ : CheckRecipeResultRegistry.insufficientHeat(recipe.mSpecialValue);
+ }
+
+ };
+ }
+
+ @Override
+ public boolean supportsVoidProtection() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsBatchMode() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsSingleRecipeLocking() {
+ return true;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack itemStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getPollutionPerTick(ItemStack aStack) {
+ return 20;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity arg0) {
+ return new MTEDigester(this.mName);
+ }
+
+ @Override
+ public void construct(ItemStack itemStack, boolean b) {
+ buildPiece(mName, itemStack, b, 3, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 3, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public String[] getStructureDescription(ItemStack arg0) {
+ return DescTextLocalization.addText("Digester.hint", 6);
+ }
+
+ public ITexture[] getTexture(IGregTechTileEntity te, ForgeDirection side, ForgeDirection facing, int colorIndex,
+ boolean active, boolean redstone) {
+
+ // Oil Cracker textures cuz I'm lazy
+
+ if (side == facing) {
+ if (active) return new ITexture[] { casingTexturePages[0][47], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ return new ITexture[] { casingTexturePages[0][47], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ }
+ return new ITexture[] { casingTexturePages[0][47] };
+ }
+
+ @Override
+ protected MultiblockTooltipBuilder createTooltip() {
+ final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder();
+ tt.addMachineType("Digester")
+ .addInfo("Controller block for the Digester")
+ .addInfo("Input ores and fluid, output water.")
+ .addInfo(DescTextLocalization.BLUEPRINT_INFO)
+ .addSeparator()
+ .addController("Front bottom")
+ .addInputHatch("Hint block with dot 1")
+ .addInputBus("Hint block with dot 1")
+ .addOutputHatch("Hint block with dot 1")
+ .addOutputBus("Hint block with dot 1")
+ .addMaintenanceHatch("Hint block with dot 1")
+ .addMufflerHatch("Hint block with dot 1")
+ .toolTipFinisher("GTNH: Lanthanides");
+ return tt;
+ }
+
+ @Override
+ public IStructureDefinition<MTEDigester> getStructureDefinition() {
+ return multiDefinition;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack arg0) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/MTEDissolutionTank.java b/src/main/java/gtnhlanth/common/tileentity/MTEDissolutionTank.java
new file mode 100644
index 0000000000..7d5a64b579
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/MTEDissolutionTank.java
@@ -0,0 +1,264 @@
+package gtnhlanth.common.tileentity;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockAdder;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose;
+import static gregtech.api.enums.HatchElement.Energy;
+import static gregtech.api.enums.HatchElement.InputBus;
+import static gregtech.api.enums.HatchElement.InputHatch;
+import static gregtech.api.enums.HatchElement.Maintenance;
+import static gregtech.api.enums.HatchElement.OutputBus;
+import static gregtech.api.enums.HatchElement.OutputHatch;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages;
+import static gregtech.api.util.GTStructureUtility.buildHatchAdder;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.jetbrains.annotations.NotNull;
+
+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 bartworks.common.loaders.ItemRegistry;
+import gregtech.api.GregTechAPI;
+import gregtech.api.interfaces.ISecondaryDescribable;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
+import gregtech.api.metatileentity.implementations.MTEEnhancedMultiBlockBase;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.recipe.check.SimpleCheckRecipeResult;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GTRecipe;
+import gregtech.api.util.MultiblockTooltipBuilder;
+import gtnhlanth.api.recipe.LanthanidesRecipeMaps;
+import gtnhlanth.util.DescTextLocalization;
+
+public class MTEDissolutionTank extends MTEEnhancedMultiBlockBase<MTEDissolutionTank>
+ implements ISurvivalConstructable, ISecondaryDescribable {
+
+ private final IStructureDefinition<MTEDissolutionTank> multiDefinition = StructureDefinition
+ .<MTEDissolutionTank>builder()
+ .addShape(
+ mName,
+ transpose(
+ new String[][] { { " sss ", "sssss", "sssss", "sssss", " sss " },
+ { "sgggs", "g---g", "g---g", "g---g", "sgggs" }, { "sgggs", "g---g", "g---g", "g---g", "sgggs" },
+ { "ss~ss", "shhhs", "shhhs", "shhhs", "sssss" }, { "s s", " ", " ", " ", "s s" } }))
+ .addElement(
+ 's',
+ buildHatchAdder(MTEDissolutionTank.class)
+ .atLeast(InputHatch, OutputHatch, InputBus, OutputBus, Maintenance, Energy)
+ .casingIndex(49)
+ .dot(1)
+ .buildAndChain(GregTechAPI.sBlockCasings4, 1))
+ .addElement('h', ofBlock(GregTechAPI.sBlockCasings1, 11))
+ .addElement('g', ofBlockAdder(MTEDissolutionTank::addGlass, ItemRegistry.bw_glasses[0], 1))
+ .build();
+
+ public MTEDissolutionTank(String name) {
+ super(name);
+ }
+
+ public MTEDissolutionTank(int id, String name, String nameRegional) {
+ super(id, name, nameRegional);
+ }
+
+ @Override
+ public IStructureDefinition<MTEDissolutionTank> getStructureDefinition() {
+ return multiDefinition;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+ return checkPiece(mName, 2, 3, 0) && mMaintenanceHatches.size() == 1;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ private boolean addGlass(Block block, int meta) {
+ return block == ItemRegistry.bw_glasses[0];
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return LanthanidesRecipeMaps.dissolutionTankRecipes;
+ }
+
+ @Override
+ protected ProcessingLogic createProcessingLogic() {
+ return new ProcessingLogic() {
+
+ @NotNull
+ @Override
+ protected CheckRecipeResult onRecipeStart(@Nonnull GTRecipe recipe) {
+ if (!checkRatio(recipe, Arrays.asList(inputFluids))) {
+ criticalStopMachine();
+ return SimpleCheckRecipeResult.ofFailurePersistOnShutdown("dissolution_ratio");
+ }
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ };
+ }
+
+ @Override
+ public boolean supportsVoidProtection() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsInputSeparation() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsBatchMode() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsSingleRecipeLocking() {
+ return true;
+ }
+
+ private boolean checkRatio(GTRecipe tRecipe, List<FluidStack> tFluidInputs) {
+ FluidStack majorGenericFluid = tRecipe.mFluidInputs[0];
+ FluidStack minorGenericFluid = tRecipe.mFluidInputs[1];
+
+ int majorAmount;
+ int minorAmount;
+
+ FluidStack fluidInputOne = tFluidInputs.get(0);
+ FluidStack fluidInputTwo = tFluidInputs.get(1);
+
+ if (fluidInputOne.getUnlocalizedName()
+ .equals(majorGenericFluid.getUnlocalizedName())) {
+ if (fluidInputTwo.getUnlocalizedName()
+ .equals(minorGenericFluid.getUnlocalizedName())) {
+ // majorInput = fluidInputOne;
+ majorAmount = fluidInputOne.amount;
+ // minorInput = fluidInputTwo;
+ minorAmount = fluidInputTwo.amount;
+ // GTLog.out.print("in first IF");
+ } else return false; // No valid other input
+
+ } else if (fluidInputTwo.getUnlocalizedName()
+ .equals(majorGenericFluid.getUnlocalizedName())) {
+ if (fluidInputOne.getUnlocalizedName()
+ .equals(minorGenericFluid.getUnlocalizedName())) {
+ // majorInput = fluidInputTwo;
+ majorAmount = fluidInputTwo.amount;
+ // minorInput = fluidInputOne;
+ minorAmount = fluidInputOne.amount;
+ // GTLog.out.print("in second if");
+ } else return false;
+
+ } else return false;
+
+ return majorAmount / tRecipe.mSpecialValue == minorAmount;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack itemStack) {
+ return 10000;
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity arg0) {
+ return new MTEDissolutionTank(this.mName);
+ }
+
+ @Override
+ public void construct(ItemStack itemStack, boolean b) {
+ buildPiece(mName, itemStack, b, 2, 3, 0);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece(mName, stackSize, 2, 3, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public String[] getStructureDescription(ItemStack arg0) {
+ return DescTextLocalization.addText("DissolutionTank.hint", 4);
+ }
+
+ @Override
+ public ITexture[] getTexture(IGregTechTileEntity te, ForgeDirection side, ForgeDirection facing, int colorIndex,
+ boolean active, boolean redstone) {
+
+ if (side == facing) {
+ if (active) return new ITexture[] { casingTexturePages[0][49], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ return new ITexture[] { casingTexturePages[0][49], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ }
+ return new ITexture[] { casingTexturePages[0][49] };
+ }
+
+ @Override
+ protected MultiblockTooltipBuilder createTooltip() {
+ final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder();
+ tt.addMachineType("Dissolution Tank")
+ .addInfo("Controller block for the Dissolution Tank")
+ .addInfo("Input Water and Fluid, output Fluid")
+ .addInfo("You must input the Fluids at the correct Ratio")
+ .addInfo(DescTextLocalization.BLUEPRINT_INFO)
+ .addSeparator()
+ .addController("Front bottom")
+ .addInputHatch("Hint block with dot 1")
+ .addInputBus("Hint block with dot 1")
+ .addOutputHatch("Hint block with dot 1")
+ .addOutputBus("Hint block with dot 1")
+ .addMaintenanceHatch("Hint block with dot 1")
+ .toolTipFinisher("GTNH: Lanthanides");
+
+ return tt;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack arg0) {
+ return false;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack arg0) {
+ return 0;
+ }
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/MTELINAC.java b/src/main/java/gtnhlanth/common/tileentity/MTELINAC.java
new file mode 100644
index 0000000000..78ea9c7846
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/MTELINAC.java
@@ -0,0 +1,749 @@
+package gtnhlanth.common.tileentity;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static gregtech.api.enums.GTValues.VN;
+import static gregtech.api.enums.HatchElement.Energy;
+import static gregtech.api.enums.HatchElement.InputHatch;
+import static gregtech.api.enums.HatchElement.Maintenance;
+import static gregtech.api.enums.HatchElement.OutputHatch;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages;
+import static gregtech.api.util.GTStructureUtility.buildHatchAdder;
+import static gtnhlanth.util.DescTextLocalization.addDotText;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidRegistry;
+import net.minecraftforge.fluids.FluidStack;
+
+import com.gtnewhorizon.structurelib.StructureLib;
+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 bartworks.API.BorosilicateGlass;
+import gregtech.api.GregTechAPI;
+import gregtech.api.enums.GTValues;
+import gregtech.api.enums.TickTime;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.MTEEnhancedMultiBlockBase;
+import gregtech.api.metatileentity.implementations.MTEHatchEnergy;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GTUtility;
+import gregtech.api.util.MultiblockTooltipBuilder;
+import gregtech.api.util.shutdown.ShutDownReason;
+import gregtech.api.util.shutdown.SimpleShutDownReason;
+import gtnhlanth.common.beamline.BeamInformation;
+import gtnhlanth.common.beamline.BeamLinePacket;
+import gtnhlanth.common.beamline.Particle;
+import gtnhlanth.common.hatch.MTEHatchInputBeamline;
+import gtnhlanth.common.hatch.MTEHatchOutputBeamline;
+import gtnhlanth.common.register.LanthItemList;
+import gtnhlanth.common.tileentity.recipe.beamline.BeamlineRecipeLoader;
+import gtnhlanth.util.DescTextLocalization;
+import gtnhlanth.util.Util;
+
+public class MTELINAC extends MTEEnhancedMultiBlockBase<MTELINAC> implements ISurvivalConstructable {
+
+ private static final IStructureDefinition<MTELINAC> STRUCTURE_DEFINITION;
+
+ protected static final String STRUCTURE_PIECE_BASE = "base";
+ protected static final String STRUCTURE_PIECE_LAYER = "layer";
+ protected static final String STRUCTURE_PIECE_END = "end";
+
+ private byte glassTier;
+
+ private boolean onEndInnerLayer = false;
+
+ private int machineTemp = 0; // Coolant temperature
+
+ private ArrayList<MTEHatchInputBeamline> mInputBeamline = new ArrayList<>();
+ private ArrayList<MTEHatchOutputBeamline> mOutputBeamline = new ArrayList<>();
+
+ private static final int CASING_INDEX = GTUtility.getCasingTextureIndex(GregTechAPI.sBlockCasings5, 14);
+
+ private static final byte MIN_GLASS_TIER = 6;
+
+ /*
+ * g: Grate Machine Casing b: Borosilicate glass c: Shielded accelerator casing v: Vacuum k: Shielded glass d:
+ * Coolant Delivery casing y: Superconducting coil
+ */
+
+ static {
+ STRUCTURE_DEFINITION = StructureDefinition.<MTELINAC>builder()
+ .addShape(
+ STRUCTURE_PIECE_BASE,
+ new String[][] { { "ggggggg", "gbbbbbg", "gbbbbbg", "gbbibbg", "gbbbbbg", "gbbbbbg", "ggg~ggg" },
+ { "ggggggg", "gcccccg", "gcccccg", "gcc-ccg", "gcccccg", "gcccccg", "ggggggg" },
+ { "ccccccc", "cvvvvvc", "kvvvvvk", "kvv-vvk", "kvvvvvk", "cvvvvvc", "jcccccj" },
+ { "cckkkcc", "cdddddc", "kdyyydk", "kdy-ydk", "kdyyydk", "cdddddc", "jcccccj" },
+ { "cckkkcc", "cdvvvdc", "kvvvvvk", "kdv-vdk", "kvvvvvk", "cdvvvdc", "jcccccj" },
+ { "cckkkcc", "cdddddc", "kdyyydk", "kdy-ydk", "kdyyydk", "cdddddc", "jcccccj" },
+ { "cckkkcc", "cdvvvdc", "kvvvvvk", "kdv-vdk", "kvvvvvk", "cdvvvdc", "jcccccj" },
+ { "cckhkcc", "cdddddc", "kdyyydk", "kdy-ydk", "kdyyydk", "cdddddc", "jcccccj" }, })
+ .addShape(
+ STRUCTURE_PIECE_LAYER,
+ new String[][] { { "cckkkcc", "cdvvvdc", "kvvvvvk", "kdv-vdk", "kvvvvvk", "cdvvvdc", "ccccccc" },
+ { "cckkkcc", "cdddddc", "kdyyydk", "kdy-ydk", "kdyyydk", "cdddddc", "ccccccc" } })
+ .addShape(
+ STRUCTURE_PIECE_END,
+ new String[][] { { "cckkkcc", "cdvvvdc", "kvvvvvk", "kdv-vdk", "kvvvvvk", "cdvvvdc", "ccccccc" },
+ { "cckhkcc", "cdddddc", "kdyyydk", "kdy-ydk", "kdyyydk", "cdddddc", "ccccccc" },
+ { "cckkkcc", "cdvvvdc", "kvvvvvk", "kdv-vdk", "kvvvvvk", "cdvvvdc", "ccccccc" },
+ { "cckkkcc", "cdddddc", "kdyyydk", "kdy-ydk", "kdyyydk", "cdddddc", "ccccccc" },
+ { "cckkkcc", "cdvvvdc", "kvvvvvk", "kdv-vdk", "kvvvvvk", "cdvvvdc", "ccccccc" },
+ { "cckkkcc", "cdddddc", "kdyyydk", "kdy-ydk", "kdyyydk", "cdddddc", "ccccccc" },
+ { "ccccccc", "cvvvvvc", "kvvvvvk", "kvv-vvk", "kvvvvvk", "cvvvvvc", "ccccccc" },
+ { "ccccccc", "ccccccc", "ccccccc", "ccc-ccc", "ccccccc", "ccccccc", "ccccccc" },
+ { "ccccccc", "cbbbbbc", "cbbbbbc", "cbbobbc", "cbbbbbc", "cbbbbbc", "ccccccc" } })
+ .addElement('c', ofBlock(LanthItemList.SHIELDED_ACCELERATOR_CASING, 0))
+ .addElement('g', ofBlock(GregTechAPI.sBlockCasings3, 10)) // Grate Machine Casing
+ .addElement(
+ 'b',
+ BorosilicateGlass.ofBoroGlass(
+ (byte) 0,
+ MIN_GLASS_TIER,
+ Byte.MAX_VALUE,
+ (te, t) -> te.glassTier = t,
+ te -> te.glassTier))
+ .addElement(
+ 'i',
+ buildHatchAdder(MTELINAC.class).hatchClass(MTEHatchInputBeamline.class)
+ .casingIndex(CASING_INDEX)
+ .dot(3)
+ .adder(MTELINAC::addBeamLineInputHatch)
+ .build())
+ .addElement(
+ 'o',
+ buildHatchAdder(MTELINAC.class).hatchClass(MTEHatchOutputBeamline.class)
+ .casingIndex(CASING_INDEX)
+ .dot(4)
+ .adder(MTELINAC::addBeamLineOutputHatch)
+ .build())
+ .addElement('v', ofBlock(LanthItemList.ELECTRODE_CASING, 0))
+ .addElement('k', ofBlock(LanthItemList.SHIELDED_ACCELERATOR_GLASS, 0))
+ .addElement('d', ofBlock(LanthItemList.COOLANT_DELIVERY_CASING, 0))
+ .addElement('y', ofBlock(GregTechAPI.sBlockCasings1, 15)) // Superconducting coil
+ .addElement(
+ 'h',
+ buildHatchAdder(MTELINAC.class).atLeast(InputHatch, OutputHatch)
+ .casingIndex(CASING_INDEX)
+ .dot(2)
+ .build())
+
+ .addElement(
+ 'j',
+ buildHatchAdder(MTELINAC.class).atLeast(Maintenance, Energy)
+ .casingIndex(CASING_INDEX)
+ .dot(1)
+ .buildAndChain(ofBlock(LanthItemList.SHIELDED_ACCELERATOR_CASING, 0)))
+
+ .build();
+ }
+
+ private float outputEnergy;
+ private int outputRate;
+ private int outputParticle;
+ private float outputFocus;
+
+ private int length;
+
+ public MTELINAC(int id, String name, String nameRegional) {
+ super(id, name, nameRegional);
+ }
+
+ public MTELINAC(String name) {
+ super(name);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity te) {
+ return new MTELINAC(this.mName);
+ }
+
+ @Override
+ protected MultiblockTooltipBuilder createTooltip() {
+ final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder();
+ tt.addMachineType("Particle Accelerator")
+ .addInfo("Controller block for the LINAC")
+ .addInfo("Accelerates charged particles to higher energies")
+ .addInfo("Increasing length increases output energy, but decreases focus")
+ .addInfo("Use a lower temperature coolant to improve focus")
+ // .addInfo("Extendable, with a minimum length of 18 blocks")
+ .addInfo(DescTextLocalization.BLUEPRINT_INFO)
+ .addInfo(DescTextLocalization.BEAMLINE_SCANNER_INFO)
+ .addInfo("Valid Coolants:");
+
+ // Valid coolant list
+ for (String fluidName : BeamlineRecipeLoader.coolantMap.keySet()) {
+
+ tt.addInfo(
+ "- " + FluidRegistry.getFluid(fluidName)
+ .getLocalizedName(null));
+
+ }
+
+ tt.addInfo("Requires (length + 1)kL/s of coolant")
+ .addSeparator()
+ .beginVariableStructureBlock(7, 7, 7, 7, 19, 83, false)
+ .addController("Front bottom")
+ .addCasingInfoRange(LanthItemList.SHIELDED_ACCELERATOR_CASING.getLocalizedName(), 325, 1285, false)
+ .addCasingInfoRange(LanthItemList.COOLANT_DELIVERY_CASING.getLocalizedName(), 148, 852, false)
+ .addCasingInfoRange(LanthItemList.SHIELDED_ACCELERATOR_GLASS.getLocalizedName(), 127, 703, false)
+ .addCasingInfoRange("Superconducting Coil Block", 56, 312, false)
+ .addCasingInfoRange(LanthItemList.ELECTRODE_CASING.getLocalizedName(), 156, 732, false)
+ .addCasingInfoExactly("Grate Machine Casing", 47, false)
+ .addCasingInfoExactly("Borosilicate Glass (LuV+)", 48, false)
+ .addEnergyHatch(addDotText(1))
+ .addMaintenanceHatch(addDotText(1))
+ .addInputHatch(addDotText(2))
+ .addOutputHatch(addDotText(2))
+ .addOtherStructurePart("Beamline Input Hatch", addDotText(3))
+ .addOtherStructurePart("Beamline Output Hatch", addDotText(4))
+
+ .toolTipFinisher("GTNH: Lanthanides");;
+ return tt;
+ }
+
+ private boolean addBeamLineInputHatch(IGregTechTileEntity te, int casingIndex) {
+
+ if (te == null) return false;
+
+ IMetaTileEntity mte = te.getMetaTileEntity();
+
+ if (mte == null) return false;
+
+ if (mte instanceof MTEHatchInputBeamline) {
+ return this.mInputBeamline.add((MTEHatchInputBeamline) mte);
+ }
+
+ return false;
+ }
+
+ private boolean addBeamLineOutputHatch(IGregTechTileEntity te, int casingIndex) {
+
+ if (te == null) return false;
+
+ IMetaTileEntity mte = te.getMetaTileEntity();
+
+ if (mte == null) return false;
+
+ if (mte instanceof MTEHatchOutputBeamline) {
+ return this.mOutputBeamline.add((MTEHatchOutputBeamline) mte);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean checkRecipe(ItemStack itemStack) {
+
+ float tempFactor = 0;
+ // Focus as determined by multi properties
+ float machineFocus = 0;
+ // Input particle focus
+ float inputFocus = 0;
+
+ // Output focus to be set
+ outputFocus = 0;
+
+ float voltageFactor = 0;
+ float inputEnergy = 0;
+
+ machineTemp = 0;
+
+ // Energy quantity determined by multi
+ float machineEnergy = 0;
+ outputEnergy = 0;
+
+ int particleId = 0;
+ outputParticle = 0;
+
+ int inputRate = 0;
+ outputRate = 0;
+
+ ArrayList<FluidStack> tFluidInputs = this.getStoredFluids();
+ if (tFluidInputs.size() == 0) {
+ this.doRandomMaintenanceDamage(); // Penalise letting coolant run dry
+ this.stopMachine(SimpleShutDownReason.ofCritical("gtnhlanth.nocoolant"));
+ return false;
+ }
+
+ // Coolant input
+ FluidStack primFluid = tFluidInputs.get(0);
+
+ // 1b (1000L)/m/operation
+ final int fluidConsumed = 1000 * length;
+
+ this.mEfficiency = (10000 - (this.getIdealStatus() - this.getRepairStatus()) * 1000);
+ this.mEfficiencyIncrease = 10000;
+
+ if (this.getInputInformation() == null) {
+ return false;
+ }
+
+ if (this.getInputInformation()
+ .getEnergy() == 0) {
+ return false;
+ }
+
+ particleId = this.getInputInformation()
+ .getParticleId();
+ Particle inputParticle = Particle.getParticleFromId(particleId);
+
+ if (!inputParticle.canAccelerate()) {
+ stopMachine(SimpleShutDownReason.ofCritical("gtnhlanth.noaccel"));
+ return false;
+ }
+
+ mMaxProgresstime = 1 * TickTime.SECOND;
+ // Consume the input tier's corresponding practical voltage instead of the maximum suggested by the logic
+ mEUt = (int) -GTValues.VP[(int) this.getInputVoltageTier()];
+
+ // Particle stays the same with this multiblock
+ outputParticle = particleId;
+
+ if (primFluid.isFluidEqual(new FluidStack(FluidRegistry.getFluid("ic2coolant"), 1))) {
+ tempFactor = calculateTemperatureFactor(60); // Default temp of 300 is unreasonable
+ machineTemp = 60; // Solely for tricorder use
+ } else {
+ tempFactor = calculateTemperatureFactor(
+ primFluid.getFluid()
+ .getTemperature());
+ machineTemp = primFluid.getFluid()
+ .getTemperature(); // Solely for tricorder use
+ }
+
+ machineFocus = Math.max(((-0.9f) * this.length * tempFactor) + 110, 5); // Min of 5
+ if (machineFocus > 90) { // Max of 90
+ machineFocus = 90;
+ }
+
+ inputFocus = this.getInputInformation()
+ .getFocus();
+
+ outputFocus = (inputFocus > machineFocus) ? ((inputFocus + machineFocus) / 2)
+ : inputFocus * (machineFocus / 100); // If input focus > machine focus, take the average of both, else
+ // weigh the former by the latter
+
+ long voltage = this.getMaxInputVoltage();
+ // voltageFactor = calculateVoltageFactor(voltage);
+
+ // machineEnergy = Math.max(-((60) / this.length) * voltageFactor + 60_000, 2000); // Minimum of 2000keV
+
+ machineEnergy = (float) Math.max(length / 4 * Math.pow(voltage, 1.0 / 3.0), 50); // Minimum of 50keV
+
+ inputEnergy = this.getInputInformation()
+ .getEnergy();
+ /*
+ * outputEnergy = Math.min(
+ * (1 + inputEnergy / Particle.getParticleFromId(outputParticle)
+ * .maxSourceEnergy()) * machineEnergy,
+ * 120_000); // TODO more complex calculation than just
+ * // addition
+ */
+
+ outputEnergy = (float) Math.pow(
+ 10,
+ 1 + inputEnergy / Particle.getParticleFromId(outputParticle)
+ .maxSourceEnergy())
+ * machineEnergy;
+
+ inputRate = this.getInputInformation()
+ .getRate();
+ outputRate = inputRate; // Cannot increase rate with this multiblock
+
+ if (Util.coolantFluidCheck(primFluid, fluidConsumed)) {
+
+ this.stopMachine(SimpleShutDownReason.ofCritical("gtnhlanth.inscoolant"));
+ return false;
+
+ }
+
+ primFluid.amount -= fluidConsumed;
+
+ Fluid fluidOutput = BeamlineRecipeLoader.coolantMap.get(
+ primFluid.getFluid()
+ .getName());
+
+ if (Objects.isNull(fluidOutput)) return false;
+
+ FluidStack fluidOutputStack = new FluidStack(fluidOutput, fluidConsumed);
+
+ if (Objects.isNull(fluidOutputStack)) return false;
+
+ this.addFluidOutputs(new FluidStack[] { fluidOutputStack });
+
+ outputAfterRecipe();
+
+ return true;
+ }
+
+ private void outputAfterRecipe() {
+
+ if (!mOutputBeamline.isEmpty()) {
+
+ BeamLinePacket packet = new BeamLinePacket(
+ new BeamInformation(outputEnergy, outputRate, outputParticle, outputFocus));
+
+ for (MTEHatchOutputBeamline o : mOutputBeamline) {
+
+ o.q = packet;
+ }
+ }
+ }
+
+ @Override
+ public void stopMachine() {
+
+ // GTLog.out.print("Machine stopped");
+ outputFocus = 0;
+ outputEnergy = 0;
+ outputParticle = 0;
+ outputRate = 0;
+ machineTemp = 0;
+ super.stopMachine();
+ }
+
+ @Override
+ public void stopMachine(ShutDownReason reason) {
+
+ outputFocus = 0;
+ outputEnergy = 0;
+ outputParticle = 0;
+ outputRate = 0;
+ machineTemp = 0;
+ super.stopMachine(reason);
+
+ }
+
+ @Override
+ public String[] getInfoData() {
+
+ long storedEnergy = 0;
+ long maxEnergy = 0;
+ for (MTEHatchEnergy tHatch : mEnergyHatches) {
+ if (tHatch.isValid()) {
+ storedEnergy += tHatch.getBaseMetaTileEntity()
+ .getStoredEU();
+ maxEnergy += tHatch.getBaseMetaTileEntity()
+ .getEUCapacity();
+ }
+ }
+
+ BeamInformation information = this.getInputInformation();
+
+ return new String[] {
+ /* 1 */ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": "
+ + EnumChatFormatting.GREEN
+ + GTUtility.formatNumbers(mProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s / "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(mMaxProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s",
+ /* 2 */ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": "
+ + EnumChatFormatting.GREEN
+ + GTUtility.formatNumbers(storedEnergy)
+ + EnumChatFormatting.RESET
+ + " EU / "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(maxEnergy)
+ + EnumChatFormatting.RESET
+ + " EU",
+ /* 3 */ StatCollector.translateToLocal("GT5U.multiblock.usage") + ": "
+ + EnumChatFormatting.RED
+ + GTUtility.formatNumbers(getActualEnergyUsage())
+ + EnumChatFormatting.RESET
+ + " EU/t",
+ /* 4 */ StatCollector.translateToLocal("GT5U.multiblock.mei") + ": "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(getMaxInputVoltage())
+ + EnumChatFormatting.RESET
+ + " EU/t(*2A) "
+ + StatCollector.translateToLocal("GT5U.machines.tier")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + VN[GTUtility.getTier(getMaxInputVoltage())]
+ + EnumChatFormatting.RESET,
+ /* 5 */ StatCollector.translateToLocal("GT5U.multiblock.problems") + ": "
+ + EnumChatFormatting.RED
+ + (getIdealStatus() - getRepairStatus())
+ + EnumChatFormatting.RESET
+ + " "
+ + StatCollector.translateToLocal("GT5U.multiblock.efficiency")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + Float.toString(mEfficiency / 100.0F)
+ + EnumChatFormatting.RESET
+ + " %",
+
+ /* 7 */ EnumChatFormatting.BOLD + StatCollector.translateToLocal("beamline.info")
+ + ": "
+ + EnumChatFormatting.RESET,
+
+ StatCollector.translateToLocal("beamline.temperature") + ": " // Temperature:
+ + EnumChatFormatting.DARK_RED
+ + machineTemp
+ + EnumChatFormatting.RESET
+ + " K", // e.g. "137 K"
+
+ StatCollector.translateToLocal("beamline.coolusage") + ": " // Coolant usage:
+ + EnumChatFormatting.AQUA
+ + length
+ + EnumChatFormatting.RESET
+ + " kL/s", // e.g. "24 kL/s
+
+ /* 8 */ EnumChatFormatting.BOLD + StatCollector.translateToLocal("beamline.in_pre")
+ + ": "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.particle") + ": " // "Multiblock Beamline Input:"
+ + EnumChatFormatting.GOLD
+ + Particle.getParticleFromId(information.getParticleId())
+ .getLocalisedName() // e.g. "Electron
+ // (e-)"
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.energy") + ": " // "Energy:"
+ + EnumChatFormatting.DARK_RED
+ + information.getEnergy()
+ + EnumChatFormatting.RESET
+ + " keV", // e.g. "10240 keV"
+ StatCollector.translateToLocal("beamline.focus") + ": " // "Focus:"
+ + EnumChatFormatting.BLUE
+ + information.getFocus()
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.amount") + ": " // "Amount:"
+ + EnumChatFormatting.LIGHT_PURPLE
+ + information.getRate(),
+ EnumChatFormatting.BOLD + StatCollector.translateToLocal("beamline.out_pre") // "Multiblock Beamline
+ // Output:"
+ + ": "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.particle") + ": "
+ + EnumChatFormatting.GOLD
+ + Particle.getParticleFromId(this.outputParticle)
+ .getLocalisedName()
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.energy") + ": "
+ + EnumChatFormatting.DARK_RED
+ + this.outputEnergy
+ + EnumChatFormatting.RESET
+ + " keV",
+ StatCollector.translateToLocal(
+ "beamline.focus") + ": " + EnumChatFormatting.BLUE + this.outputFocus + " " + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.amount") + ": "
+ + EnumChatFormatting.LIGHT_PURPLE
+ + this.outputRate, };
+ }
+
+ private BeamInformation getInputInformation() {
+
+ for (MTEHatchInputBeamline in : this.mInputBeamline) { // Easy way to find the desired input. Efficient? No.
+ // Will it matter? No :boubs_glasses:
+
+ if (in.q == null) return new BeamInformation(0, 0, 0, 0);
+ // if (in.q == null) return new BeamInformation(10000, 10, 0, 90); // temporary for testing purposes
+
+ return in.q.getContent();
+ }
+ return null;
+ }
+
+ private static float calculateTemperatureFactor(int fluidTemp) {
+
+ float factor = (float) Math.pow(1.1, 0.2 * fluidTemp);
+ return factor;
+ }
+
+ /*
+ * private static float calculateVoltageFactor(long voltage) {
+ * float factor = (float) Math.pow(1.00009, -(0.1 * voltage - 114000));
+ * return factor;
+ * }
+ */
+
+ @Override
+ public String[] getStructureDescription(ItemStack arg0) {
+ return DescTextLocalization.addText("LINAC.hint", 11);
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity mte, ItemStack stack) {
+
+ mInputBeamline.clear();
+ mOutputBeamline.clear();
+
+ this.outputEnergy = 0;
+ this.outputRate = 0;
+ this.outputParticle = 0;
+ this.outputFocus = 0;
+
+ this.glassTier = 0;
+
+ this.onEndInnerLayer = false;
+
+ length = 8; // Base piece length
+
+ if (!checkPiece(STRUCTURE_PIECE_BASE, 3, 6, 0)) return false;
+
+ while (length < 128) {
+
+ if (!checkPiece(STRUCTURE_PIECE_LAYER, 3, 6, -length)) {
+ if (!checkPiece(STRUCTURE_PIECE_END, 3, 6, -length)) {
+ return false;
+ }
+ break;
+ } ;
+
+ length += 2;
+ }
+
+ // if (!checkPiece(STRUCTURE_PIECE_END, 3, 6, -length)) return false;
+
+ // Likely off by one or two, not visible to player however so doesn't particularly matter
+ length += 8;
+
+ return this.mInputBeamline.size() == 1 && this.mOutputBeamline.size() == 1
+ && this.mMaintenanceHatches.size() == 1
+ && this.mEnergyHatches.size() <= 2
+ && this.glassTier >= MIN_GLASS_TIER;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+
+ buildPiece(STRUCTURE_PIECE_BASE, stackSize, hintsOnly, 3, 6, 0);
+
+ int lLength = Math.max(stackSize.stackSize + 7, 8); // !!
+
+ if (!(lLength % 2 == 0)) {
+ lLength++; // Otherwise you get gaps at the end
+ }
+
+ for (int i = -8; i > -lLength - 1; i -= 2) {
+
+ // GTLog.out.print("Building inner piece! i = " + i);
+
+ buildPiece(STRUCTURE_PIECE_LAYER, stackSize, hintsOnly, 3, 6, i);
+ }
+
+ buildPiece(STRUCTURE_PIECE_END, stackSize, hintsOnly, 3, 6, -(lLength + 2));
+
+ StructureLib.addClientSideChatMessages("Length: " + (11 + lLength) + " blocks.");
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+
+ elementBudget = 200; // Maybe make a config
+
+ if (mMachine) return -1;
+
+ int build = 0;
+
+ build = survivialBuildPiece(STRUCTURE_PIECE_BASE, stackSize, 3, 6, 0, elementBudget, env, false, true);
+
+ if (build >= 0) return build; // Incomplete
+
+ int lLength = Math.max(stackSize.stackSize + 7, 8); // !!
+
+ if (!(lLength % 2 == 0)) {
+ lLength++; // Otherwise you get gaps at the end
+ }
+
+ for (int i = -8; i > -lLength - 1; i -= 2) {
+
+ build = survivialBuildPiece(STRUCTURE_PIECE_LAYER, stackSize, 3, 6, i, elementBudget, env, false, true);
+
+ if (build >= 0) return build;
+
+ }
+
+ int finalOutput = survivialBuildPiece(
+ STRUCTURE_PIECE_END,
+ stackSize,
+ 3,
+ 6,
+ -(lLength + 2),
+ elementBudget,
+ env,
+ false,
+ true);
+
+ return finalOutput;
+ }
+
+ @Override
+ public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection facing,
+ int aColorIndex, boolean active, boolean aRedstone) {
+
+ // Placeholder
+ if (side == facing) {
+ if (active) return new ITexture[] { casingTexturePages[0][47], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ return new ITexture[] { casingTexturePages[0][47], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ }
+ return new ITexture[] { casingTexturePages[0][47] };
+ }
+
+ @Override
+ public IStructureDefinition<MTELINAC> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ public boolean addInputHatchToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ this.onEndInnerLayer = true;
+ return super.addInputHatchToMachineList(aTileEntity, aBaseCasingIndex);
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/MTESourceChamber.java b/src/main/java/gtnhlanth/common/tileentity/MTESourceChamber.java
new file mode 100644
index 0000000000..68cc750005
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/MTESourceChamber.java
@@ -0,0 +1,409 @@
+package gtnhlanth.common.tileentity;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static gregtech.api.enums.GTValues.VN;
+import static gregtech.api.enums.HatchElement.Energy;
+import static gregtech.api.enums.HatchElement.InputBus;
+import static gregtech.api.enums.HatchElement.Maintenance;
+import static gregtech.api.enums.HatchElement.OutputBus;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages;
+import static gregtech.api.util.GTStructureUtility.buildHatchAdder;
+import static gtnhlanth.util.DescTextLocalization.BLUEPRINT_INFO;
+import static gtnhlanth.util.DescTextLocalization.addDotText;
+
+import java.util.ArrayList;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+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 gregtech.api.GregTechAPI;
+import gregtech.api.enums.GTValues;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.MTEEnhancedMultiBlockBase;
+import gregtech.api.metatileentity.implementations.MTEHatchEnergy;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GTUtility;
+import gregtech.api.util.MultiblockTooltipBuilder;
+import gregtech.api.util.shutdown.SimpleShutDownReason;
+import gtnhlanth.common.beamline.BeamInformation;
+import gtnhlanth.common.beamline.BeamLinePacket;
+import gtnhlanth.common.beamline.Particle;
+import gtnhlanth.common.hatch.MTEHatchOutputBeamline;
+import gtnhlanth.common.register.LanthItemList;
+import gtnhlanth.common.tileentity.recipe.beamline.BeamlineRecipeAdder2;
+import gtnhlanth.common.tileentity.recipe.beamline.RecipeSC;
+import gtnhlanth.util.DescTextLocalization;
+
+public class MTESourceChamber extends MTEEnhancedMultiBlockBase<MTESourceChamber> implements ISurvivalConstructable {
+
+ private static final IStructureDefinition<MTESourceChamber> STRUCTURE_DEFINITION;
+
+ private ArrayList<MTEHatchOutputBeamline> mOutputBeamline = new ArrayList<>();
+
+ private static final int CASING_INDEX = GTUtility.getCasingTextureIndex(GregTechAPI.sBlockCasings5, 14);
+
+ private float outputEnergy;
+ private int outputRate;
+ private int outputParticle;
+ private float outputFocus;
+
+ static {
+ STRUCTURE_DEFINITION = StructureDefinition.<MTESourceChamber>builder()
+ .addShape(
+ "sc",
+ new String[][] { { "ccccc", "ckkkc", "ckikc", "ckkkc", "dd~dd" },
+ { "ckkkc", "keeek", "ke-ek", "keeek", "ccocc" }, { "ckkkc", "k---k", "k---k", "k---k", "ccccc" },
+ { "ckkkc", "k---k", "k---k", "k---k", "ccccc" }, { "ckkkc", "keeek", "ke-ek", "keeek", "ccccc" },
+ { "ccccc", "ckkkc", "ckbkc", "ckkkc", "ccccc" } })
+ .addElement('c', ofBlock(LanthItemList.SHIELDED_ACCELERATOR_CASING, 0))
+ .addElement('k', ofBlock(LanthItemList.SHIELDED_ACCELERATOR_GLASS, 0))
+ .addElement('e', ofBlock(LanthItemList.ELECTRODE_CASING, 0))
+ .addElement(
+ 'b',
+ buildHatchAdder(MTESourceChamber.class).hatchClass(MTEHatchOutputBeamline.class)
+ .casingIndex(CASING_INDEX)
+ .dot(4)
+ .adder(MTESourceChamber::addBeamLineOutputHatch)
+ .build())
+ .addElement(
+ 'i',
+ buildHatchAdder(MTESourceChamber.class).atLeast(InputBus)
+ .casingIndex(CASING_INDEX)
+ .dot(1)
+ .build())
+ .addElement(
+ 'o',
+ buildHatchAdder(MTESourceChamber.class).atLeast(OutputBus)
+ .casingIndex(CASING_INDEX)
+ .dot(2)
+ .build())
+ .addElement(
+ 'd',
+ buildHatchAdder(MTESourceChamber.class).atLeast(Maintenance, Energy)
+ .casingIndex(CASING_INDEX)
+ .dot(3)
+ .buildAndChain(ofBlock(LanthItemList.SHIELDED_ACCELERATOR_CASING, 0)))
+
+ .build();
+ }
+
+ public MTESourceChamber(int id, String name, String nameRegional) {
+ super(id, name, nameRegional);
+ }
+
+ public MTESourceChamber(String name) {
+ super(name);
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece("sc", stackSize, 2, 4, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity te) {
+ return new MTESourceChamber(this.mName);
+ }
+
+ @Override
+ protected MultiblockTooltipBuilder createTooltip() {
+ final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder();
+ tt.addMachineType("Particle Source")
+ .addInfo("Controller block for the Source Chamber")
+ .addInfo(BLUEPRINT_INFO)
+ .addInfo(DescTextLocalization.BEAMLINE_SCANNER_INFO)
+ .addSeparator()
+ .beginStructureBlock(5, 5, 6, true)
+ .addController("Front bottom")
+ .addCasingInfoExactly(LanthItemList.SHIELDED_ACCELERATOR_CASING.getLocalizedName(), 56, false)
+ .addCasingInfoExactly(LanthItemList.SHIELDED_ACCELERATOR_GLASS.getLocalizedName(), 52, false)
+ .addCasingInfoExactly(LanthItemList.ELECTRODE_CASING.getLocalizedName(), 16, false)
+ .addOtherStructurePart("Beamline Output Hatch", addDotText(4))
+ .addEnergyHatch(addDotText(3))
+ .addMaintenanceHatch(addDotText(3))
+ .addInputBus(addDotText(1))
+ .addOutputBus(addDotText(2))
+ .toolTipFinisher("GTNH: Lanthanides");
+ return tt;
+ }
+
+ private boolean addBeamLineOutputHatch(IGregTechTileEntity te, int casingIndex) {
+
+ if (te == null) return false;
+
+ IMetaTileEntity mte = te.getMetaTileEntity();
+
+ if (mte == null) return false;
+
+ if (mte instanceof MTEHatchOutputBeamline) {
+ return this.mOutputBeamline.add((MTEHatchOutputBeamline) mte);
+ }
+
+ return false;
+ }
+ /*
+ * protected OverclockDescriber createOverclockDescriber() { return new EUNoTotalOverclockDescriber((byte) 4, 1); }
+ */
+
+ @Override
+ public boolean checkRecipe(ItemStack itemStack) {
+
+ // GTLog.out.print("In checkRecipe");
+
+ // No input particle, so no input quantities
+
+ outputFocus = 0;
+ outputEnergy = 0;
+ outputParticle = 0;
+ outputRate = 0;
+
+ ItemStack[] tItems = this.getStoredInputs()
+ .toArray(new ItemStack[0]);
+ // GTLog.out.print(Arrays.toString(tItems));
+ long tVoltageMaxTier = this.getMaxInputVoltage(); // Used to keep old math the same
+ long tVoltageActual = GTValues.VP[(int) this.getInputVoltageTier()];
+
+ RecipeSC tRecipe = (RecipeSC) BeamlineRecipeAdder2.instance.SourceChamberRecipes
+ .findRecipe(this.getBaseMetaTileEntity(), false, tVoltageActual, new FluidStack[] {}, tItems);
+
+ if (tRecipe == null || !tRecipe.isRecipeInputEqual(true, new FluidStack[] {}, tItems)) return false; // Consumes
+ // input
+ // item
+
+ this.mEfficiency = (10000 - (this.getIdealStatus() - this.getRepairStatus()) * 1000);
+ this.mEfficiencyIncrease = 10000;
+
+ this.mMaxProgresstime = tRecipe.mDuration;
+ if (mMaxProgresstime == Integer.MAX_VALUE - 1 && this.mEUt == Integer.MAX_VALUE - 1) return false;
+
+ mEUt = (int) -tVoltageActual;
+ if (this.mEUt > 0) this.mEUt = (-this.mEUt);
+
+ outputParticle = tRecipe.particleId;
+ float maxParticleEnergy = Particle.getParticleFromId(outputParticle)
+ .maxSourceEnergy(); // The maximum energy a
+ // particle can possess
+ // when produced by this
+ // multiblock
+ float maxMaterialEnergy = tRecipe.maxEnergy; // The maximum energy for the recipe processed
+ outputEnergy = (float) Math.min(
+ (-maxMaterialEnergy) * Math.pow(1.001, -(tRecipe.energyRatio) * (tVoltageMaxTier - tRecipe.mEUt))
+ + maxMaterialEnergy,
+ maxParticleEnergy);
+
+ if (outputEnergy <= 0) {
+ stopMachine(SimpleShutDownReason.ofCritical("gtnhlanth.scerror"));
+ return false;
+ }
+
+ outputFocus = tRecipe.focus;
+ outputRate = tRecipe.rate;
+
+ this.mOutputItems = tRecipe.mOutputs;
+ this.updateSlots();
+
+ outputAfterRecipe();
+
+ return true;
+ }
+
+ @Override
+ public String[] getStructureDescription(ItemStack arg0) {
+ return DescTextLocalization.addText("SourceChamber.hint", 7); // Generate 7 localised hint strings in structure
+ // description
+ }
+
+ private void outputAfterRecipe() {
+
+ if (!mOutputBeamline.isEmpty()) {
+
+ BeamLinePacket packet = new BeamLinePacket(
+ new BeamInformation(outputEnergy, outputRate, outputParticle, outputFocus));
+
+ for (MTEHatchOutputBeamline o : mOutputBeamline) {
+
+ o.q = packet;
+ }
+ }
+ }
+
+ @Override
+ public void stopMachine() {
+ outputFocus = 0;
+ outputEnergy = 0;
+ outputParticle = 0;
+ outputRate = 0;
+ super.stopMachine();
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return BeamlineRecipeAdder2.instance.SourceChamberRecipes;
+ }
+
+ @Override
+ public String[] getInfoData() {
+
+ long storedEnergy = 0;
+ long maxEnergy = 0;
+ for (MTEHatchEnergy tHatch : mEnergyHatches) {
+ if (tHatch.isValid()) {
+ storedEnergy += tHatch.getBaseMetaTileEntity()
+ .getStoredEU();
+ maxEnergy += tHatch.getBaseMetaTileEntity()
+ .getEUCapacity();
+ }
+ }
+
+ return new String[] {
+ /* 1 */ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": "
+ + EnumChatFormatting.GREEN
+ + GTUtility.formatNumbers(mProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s / "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(mMaxProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s",
+ /* 2 */ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": "
+ + EnumChatFormatting.GREEN
+ + GTUtility.formatNumbers(storedEnergy)
+ + EnumChatFormatting.RESET
+ + " EU / "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(maxEnergy)
+ + EnumChatFormatting.RESET
+ + " EU",
+ /* 3 */ StatCollector.translateToLocal("GT5U.multiblock.usage") + ": "
+ + EnumChatFormatting.RED
+ + GTUtility.formatNumbers(getActualEnergyUsage())
+ + EnumChatFormatting.RESET
+ + " EU/t",
+ /* 4 */ StatCollector.translateToLocal("GT5U.multiblock.mei") + ": "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(getMaxInputVoltage())
+ + EnumChatFormatting.RESET
+ + " EU/t(*2A) "
+ + StatCollector.translateToLocal("GT5U.machines.tier")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + VN[GTUtility.getTier(getMaxInputVoltage())]
+ + EnumChatFormatting.RESET,
+ /* 5 */ StatCollector.translateToLocal("GT5U.multiblock.problems") + ": "
+ + EnumChatFormatting.RED
+ + (getIdealStatus() - getRepairStatus())
+ + EnumChatFormatting.RESET
+ + " "
+ + StatCollector.translateToLocal("GT5U.multiblock.efficiency")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + Float.toString(mEfficiency / 100.0F)
+ + EnumChatFormatting.RESET
+ + " %",
+ EnumChatFormatting.BOLD + StatCollector.translateToLocal("beamline.out_pre")
+ + ": "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.particle") + ": "
+ + EnumChatFormatting.GOLD
+ + Particle.getParticleFromId(this.outputParticle)
+ .getLocalisedName()
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.energy") + ": "
+ + EnumChatFormatting.DARK_RED
+ + this.outputEnergy
+ + EnumChatFormatting.RESET
+ + " keV",
+ StatCollector.translateToLocal(
+ "beamline.focus") + ": " + EnumChatFormatting.BLUE + this.outputFocus + " " + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.amount") + ": "
+ + EnumChatFormatting.LIGHT_PURPLE
+ + this.outputRate, };
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece("sc", stackSize, hintsOnly, 2, 4, 0);
+ }
+
+ @Override
+ public IStructureDefinition<MTESourceChamber> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+
+ this.mOutputBeamline.clear(); // Necessary due to the nature of the beamline hatch adder
+
+ return checkPiece("sc", 2, 4, 0) && this.mMaintenanceHatches.size() == 1
+ && this.mInputBusses.size() == 1
+ && this.mOutputBusses.size() == 1
+ && this.mOutputBeamline.size() == 1
+ && this.mEnergyHatches.size() == 1;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection side, ForgeDirection facing,
+ int colorIndex, boolean active, boolean redstoneLevel) {
+
+ // Placeholder
+ if (side == facing) {
+ if (active) return new ITexture[] { casingTexturePages[1][14], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ return new ITexture[] { casingTexturePages[1][14], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ }
+ return new ITexture[] { casingTexturePages[1][14] };
+ }
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/MTESynchrotron.java b/src/main/java/gtnhlanth/common/tileentity/MTESynchrotron.java
new file mode 100644
index 0000000000..3b67f8e172
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/MTESynchrotron.java
@@ -0,0 +1,1077 @@
+package gtnhlanth.common.tileentity;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockAdder;
+import static gregtech.api.enums.GTValues.VN;
+import static gregtech.api.enums.HatchElement.Energy;
+import static gregtech.api.enums.HatchElement.InputHatch;
+import static gregtech.api.enums.HatchElement.Maintenance;
+import static gregtech.api.enums.HatchElement.OutputHatch;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages;
+import static gregtech.api.util.GTStructureUtility.buildHatchAdder;
+import static gtnhlanth.util.DescTextLocalization.addDotText;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidRegistry;
+import net.minecraftforge.fluids.FluidStack;
+
+import com.google.common.collect.ImmutableMap;
+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 bartworks.API.BorosilicateGlass;
+import gregtech.api.GregTechAPI;
+import gregtech.api.enums.GTValues;
+import gregtech.api.enums.TickTime;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.MTEEnhancedMultiBlockBase;
+import gregtech.api.metatileentity.implementations.MTEHatchEnergy;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GTUtility;
+import gregtech.api.util.MultiblockTooltipBuilder;
+import gregtech.api.util.shutdown.ShutDownReason;
+import gregtech.api.util.shutdown.SimpleShutDownReason;
+import gtnhlanth.common.beamline.BeamInformation;
+import gtnhlanth.common.beamline.BeamLinePacket;
+import gtnhlanth.common.beamline.Particle;
+import gtnhlanth.common.block.BlockAntennaCasing;
+import gtnhlanth.common.hatch.MTEHatchInputBeamline;
+import gtnhlanth.common.hatch.MTEHatchOutputBeamline;
+import gtnhlanth.common.register.LanthItemList;
+import gtnhlanth.common.tileentity.recipe.beamline.BeamlineRecipeLoader;
+import gtnhlanth.util.DescTextLocalization;
+import gtnhlanth.util.Util;
+
+public class MTESynchrotron extends MTEEnhancedMultiBlockBase<MTESynchrotron> implements ISurvivalConstructable {
+
+ private static final IStructureDefinition<MTESynchrotron> STRUCTURE_DEFINITION;
+
+ protected static final String STRUCTURE_PIECE_ENTRANCE = "entrance";
+ protected static final String STRUCTURE_PIECE_BASE = "base";
+
+ public static final int CONSUMED_FLUID = 32_000; // Fluid consumed per processed recipe, maybe increase with EU
+ public static final int MIN_INPUT_FOCUS = 25; // Inclusive
+
+ private ArrayList<MTEHatchInputBeamline> mInputBeamline = new ArrayList<>();
+ private ArrayList<MTEHatchOutputBeamline> mOutputBeamline = new ArrayList<>();
+
+ public ArrayList<BlockAntennaCasing> mAntennaCasings = new ArrayList<>();
+
+ private static final int CASING_INDEX = GTUtility.getCasingTextureIndex(GregTechAPI.sBlockCasings5, 14);
+
+ private static final byte MIN_GLASS_TIER = 6;
+
+ private int energyHatchTier;
+
+ private int antennaeTier;
+
+ private Byte glassTier;
+
+ /*
+ * c: Shielded accelerator casing v: Vacuum k: Superconducting coil d: Coolant Delivery casing
+ */
+
+ // TODO: E > 1200eV for x-ray lithography
+ // spotless:off
+ static {
+
+ STRUCTURE_DEFINITION = StructureDefinition.<MTESynchrotron>builder().addShape(
+ STRUCTURE_PIECE_ENTRANCE,
+
+
+
+ new String[][] {
+ {
+ " ",
+ " ccc ",
+ " cgggc ",
+ " cgvgc ",
+ " cgggc ",
+ " ccc "
+ }
+ })
+ .addShape(
+ STRUCTURE_PIECE_BASE,
+
+ new String[][] {
+ {
+ " ",
+ " ccc ",
+ " ccccc cjjjjjc ",
+ " cc-cc cjjc~cjjc ",
+ " ccccc cjjjjjc ",
+ " ccc ",
+ " "
+ },
+ {
+ " ",
+ " ccc ccccccccccc ",
+ " c---c ccc-------ccc ",
+ " c---c ccc-------ccc ",
+ " c---c ccc-------ccc ",
+ " ccc ccccccccccc ",
+ " "
+ },
+ {
+ " ccccccccccc ",
+ " ccc cc-----------cc ",
+ " c---c cc-------------cc ",
+ " c---c cc-------------cc ",
+ " c---c cc-------------cc ",
+ " ccc ccc---------ccc ",
+ " ccccccccccc "
+ },
+ {
+ " ccccccccccccccc ",
+ " ccc cc---------------cc ",
+ " c---ccc-----------------c ",
+ " c---ccc-----------------cc ",
+ " c---ccc-----------------c ",
+ " ccc cc---------------cc ",
+ " ccccccccccccccc ",
+
+ },
+ {
+ " ccc ccccccccccccccccc ",
+ " ckkkccc-----------------cc ",
+ "ck---kc-------------------cc ",
+ "ck---kc--------------------c ",
+ "ck---kc-------------------cc ",
+ " ckkkccc-----------------cc ",
+ " ccc cccccccccccccccccc "
+
+ },
+ {
+ " cccccccccccc ccccccc ",
+ " cdddcc-------ccccc-------cc ",
+ "cd---d----------------------c ",
+ "cd---d----------------------c ",
+ "cd---d----------------------c ",
+ " cdddcc-------ccccc-------cc ",
+ " cccccccccccc ccccccc ",
+ },
+ {
+ " ccccccccc ccccc ",
+ " ckkkc-----cccc cccc-----cc ",
+ "ck---k-------ccccccc--------c ",
+ "ck---k-------ccccccc---------c ",
+ "ck---k-------ccccccc--------c ",
+ " ckkkc-----cccc cccc-----cc ",
+ " ccccccccc ccccc "
+ },
+ {
+ " cccccccc ccccc ",
+ " c--------cc cc-----cc ",
+ "c----------cc cc-------c ",
+ "c----------cc cc-------c ",
+ "c----------cc cc-------c ",
+ " c--------cc cc-----cc ",
+ " cccccccc ccccc "
+
+ },
+ {
+ " ccccccc ccccc ",
+ " c-------c c-----c ",
+ "c---------c c-------c ",
+ "c---------c c-------c ",
+ "c---------c c-------c ",
+ " c-------c c-----c ",
+ " ccccccc ccccc "
+
+ },
+ {
+ " cccccc ccccc ",
+ " c------c c-----c ",
+ "c--------c c------c ",
+ "c--------c c------c ",
+ "c--------c c------c ",
+ " c------c c-----c ",
+ " cccccc ccccc "
+
+ },
+ {
+ " ccccc cccc ",
+ " c-----c c----c ",
+ "c-------c c------c ",
+ "c-------c c------c ",
+ "c-------c c------c ",
+ " c-----c c----c ",
+ " ccccc cccc "
+
+ },
+ {
+ " cccc ccc ",
+ " c----cc cc---cc ",
+ "c------c c-----c ",
+ "c------c c-----c ",
+ "c------c c-----c ",
+ " c----cc cc---cc ",
+ " cccc ccc "
+
+ },
+ {
+ " cccc cccc ",
+ " c---cc c----c ",
+ "c------c c-----c ",
+ "c------c c-----cc ",
+ "c------c c-----c ",
+ " c---cc cc---c ",
+ " cccc cccc "
+
+ },
+ {
+ " cccc cccc ",
+ " c---cc c----c ",
+ "c-----c c----cc ",
+ "c-----c c----cc ",
+ "c-----c c----cc ",
+ " c---cc cc---c ",
+ " cccc cccc "
+
+ },
+ {
+ " ccc ccc ",
+ " ckkkcc cckkkc ",
+ "ck---kc ck---kc ",
+ "ck---kc ck---kc ",
+ "ck---kc ck---kc ",
+ " ckkkcc cckkkc ",
+ " ccc ccc "
+
+ },
+ {
+ " cec cec ",
+ " cnanc cnanc ",
+ "cn---nc cn---nc ",
+ "cn---nc cn---nc ",
+ "cn---nc cn---nc ",
+ " cnnnc cnnnc ",
+ " ccc ccc "
+
+ },
+ {
+ " cic cic ",
+ " cndnc cndnc ",
+ "cn---nc cn---nc ",
+ "cn---nc cn---nc ",
+ "cn---nc cn---nc ",
+ " cndnc cndnc ",
+ " coc coc "
+
+ },
+ {
+ " cec cec ",
+ " cnanc cnanc ",
+ "cn---nc cn---nc ",
+ "cn---nc cn---nc ",
+ "cn---nc cn---nc ",
+ " cnnnc cnnnc ",
+ " ccc ccc "
+
+ },
+ {
+ " ccc ccc ",
+ " ckkkcc cckkkc ",
+ "ck---kc ck---kc ",
+ "ck---kc ck---kc ",
+ "ck---kc ck---kc ",
+ " ckkkcc cckkkc ",
+ " ccc ccc "
+
+ },
+ {
+ " cccc cccc ",
+ " c----c c----c ",
+ "cc----c c----cc ",
+ "cc----c c----cc ",
+ "cc----c c----cc ",
+ " c---cc cc---c ",
+ " cccc cccc "
+
+ },
+ {
+ " cccc cccc ",
+ " c----c c----c ",
+ " c-----c c-----c ",
+ "cc-----c c-----cc ",
+ " c-----c c-----c ",
+ " c---cc cc---c ",
+ " cccc cccc "
+
+ },
+ {
+ " ccc ccc ",
+ " cc---cc cc---cc ",
+ " c-----c c-----c ",
+ " c-----c c-----c ",
+ " c-----c c-----c ",
+ " cc---cc cc---cc ",
+ " ccc ccc "
+
+ },
+ {
+ " cccc cccc ",
+ " c----c c----c ",
+ " c------c c------c ",
+ " c------c c------c ",
+ " c------c c------c ",
+ " c----c c----c ",
+ " cccc cccc "
+
+ },
+ {
+ " ccccc ccccc ",
+ " c-----c c-----c ",
+ " c------c c------c ",
+ " c------c c------c ",
+ " c------c c------c ",
+ " c-----c c-----c ",
+ " ccccc ccccc "
+
+ },
+ {
+ " ccccc ccccc ",
+ " c-----c c-----c ",
+ " c-------c c-------c ",
+ " c-------c c-------c ",
+ " c-------c c-------c ",
+ " c-----c c-----c ",
+ " ccccc ccccc "
+
+ },
+ {
+ " ccccc ccccc ",
+ " c-----cc cc-----c ",
+ " c-------cc cc-------cc ",
+ " c-------cc cc-------cc ",
+ " c-------cc cc-------cc ",
+ " c-----cc cc------c ",
+ " ccccc cccccc "
+
+ },
+ {
+ " ccccc ccccccc ",
+ " cc-----cccc cccc-----ccc ",
+ " c--------ccccccc--------cccc ",
+ " c--------ccccccc--------cccc ",
+ " c--------ccccccc--------cccc ",
+ " cc-----cccc cccc------cc ",
+ " ccccc cccccc "
+
+ },
+ {
+ " ccccccc cccccccccc ",
+ " cc-------ccccc--------cccc ",
+ " c---------kdkdk--------ccccccccc",
+ " c---------kdkdk--------ccccccccc",
+ " c---------kdkdk--------ccccccccc",
+ " cc-------ccccc--------cccc ",
+ " ccccccc cccccccc "
+
+ },
+ {
+ " cccccccccccccccccccc ",
+ " cc-------------------ccccccccc",
+ " cc---------------------------cg",
+ " c----------------------------cg",
+ " cc---------------------------cg",
+ " c-------------------ccccccccc",
+ " ccccccccccccccccccc "
+
+ },
+ {
+ " ccccccccccccccccccc ",
+ " cc-----------------cccccccccc",
+ " c--------------------------cg",
+ " cc---------------------------b",
+ " c--------------------------cg",
+ " c-----------------cccccccccc",
+ " ccccccccccccccccc "
+
+ },
+ {
+ " ccccccccccccccc ",
+ " ccc-------------ccccccccccc",
+ " cc------------------------cg",
+ " cc------------------------cg",
+ " cc------------------------cg",
+ " ccc-------------ccccccccccc",
+ " ccccccccccccc "
+
+ },
+ {
+ " ",
+ " cccccccccccccccccc ",
+ " ccc-kdkdk------ccccccccccc",
+ " cc--kdkdk------ccccccccccc",
+ " ccc-kdkdk------ccccccccccc",
+ " cccccccccccccccccc "
+
+ },
+ {
+ " ",
+ " ",
+ " cccccccccccccccc ",
+ " ccccccccccccccccc ",
+ " cccccccccccccccc ",
+ " ",
+ " "
+
+ }
+
+ }
+
+ ).addElement('c', ofBlock(LanthItemList.SHIELDED_ACCELERATOR_CASING, 0))
+ .addElement('k', ofBlock(GregTechAPI.sBlockCasings1, 15)) // Superconducting coils
+ .addElement('d', ofBlock(LanthItemList.COOLANT_DELIVERY_CASING, 0))
+ .addElement('e', buildHatchAdder(MTESynchrotron.class).atLeast(ImmutableMap.of(Energy, 4)).dot(6).casingIndex(CASING_INDEX).build())
+ .addElement('n', ofBlock(LanthItemList.NIOBIUM_CAVITY_CASING, 0))
+ .addElement('a', ofBlockAdder(MTESynchrotron::addAntenna, LanthItemList.ANTENNA_CASING_T1, 0)) //Antenna Casings
+ .addElement('i', buildHatchAdder(MTESynchrotron.class).atLeast(ImmutableMap.of(InputHatch, 2)).dot(4).casingIndex(CASING_INDEX).build())
+ .addElement('o', buildHatchAdder(MTESynchrotron.class).atLeast(ImmutableMap.of(OutputHatch, 2)).dot(5).casingIndex(CASING_INDEX).build())
+ .addElement('v', buildHatchAdder(MTESynchrotron.class).hatchClass(MTEHatchInputBeamline.class).casingIndex(CASING_INDEX)
+ .dot(1).adder(MTESynchrotron::addBeamlineInputHatch).build())
+ .addElement('b', buildHatchAdder(MTESynchrotron.class).hatchClass(MTEHatchOutputBeamline.class).casingIndex(CASING_INDEX)
+ .dot(2).adder(MTESynchrotron::addBeamlineOutputHatch).build())
+ .addElement('g', BorosilicateGlass.ofBoroGlass((byte) 0, MIN_GLASS_TIER, Byte.MAX_VALUE, (te, t) -> te.glassTier = t, te -> te.glassTier))
+ .addElement('j',
+ buildHatchAdder(MTESynchrotron.class).atLeast(Maintenance).dot(3).casingIndex(CASING_INDEX)
+ .buildAndChain(LanthItemList.SHIELDED_ACCELERATOR_CASING, 0))
+
+ .build();
+
+
+
+ }
+
+ // spotless:on
+
+ /*
+ * v = pi * lorentz^2 * sfreq sfreq = sw / 2pi sw = e * B / mass(e) * c v = (e * B * l^2) / (2 * mass(e) * c) =
+ * 292.718624222 * l^2 * B
+ */
+
+ private float outputEnergy;
+ private int outputRate;
+ private int outputParticle;
+ private float outputFocus;
+ private float machineFocus;
+
+ private int machineTemp;
+
+ public MTESynchrotron(String aName) {
+ super(aName);
+ }
+
+ public MTESynchrotron(int id, String name, String nameRegional) {
+ super(id, name, nameRegional);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
+ return new MTESynchrotron(this.mName);
+ }
+
+ @Override
+ protected MultiblockTooltipBuilder createTooltip() {
+ final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder();
+ tt.addMachineType("Particle Accelerator")
+ .addInfo("Controller block for the Synchrotron")
+ .addInfo("Torus-shaped, accelerates electrons to produce high-energy electromagnetic radiation")
+ .addInfo(DescTextLocalization.BLUEPRINT_INFO)
+ .addInfo(DescTextLocalization.BEAMLINE_SCANNER_INFO)
+ .addInfo("Valid Coolants:");
+
+ // Valid coolant list
+ for (String fluidName : BeamlineRecipeLoader.coolantMap.keySet()) {
+
+ tt.addInfo(
+ "- " + FluidRegistry.getFluid(fluidName)
+ .getLocalizedName(null));
+
+ }
+
+ tt.addInfo("Requires 32 kL/s of coolant")
+ .addSeparator()
+ .beginStructureBlock(36, 7, 34, true)
+ .addController("Front middle")
+ .addCasingInfoExactly(LanthItemList.SHIELDED_ACCELERATOR_CASING.getLocalizedName(), 676, false)
+ .addCasingInfoExactly("Superconducting Coil Block", 90, false)
+ .addCasingInfoExactly("Niobium Cavity Casing", 64, false)
+ .addCasingInfoExactly(LanthItemList.COOLANT_DELIVERY_CASING.getLocalizedName(), 28, false)
+ .addCasingInfoExactly("Borosilicate Glass Block (LuV+)", 16, false)
+ .addCasingInfoExactly("Antenna Casing (must match)", 4, true)
+ .addOtherStructurePart("Beamline Input Hatch", addDotText(1))
+ .addOtherStructurePart("Beamline Output Hatch", addDotText(2))
+ .addMaintenanceHatch(addDotText(3))
+ .addInputHatch(addDotText(4))
+ .addOutputHatch(addDotText(5))
+ .addEnergyHatch(addDotText(6))
+
+ .toolTipFinisher("GTNH: Lanthanides");
+ return tt;
+ }
+
+ private boolean addBeamlineInputHatch(IGregTechTileEntity te, int casingIndex) {
+
+ if (te == null) return false;
+
+ IMetaTileEntity mte = te.getMetaTileEntity();
+
+ if (mte == null) return false;
+
+ if (mte instanceof MTEHatchInputBeamline) {
+ return this.mInputBeamline.add((MTEHatchInputBeamline) mte);
+ }
+
+ return false;
+
+ }
+
+ private boolean addBeamlineOutputHatch(IGregTechTileEntity te, int casingIndex) {
+
+ if (te == null) return false;
+
+ IMetaTileEntity mte = te.getMetaTileEntity();
+
+ if (mte == null) return false;
+
+ if (mte instanceof MTEHatchOutputBeamline) {
+ return this.mOutputBeamline.add((MTEHatchOutputBeamline) mte);
+ }
+
+ return false;
+
+ }
+
+ @Override
+ public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection facing,
+ int aColorIndex, boolean active, boolean aRedstone) {
+ // Placeholder
+ if (side == facing) {
+ if (active) return new ITexture[] { casingTexturePages[1][14], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ return new ITexture[] { casingTexturePages[1][14], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ }
+ return new ITexture[] { casingTexturePages[1][14] };
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ elementBudget = 200;
+
+ if (mMachine) return -1;
+
+ int build = survivialBuildPiece(STRUCTURE_PIECE_ENTRANCE, stackSize, 16, 3, 1, elementBudget, env, false, true);
+
+ if (build >= 0) return build;
+
+ return survivialBuildPiece(STRUCTURE_PIECE_BASE, stackSize, 16, 3, 0, elementBudget, env, false, true);
+
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece(STRUCTURE_PIECE_ENTRANCE, stackSize, hintsOnly, 16, 3, 1);
+ buildPiece(STRUCTURE_PIECE_BASE, stackSize, hintsOnly, 16, 3, 0);
+
+ }
+
+ @Override
+ public IStructureDefinition<MTESynchrotron> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ public boolean addEnergyInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) {
+ if (aTileEntity == null) {
+ return false;
+ }
+ IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity();
+ if (aMetaTileEntity == null) return false;
+ if (aMetaTileEntity instanceof MTEHatchEnergy) {
+
+ MTEHatchEnergy hatch = (MTEHatchEnergy) aMetaTileEntity;
+
+ // First energy hatch added
+ if (this.mEnergyHatches.size() == 0) this.energyHatchTier = hatch.mTier;
+
+ // Disallow any hatches that don't match the tier of the first hatch added
+ if (hatch.mTier != this.energyHatchTier) return false;
+
+ hatch.updateTexture(aBaseCasingIndex);
+ hatch.updateCraftingIcon(this.getMachineCraftingIcon());
+ return mEnergyHatches.add(hatch);
+ }
+ return false;
+ }
+
+ private boolean addAntenna(Block block, int meta) {
+
+ if (block == null) return false;
+
+ if (!(block instanceof BlockAntennaCasing)) return false;
+
+ BlockAntennaCasing antennaBlock = (BlockAntennaCasing) block;
+
+ int antennaTier = antennaBlock.getTier();
+
+ // First antenna casing added
+ if (this.mAntennaCasings.size() == 0) this.antennaeTier = antennaTier;
+
+ if (antennaTier != this.antennaeTier) return false;
+
+ return mAntennaCasings.add(antennaBlock);
+
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack aStack) {
+ return true;
+ }
+
+ @Override
+ public boolean checkRecipe(ItemStack aStack) {
+
+ float inputEnergy = 0;
+ float inputFocus = 0;
+ float inputRate = 0;
+ int inputParticleId = 0;
+
+ machineFocus = 0;
+ machineTemp = 0;
+
+ outputEnergy = 0;
+ outputFocus = 0;
+ outputRate = 0;
+ outputParticle = 0;
+
+ float tempFactor = 0;
+
+ float voltageFactor = 0;
+
+ ArrayList<FluidStack> fluidList = this.getStoredFluids();
+
+ if (fluidList.size() == 0) {
+
+ this.stopMachine(SimpleShutDownReason.ofCritical("gtnhlanth.nocoolant"));
+
+ return false;
+ }
+
+ this.mEfficiency = (10000 - (this.getIdealStatus() - this.getRepairStatus()) * 1000);
+ this.mEfficiencyIncrease = 10000;
+
+ if (this.getInputInformation() == null) {
+ return false;
+ }
+
+ if (this.getInputInformation()
+ .getEnergy() == 0) { // Only really applies if there's no input
+ return false;
+ }
+
+ if (this.getInputInformation()
+ .getFocus() < MIN_INPUT_FOCUS) {
+ return false;
+ }
+
+ inputParticleId = this.getInputInformation()
+ .getParticleId();
+
+ Particle inputParticle = Particle.getParticleFromId(inputParticleId);
+
+ if (!inputParticle.canAccelerate()) {
+ stopMachine(SimpleShutDownReason.ofCritical("gtnhlanth.noaccel"));
+ return false;
+ }
+
+ mMaxProgresstime = TickTime.SECOND;
+
+ long voltage = this.getMaxInputVoltage();
+ mEUt = (int) (-voltage / GTValues.V[(int) this.getInputVoltageTier()]
+ * GTValues.VP[(int) this.getInputVoltageTier()]); // Multiply VP by amps
+
+ outputParticle = 1; // Photon
+
+ FluidStack primaryFluid = fluidList.get(0);
+
+ int fluidTemperature;
+
+ if (primaryFluid.isFluidEqual(new FluidStack(FluidRegistry.getFluid("ic2coolant"), 1))) {
+ fluidTemperature = 60; // Default temp of 300 is unreasonable
+ } else {
+ fluidTemperature = primaryFluid.getFluid()
+ .getTemperature();
+ }
+
+ machineTemp = fluidTemperature; // Solely for tricorder info
+
+ machineFocus = getMachineFocus(fluidTemperature);
+
+ inputFocus = this.getInputInformation()
+ .getFocus();
+
+ outputFocus = (inputFocus > machineFocus) ? ((inputFocus + machineFocus) / 2.5f)
+ : inputFocus * (machineFocus / 100); // If input focus > machine focus, divide their sum by 2.5, else
+ // weigh the former by the latter. This punishes having too low a
+ // machine focus for low values of input focus
+ // E.g. An input focus of 50 requires a machine focus of 100 to get an
+ // output focus of 50,
+ // whereas an input focus of 60 only requires around 80
+ // In general, as input focus increases, output scales better with
+ // machine focus
+
+ voltageFactor = getVoltageFactor(voltage, this.antennaeTier);
+
+ inputEnergy = this.getInputInformation()
+ .getEnergy();
+ float mass = inputParticle.getMass();
+
+ // Perhaps divide by mass somehow here too
+ outputEnergy = (float) calculateOutputParticleEnergy(voltage, inputEnergy, this.antennaeTier); // maybe
+ // adjust
+ // behaviour here
+
+ inputRate = this.getInputInformation()
+ .getRate();
+
+ outputRate = (int) (inputRate * getOutputRatetio(voltageFactor, this.antennaeTier));
+
+ if (outputRate == 0) {
+ stopMachine(SimpleShutDownReason.ofCritical("gtnhlanth.low_input_rate"));
+ return false;
+ }
+
+ if (Util.coolantFluidCheck(primaryFluid, CONSUMED_FLUID)) {
+
+ stopMachine(SimpleShutDownReason.ofCritical("gtnhlanth.inscoolant"));
+ return false;
+
+ }
+
+ primaryFluid.amount -= CONSUMED_FLUID;
+
+ Fluid fluidOutput = BeamlineRecipeLoader.coolantMap.get(
+ primaryFluid.getFluid()
+ .getName());
+
+ if (Objects.isNull(fluidOutput)) return false;
+
+ FluidStack fluidOutputStack = new FluidStack(fluidOutput, CONSUMED_FLUID);
+
+ if (Objects.isNull(fluidOutputStack)) return false;
+
+ this.addFluidOutputs(new FluidStack[] { fluidOutputStack });
+
+ outputAfterRecipe();
+
+ return true;
+ }
+
+ private void outputAfterRecipe() {
+
+ if (!mOutputBeamline.isEmpty()) {
+
+ BeamLinePacket packet = new BeamLinePacket(
+ new BeamInformation(outputEnergy, outputRate, outputParticle, outputFocus));
+
+ for (MTEHatchOutputBeamline o : mOutputBeamline) {
+
+ o.q = packet;
+ }
+ }
+ }
+
+ @Override
+ public void stopMachine() {
+
+ outputFocus = 0;
+ outputEnergy = 0;
+ outputParticle = 0;
+ outputRate = 0;
+ machineFocus = 0;
+ machineTemp = 0;
+ super.stopMachine();
+
+ }
+
+ @Override
+ public void stopMachine(ShutDownReason reason) {
+
+ outputFocus = 0;
+ outputEnergy = 0;
+ outputParticle = 0;
+ outputRate = 0;
+ machineFocus = 0;
+ machineTemp = 0;
+ super.stopMachine(reason);
+
+ }
+
+ private BeamInformation getInputInformation() {
+
+ for (MTEHatchInputBeamline in : this.mInputBeamline) {
+
+ if (in.q == null) return new BeamInformation(0, 0, 0, 0);
+ // if (in.q == null) return new BeamInformation(10000, 10, 0, 90); // TODO temporary for testing purposes
+
+ return in.q.getContent();
+ }
+ return null;
+ }
+
+ private static float getVoltageFactor(long mEU, int antennaTier) {
+
+ // float factor = (float) Math.pow(1.00004, -mEU * Math.pow(antennaTier, 1.0/3.0) + 80000);
+ float factor = (float) -Math.pow(1.1, -mEU / 2000 * Math.pow(antennaTier, 2.0 / 3.0)) + 1; // Strictly improves
+ // with higher tier
+ // antenna
+ return (float) Math.max(1.0, factor);
+
+ }
+
+ /*
+ * private static float getTemperatureFactor(int temperature) { float factor = (float) Math.pow(1.11, 0.18 *
+ * temperature); return factor; }
+ */
+ private static double calculateOutputParticleEnergy(long voltage, double inputParticleEnergy, int antennaTier) {
+
+ /*
+ * Energy in general increases as input energy increases, with the relationship between the machine EUt and
+ * energy being an negative exponential, with a maximum depending on both input particle energy and antenna
+ * tier. The extent to which the output depends on the former is determined by the cbrt of the latter, meaning
+ * that increases in antenna tier result in diminishing returns. In the same way, the curve of the output energy
+ * vs. machine voltage exponential depends on antenna tier, with an increase in antenna tier resulting in a more
+ * shallow curve up. The effect of this also increases with the tier. LaTeX:
+ * -\frac{l^{1.11t^{\frac{1}{3}}}}{40000000}\cdot\left(0.15^{\frac{2}{t^{\frac{3}{2}}}}\right)^{\frac{x}{60768}}
+ * \ +\ \frac{l^{1.11t^{\frac{1}{3}}}}{40000000}
+ */
+
+ double energy = (Math.pow(inputParticleEnergy, 1.13 * Math.pow(antennaTier, 4.0 / 9.0)) / 40_000_000)
+ * (-Math.pow(Math.pow(0.15, 2.0 / (Math.pow(antennaTier, 5.0 / 2.0))), voltage / 60768.0) + 1); // In
+ // keV
+
+ return energy;
+
+ }
+
+ private static float getMachineFocus(int temperature) {
+
+ return (float) Math.max(Math.min(Math.pow(1.5, -1.0 / 40.0 * (temperature - 480)), 90), 10);
+ }
+
+ // Punny, right?
+ private static float getOutputRatetio(float voltageFactor, int antennaTier) {
+ return (float) (voltageFactor / (10 / Math.pow(2.5, antennaTier))); // Scale ratio with antenna tier, such a
+ // high
+ // exponential should be fine so long as
+ // there
+ // are only few antenna tiers
+ }
+
+ @Override
+ public String[] getStructureDescription(ItemStack arg0) {
+ return DescTextLocalization.addText("Synchrotron.hint", 12);
+ }
+
+ @Override
+ public String[] getInfoData() {
+
+ long storedEnergy = 0;
+ long maxEnergy = 0;
+ for (MTEHatchEnergy tHatch : mEnergyHatches) {
+ if (tHatch.isValid()) {
+ storedEnergy += tHatch.getBaseMetaTileEntity()
+ .getStoredEU();
+ maxEnergy += tHatch.getBaseMetaTileEntity()
+ .getEUCapacity();
+ }
+ }
+
+ BeamInformation information = this.getInputInformation();
+
+ return new String[] {
+ /* 1 */ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": "
+ + EnumChatFormatting.GREEN
+ + GTUtility.formatNumbers(mProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s / "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(mMaxProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s",
+ /* 2 */ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": "
+ + EnumChatFormatting.GREEN
+ + GTUtility.formatNumbers(storedEnergy)
+ + EnumChatFormatting.RESET
+ + " EU / "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(maxEnergy)
+ + EnumChatFormatting.RESET
+ + " EU",
+ /* 3 */ StatCollector.translateToLocal("GT5U.multiblock.usage") + ": "
+ + EnumChatFormatting.RED
+ + GTUtility.formatNumbers(getActualEnergyUsage())
+ + EnumChatFormatting.RESET
+ + " EU/t",
+ /* 4 */ StatCollector.translateToLocal("GT5U.multiblock.mei") + ": "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(getMaxInputVoltage())
+ + EnumChatFormatting.RESET
+ + " EU/t(*2A) "
+ + StatCollector.translateToLocal("GT5U.machines.tier")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + VN[GTUtility.getTier(getMaxInputVoltage())]
+ + EnumChatFormatting.RESET,
+ /* 5 */ StatCollector.translateToLocal("GT5U.multiblock.problems") + ": "
+ + EnumChatFormatting.RED
+ + (getIdealStatus() - getRepairStatus())
+ + EnumChatFormatting.RESET
+ + " "
+ + StatCollector.translateToLocal("GT5U.multiblock.efficiency")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + Float.toString(mEfficiency / 100.0F)
+ + EnumChatFormatting.RESET
+ + " %",
+
+ /* 7 */ EnumChatFormatting.BOLD + StatCollector.translateToLocal("beamline.info")
+ + ": "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.focus") + ": " // Machine Focus:
+ + EnumChatFormatting.BLUE
+ + machineFocus
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.temperature") + ": " // Temperature:
+ + EnumChatFormatting.DARK_RED
+ + machineTemp
+ + EnumChatFormatting.RESET
+ + " K", // e.g. "137 K"
+ StatCollector.translateToLocal("beamline.coolusage") + ": " // Coolant Usage:
+ + EnumChatFormatting.AQUA
+ + 32_000
+ + EnumChatFormatting.RESET
+ + " kL/s", // 32 kL/s
+
+ /* 8 */ EnumChatFormatting.BOLD + StatCollector.translateToLocal("beamline.in_pre")
+ + ": "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.particle") + ": " // "Multiblock Beamline Input:"
+ + EnumChatFormatting.GOLD
+ + Particle.getParticleFromId(information.getParticleId())
+ .getLocalisedName() // e.g. "Electron
+ // (e-)"
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.energy") + ": " // "Energy:"
+ + EnumChatFormatting.DARK_RED
+ + information.getEnergy()
+ + EnumChatFormatting.RESET
+ + " keV", // e.g. "10240 keV"
+ StatCollector.translateToLocal("beamline.focus") + ": " // "Focus:"
+ + EnumChatFormatting.BLUE
+ + information.getFocus()
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.amount") + ": " // "Amount:"
+ + EnumChatFormatting.LIGHT_PURPLE
+ + information.getRate(),
+ EnumChatFormatting.BOLD + StatCollector.translateToLocal("beamline.out_pre") // "Multiblock Beamline
+ // Output:"
+ + ": "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.particle") + ": "
+ + EnumChatFormatting.GOLD
+ + Particle.getParticleFromId(this.outputParticle)
+ .getLocalisedName()
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.energy") + ": "
+ + EnumChatFormatting.DARK_RED
+ + this.outputEnergy * 1000
+ + EnumChatFormatting.RESET
+ + " eV",
+ StatCollector.translateToLocal(
+ "beamline.focus") + ": " + EnumChatFormatting.BLUE + this.outputFocus + " " + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.amount") + ": "
+ + EnumChatFormatting.LIGHT_PURPLE
+ + this.outputRate, };
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) {
+
+ this.mInputBeamline.clear();
+ this.mOutputBeamline.clear();
+
+ this.mAntennaCasings.clear();
+
+ this.mEnergyHatches.clear();
+ this.energyHatchTier = 0;
+ this.antennaeTier = 0;
+
+ this.glassTier = 0;
+
+ this.outputEnergy = 0;
+ this.outputRate = 0;
+ this.outputFocus = 0;
+ this.outputParticle = 0;
+
+ if (!checkPiece(STRUCTURE_PIECE_ENTRANCE, 16, 3, 1)) return false;
+ if (!checkPiece(STRUCTURE_PIECE_BASE, 16, 3, 0)) return false;
+
+ return this.mInputBeamline.size() == 1 && this.mOutputBeamline.size() == 1
+ && this.mMaintenanceHatches.size() == 1
+ && this.mEnergyHatches.size() == 4
+ && this.glassTier >= MIN_GLASS_TIER;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack aStack) {
+ return 10000;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack aStack) {
+ return 0;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack aStack) {
+ return false;
+ }
+
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/MTETargetChamber.java b/src/main/java/gtnhlanth/common/tileentity/MTETargetChamber.java
new file mode 100644
index 0000000000..8545d5e23a
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/MTETargetChamber.java
@@ -0,0 +1,480 @@
+package gtnhlanth.common.tileentity;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockAdder;
+import static gregtech.api.enums.GTValues.VN;
+import static gregtech.api.enums.HatchElement.Energy;
+import static gregtech.api.enums.HatchElement.InputBus;
+import static gregtech.api.enums.HatchElement.Maintenance;
+import static gregtech.api.enums.HatchElement.OutputBus;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_GLOW;
+import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages;
+import static gregtech.api.util.GTStructureUtility.buildHatchAdder;
+import static gtnhlanth.util.DescTextLocalization.BLUEPRINT_INFO;
+import static gtnhlanth.util.DescTextLocalization.addDotText;
+
+import java.util.ArrayList;
+
+import net.minecraft.block.Block;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.FluidStack;
+
+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 bartworks.common.loaders.ItemRegistry;
+import gregtech.api.GregTechAPI;
+import gregtech.api.enums.TickTime;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.MTEEnhancedMultiBlockBase;
+import gregtech.api.metatileentity.implementations.MTEHatchEnergy;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GTRecipe;
+import gregtech.api.util.GTUtility;
+import gregtech.api.util.MultiblockTooltipBuilder;
+import gtnhlanth.common.beamline.BeamInformation;
+import gtnhlanth.common.beamline.Particle;
+import gtnhlanth.common.hatch.MTEBusInputFocus;
+import gtnhlanth.common.hatch.MTEHatchInputBeamline;
+import gtnhlanth.common.register.LanthItemList;
+import gtnhlanth.common.tileentity.recipe.beamline.BeamlineRecipeAdder2;
+import gtnhlanth.common.tileentity.recipe.beamline.RecipeTC;
+import gtnhlanth.util.DescTextLocalization;
+
+public class MTETargetChamber extends MTEEnhancedMultiBlockBase<MTETargetChamber> implements ISurvivalConstructable {
+
+ private static final IStructureDefinition<MTETargetChamber> STRUCTURE_DEFINITION;
+
+ private ArrayList<MTEHatchInputBeamline> mInputBeamline = new ArrayList<>();
+
+ private ArrayList<MTEBusInputFocus> mInputFocus = new ArrayList<>();
+
+ private static final int CASING_INDEX_FRONT = GTUtility.getCasingTextureIndex(GregTechAPI.sBlockCasings3, 10); // Grate
+ private static final int CASING_INDEX_CENTRE = GTUtility.getCasingTextureIndex(GregTechAPI.sBlockCasings5, 14); // Shielded
+ // Acc.
+
+ private float inputEnergy;
+ private float inputRate;
+ private int inputParticle;
+ private float inputFocus;
+
+ // spotless:off
+ static {
+ STRUCTURE_DEFINITION = StructureDefinition.<MTETargetChamber>builder()
+ .addShape(
+ "base",
+ new String[][] {
+ {"ggggg", "gjjjg", "gjbjg", "gjjjg", "ff~ff"},
+ {"cslsc", "s-r-s", "srhrs", "s-r-s", "ccccc"},
+ {"csssc", "s---s", "s---s", "s---s", "ccccc"},
+ {"csssc", "s---s", "s---s", "s---s", "ccccc"},
+ {"cstsc", "s-u-s", "suius", "s-u-s", "ccccc"},
+ {"ggggg", "gjjjg", "gjojg", "gjjjg", "ggggg"}})
+
+ .addElement('g', ofBlock(GregTechAPI.sBlockCasings3, 10)) //Grate casing
+ .addElement(
+ 'f',
+ buildHatchAdder(MTETargetChamber.class).atLeast(Maintenance, Energy)
+ .casingIndex(CASING_INDEX_FRONT).dot(2).buildAndChain(ofBlock(GregTechAPI.sBlockCasings3, 10)))
+
+ .addElement('j', ofBlockAdder(MTETargetChamber::addGlass, ItemRegistry.bw_glasses[0], 1))
+ .addElement('b', buildHatchAdder(MTETargetChamber.class).hatchClass(MTEHatchInputBeamline.class).casingIndex(CASING_INDEX_CENTRE).dot(5).adder(MTETargetChamber::addBeamLineInputHatch).build())
+ .addElement('c', ofBlock(LanthItemList.SHIELDED_ACCELERATOR_CASING, 0))
+
+ .addElement('l', buildHatchAdder(MTETargetChamber.class).hatchClass(MTEBusInputFocus.class).casingIndex(CASING_INDEX_CENTRE).dot(1).adder(MTETargetChamber::addFocusInputHatch).build())
+
+ .addElement('t', buildHatchAdder(MTETargetChamber.class).atLeast(InputBus).casingIndex(CASING_INDEX_CENTRE).dot(3).build())
+ .addElement('s', ofBlock(LanthItemList.SHIELDED_ACCELERATOR_GLASS, 0))
+ .addElement('r', ofBlock(LanthItemList.FOCUS_MANIPULATION_CASING, 0))
+ .addElement('h', ofBlock(LanthItemList.FOCUS_HOLDER, 0))
+ .addElement('u', ofBlock(LanthItemList.TARGET_RECEPTACLE_CASING, 0))
+ .addElement('i', ofBlock(LanthItemList.TARGET_HOLDER, 0))
+ .addElement('o', buildHatchAdder(MTETargetChamber.class).atLeast(OutputBus).casingIndex(CASING_INDEX_CENTRE).dot(4).build())
+
+ .build();
+ }
+ //spotless:on
+
+ private boolean addGlass(Block block, int meta) {
+ return block == ItemRegistry.bw_glasses[0];
+ }
+
+ private boolean addBeamLineInputHatch(IGregTechTileEntity te, int casingIndex) {
+
+ if (te == null) return false;
+
+ IMetaTileEntity mte = te.getMetaTileEntity();
+
+ if (mte == null) return false;
+
+ if (mte instanceof MTEHatchInputBeamline) {
+ return this.mInputBeamline.add((MTEHatchInputBeamline) mte);
+ }
+
+ return false;
+ }
+
+ private boolean addFocusInputHatch(IGregTechTileEntity te, int casingIndex) {
+
+ if (te == null) return false;
+
+ IMetaTileEntity mte = te.getMetaTileEntity();
+
+ if (mte == null) return false;
+
+ if (mte instanceof MTEBusInputFocus) {
+ return this.mInputFocus.add((MTEBusInputFocus) mte);
+ }
+
+ return false;
+ }
+
+ public MTETargetChamber(int id, String name, String nameRegional) {
+ super(id, name, nameRegional);
+ }
+
+ public MTETargetChamber(String name) {
+ super(name);
+ }
+
+ @Override
+ public IMetaTileEntity newMetaEntity(IGregTechTileEntity te) {
+ return new MTETargetChamber(this.mName);
+ }
+
+ @Override
+ public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection side, ForgeDirection facing,
+ int colorIndex, boolean active, boolean redstoneLevel) {
+ // Placeholder
+ if (side == facing) {
+ if (active) return new ITexture[] { casingTexturePages[0][47], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ return new ITexture[] { casingTexturePages[0][47], TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER)
+ .extFacing()
+ .build(),
+ TextureFactory.builder()
+ .addIcon(OVERLAY_FRONT_OIL_CRACKER_GLOW)
+ .extFacing()
+ .glow()
+ .build() };
+ }
+ return new ITexture[] { casingTexturePages[0][47] };
+ }
+
+ @Override
+ protected MultiblockTooltipBuilder createTooltip() {
+ final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder();
+ tt.addMachineType("Collision Chamber")
+ .addInfo("Controller block for the Target Chamber")
+ .addInfo("Hitting things with other things")
+
+ .addInfo(BLUEPRINT_INFO)
+ .addInfo(DescTextLocalization.BEAMLINE_SCANNER_INFO)
+ .addSeparator()
+ .beginStructureBlock(5, 5, 6, true)
+ .addController("Front bottom")
+ .addCasingInfoExactly("Grate Machine Casing", 29, false)
+ .addCasingInfoExactly("Shielded Accelerator Casing", 28, false)
+ .addCasingInfoExactly("Borosilicate Glass", 16, true)
+ .addCasingInfoExactly(LanthItemList.SHIELDED_ACCELERATOR_GLASS.getLocalizedName(), 34, false)
+ .addCasingInfoExactly(LanthItemList.TARGET_RECEPTACLE_CASING.getLocalizedName(), 4, false)
+ .addCasingInfoExactly(LanthItemList.FOCUS_MANIPULATION_CASING.getLocalizedName(), 4, false)
+ .addCasingInfoExactly(LanthItemList.FOCUS_HOLDER.getLocalizedName(), 1, false)
+ .addCasingInfoExactly(LanthItemList.TARGET_HOLDER.getLocalizedName(), 1, false)
+ .addOtherStructurePart("Focus Input Bus", addDotText(1))
+ .addMaintenanceHatch(addDotText(2))
+ .addEnergyHatch(addDotText(2))
+ .addInputBus(addDotText(3))
+ .addOutputBus(addDotText(4))
+ .addOtherStructurePart("Beamline Input Hatch", addDotText(5))
+ .toolTipFinisher("GTNH: Lanthanides");
+ return tt;
+ }
+
+ @Override
+ public void construct(ItemStack stackSize, boolean hintsOnly) {
+ buildPiece("base", stackSize, hintsOnly, 2, 4, 0);
+
+ }
+
+ @Override
+ public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) {
+ if (mMachine) return -1;
+ return survivialBuildPiece("base", stackSize, 2, 4, 0, elementBudget, env, false, true);
+ }
+
+ @Override
+ public IStructureDefinition<MTETargetChamber> getStructureDefinition() {
+ return STRUCTURE_DEFINITION;
+ }
+
+ @Override
+ public RecipeMap<?> getRecipeMap() {
+ return BeamlineRecipeAdder2.instance.TargetChamberRecipes;
+ }
+
+ @Override
+ public boolean checkRecipe(ItemStack itemStack) {
+
+ inputEnergy = 0;
+ inputRate = 0;
+ inputParticle = 0;
+ inputFocus = 0;
+
+ ArrayList<ItemStack> tItems = this.getStoredInputs();
+ ItemStack tFocusItem = this.getFocusItemStack();
+
+ ItemStack tFocusItemZeroDamage = null;
+
+ if (tFocusItem != null) {
+
+ tFocusItemZeroDamage = tFocusItem.copy();
+ tFocusItemZeroDamage.setItemDamage(0);
+ }
+
+ ArrayList<ItemStack> tItemsWithFocusItem = new ArrayList<>();
+ tItemsWithFocusItem.add(tFocusItemZeroDamage);
+ tItemsWithFocusItem.addAll(tItems);
+
+ long tVoltage = this.getMaxInputVoltage();
+
+ ItemStack[] tItemsArray = tItems.toArray(new ItemStack[0]);
+
+ ItemStack[] tItemsWithFocusItemArray = tItemsWithFocusItem.toArray(new ItemStack[0]);
+
+ RecipeTC tRecipe = (RecipeTC) BeamlineRecipeAdder2.instance.TargetChamberRecipes.findRecipeQuery()
+ .items(tItemsWithFocusItemArray)
+ .voltage(tVoltage)
+ .filter((GTRecipe recipe) -> {
+
+ RecipeTC recipeTc = (RecipeTC) recipe;
+
+ BeamInformation inputInfo = this.getInputInformation();
+
+ int particle = recipeTc.particleId;
+
+ return (particle == inputInfo.getParticleId()
+ && !(inputInfo.getEnergy() < recipeTc.minEnergy || inputInfo.getEnergy() > recipeTc.maxEnergy));
+
+ })
+ .find();
+
+ if (tRecipe == null || !tRecipe.isRecipeInputEqual(true, new FluidStack[] {}, tItemsWithFocusItemArray))
+ return false;
+
+ if (tRecipe.focusItem != null) {
+ if (tRecipe.focusItem.getItem() != tFocusItem.getItem()) return false;
+ }
+
+ this.mEfficiency = (10000 - (this.getIdealStatus() - this.getRepairStatus()) * 1000);
+ this.mEfficiencyIncrease = 10000;
+
+ BeamInformation inputInfo = this.getInputInformation();
+
+ if (inputInfo == null) return false;
+
+ inputEnergy = inputInfo.getEnergy();
+ inputRate = inputInfo.getRate();
+ inputParticle = inputInfo.getParticleId();
+ inputFocus = inputInfo.getFocus();
+
+ if (inputEnergy < tRecipe.minEnergy || inputEnergy > tRecipe.maxEnergy) return false;
+
+ if (inputFocus < tRecipe.minFocus) return false;
+
+ if (inputParticle != tRecipe.particleId) return false;
+
+ this.mMaxProgresstime = Math.max(Math.round((tRecipe.amount / inputRate * 5 * TickTime.SECOND)), 1); // 5
+ // seconds
+ // per
+ // integer multiple
+ // over the rate. E.g., 100a, 10r
+ // would equal 50 seconds
+ if (this.mMaxProgresstime == Integer.MAX_VALUE - 1 && this.mEUt == Integer.MAX_VALUE - 1) return false;
+
+ mEUt = (int) -tVoltage;
+ if (this.mEUt > 0) this.mEUt = (-this.mEUt);
+
+ this.mOutputItems = tRecipe.mOutputs;
+
+ if (tRecipe.focusItem != null) // Recipe actually uses the mask, can also assume machine mask item is nonnull
+ // due to above conditions
+ mInputFocus.get(0)
+ .depleteFocusDurability(1);
+
+ this.updateSlots();
+
+ return true;
+ }
+
+ private BeamInformation getInputInformation() {
+
+ for (MTEHatchInputBeamline in : this.mInputBeamline) {
+
+ if (in.q == null) return new BeamInformation(0, 0, 0, 0);
+ // if (in.q == null) return new BeamInformation(10, 10, Particle.PHOTON.ordinal(), 90); // temporary
+ // for
+ // testing purposes
+
+ return in.q.getContent();
+ }
+ return null;
+ }
+
+ private ItemStack getFocusItemStack() {
+
+ for (MTEBusInputFocus hatch : this.mInputFocus) {
+ return hatch.getContentUsageSlots()
+ .get(0);
+ }
+
+ return null;
+
+ }
+
+ @Override
+ public boolean checkMachine(IGregTechTileEntity arg0, ItemStack arg1) {
+
+ mInputBeamline.clear();
+ mInputFocus.clear();
+
+ if (!checkPiece("base", 2, 4, 0)) return false;
+
+ return this.mInputBeamline.size() == 1 && this.mMaintenanceHatches.size() == 1
+ && this.mInputBusses.size() == 1
+ && this.mOutputBusses.size() == 1
+ && this.mInputFocus.size() == 1;
+ }
+
+ @Override
+ public boolean explodesOnComponentBreak(ItemStack arg0) {
+ return false;
+ }
+
+ @Override
+ public int getDamageToComponent(ItemStack arg0) {
+ return 0;
+ }
+
+ @Override
+ public int getMaxEfficiency(ItemStack arg0) {
+ return 10000;
+ }
+
+ @Override
+ public boolean isCorrectMachinePart(ItemStack arg0) {
+ return true;
+ }
+
+ @Override
+ public String[] getStructureDescription(ItemStack arg0) {
+ return DescTextLocalization.addText("TargetChamber.hint", 13);
+ }
+
+ @Override
+ public String[] getInfoData() {
+
+ long storedEnergy = 0;
+ long maxEnergy = 0;
+ for (MTEHatchEnergy tHatch : mEnergyHatches) {
+ if (tHatch.isValid()) {
+ storedEnergy += tHatch.getBaseMetaTileEntity()
+ .getStoredEU();
+ maxEnergy += tHatch.getBaseMetaTileEntity()
+ .getEUCapacity();
+ }
+ }
+
+ BeamInformation information = this.getInputInformation();
+
+ return new String[] {
+ /* 1 */ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": "
+ + EnumChatFormatting.GREEN
+ + GTUtility.formatNumbers(mProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s / "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(mMaxProgresstime / 20)
+ + EnumChatFormatting.RESET
+ + " s",
+ /* 2 */ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": "
+ + EnumChatFormatting.GREEN
+ + GTUtility.formatNumbers(storedEnergy)
+ + EnumChatFormatting.RESET
+ + " EU / "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(maxEnergy)
+ + EnumChatFormatting.RESET
+ + " EU",
+ /* 3 */ StatCollector.translateToLocal("GT5U.multiblock.usage") + ": "
+ + EnumChatFormatting.RED
+ + GTUtility.formatNumbers(getActualEnergyUsage())
+ + EnumChatFormatting.RESET
+ + " EU/t",
+ /* 4 */ StatCollector.translateToLocal("GT5U.multiblock.mei") + ": "
+ + EnumChatFormatting.YELLOW
+ + GTUtility.formatNumbers(getMaxInputVoltage())
+ + EnumChatFormatting.RESET
+ + " EU/t(*2A) "
+ + StatCollector.translateToLocal("GT5U.machines.tier")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + VN[GTUtility.getTier(getMaxInputVoltage())]
+ + EnumChatFormatting.RESET,
+ /* 5 */ StatCollector.translateToLocal("GT5U.multiblock.problems") + ": "
+ + EnumChatFormatting.RED
+ + (getIdealStatus() - getRepairStatus())
+ + EnumChatFormatting.RESET
+ + " "
+ + StatCollector.translateToLocal("GT5U.multiblock.efficiency")
+ + ": "
+ + EnumChatFormatting.YELLOW
+ + Float.toString(mEfficiency / 100.0F)
+ + EnumChatFormatting.RESET
+ + " %",
+
+ /* 6 */ EnumChatFormatting.BOLD + StatCollector.translateToLocal("beamline.in_pre")
+ + ": "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.particle") + ": " // "Multiblock Beamline Input:"
+ + EnumChatFormatting.GOLD
+ + Particle.getParticleFromId(information.getParticleId())
+ .getLocalisedName() // e.g. "Electron
+ // (e-)"
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.energy") + ": " // "Energy:"
+ + EnumChatFormatting.DARK_RED
+ + information.getEnergy() * 1000 // In line with the synchrotron's output
+ + EnumChatFormatting.RESET
+ + " eV", // e.g. "10240 eV"
+ StatCollector.translateToLocal("beamline.focus") + ": " // "Focus:"
+ + EnumChatFormatting.BLUE
+ + information.getFocus()
+ + " "
+ + EnumChatFormatting.RESET,
+ StatCollector.translateToLocal("beamline.amount") + ": " // "Amount:"
+ + EnumChatFormatting.LIGHT_PURPLE
+ + information.getRate(), };
+ }
+
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/BeamlineRecipeAdder2.java b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/BeamlineRecipeAdder2.java
new file mode 100644
index 0000000000..dad71375c3
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/BeamlineRecipeAdder2.java
@@ -0,0 +1,165 @@
+package gtnhlanth.common.tileentity.recipe.beamline;
+
+import java.util.Arrays;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.StatCollector;
+
+import gregtech.api.gui.modularui.GTUITextures;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMapBackend;
+import gregtech.api.recipe.RecipeMapBuilder;
+import gregtech.api.util.GTUtility;
+import gtnhlanth.common.beamline.Particle;
+
+public class BeamlineRecipeAdder2 {
+
+ public static final BeamlineRecipeAdder2 instance = new BeamlineRecipeAdder2();
+
+ public final RecipeMap<RecipeMapBackend> SourceChamberRecipes = RecipeMapBuilder.of("gtnhlanth.recipe.sc")
+ .minInputs(0, 0)
+ .maxIO(1, 2, 0, 0)
+ .amperage(1)
+ .frontend(SourceChamberFrontend::new)
+ .progressBar(GTUITextures.PROGRESSBAR_ASSEMBLY_LINE_1)
+ .neiSpecialInfoFormatter((recipeInfo) -> {
+
+ RecipeSC recipe = (RecipeSC) recipeInfo.recipe;
+
+ float focus = recipe.focus;
+ float maxEnergy = recipe.maxEnergy;
+
+ int amount = recipe.rate;
+
+ Particle particle = Particle.getParticleFromId(recipe.particleId);
+
+ return Arrays.asList(
+
+ // StatCollector.translateToLocal("beamline.particle") + ": " + particle.getLocalisedName(),
+
+ StatCollector.translateToLocal("beamline.energy") + ": <="
+ + GTUtility.formatNumbers(Math.min(maxEnergy, particle.maxSourceEnergy()))
+ + " keV",
+
+ StatCollector.translateToLocal("beamline.focus") + ": " + GTUtility.formatNumbers(focus),
+
+ StatCollector.translateToLocal("beamline.rate") + ": " + GTUtility.formatNumbers(amount)
+
+ );
+ })
+ // .slotOverlays(null)
+
+ .build();
+
+ public final RecipeMap<RecipeMapBackend> TargetChamberRecipes = RecipeMapBuilder.of("gtnhlanth.recipe.tc")
+ .minInputs(0, 0)
+ .maxIO(3, 4, 0, 0)
+ .frontend(TargetChamberFrontend::new)
+ .neiSpecialInfoFormatter(((recipeInfo) -> {
+
+ RecipeTC recipe = (RecipeTC) recipeInfo.recipe;
+
+ float minEnergy = recipe.minEnergy;
+ float maxEnergy = recipe.maxEnergy;
+
+ float minFocus = recipe.minFocus;
+
+ float amount = recipe.amount;
+
+ Particle particle = Particle.getParticleFromId(recipe.particleId);
+
+ return Arrays.asList(
+
+ // StatCollector.translateToLocal("beamline.particle") + ": " + particle.getLocalisedName(),
+
+ StatCollector.translateToLocal("beamline.energy") + ": "
+ + GTUtility.formatNumbers(minEnergy * 1000)
+ + "-"
+ + GTUtility.formatNumbers(maxEnergy * 1000)
+ + " eV", // Note the eV unit
+
+ StatCollector.translateToLocal("beamline.focus") + ": >=" + GTUtility.formatNumbers(minFocus),
+
+ StatCollector.translateToLocal("beamline.amount") + ": " + GTUtility.formatNumbers(amount)
+
+ );
+ }))
+ // .slotOverlays(null)
+ .progressBar(GTUITextures.PROGRESSBAR_ASSEMBLY_LINE_1)
+ .progressBarPos(108, 22)
+ .neiTransferRect(100, 22, 28, 18)
+ .build();
+
+ /***
+ *
+ * @param itemInputs - duh
+ * @param itemOutputs - duh
+ * @param particleId - The ID of the {@link Particle} generated by the recipe.
+ * It is recommended to use Particle#ordinal()
+ * @param rate - The rate/amount of particles generated
+ * @param maxEnergy - The maximum energy particles generated by this recipe can possess (keV). Set this value >=
+ * max particle energy to limit it to the latter
+ * @param focus - Focus of the particle generated
+ * @param energyRatio - Set high for little-to-no EUt energy scaling, low for the opposite
+ * @param minEUt - Minimum EUt required for the recipe. ! May not output if input energy is equal to minimum !
+ */
+ public boolean addSourceChamberRecipe(ItemStack[] itemInputs, ItemStack[] itemOutputs, int particleId, int rate,
+ float maxEnergy, float focus, float energyRatio, int minEUt) {
+
+ return (SourceChamberRecipes.addRecipe(
+ new RecipeSC(
+ false,
+ itemInputs,
+ itemOutputs,
+ null,
+ new int[] {},
+ null,
+ null,
+ 20,
+ minEUt,
+ particleId,
+ rate,
+ maxEnergy,
+ focus,
+ energyRatio))
+ != null);
+ }
+
+ /***
+ *
+ * @param itemInput - The item to be used as a target. Should have durability
+ * @param itemOutput - duh
+ * @param particleId - The ID of the {@link Particle} used by the recipe. It
+ * is recommended to use Particle#ordinal()
+ * @param amount - The total amount of particles required for the recipe to come to completion. The duration of
+ * the recipe will be determined by this and the input particle rate.
+ * @param minEnergy - The minimum energy amount required by this recipe in keV (inclusive)
+ * @param maxEnergy - The maximum energy amount allowed by this recipe in keV (inclusive)
+ * @param minFocus - Minimum focus allowed by the recipe
+ * @param energyRatio - Set high for little-to-no EUt energy scaling, low for the opposite
+ * @param minEUt - Minimum EUt required for the recipe to start
+ */
+
+ public boolean addTargetChamberRecipe(ItemStack itemInput, ItemStack itemOutput, ItemStack itemFocus,
+ int particleId, int amount, float minEnergy, float maxEnergy, float minFocus, float energyRatio, int minEUt) {
+
+ return (TargetChamberRecipes.addRecipe(
+ new RecipeTC(
+ false,
+ itemInput,
+ itemOutput,
+ itemFocus,
+ particleId,
+ amount,
+ minEnergy,
+ maxEnergy,
+ minFocus,
+ energyRatio,
+ minEUt),
+ false,
+ false,
+ false) != null);
+
+ }
+
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/BeamlineRecipeLoader.java b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/BeamlineRecipeLoader.java
new file mode 100644
index 0000000000..d71b9a571e
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/BeamlineRecipeLoader.java
@@ -0,0 +1,193 @@
+package gtnhlanth.common.tileentity.recipe.beamline;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidRegistry;
+
+import gregtech.api.enums.ItemList;
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.OrePrefixes;
+import gregtech.api.util.GTOreDictUnificator;
+import gregtech.api.util.GTUtility;
+import gtPlusPlus.core.material.MaterialsElements;
+import gtnhlanth.common.beamline.Particle;
+import gtnhlanth.common.item.MaskList;
+import gtnhlanth.common.register.LanthItemList;
+import gtnhlanth.common.register.WerkstoffMaterialPool;
+
+public class BeamlineRecipeLoader {
+
+ public static final HashMap<String, Fluid> coolantMap = new HashMap<>();
+
+ private static final ItemList[] VIABLE_WAFERS = new ItemList[] { ItemList.Circuit_Silicon_Wafer,
+ ItemList.Circuit_Silicon_Wafer2, ItemList.Circuit_Silicon_Wafer3, ItemList.Circuit_Silicon_Wafer4,
+ ItemList.Circuit_Silicon_Wafer5, ItemList.Circuit_Silicon_Wafer6, ItemList.Circuit_Silicon_Wafer7 };
+
+ public static void load() {
+
+ /*
+ * Coolant list
+ */
+
+ coolantMap.put(
+ Materials.LiquidNitrogen.getGas(1L)
+ .getFluid()
+ .getName(),
+ Materials.Nitrogen.getGas(1L)
+ .getFluid());
+ coolantMap.put(
+ Materials.LiquidOxygen.getGas(1L)
+ .getFluid()
+ .getName(),
+ Materials.Oxygen.getGas(1L)
+ .getFluid());
+ coolantMap.put("ic2coolant", FluidRegistry.getFluid("ic2hotcoolant"));
+ coolantMap.put(
+ Materials.SuperCoolant.getFluid(1L)
+ .getFluid()
+ .getName(),
+ Materials.Water.getFluid(1L)
+ .getFluid());
+
+ /*
+ * ELECTRON
+ */
+ BeamlineRecipeAdder2.instance.addSourceChamberRecipe(
+ new ItemStack[] { GTOreDictUnificator.get(OrePrefixes.stick, Materials.Tungsten, 1) },
+ null,
+ Particle.ELECTRON.ordinal(),
+ 20,
+ 1000,
+ 98,
+ 0.1f,
+ 7680);
+
+ BeamlineRecipeAdder2.instance.addSourceChamberRecipe(
+ new ItemStack[] { WerkstoffMaterialPool.LanthanumHexaboride.get(OrePrefixes.stickLong, 1) },
+ null,
+ Particle.ELECTRON.ordinal(),
+ 60,
+ 5000,
+ 99,
+ 0.3f,
+ 7680);
+
+ /*
+ * NEUTRON
+ */
+ BeamlineRecipeAdder2.instance.addSourceChamberRecipe(
+ new ItemStack[] { MaterialsElements.getInstance().CALIFORNIUM.getDust(1) },
+ null,
+ Particle.NEUTRON.ordinal(),
+ 10,
+ 9000,
+ 95,
+ 999,
+ 1920);
+
+ /*
+ * ALPHA
+ */
+ BeamlineRecipeAdder2.instance.addSourceChamberRecipe(
+ new ItemStack[] { Materials.Uranium.getDust(1) },
+ new ItemStack[] { WerkstoffMaterialPool.Thorium234.get(OrePrefixes.dust, 1) },
+ Particle.ALPHA.ordinal(),
+ 1,
+ 4270,
+ 90,
+ 999,
+ 480);
+
+ /*
+ * TARGET CHAMBER
+ */
+
+ for (MaskList mask : MaskList.values()) {
+
+ if (mask.getProducedItem() == null) // Blank or error
+ continue;
+
+ int index = 0;
+ for (ItemList wafer : VIABLE_WAFERS) {
+
+ index++;
+
+ if (!Arrays.asList(mask.getForbiddenWafers())
+ .contains(wafer)) {
+
+ BeamlineRecipeAdder2.instance.addTargetChamberRecipe(
+ wafer.get(1),
+ GTUtility.copyAmountUnsafe((int) Math.pow(2, index + 2), mask.getProducedItem()),
+ new ItemStack(LanthItemList.maskMap.get(mask), 0),
+ 1,
+ mask.getBaselineAmount() * (int) Math.pow(Math.sqrt(3), index - 1), // 3x recipe amount increase
+ // per 2 increases in wafer
+ // tier. This greatly
+ // incentivises the use of
+ // higher tier boule wafer
+ // recipes
+ mask.getMinEnergy(),
+ mask.getMaxEnergy(),
+ mask.getMinFocus(),
+ 1,
+ 1920);
+
+ }
+
+ }
+
+ /*
+ * if (!Arrays.asList(MaskList.CPU.getForbiddenWafers()).contains(wafer)) {
+ * BeamlineRecipeAdder.instance.addTargetChamberRecipe( wafer.get(1), GT_Utility.copyAmountUnsafe((int)
+ * Math.pow(2, index + 2), ItemList.Circuit_Wafer_CPU.get(1)), //Varies new
+ * ItemStack(LanthItemList.maskMap.get(MaskList.CPU), 0), // Varies 0, 10 * (int) Math.pow(2, index - 1), //
+ * Varies 1, //Varies 10000000, //Varies 50, //Varies 1, 1920 ); } /* PPIC
+ */
+
+ /*
+ * if (!Arrays.asList(MaskList.PPIC.getForbiddenWafers()).contains(wafer)) {
+ * GTLog.out.print("Adding recipe for PPIC with " + wafer.get(1).getUnlocalizedName() + " amount: " + 40 *
+ * (int) Math.pow(2, index - 1)); BeamlineRecipeAdder.instance.addTargetChamberRecipe( wafer.get(1),
+ * ItemList.Circuit_Wafer_PPIC.get((int) Math.pow(2, index + 2)), //Varies new
+ * ItemStack(LanthItemList.maskMap.get(MaskList.PPIC), 0), // Varies 0, 40 * (int) Math.pow(2, index - 1),
+ * // Varies 1, //Varies 10000000, //Varies 50, //Varies 1, 1920 ); }
+ */
+
+ }
+ /*
+ * BeamlineRecipeAdder2.instance.addTargetChamberRecipe( new ItemStack(Items.coal, 1), new
+ * ItemStack(Items.diamond, 1), null, 1, 20, 100, 1000, 60, 1, 1920);
+ * BeamlineRecipeAdder2.instance.addTargetChamberRecipe( new ItemStack(Items.coal, 1), new
+ * ItemStack(Items.cooked_chicken, 1), null, 1, 20, 1, 10, 60, 1, 1920);
+ */
+
+ BeamlineRecipeAdder2.instance.addTargetChamberRecipe(
+ new ItemStack(Items.chicken, 1),
+ new ItemStack(Items.cooked_chicken),
+ null,
+ Particle.PHOTON.ordinal(),
+ 400,
+ 5,
+ 20,
+ 80,
+ 1,
+ 7864320);
+
+ BeamlineRecipeAdder2.instance.addTargetChamberRecipe(
+ new ItemStack(Items.chicken, 1),
+ new ItemStack(Items.egg),
+ null,
+ Particle.PHOTON.ordinal(),
+ 400,
+ 21,
+ 600,
+ 80,
+ 1,
+ 7864320);
+
+ }
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/RecipeSC.java b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/RecipeSC.java
new file mode 100644
index 0000000000..979cb6a8bb
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/RecipeSC.java
@@ -0,0 +1,52 @@
+package gtnhlanth.common.tileentity.recipe.beamline;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+
+import gregtech.api.util.GTRecipe;
+import gregtech.api.util.GTUtility;
+import gtnhlanth.common.register.LanthItemList;
+
+public class RecipeSC extends GTRecipe {
+
+ public int particleId;
+ public int rate;
+ public float maxEnergy;
+ public float focus;
+ public float energyRatio;
+
+ public RecipeSC(boolean aOptimize, ItemStack[] aInputs, ItemStack[] aOutputs, Object aSpecialItems, int[] aChances,
+ FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, int particleId, int rate,
+ float maxEnergy, float focus, float energyRatio) {
+
+ super(aOptimize, aInputs, aOutputs, null, aChances, null, null, aDuration, aEUt, 0);
+
+ this.particleId = particleId;
+ this.rate = rate;
+ this.maxEnergy = maxEnergy;
+ this.focus = focus;
+ this.energyRatio = energyRatio;
+ }
+
+ @Override
+ public ItemStack getRepresentativeOutput(int aIndex) {
+
+ ArrayList<ItemStack> mOutputsWithParticle = new ArrayList<>();
+
+ ItemStack particleStack = new ItemStack(LanthItemList.PARTICLE_ITEM);
+
+ Items.ender_pearl.setDamage(particleStack, this.particleId);
+
+ mOutputsWithParticle.addAll(Arrays.asList(mOutputs));
+ mOutputsWithParticle.add(particleStack);
+
+ ItemStack[] mOutputsWithParticleArray = mOutputsWithParticle.toArray(new ItemStack[0]);
+
+ if (aIndex < 0 || aIndex >= mOutputsWithParticleArray.length) return null;
+ return GTUtility.copyOrNull(mOutputsWithParticleArray[aIndex]);
+ }
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/RecipeTC.java b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/RecipeTC.java
new file mode 100644
index 0000000000..30be015abb
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/RecipeTC.java
@@ -0,0 +1,71 @@
+package gtnhlanth.common.tileentity.recipe.beamline;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+
+import gregtech.api.util.GTRecipe;
+import gregtech.api.util.GTUtility;
+import gtnhlanth.common.register.LanthItemList;
+
+public class RecipeTC extends GTRecipe {
+
+ public int particleId;
+ public int amount;
+
+ public float minEnergy;
+ public float maxEnergy;
+
+ public float minFocus;
+ public float energyRatio;
+
+ public ItemStack focusItem;
+
+ public RecipeTC(boolean aOptimize, ItemStack aInput, ItemStack aOutput, ItemStack aFocusItem, int particleId,
+ int amount, float minEnergy, float maxEnergy, float minFocus, float energyRatio, int aEUt) {
+
+ super(
+ aOptimize,
+ new ItemStack[] { aFocusItem, aInput },
+ new ItemStack[] { aOutput },
+ null,
+ null,
+ null,
+ null,
+ 1,
+ aEUt,
+ 0);
+
+ this.particleId = particleId;
+ this.amount = amount;
+
+ this.minEnergy = minEnergy;
+ this.maxEnergy = maxEnergy;
+
+ this.minFocus = minFocus;
+
+ this.energyRatio = energyRatio;
+
+ this.focusItem = aFocusItem;
+ }
+
+ @Override
+ public ItemStack getRepresentativeInput(int aIndex) {
+
+ ArrayList<ItemStack> mInputsWithParticle = new ArrayList<>();
+
+ ItemStack particleStack = new ItemStack(LanthItemList.PARTICLE_ITEM);
+ Items.ender_pearl.setDamage(particleStack, this.particleId);
+
+ mInputsWithParticle.add(particleStack);
+ mInputsWithParticle.addAll(Arrays.asList(mInputs));
+
+ ItemStack[] mInputsWithParticleArray = mInputsWithParticle.toArray(new ItemStack[0]);
+
+ if (aIndex < 0 || aIndex >= mInputsWithParticleArray.length) return null;
+ return GTUtility.copyOrNull(mInputsWithParticleArray[aIndex]);
+ }
+
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/SourceChamberFrontend.java b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/SourceChamberFrontend.java
new file mode 100644
index 0000000000..3d8a3abfd1
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/SourceChamberFrontend.java
@@ -0,0 +1,24 @@
+package gtnhlanth.common.tileentity.recipe.beamline;
+
+import gregtech.api.recipe.BasicUIPropertiesBuilder;
+import gregtech.api.recipe.NEIRecipePropertiesBuilder;
+import gregtech.api.recipe.RecipeMapFrontend;
+import gregtech.nei.RecipeDisplayInfo;
+
+public class SourceChamberFrontend extends RecipeMapFrontend {
+
+ public SourceChamberFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder,
+ NEIRecipePropertiesBuilder neiPropertiesBuilder) {
+ super(uiPropertiesBuilder, neiPropertiesBuilder);
+ }
+
+ @Override
+ public void drawDescription(RecipeDisplayInfo recipeInfo) {
+ drawEnergyInfo(recipeInfo);
+ // drawDurationInfo(recipeInfo); Unnecessary and misleading
+ drawSpecialInfo(recipeInfo);
+ drawMetadataInfo(recipeInfo);
+ drawRecipeOwnerInfo(recipeInfo);
+ }
+
+}
diff --git a/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/TargetChamberFrontend.java b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/TargetChamberFrontend.java
new file mode 100644
index 0000000000..87852381e6
--- /dev/null
+++ b/src/main/java/gtnhlanth/common/tileentity/recipe/beamline/TargetChamberFrontend.java
@@ -0,0 +1,109 @@
+package gtnhlanth.common.tileentity.recipe.beamline;
+
+import static gregtech.api.util.GTUtility.trans;
+
+import java.util.List;
+
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.StatCollector;
+
+import com.gtnewhorizons.modularui.api.math.Pos2d;
+
+import gregtech.api.recipe.BasicUIPropertiesBuilder;
+import gregtech.api.recipe.NEIRecipePropertiesBuilder;
+import gregtech.api.recipe.RecipeMapFrontend;
+import gregtech.api.util.GTUtility;
+import gregtech.api.util.OverclockCalculator;
+import gregtech.common.gui.modularui.UIHelper;
+import gregtech.nei.GTNEIDefaultHandler;
+import gregtech.nei.RecipeDisplayInfo;
+import gtnhlanth.util.Util;
+
+public class TargetChamberFrontend extends RecipeMapFrontend {
+
+ public TargetChamberFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder,
+ NEIRecipePropertiesBuilder neiPropertiesBuilder) {
+ super(uiPropertiesBuilder, neiPropertiesBuilder);
+ }
+
+ public void drawDescription(RecipeDisplayInfo recipeInfo) {
+ drawEnergyInfo(recipeInfo);
+ // drawDurationInfo(recipeInfo);
+ drawSpecialInfo(recipeInfo);
+ drawMetadataInfo(recipeInfo);
+ drawRecipeOwnerInfo(recipeInfo);
+ }
+
+ @Override
+ protected void drawNEIOverlayForInput(GTNEIDefaultHandler.FixedPositionedStack stack) {
+ if (stack.isNotConsumed()) { // The stack actually takes damage, but is technically still not considered to be
+ // consumed by the code
+ drawNEIOverlayText("PC", stack);
+ }
+ }
+
+ @Override
+ protected List<String> handleNEIItemInputTooltip(List<String> currentTip,
+ GTNEIDefaultHandler.FixedPositionedStack pStack) {
+ if (pStack.isNotConsumed()) { // See above
+ currentTip.add(EnumChatFormatting.GRAY + StatCollector.translateToLocal("gtnhlanth.tt.pc")); // Partially
+ // consumed:
+ // Takes damage
+ // in the
+ // process
+ }
+ return currentTip;
+ }
+
+ @Override
+ public void drawEnergyInfo(RecipeDisplayInfo recipeInfo) {
+ if (recipeInfo.calculator.getConsumption() <= 0) return;
+
+ // recipeInfo.drawText(trans("152", "Total: ") + getTotalPowerString(recipeInfo.calculator));
+
+ recipeInfo.drawText(trans("153", "Usage: ") + getEUtDisplay(recipeInfo.calculator));
+ recipeInfo.drawText(trans("154", "Voltage: ") + getVoltageString(recipeInfo.calculator));
+ recipeInfo.drawText(trans("155", "Amperage: ") + getAmperageString(recipeInfo.calculator));
+
+ }
+
+ @Override
+ public List<Pos2d> getItemOutputPositions(int itemOutputCount) {
+ return UIHelper.getGridPositions(itemOutputCount, 128, 24, 1, 3); // Make output items display vertically, not
+ // in a square
+ }
+
+ @Override
+ public List<Pos2d> getItemInputPositions(int itemInputCount) {
+
+ /*
+ * Pos2d posParticle = new Pos2d(8, 28); // Particle item ArrayList<Pos2d> posList = new ArrayList<>();
+ * posList.add(posParticle); posList.addAll(UIHelper.getGridPositions(itemInputCount - 1, 36, 28, 3));
+ */
+
+ List<Pos2d> posList = Util.getGridPositions(itemInputCount, 8, 20, 3, 1, 20);
+ return posList;
+ }
+
+ private String getEUtDisplay(OverclockCalculator calculator) {
+ return getEUtWithoutTier(calculator);
+ }
+
+ private String getEUtWithoutTier(OverclockCalculator calculator) {
+ return GTUtility.formatNumbers(calculator.getConsumption()) + " EU/t";
+ }
+
+ private String getVoltageString(OverclockCalculator calculator) {
+ long voltage = computeVoltageForEURate(calculator.getConsumption());
+ return GTUtility.formatNumbers(voltage) + " EU/t" + GTUtility.getTierNameWithParentheses(voltage);
+ }
+
+ private long computeVoltageForEURate(long euPerTick) {
+ return euPerTick;
+ }
+
+ private String getAmperageString(OverclockCalculator calculator) {
+ return GTUtility.formatNumbers(1);
+ }
+
+}