diff options
author | Sampsa <69092953+S4mpsa@users.noreply.github.com> | 2024-09-12 15:03:41 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-12 14:03:41 +0200 |
commit | c2faa68ac8369db571e8136962b1cac5db206dd0 (patch) | |
tree | a2e6ab7379d32e13ca3a5a8de847e99957bfdf49 /src/main/java/goodgenerator/blocks/tileEntity | |
parent | 07cc2ec931b0e479026e78298a7bd926019c9334 (diff) | |
download | GT5-Unofficial-c2faa68ac8369db571e8136962b1cac5db206dd0.tar.gz GT5-Unofficial-c2faa68ac8369db571e8136962b1cac5db206dd0.tar.bz2 GT5-Unofficial-c2faa68ac8369db571e8136962b1cac5db206dd0.zip |
Add Antimatter Power Generation (#3117)
Co-authored-by: BlueWeabo <ilia.iliev2005@gmail.com>
Co-authored-by: Mary <33456283+FourIsTheNumber@users.noreply.github.com>
Co-authored-by: BucketBrigade <138534411+CookieBrigade@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Diffstat (limited to 'src/main/java/goodgenerator/blocks/tileEntity')
4 files changed, 1754 insertions, 0 deletions
diff --git a/src/main/java/goodgenerator/blocks/tileEntity/AntimatterForge.java b/src/main/java/goodgenerator/blocks/tileEntity/AntimatterForge.java new file mode 100644 index 0000000000..4bf48910e8 --- /dev/null +++ b/src/main/java/goodgenerator/blocks/tileEntity/AntimatterForge.java @@ -0,0 +1,978 @@ +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<AntimatterForge> + 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 float[] modifiers = { 0.0f, 0.0f, 0.0f, 0.0f }; + private FluidStack[] upgradeFluids = { null, null, null, null }; + private int[] fluidConsumptions = { 0, 0, 0, 0 }; + + public static final String MAIN_NAME = "antimatterForge"; + private int speed = 100; + private long rollingCost = 0L; + private boolean isLoadedChunk; + public GTRecipe mLastRecipe; + public int para; + private 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 List<AntimatterOutputHatch> amOutputHatches = new ArrayList<>(16); + private static final ClassValue<IStructureDefinition<AntimatterForge>> STRUCTURE_DEFINITION = new ClassValue<IStructureDefinition<AntimatterForge>>() { + + @Override + protected IStructureDefinition<AntimatterForge> computeValue(Class<?> type) { + return StructureDefinition.<AntimatterForge>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.<AntimatterForge>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.<AntimatterForge>builder() + .anyOf(HatchElement.Energy.or(HatchElement.ExoticEnergy)) + .adder(AntimatterForge::addEnergyInjector) + .casingIndex(x.textureIndex(2)) + .dot(4) + .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_BLUE + + "Antimatter" + + EnumChatFormatting.GRAY + + " * " + + String.valueOf(this.passiveBaseMult) + + ")^" + + EnumChatFormatting.GREEN + + String.valueOf(this.passiveBaseExp) + + EnumChatFormatting.GRAY + + " EU/t passively. The consumption decays by 0.5% every tick when empty") + .addInfo( + "Uses (" + EnumChatFormatting.DARK_BLUE + + "Antimatter" + + EnumChatFormatting.GRAY + + " * " + + String.valueOf(this.activeBaseMult) + + ")^" + + EnumChatFormatting.DARK_PURPLE + + String.valueOf(this.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 5 seconds") + .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_BLUE + + "Antimatter" + + EnumChatFormatting.GRAY + + "^" + + EnumChatFormatting.GOLD + + String.valueOf(this.coefficientBaseExp) + + EnumChatFormatting.GRAY + + ") * N(" + + EnumChatFormatting.AQUA + + String.valueOf(this.baseSkew) + + EnumChatFormatting.GRAY + + ", 1) of antimatter per cycle, consuming equal amounts of Protomatter") + .addInfo("The change can be negative! (N = Skewed Normal Distribution)") + .addSeparator() + .addInfo("Can be supplied with stabilization fluids to improve antimatter generation") + .addInfo( + EnumChatFormatting.GREEN + "Magnetic Stabilization" + + EnumChatFormatting.GRAY + + " (Uses " + + EnumChatFormatting.DARK_BLUE + + "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_BLUE + + "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_BLUE + + "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_BLUE + + "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) + .addSeparator() + .addEnergyHatch("1-9, Hint block with dot 4", 4) + .addInputHatch("1-6, Hint block with dot 1", 1) + .toolTipFinisher("Good Generator"); + return tt; + } + + @Override + public IStructureDefinition<AntimatterForge> 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 (int i = 0; i < amOutputHatches.size(); i++) { + if (amOutputHatches.get(i) == null || !amOutputHatches.get(i) + .isValid() + || amOutputHatches.get(i) + .getFluid() == null) + continue; + antimatterStored += amOutputHatches.get(i) + .getFluid().amount; + } + return antimatterStored; + } + + private void setModifiers(FluidStack inputFluid, float step, FluidStack[] upgradeFluids, int upgradeId) { + for (int tier = 1; tier <= upgradeFluids.length; tier++) { + if (inputFluid.isFluidEqual(upgradeFluids[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 (int i = 0; i < amOutputHatches.size(); i++) { + if (amOutputHatches.get(i) == null || !amOutputHatches.get(i) + .isValid() + || amOutputHatches.get(i) + .getFluid() == null) + continue; + FluidStack fluid = amOutputHatches.get(i) + .getFluid() + .copy(); + ratioLosses -= amOutputHatches.get(i) + .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 / 7)); + fluidConsumptions[ACTIVATION_ID] = (int) Math.ceil(Math.pow(totalAntimatterAmount, 1 / 3)); + + for (int i = 0; i < modifiers.length; i++) { + modifiers[i] = 0.0f; + upgradeFluids[i] = null; + } + + List<FluidStack> inputFluids = getStoredFluids(); + for (int i = 0; i < inputFluids.size(); i++) { + FluidStack inputFluid = inputFluids.get(i); + 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((long) 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 (int i = 0; i < amOutputHatches.size(); i++) { + if (amOutputHatches.get(i) == null || !amOutputHatches.get(i) + .isValid() + || amOutputHatches.get(i) + .getFluid() == null) + continue; + FluidStack fluid = amOutputHatches.get(i) + .getFluid() + .copy(); + amOutputHatches.get(i) + .drain((int) Math.floor(fluid.amount * 0.1), true); + } + } + + private int distributeAntimatterToHatch(List<AntimatterOutputHatch> 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((long) (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 + + " EU/t" }; + } + + 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) { + TileAntimatter render = forceGetAntimatterRender(); + + if (antimatterAmount < 0) { + setProtoRender(false); + render.setCoreSize(0); + return; + } + + float size = (float) Math.pow(antimatterAmount, 0.17); + render.setCoreSize(size); + } + + public void setProtoRender(boolean flag) { + TileAntimatter render = forceGetAntimatterRender(); + render.setProtomatterRender(flag); + if (flag) render.setRotationFields(getRotation(), getDirection()); + } + + 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); + } + + public TileAntimatter forceGetAntimatterRender() { + TileAntimatter render = getAntimatterRender(); + if (render != null) return render; + else createAntimatterRender(); + return getAntimatterRender(); + } + +} diff --git a/src/main/java/goodgenerator/blocks/tileEntity/AntimatterGenerator.java b/src/main/java/goodgenerator/blocks/tileEntity/AntimatterGenerator.java new file mode 100644 index 0000000000..89bb56acdd --- /dev/null +++ b/src/main/java/goodgenerator/blocks/tileEntity/AntimatterGenerator.java @@ -0,0 +1,572 @@ +package goodgenerator.blocks.tileEntity; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static gregtech.api.enums.Textures.BlockIcons.*; +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; +import static gregtech.api.util.GTStructureUtility.buildHatchAdder; +import static gregtech.api.util.GTStructureUtility.ofFrame; +import static gregtech.common.misc.WirelessNetworkManager.addEUToGlobalEnergyMap; +import static gregtech.common.misc.WirelessNetworkManager.strongCheckOrAddUser; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +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.IConstructable; +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.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import bartworks.common.loaders.ItemRegistry; +import goodgenerator.blocks.structures.AntimatterStructures; +import goodgenerator.loader.Loaders; +import gregtech.api.GregTechAPI; +import gregtech.api.enums.HatchElement; +import gregtech.api.enums.Materials; +import gregtech.api.enums.MaterialsUEVplus; +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GTUITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.MTEExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.MTEHatch; +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.GTUtility; +import gregtech.api.util.HatchElementBuilder; +import gregtech.api.util.MultiblockTooltipBuilder; +import kekztech.client.gui.KTUITextures; +import tectech.thing.metaTileEntity.hatch.MTEHatchDynamoTunnel; + +public class AntimatterGenerator extends MTEExtendedPowerMultiBlockBase + implements IConstructable, ISurvivalConstructable { + + public static final String MAIN_NAME = "antimatterGenerator"; + protected IStructureDefinition<AntimatterGenerator> multiDefinition = null; + protected int times = 1; + private UUID owner_uuid; + private boolean wirelessEnabled = false; + private boolean canUseWireless = true; + private long euCapacity = 0; + private long euLastCycle = 0; + private float annihilationEfficiency = 0f; + + private static final ClassValue<IStructureDefinition<AntimatterGenerator>> STRUCTURE_DEFINITION = new ClassValue<IStructureDefinition<AntimatterGenerator>>() { + + @Override + protected IStructureDefinition<AntimatterGenerator> computeValue(Class<?> type) { + return StructureDefinition.<AntimatterGenerator>builder() + .addShape(MAIN_NAME, AntimatterStructures.ANTIMATTER_GENERATOR) + .addElement('F', lazy(x -> ofFrame(Materials.Naquadria))) // Naquadria Frame Box + .addElement('D', lazy(x -> ofBlock(x.getCasingBlock(1), x.getCasingMeta(1)))) // Black Casing + .addElement('G', lazy(x -> ofBlock(x.getCoilBlock(1), x.getCoilMeta(1)))) // Annihilation Coil + .addElement('B', lazy(x -> ofBlock(x.getCoilBlock(2), x.getCoilMeta(2)))) // Containment Coil + .addElement('C', lazy(x -> ofBlock(x.getCasingBlock(2), x.getCasingMeta(2)))) // White Casing + .addElement('A', lazy(x -> ofBlock(x.getGlassBlock(), x.getGlassMeta()))) // Glass + .addElement('E', lazy(x -> ofBlock(GregTechAPI.sBlockCasings9, 1))) // Filter Casing + .addElement( + 'H', + lazy( + x -> HatchElementBuilder.<AntimatterGenerator>builder() + .anyOf(HatchElement.ExoticEnergy) + .adder(AntimatterGenerator::addLaserSource) + .casingIndex(x.textureIndex(2)) + .dot(1) + .buildAndChain(x.getCasingBlock(2), x.getCasingMeta(2)))) + .addElement( + 'I', + lazy( + x -> buildHatchAdder(AntimatterGenerator.class).atLeast(HatchElement.InputHatch) + .casingIndex(x.textureIndex(1)) + .dot(2) + .buildAndChain(x.getCasingBlock(1), x.getCasingMeta(1)))) + .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())); + }; + + private boolean addLaserSource(IGregTechTileEntity aBaseMetaTileEntity, int aBaseCasingIndex) { + IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof MTEHatchDynamoTunnel tHatch) { + tHatch.updateTexture(aBaseCasingIndex); + return mExoticEnergyHatches.add(tHatch); + } + return false; + } + + public AntimatterGenerator(String name) { + super(name); + } + + public AntimatterGenerator(int id, String name, String nameRegional) { + super(id, name, nameRegional); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return null; + } + + @Override + public CheckRecipeResult checkProcessing() { + startRecipeProcessing(); + List<FluidStack> inputFluids = getStoredFluids(); + long containedAntimatter = 0; + FluidStack catalystFluid = null; + int i = 0; + + while (i < inputFluids.size()) { + FluidStack inputFluid = inputFluids.get(i); + if (inputFluid.isFluidEqual(MaterialsUEVplus.Antimatter.getFluid(1))) { + containedAntimatter += inputFluid.amount; + } else { + catalystFluid = inputFluid.copy(); + } + // We annihilate everything, even if it was the wrong fluid + inputFluid.amount = 0; + i++; + } + // If i != 2, we iterated more than 2 times and have too many fluids. + if (i == 2 && containedAntimatter > 0 && catalystFluid != null) { + createEU(containedAntimatter, catalystFluid); + } + + endRecipeProcessing(); + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + // (Antimatter^(EXP) * 1e12 )/(Math.min((Antimatter/Matter),(Matter/Antimatter))) + public void createEU(long antimatter, FluidStack catalyst) { + Float modifier = null; + + if (catalyst.isFluidEqual(Materials.Copper.getMolten(1L))) { + modifier = 1.0F; + } else if (catalyst.isFluidEqual(Materials.SuperconductorUIVBase.getMolten(1L))) { + modifier = 1.02F; + } else if (catalyst.isFluidEqual(Materials.SuperconductorUMVBase.getMolten(1L))) { + modifier = 1.03F; + } else if (catalyst.isFluidEqual(MaterialsUEVplus.BlackDwarfMatter.getMolten(1L))) { + modifier = 1.04F; + } + long catalystCount = catalyst.amount; + long generatedEU = 0; + + if (modifier != null) { + float efficiency = Math + .min(((float) antimatter / (float) catalystCount), ((float) catalystCount / (float) antimatter)); + this.annihilationEfficiency = efficiency; + generatedEU = (long) ((Math.pow(antimatter, modifier) * 1e12) * efficiency); + } + + if (wirelessEnabled && modifier >= 1.03F) { + // Clamp the EU to the maximum of the hatches so wireless cannot bypass the limitations + generatedEU = Math.min(generatedEU, euCapacity); + this.euLastCycle = generatedEU; + addEUToGlobalEnergyMap(owner_uuid, generatedEU); + } else { + this.euLastCycle = generatedEU; + float invHatchCount = 1.0F / (float) mExoticEnergyHatches.size(); + for (MTEHatch tHatch : getExoticEnergyHatches()) { + if (tHatch instanceof MTEHatchDynamoTunnel tLaserSource) { + tLaserSource.setEUVar(tLaserSource.getEUVar() + (long) (generatedEU * invHatchCount)); + } + } + } + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + this.euCapacity = 0; + for (MTEHatch tHatch : getExoticEnergyHatches()) { + if (tHatch instanceof MTEHatchDynamoTunnel tLaserSource) { + this.euCapacity += tLaserSource.maxEUStore(); + } + } + return checkPiece(MAIN_NAME, 17, 41, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(MAIN_NAME, stackSize, 17, 41, 0, elementBudget, env, false, true); + } + + @Override + public void construct(ItemStack itemStack, boolean hintsOnly) { + buildPiece(MAIN_NAME, itemStack, hintsOnly, 17, 41, 0); + } + + @Override + public void saveNBTData(NBTTagCompound nbt) { + nbt.setBoolean("wirelessEnabled", wirelessEnabled); + super.saveNBTData(nbt); + } + + @Override + public void loadNBTData(NBTTagCompound nbt) { + wirelessEnabled = nbt.getBoolean("wirelessEnabled"); + super.loadNBTData(nbt); + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getPollutionPerTick(ItemStack aStack) { + return 0; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new AntimatterGenerator(this.MAIN_NAME); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + wirelessEnabled = !wirelessEnabled; + GTUtility.sendChatToPlayer(aPlayer, "Wireless network mode " + (wirelessEnabled ? "enabled." : "disabled.")); + if (wirelessEnabled) { + GTUtility.sendChatToPlayer(aPlayer, "Wireless only works with UMV Superconductor Base or better."); + } + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPreTick(aBaseMetaTileEntity, aTick); + + if (aBaseMetaTileEntity.isServerSide()) { + + // On first tick find the player name and attempt to add them to the map. + if (aTick == 1) { + + // UUID and username of the owner. + owner_uuid = aBaseMetaTileEntity.getOwnerUuid(); + + strongCheckOrAddUser(owner_uuid); + } + } + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder(); + tt.addMachineType("Antimatter Generator") + .addInfo("Annihilating antimatter like it's 2205!") + .addSeparator() + .addInfo("Generates energy by reacting Semi-Stable Antimatter with matter") + .addInfo("Annihilation uses an equal amount of antimatter and matter") + .addInfo( + "Consumes " + EnumChatFormatting.GOLD + + "all inputs" + + EnumChatFormatting.GRAY + + " every processing cycle") + .addInfo( + "Imbalance between antimatter and matter " + EnumChatFormatting.RED + + "will waste energy!" + + EnumChatFormatting.GRAY) + .addInfo( + "Any EU that does not fit in laser hatches will be " + EnumChatFormatting.RED + + "voided" + + EnumChatFormatting.GRAY) + .addSeparator() + .addInfo("Antimatter base energy value: 1,000,000,000 EU/L") + .addInfo("Energy production is exponentially increased depending on the matter used:") + .addInfo("Molten Copper: 1.00") + .addInfo("Molten SC UIV Base: 1.02") + .addInfo("Molten SC UMV Base: 1.03") + .addInfo("Molten Black Dwarf Matter: 1.04") + .addSeparator() + .addInfo("Enable wireless EU mode with screwdriver") + .addInfo("Wireless mode requires SC UMV Base or better") + .addInfo("Wireless mode uses hatch capacity limit") + .addDynamoHatch("1-9, Hint block with dot 4", 4) + .addInputHatch("1-6, Hint block with dot 1", 1) + .toolTipFinisher("Good Generator"); + return tt; + } + + protected boolean canUseWireless() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + builder.widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (!widget.isClient()) { + canUseWireless = canUseWireless(); + } + if (canUseWireless) { + wirelessEnabled = !wirelessEnabled; + } + }) + .setPlayClickSound(true) + .setBackground(() -> { + List<UITexture> ret = new ArrayList<>(); + ret.add(GTUITextures.BUTTON_STANDARD); + if (canUseWireless) { + if (wirelessEnabled) { + ret.add(KTUITextures.OVERLAY_BUTTON_WIRELESS_ON); + } else { + ret.add(KTUITextures.OVERLAY_BUTTON_WIRELESS_OFF); + } + } else { + ret.add(KTUITextures.OVERLAY_BUTTON_WIRELESS_OFF_DISABLED); + } + return ret.toArray(new IDrawable[0]); + }) + .setPos(80, 91) + .setSize(16, 16) + .addTooltip(StatCollector.translateToLocal("gui.kekztech_lapotronicenergyunit.wireless")) + .setTooltipShowUpDelay(TOOLTIP_DELAY)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> wirelessEnabled, val -> wirelessEnabled = val)) + .widget(new FakeSyncWidget.BooleanSyncer(this::canUseWireless, val -> canUseWireless = val)); + } + + @Override + public String[] getInfoData() { + 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.AntimatterGenerator.0") + ": " + + EnumChatFormatting.GREEN + + GTUtility.formatNumbers(this.euLastCycle) + + EnumChatFormatting.RESET + + " EU", + StatCollector.translateToLocal("gui.AntimatterGenerator.1") + ": " + + EnumChatFormatting.AQUA + + GTUtility.formatNumbers(Math.ceil(this.annihilationEfficiency * 100)) + + EnumChatFormatting.RESET + + " %" }; + } + + private long getEnergyProduced() { + return this.euLastCycle; + } + + private float getEfficiency() { + return this.annihilationEfficiency; + } + + protected long energyProducedCache; + protected float efficiencyCache; + 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.AntimatterGenerator.0") + ": " + + EnumChatFormatting.BLUE + + standardFormat.format(energyProducedCache) + + EnumChatFormatting.WHITE + + " EU") + .setDefaultColor(COLOR_TEXT_WHITE.get())) + .widget(new FakeSyncWidget.LongSyncer(this::getEnergyProduced, val -> energyProducedCache = val)) + .widget( + new TextWidget() + .setStringSupplier( + () -> StatCollector.translateToLocal("gui.AntimatterGenerator.1") + ": " + + EnumChatFormatting.RED + + numberFormat.format(Math.ceil(efficiencyCache * 100)) + + EnumChatFormatting.WHITE + + " %") + .setDefaultColor(COLOR_TEXT_WHITE.get())) + .widget(new FakeSyncWidget.FloatSyncer(this::getEfficiency, val -> efficiencyCache = val)); + } + + @Override + public IStructureDefinition<AntimatterGenerator> getStructureDefinition() { + return STRUCTURE_DEFINITION.get(getClass()); + } + + 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 + @SuppressWarnings("ALL") + 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() }; + } + + public Block getCoilBlock(int type) { + switch (type) { + case 1: + return Loaders.antimatterAnnihilationMatrix; + case 2: + return Loaders.protomatterActivationCoil; + default: + return Loaders.antimatterAnnihilationMatrix; + } + } + + public int getCoilMeta(int type) { + return 0; + } + + 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) { + return 0; + } + + public Block getFrameBlock() { + return Loaders.antimatterContainmentCasing; + } + + public int getFrameMeta() { + return 0; + } + + public Block getGlassBlock() { + return ItemRegistry.bw_realglas2; + } + + public int getGlassMeta() { + 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; + } + } + + @Override + public boolean getDefaultHasMaintenanceChecks() { + return false; + } + +} diff --git a/src/main/java/goodgenerator/blocks/tileEntity/AntimatterOutputHatch.java b/src/main/java/goodgenerator/blocks/tileEntity/AntimatterOutputHatch.java new file mode 100644 index 0000000000..f575e2f315 --- /dev/null +++ b/src/main/java/goodgenerator/blocks/tileEntity/AntimatterOutputHatch.java @@ -0,0 +1,74 @@ +package goodgenerator.blocks.tileEntity; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.Materials; +import gregtech.api.enums.MaterialsUEVplus; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.MTEHatchOutput; + +public class AntimatterOutputHatch extends MTEHatchOutput { + + private static final FluidStack ANTIMATTER = Materials.Antimatter.getFluid(1); + + public AntimatterOutputHatch(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, 11); + this.mDescriptionArray[1] = "Stores Antimatter"; + this.mDescriptionArray[2] = "Antimatter can be inserted from any side"; + this.mDescriptionArray[3] = "Capacity: 16,384,000L"; + } + + public AntimatterOutputHatch(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + setLockedFluidName( + MaterialsUEVplus.Antimatter.getFluid(1) + .getFluid() + .getName()); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new AntimatterOutputHatch(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public int getCapacity() { + return 16_384_000; + } + + @Override + public boolean isFluidLocked() { + return true; + } + + @Override + protected void onEmptyingContainerWhenEmpty() { + // Disable removing the lock + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (!getBaseMetaTileEntity().getCoverInfoAtSide(side) + .isGUIClickable()) return; + if (aPlayer.isSneaking()) { + mMode = (byte) ((mMode + 9) % 10); + } else { + mMode = (byte) ((mMode + 1) % 10); + } + } + + @Override + public boolean isLiquidInput(ForgeDirection side) { + return side != this.getBaseMetaTileEntity() + .getFrontFacing(); + } + + @Override + public boolean isLiquidOutput(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } +} diff --git a/src/main/java/goodgenerator/blocks/tileEntity/render/TileAntimatter.java b/src/main/java/goodgenerator/blocks/tileEntity/render/TileAntimatter.java new file mode 100644 index 0000000000..8e2027b36d --- /dev/null +++ b/src/main/java/goodgenerator/blocks/tileEntity/render/TileAntimatter.java @@ -0,0 +1,130 @@ + +package goodgenerator.blocks.tileEntity.render; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation; + +public class TileAntimatter extends TileEntity { + + public boolean shouldRender = true; + + // Antimatter Core settings + public static final float spikeR = 0.82f, spikeG = 0.92f, spikeB = 1f; + public static final float coreR = 0.43f, coreG = 0.40f, coreB = 1f; + public static final float maximalRadius = 9; // Includes core radius + spike length + // Due to being partially managed by a global timer, rotationSpeedMultiplier shouldn't change + // Otherwise it'll cause a snapping effect + public final float rotationSpeedMultiplier = 1; + + public float coreScale = 1f; + public float coreScaleSnapshot = 1f; + public final float coreScaleTransitionTime = 2.5f; + public float timeSnapshot; + public float spikeFactor = 1f; + + // Protomatter Settings + public static float protoSpiralMaxRadius = .5f; + public static final float protoR = 0.2f, protoG = 0.2f, protoB = 0.2f; + public float protomatterScale = .2f; + public boolean protomatterRender = false; + public float rotX = 0, rotY = 0, rotZ = 0; + public float rotationAngle = 0; + + @Override + public void writeToNBT(NBTTagCompound compound) { + super.writeToNBT(compound); + compound.setFloat("coreScale", coreScale); + compound.setFloat("coreScaleSnapshot", coreScaleSnapshot); + compound.setFloat("currentTime", timeSnapshot); + compound.setFloat("spikeFactor", spikeFactor); + compound.setBoolean("protomatterRender", protomatterRender); + + compound.setFloat("rotX", rotX); + compound.setFloat("rotY", rotY); + compound.setFloat("rotZ", rotZ); + compound.setFloat("rotationAngle", rotationAngle); + } + + @Override + public void readFromNBT(NBTTagCompound compound) { + super.readFromNBT(compound); + coreScale = compound.getFloat("coreScale"); + coreScaleSnapshot = compound.getFloat("coreScaleSnapshot"); + timeSnapshot = compound.getFloat("currentTime"); + spikeFactor = compound.getFloat("spikeFactor"); + protomatterRender = compound.getBoolean("protomatterRender"); + + rotX = compound.getFloat("rotX"); + rotY = compound.getFloat("rotY"); + rotZ = compound.getFloat("rotZ"); + rotationAngle = compound.getFloat("rotationAngle"); + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + writeToNBT(nbttagcompound); + return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 1, nbttagcompound); + } + + @Override + public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { + readFromNBT(pkt.func_148857_g()); + worldObj.markBlockRangeForRenderUpdate(xCoord, yCoord, zCoord, xCoord, yCoord, zCoord); + } + + @Override + public AxisAlignedBB getRenderBoundingBox() { + return AxisAlignedBB.getBoundingBox( + xCoord - maximalRadius - 1, + yCoord - maximalRadius - 1, + zCoord - maximalRadius - 1, + xCoord + maximalRadius + 1, + yCoord + maximalRadius + 1, + zCoord + maximalRadius + 1); + } + + @Override + public double getMaxRenderDistanceSquared() { + return 65536; + } + + public void setProtomatterRender(boolean flag) { + protomatterRender = flag; + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + public float getSpiralRadius(float normalization) { + return Math.min(coreScale / 2.0f * normalization, protoSpiralMaxRadius); + } + + public void setCoreSize(float diameter) { + coreScaleSnapshot = coreScale; + coreScale = diameter; + timeSnapshot = this.getWorldObj() + .getWorldInfo() + .getWorldTotalTime(); + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + public void setRotationFields(Rotation rotation, ForgeDirection direction) { + switch (rotation) { + case NORMAL -> rotationAngle = 0; + case CLOCKWISE -> rotationAngle = 90; + case COUNTER_CLOCKWISE -> rotationAngle = -90; + case UPSIDE_DOWN -> rotationAngle = 180; + } + rotX = direction.offsetX; + rotY = direction.offsetY; + rotZ = direction.offsetZ; + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + +} |