package goodgenerator.blocks.tileEntity; import static com.gtnewhorizon.structurelib.structure.StructureUtility.*; import static gregtech.api.enums.Textures.BlockIcons.*; import static gregtech.api.util.GTStructureUtility.buildHatchAdder; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Random; import javax.annotation.Nonnull; import net.minecraft.block.Block; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StatCollector; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import 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 com.gtnewhorizons.modularui.api.NumberFormatMUI; import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; import com.gtnewhorizons.modularui.common.widget.SlotWidget; import com.gtnewhorizons.modularui.common.widget.TextWidget; import goodgenerator.blocks.structures.AntimatterStructures; import goodgenerator.blocks.tileEntity.render.TileAntimatter; import goodgenerator.items.GGMaterial; import goodgenerator.loader.Loaders; import gregtech.api.enums.HatchElement; import gregtech.api.enums.Materials; import gregtech.api.enums.MaterialsUEVplus; import gregtech.api.enums.Textures; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.interfaces.tileentity.IOverclockDescriptionProvider; import gregtech.api.metatileentity.implementations.MTEExtendedPowerMultiBlockBase; import gregtech.api.metatileentity.implementations.MTEHatch; import gregtech.api.metatileentity.implementations.MTEHatchInput; import gregtech.api.metatileentity.implementations.MTEHatchOutput; import gregtech.api.objects.GTChunkManager; import gregtech.api.objects.GTItemStack; import gregtech.api.objects.overclockdescriber.OverclockDescriber; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.ExoticEnergyInputHelper; import gregtech.api.util.GTRecipe; import gregtech.api.util.GTUtility; import gregtech.api.util.HatchElementBuilder; import gregtech.api.util.MultiblockTooltipBuilder; import gregtech.api.util.shutdown.ShutDownReason; import gregtech.api.util.shutdown.ShutDownReasonRegistry; import gregtech.common.tileentities.machines.IDualInputHatch; public class AntimatterForge extends MTEExtendedPowerMultiBlockBase implements ISurvivalConstructable, IOverclockDescriptionProvider { private static final FluidStack[] magneticUpgrades = { Materials.TengamAttuned.getMolten(1L), MaterialsUEVplus.Time.getMolten(1L) }; private static final FluidStack[] gravityUpgrades = { MaterialsUEVplus.SpaceTime.getMolten(1L), MaterialsUEVplus.Space.getMolten(1L), MaterialsUEVplus.Eternity.getMolten(1L) }; private static final FluidStack[] containmentUpgrades = { GGMaterial.shirabon.getMolten(1), MaterialsUEVplus.MagnetohydrodynamicallyConstrainedStarMatter.getMolten(1L) }; private static final FluidStack[] activationUpgrades = { GGMaterial.naquadahBasedFuelMkVDepleted.getFluidOrGas(1), GGMaterial.naquadahBasedFuelMkVIDepleted.getFluidOrGas(1) }; private static final int MAGNETIC_ID = 0; private static final int GRAVITY_ID = 1; private static final int CONTAINMENT_ID = 2; private static final int ACTIVATION_ID = 3; private static final int BASE_CONSUMPTION = 10_000_000; private static final int passiveBaseMult = 1000; private static final int activeBaseMult = 10000; private static final float passiveBaseExp = 1.5f; private static final float activeBaseExp = 1.5f; private static final float coefficientBaseExp = 0.5f; private static final float baseSkew = 0.2f; private final float[] modifiers = { 0.0f, 0.0f, 0.0f, 0.0f }; private final FluidStack[] upgradeFluids = { null, null, null, null }; private final int[] fluidConsumptions = { 0, 0, 0, 0 }; public static final String MAIN_NAME = "antimatterForge"; private final int speed = 20; private long rollingCost = 0L; private boolean isLoadedChunk; public GTRecipe mLastRecipe; public int para; private final Random r = new Random(); // Values for displaying cycle data private long guiAntimatterAmount = 0; private long guiAntimatterChange = 0; private long guiPassiveEnergy = 0; private long guiActiveEnergy = 0; private final boolean canRender = false; private final List amOutputHatches = new ArrayList<>(16); private static final ClassValue> STRUCTURE_DEFINITION = new ClassValue<>() { @Override protected IStructureDefinition computeValue(Class type) { return StructureDefinition.builder() .addShape(MAIN_NAME, AntimatterStructures.ANTIMATTER_FORGE) .addElement('A', lazy(x -> ofBlock(x.getFrameBlock(), x.getFrameMeta()))) .addElement('B', lazy(x -> ofBlock(x.getCoilBlock(), x.getCoilMeta()))) .addElement('C', lazy(x -> ofBlock(x.getCasingBlock(2), x.getCasingMeta(2)))) .addElement('D', lazy(x -> ofBlock(x.getCasingBlock(1), x.getCasingMeta(1)))) .addElement( 'F', lazy( x -> HatchElementBuilder.builder() .anyOf(HatchElement.InputHatch) .adder(AntimatterForge::addFluidIO) .casingIndex(x.textureIndex(2)) .dot(1) .buildAndChain(x.getCasingBlock(2), x.getCasingMeta(2)))) .addElement( 'E', lazy( x -> buildHatchAdder(AntimatterForge.class).adder(AntimatterForge::addAntimatterHatch) .hatchClass(AntimatterOutputHatch.class) .casingIndex(x.textureIndex(1)) .dot(3) .build())) .addElement( 'H', lazy( x -> HatchElementBuilder.builder() .anyOf(HatchElement.Energy.or(HatchElement.ExoticEnergy)) .adder(AntimatterForge::addEnergyInjector) .casingIndex(x.textureIndex(2)) .dot(2) .buildAndChain(x.getCasingBlock(2), x.getCasingMeta(2)))) .build(); } }; static { Textures.BlockIcons.setCasingTextureForId( 53, TextureFactory.of( TextureFactory.builder() .addIcon(MACHINE_CASING_ANTIMATTER) .extFacing() .build(), TextureFactory.builder() .addIcon(MACHINE_CASING_ANTIMATTER_GLOW) .extFacing() .glow() .build())); } public AntimatterForge(int aID, String aName, String aNameRegional) { super(aID, aName, aNameRegional); } public AntimatterForge(String aName) { super(aName); } @Override public IMetaTileEntity newMetaEntity(IGregTechTileEntity arg0) { return new AntimatterForge(MAIN_NAME); } @Override protected MultiblockTooltipBuilder createTooltip() { final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder(); tt.addMachineType("Antimatter Forge") .addInfo(EnumChatFormatting.LIGHT_PURPLE + "Dimensions not included!" + EnumChatFormatting.GRAY) .addInfo("Converts protomatter into antimatter") .addInfo( "Consumes 10 000 000 + (" + EnumChatFormatting.DARK_AQUA + "Antimatter" + EnumChatFormatting.GRAY + " * " + passiveBaseMult + ")^" + EnumChatFormatting.GREEN + passiveBaseExp + EnumChatFormatting.GRAY + " EU/t passively. The consumption decays by 0.5% every tick when empty") .addInfo( "Uses (" + EnumChatFormatting.DARK_AQUA + "Antimatter" + EnumChatFormatting.GRAY + " * " + activeBaseMult + ")^" + EnumChatFormatting.DARK_PURPLE + activeBaseExp + EnumChatFormatting.GRAY + " EU per operation to produce antimatter") .addSeparator() .addInfo("Every cycle, the lowest amount of antimatter in the 16 antimatter hatches is recorded") .addInfo("Cycles every second") .addInfo( "All hatches with more than the lowest amount will " + EnumChatFormatting.RED + "lose half the difference!" + EnumChatFormatting.GRAY) .addInfo( "If the machine runs out of energy or protomatter during a cycle, " + EnumChatFormatting.RED + "10% of antimatter will be voided!" + EnumChatFormatting.GRAY) .addInfo( "Produces (" + EnumChatFormatting.DARK_AQUA + "Antimatter" + EnumChatFormatting.GRAY + "^" + EnumChatFormatting.GOLD + coefficientBaseExp + EnumChatFormatting.GRAY + ") * N(" + EnumChatFormatting.AQUA + baseSkew + EnumChatFormatting.GRAY + ", 0.25) of antimatter per cycle, consuming equal amounts of Protomatter") .addInfo( "The change is split between the 16 Antimatter Hatches, sampled from N(" + EnumChatFormatting.AQUA + baseSkew + EnumChatFormatting.GRAY + ", 1) (Gaussian distribution with mean of " + baseSkew + ")") .addInfo("The total change can be negative!") .addSeparator() .addInfo("Can be supplied with stabilization fluids to improve antimatter generation") .addInfo( EnumChatFormatting.GREEN + "Magnetic Stabilization" + EnumChatFormatting.GRAY + " (Uses " + EnumChatFormatting.DARK_AQUA + "Antimatter" + EnumChatFormatting.GRAY + "^0.5 per cycle)") .addInfo( "1. Molten Purified Tengam - Passive cost exponent " + EnumChatFormatting.GREEN + "-0.15" + EnumChatFormatting.GRAY) .addInfo( "2. Tachyon Rich Fluid - Passive cost exponent " + EnumChatFormatting.GREEN + "-0.3" + EnumChatFormatting.GRAY) .addInfo( EnumChatFormatting.DARK_PURPLE + "Gravity Stabilization" + EnumChatFormatting.GRAY + " (Uses " + EnumChatFormatting.DARK_AQUA + "Antimatter" + EnumChatFormatting.GRAY + "^0.5 per cycle)") .addInfo( "1. Molten Spacetime - Active cost exponent " + EnumChatFormatting.DARK_PURPLE + "-0.05" + EnumChatFormatting.GRAY) .addInfo( "2. Spatially Enlarged Fluid - Active cost exponent " + EnumChatFormatting.DARK_PURPLE + "-0.10" + EnumChatFormatting.GRAY) .addInfo( "3. Molten Eternity - Active cost exponent " + EnumChatFormatting.DARK_PURPLE + "-0.15" + EnumChatFormatting.GRAY) .addInfo( EnumChatFormatting.GOLD + "Containment Stabilization" + EnumChatFormatting.GRAY + " (Uses " + EnumChatFormatting.DARK_AQUA + "Antimatter" + EnumChatFormatting.GRAY + "^(2/7) per operation)") .addInfo( "1. Molten Shirabon - Production exponent " + EnumChatFormatting.GOLD + "+0.05" + EnumChatFormatting.GRAY) .addInfo( "2. Molten MHDCSM - Production exponent " + EnumChatFormatting.GOLD + "+0.10" + EnumChatFormatting.GRAY) .addInfo( EnumChatFormatting.AQUA + "Activation Stabilization" + EnumChatFormatting.GRAY + " (Uses " + EnumChatFormatting.DARK_AQUA + "Antimatter" + EnumChatFormatting.GRAY + "^(1/3) per operation)") .addInfo( "1. Depleted Naquadah Fuel Mk V - Distribution skew " + EnumChatFormatting.AQUA + "+0.05" + EnumChatFormatting.GRAY) .addInfo( "2. Depleted Naquadah Fuel Mk VI - Distribution skew " + EnumChatFormatting.AQUA + "+0.10" + EnumChatFormatting.GRAY) .addInfo("Each stabilization can only use one of the fluids at a time") .addCasingInfoMin("Antimatter Containment Casing", 512, false) .addCasingInfoMin("Magnetic Flux Casing", 2274, false) .addCasingInfoMin("Gravity Stabilization Casing", 623, false) .addCasingInfoMin("Protomatter Activation Coil", 126, false) .addInputHatch("1-6, Hint block with dot 1", 1) .addEnergyHatch("1-9, Hint block with dot 2", 2) .addOtherStructurePart("Antimatter Hatch", "16, Hint Block with dot 3", 3) .toolTipFinisher(); return tt; } @Override public IStructureDefinition getStructureDefinition() { return STRUCTURE_DEFINITION.get(getClass()); } public Block getCasingBlock(int type) { switch (type) { case 1: return Loaders.magneticFluxCasing; case 2: return Loaders.gravityStabilizationCasing; default: return Loaders.magneticFluxCasing; } } public int getCasingMeta(int type) { switch (type) { case 1: return 0; case 2: return 0; default: return 0; } } public Block getCoilBlock() { return Loaders.protomatterActivationCoil; } public int getCoilMeta() { return 0; } public Block getFrameBlock() { return Loaders.antimatterContainmentCasing; } public int getFrameMeta() { return 0; } public int textureIndex(int type) { switch (type) { case 1: return (12 << 7) + 9; case 2: return (12 << 7) + 10; default: return (12 << 7) + 9; } } private static final ITexture textureOverlay = TextureFactory.of( TextureFactory.builder() .addIcon(OVERLAY_FUSION1) .extFacing() .build(), TextureFactory.builder() .addIcon(OVERLAY_FUSION1_GLOW) .extFacing() .glow() .build()); public ITexture getTextureOverlay() { return textureOverlay; } @Override public boolean allowCoverOnSide(ForgeDirection side, GTItemStack aStack) { return side != getBaseMetaTileEntity().getFrontFacing(); } @Override public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { return checkPiece(MAIN_NAME, 26, 26, 4); } @Override public void construct(ItemStack itemStack, boolean b) { buildPiece(MAIN_NAME, itemStack, b, 26, 26, 4); } @Override public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { if (mMachine) return -1; int realBudget = elementBudget >= 200 ? elementBudget : Math.min(200, elementBudget * 5); return survivialBuildPiece(MAIN_NAME, stackSize, 26, 26, 4, realBudget, env, false, true); } @Override public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection facing, int colorIndex, boolean aActive, boolean aRedstone) { if (side == facing) return new ITexture[] { TextureFactory.builder() .addIcon(MACHINE_CASING_ANTIMATTER) .extFacing() .build(), getTextureOverlay() }; if (aActive) return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(53) }; return new ITexture[] { TextureFactory.builder() .addIcon(MACHINE_CASING_ANTIMATTER) .extFacing() .build() }; } @Override public boolean isCorrectMachinePart(ItemStack aStack) { return true; } @Override public void onMachineBlockUpdate() { mUpdate = 100; } @Override public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { super.onPostTick(aBaseMetaTileEntity, aTick); if (aBaseMetaTileEntity.isServerSide()) { FluidStack[] antimatterStored = new FluidStack[16]; long totalAntimatterAmount = 0; for (int i = 0; i < amOutputHatches.size(); i++) { if (amOutputHatches.get(i) == null || !amOutputHatches.get(i) .isValid() || amOutputHatches.get(i) .getFluid() == null) continue; antimatterStored[i] = amOutputHatches.get(i) .getFluid() .copy(); totalAntimatterAmount += antimatterStored[i].amount; } drainEnergyInput(calculateEnergyContainmentCost(totalAntimatterAmount)); if ((this.mProgresstime >= this.mMaxProgresstime) && (!isAllowedToWork())) { setProtoRender(false); } } } private long calculateContainedAntimatter() { long antimatterStored = 0; for (AntimatterOutputHatch amOutputHatch : amOutputHatches) { if (amOutputHatch != null && amOutputHatch.isValid() && amOutputHatch.getFluid() != null) { antimatterStored += amOutputHatch.getFluid().amount; } } return antimatterStored; } private void setModifiers(FluidStack inputFluid, float step, FluidStack[] fluidArray, int upgradeId) { for (int tier = 1; tier <= fluidArray.length; tier++) { if (inputFluid.isFluidEqual(fluidArray[tier - 1])) { if (inputFluid.amount >= fluidConsumptions[upgradeId]) { modifiers[upgradeId] = step * tier; upgradeFluids[upgradeId] = inputFluid; } } } } @Override public CheckRecipeResult checkProcessing() { startRecipeProcessing(); FluidStack[] antimatterStored = new FluidStack[16]; long totalAntimatterAmount = 0; long minAntimatterAmount = Long.MAX_VALUE; // Calculate the total amount of antimatter in all 16 hatches and the minimum amount found in any individual // hatch for (int i = 0; i < amOutputHatches.size(); i++) { if (amOutputHatches.get(i) == null || !amOutputHatches.get(i) .isValid() || amOutputHatches.get(i) .getFluid() == null) continue; antimatterStored[i] = amOutputHatches.get(i) .getFluid() .copy(); totalAntimatterAmount += antimatterStored[i].amount; minAntimatterAmount = Math.min(minAntimatterAmount, antimatterStored[i].amount); } int ratioLosses = 0; // Reduce the amount of antimatter in each hatch by half of the difference between the lowest amount and current // hatch contents for (AntimatterOutputHatch amOutputHatch : amOutputHatches) { if (amOutputHatch != null && amOutputHatch.isValid() && amOutputHatch.getFluid() != null) { FluidStack fluid = amOutputHatch.getFluid() .copy(); ratioLosses -= amOutputHatch.drain((int) ((fluid.amount - minAntimatterAmount) * 0.5), true).amount; } } // Check for upgrade fluids long containedProtomatter = 0; fluidConsumptions[MAGNETIC_ID] = (int) Math.ceil(Math.pow(totalAntimatterAmount, 0.5)); fluidConsumptions[GRAVITY_ID] = (int) Math.ceil(Math.pow(totalAntimatterAmount, 0.5)); fluidConsumptions[CONTAINMENT_ID] = (int) Math.ceil(Math.pow(totalAntimatterAmount, 2.0f / 7.0f)); fluidConsumptions[ACTIVATION_ID] = (int) Math.ceil(Math.pow(totalAntimatterAmount, 1.0f / 3.0f)); for (int i = 0; i < modifiers.length; i++) { modifiers[i] = 0.0f; upgradeFluids[i] = null; } List inputFluids = getStoredFluids(); for (FluidStack inputFluid : inputFluids) { setModifiers(inputFluid, -0.15f, magneticUpgrades, MAGNETIC_ID); setModifiers(inputFluid, -0.05f, gravityUpgrades, GRAVITY_ID); setModifiers(inputFluid, 0.05f, containmentUpgrades, CONTAINMENT_ID); setModifiers(inputFluid, 0.05f, activationUpgrades, ACTIVATION_ID); } long energyCost = calculateEnergyCost(totalAntimatterAmount); // If we run out of energy, reduce contained antimatter by 10% if (!drainEnergyInput(energyCost)) { decimateAntimatter(); stopMachine(ShutDownReasonRegistry.POWER_LOSS); endRecipeProcessing(); setProtoRender(false); return CheckRecipeResultRegistry.insufficientPower(energyCost); } // Drain upgrade fluids for (int i = 0; i < upgradeFluids.length; i++) { FluidStack upgradeFluid = upgradeFluids[i]; if (upgradeFluid != null) { for (FluidStack inputFluid : inputFluids.toArray(new FluidStack[0])) { if (inputFluid.isFluidEqual(upgradeFluid)) { inputFluid.amount -= fluidConsumptions[i]; } } } } int antimatterChange = distributeAntimatterToHatch( amOutputHatches, totalAntimatterAmount, containedProtomatter); // We didn't have enough protomatter, reduce antimatter by 10% and stop the machine. if (!this.depleteInput(MaterialsUEVplus.Protomatter.getFluid(Math.abs(antimatterChange)))) { decimateAntimatter(); stopMachine(ShutDownReasonRegistry.outOfFluid(MaterialsUEVplus.Protomatter.getFluid(1L))); endRecipeProcessing(); setProtoRender(false); return CheckRecipeResultRegistry.NO_FUEL_FOUND; } this.guiAntimatterChange = ratioLosses + antimatterChange; this.guiAntimatterAmount = calculateContainedAntimatter(); updateAntimatterSize(this.guiAntimatterAmount); setProtoRender(true); mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); mEfficiencyIncrease = 10000; mMaxProgresstime = speed; endRecipeProcessing(); return CheckRecipeResultRegistry.SUCCESSFUL; } /* * How much passive energy is drained every tick * Base containment cost: 10M EU/t * The containment cost ramps up by the amount of antimatter each tick, up to 1000 times * If the current cost is more than 1000 times the amount of antimatter, or * if no antimatter is in the hatches, the value will decay by 1% every tick */ private long calculateEnergyContainmentCost(long antimatterAmount) { if (antimatterAmount == 0) { rollingCost *= 0.995; if (rollingCost < 100) rollingCost = 0; } else if (rollingCost < antimatterAmount * 1000) { rollingCost += antimatterAmount; } else { rollingCost *= 0.995; } long value = BASE_CONSUMPTION + (long) Math.pow(rollingCost, 1.5 + modifiers[MAGNETIC_ID]); this.guiPassiveEnergy = value; return value; } // How much energy is consumed when machine does one operation // Base formula: (Antimatter * 10000) ^ (1.5) private long calculateEnergyCost(long antimatterAmount) { long value = (long) Math.pow(antimatterAmount * activeBaseMult, activeBaseExp + modifiers[GRAVITY_ID]); this.guiActiveEnergy = value; return value; } private void decimateAntimatter() { for (AntimatterOutputHatch amOutputHatch : amOutputHatches) { if (amOutputHatch != null && amOutputHatch.isValid() && amOutputHatch.getFluid() != null) { FluidStack fluid = amOutputHatch.getFluid() .copy(); amOutputHatch.drain((int) Math.floor(fluid.amount * 0.1), true); } } } private int distributeAntimatterToHatch(List hatches, long totalAntimatterAmount, long protomatterAmount) { double coeff = Math.pow((totalAntimatterAmount), 0.5 + modifiers[CONTAINMENT_ID]); int difference = 0; for (AntimatterOutputHatch hatch : hatches) { // Skewed normal distribution multiplied by coefficient from antimatter amount // We round up so you are guaranteed to be antimatter positive on the first run (reduces startup RNG) int change = (int) (Math.ceil((r.nextGaussian() + baseSkew + modifiers[ACTIVATION_ID]) * (coeff / 16))); difference += change; if (change >= 0) { hatch.fill(MaterialsUEVplus.Antimatter.getFluid(change), true); } else { hatch.drain(-change, true); } } return difference; } @Override public void clearHatches() { super.clearHatches(); amOutputHatches.clear(); } @Override public void onRemoval() { if (this.isLoadedChunk) GTChunkManager.releaseTicket((TileEntity) getBaseMetaTileEntity()); super.onRemoval(); } public int getChunkX() { return getBaseMetaTileEntity().getXCoord() >> 4; } public int getChunkZ() { return getBaseMetaTileEntity().getZCoord() >> 4; } private boolean addEnergyInjector(IGregTechTileEntity aBaseMetaTileEntity, int aBaseCasingIndex) { IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); if (aMetaTileEntity == null) return false; if (aMetaTileEntity instanceof MTEHatch hatch && ExoticEnergyInputHelper.isExoticEnergyInput(aMetaTileEntity)) { hatch.updateTexture(aBaseCasingIndex); hatch.updateCraftingIcon(this.getMachineCraftingIcon()); return mExoticEnergyHatches.add(hatch); } return false; } private boolean addFluidIO(IGregTechTileEntity aBaseMetaTileEntity, int aBaseCasingIndex) { IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); if (aMetaTileEntity == null) return false; if (aMetaTileEntity instanceof MTEHatch hatch) { hatch.updateTexture(aBaseCasingIndex); hatch.updateCraftingIcon(this.getMachineCraftingIcon()); } if (aMetaTileEntity instanceof MTEHatchInput tInput) { tInput.mRecipeMap = getRecipeMap(); return mInputHatches.add(tInput); } if (aMetaTileEntity instanceof AntimatterOutputHatch tAntimatter) { return amOutputHatches.add(tAntimatter); } if (aMetaTileEntity instanceof MTEHatchOutput tOutput) { return mOutputHatches.add(tOutput); } if (aMetaTileEntity instanceof IDualInputHatch tInput) { tInput.updateCraftingIcon(this.getMachineCraftingIcon()); return mDualInputHatches.add(tInput); } return false; } private boolean addAntimatterHatch(IGregTechTileEntity aBaseMetaTileEntity, int aBaseCasingIndex) { IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); if (aMetaTileEntity == null) return false; if (aMetaTileEntity instanceof MTEHatch hatch) { hatch.updateTexture(aBaseCasingIndex); hatch.updateCraftingIcon(this.getMachineCraftingIcon()); } if (aMetaTileEntity instanceof AntimatterOutputHatch tAntimatter) { return amOutputHatches.add(tAntimatter); } return false; } @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 OverclockDescriber getOverclockDescriber() { return null; } @Override public String[] getInfoData() { IGregTechTileEntity baseMetaTileEntity = getBaseMetaTileEntity(); long storedEnergy = 0; long maxEnergy = 0; for (MTEHatch tHatch : mExoticEnergyHatches) { storedEnergy += tHatch.getBaseMetaTileEntity() .getStoredEU(); maxEnergy += tHatch.getBaseMetaTileEntity() .getEUCapacity(); } return new String[] { EnumChatFormatting.BLUE + "Antimatter Forge " + EnumChatFormatting.GRAY, StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + EnumChatFormatting.GREEN + GTUtility.formatNumbers(mProgresstime) + EnumChatFormatting.RESET + "t / " + EnumChatFormatting.YELLOW + GTUtility.formatNumbers(mMaxProgresstime) + EnumChatFormatting.RESET + "t", StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + EnumChatFormatting.GREEN + GTUtility.formatNumbers(storedEnergy) + EnumChatFormatting.RESET + " EU / " + EnumChatFormatting.YELLOW + GTUtility.formatNumbers(maxEnergy) + EnumChatFormatting.RESET + " EU", StatCollector.translateToLocal("gui.AntimatterForge.0") + ": " + EnumChatFormatting.BLUE + GTUtility.formatNumbers(this.guiAntimatterAmount) + EnumChatFormatting.RESET + " L", StatCollector.translateToLocal("gui.AntimatterForge.1") + ": " + EnumChatFormatting.RED + GTUtility.formatNumbers(this.guiPassiveEnergy) + EnumChatFormatting.RESET + " EU/t", StatCollector.translateToLocal("gui.AntimatterForge.2") + ": " + EnumChatFormatting.LIGHT_PURPLE + GTUtility.formatNumbers(this.guiActiveEnergy) + EnumChatFormatting.RESET + " EU/t", StatCollector.translateToLocal("gui.AntimatterForge.3") + ": " + EnumChatFormatting.AQUA + GTUtility.formatNumbers(this.guiAntimatterChange) + EnumChatFormatting.RESET + " L" }; } private long getAntimatterAmount() { return this.guiAntimatterAmount; } private long getPassiveConsumption() { return this.guiPassiveEnergy; } private long getActiveConsumption() { return this.guiActiveEnergy; } private long getAntimatterChange() { return this.guiAntimatterChange; } protected long antimatterAmountCache; protected long passiveCostCache; protected long activeCostCache; protected long antimatterChangeCache; protected static final NumberFormatMUI numberFormat = new NumberFormatMUI(); protected static DecimalFormat standardFormat; static { DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US); dfs.setExponentSeparator("e"); standardFormat = new DecimalFormat("0.00E0", dfs); } @Override protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { super.drawTexts(screenElements, inventorySlot); screenElements .widget( new TextWidget() .setStringSupplier( () -> StatCollector.translateToLocal("gui.AntimatterForge.0") + ": " + EnumChatFormatting.BLUE + numberFormat.format(antimatterAmountCache) + EnumChatFormatting.WHITE + " L") .setDefaultColor(COLOR_TEXT_WHITE.get())) .widget(new FakeSyncWidget.LongSyncer(this::getAntimatterAmount, val -> antimatterAmountCache = val)) .widget( new TextWidget() .setStringSupplier( () -> StatCollector.translateToLocal("gui.AntimatterForge.1") + ": " + EnumChatFormatting.RED + standardFormat.format(passiveCostCache) + EnumChatFormatting.WHITE + " EU/t") .setDefaultColor(COLOR_TEXT_WHITE.get())) .widget(new FakeSyncWidget.LongSyncer(this::getPassiveConsumption, val -> passiveCostCache = val)) .widget( new TextWidget() .setStringSupplier( () -> StatCollector.translateToLocal("gui.AntimatterForge.2") + ": " + EnumChatFormatting.LIGHT_PURPLE + standardFormat.format(activeCostCache) + EnumChatFormatting.WHITE + " EU") .setDefaultColor(COLOR_TEXT_WHITE.get())) .widget(new FakeSyncWidget.LongSyncer(this::getActiveConsumption, val -> activeCostCache = val)) .widget( new TextWidget() .setStringSupplier( () -> StatCollector.translateToLocal("gui.AntimatterForge.3") + ": " + EnumChatFormatting.AQUA + numberFormat.format(antimatterChangeCache) + EnumChatFormatting.WHITE + " L") .setDefaultColor(COLOR_TEXT_WHITE.get())) .widget(new FakeSyncWidget.LongSyncer(this::getAntimatterChange, val -> antimatterChangeCache = val)); } @Override public boolean getDefaultHasMaintenanceChecks() { return false; } @Override public void stopMachine(@Nonnull ShutDownReason reason) { super.stopMachine(reason); setProtoRender(false); } @Override public void onBlockDestroyed() { super.onBlockDestroyed(); destroyAntimatterRender(); } public void updateAntimatterSize(float antimatterAmount) { if (antimatterAmount <= 0) { destroyAntimatterRender(); return; } TileAntimatter render = getAntimatterRender(); if (render == null) { createAntimatterRender(); render = getAntimatterRender(); } float size = (float) Math.pow(antimatterAmount, 0.17); render.setCoreSize(size); } public void setProtoRender(boolean flag) { TileAntimatter render = getAntimatterRender(); if (render == null) return; render.setProtomatterRender(flag); if (!flag) return; render.setRotationFields(getDirection(), getRotation()); } public TileAntimatter getAntimatterRender() { IGregTechTileEntity gregTechTileEntity = this.getBaseMetaTileEntity(); World world = gregTechTileEntity.getWorld(); if (world == null) { return null; } int x = gregTechTileEntity.getXCoord(); int y = gregTechTileEntity.getYCoord(); int z = gregTechTileEntity.getZCoord(); double xOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetX; double zOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetZ; double yOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetY; int wX = (int) (x + xOffset); int wY = (int) (y + yOffset); int wZ = (int) (z + zOffset); return (TileAntimatter) world.getTileEntity(wX, wY, wZ); } public void destroyAntimatterRender() { IGregTechTileEntity gregTechTileEntity = this.getBaseMetaTileEntity(); World world = gregTechTileEntity.getWorld(); if (world == null) { return; } int x = gregTechTileEntity.getXCoord(); int y = gregTechTileEntity.getYCoord(); int z = gregTechTileEntity.getZCoord(); int xOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetX; int yOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetY; int zOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetZ; int xTarget = x + xOffset; int yTarget = y + yOffset; int zTarget = z + zOffset; world.setBlock(xTarget, yTarget, zTarget, Blocks.air); } public void createAntimatterRender() { IGregTechTileEntity gregTechTileEntity = this.getBaseMetaTileEntity(); World world = gregTechTileEntity.getWorld(); if (world == null) { return; } int x = gregTechTileEntity.getXCoord(); int y = gregTechTileEntity.getYCoord(); int z = gregTechTileEntity.getZCoord(); int xOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetX; int yOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetY; int zOffset = 16 * getExtendedFacing().getRelativeBackInWorld().offsetZ; int wX = x + xOffset; int wY = y + yOffset; int wZ = z + zOffset; world.setBlock(wX, wY, wZ, Blocks.air); world.setBlock(wX, wY, wZ, Loaders.antimatterRenderBlock); } }