diff --git a/README.md b/README.md index 005dddd8d..7d1550dcb 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ -# Destroy +# Destroy - Snapshot 𝑖 -Destroy is a chemistry-themed add-on to the popular Create mod. Right now it's under development. +A modified version of [Destroy](https://modrinth.com/mod/destroy/) that aims to fix several bugs which prevented the automation of many processes in Survival mode. +Comes with a handful of quality of life features, including minor recipe tweaks and better readability when viewing chemical reactions in JEI. -Find out more on the [Discord](https://discord.gg/6EBJ3AzbHu) and [Modrinth](https://modrinth.com/mod/destroy/) page. - -Currently, 1.0 is in development. **This will still be a beta release**. - -# License - -All rights are reserved unless otherwise explicitly stated. +This is currently based on the 0.1.1 version, which is **not** compatible with the latest version of Create! +Make sure you have the following mods installed before running this: +- [Create 0.5.1j](https://modrinth.com/mod/create/version/1.20.1-0.5.1.j) +- [Petrolpark's Library 1.4.2](https://modrinth.com/mod/petrolpark/version/1.20.1-1.4.2) +If you run into any issues, please report them here, not on the main Destroy GitHub page. Thank you! \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5ca6c860a..189afad7f 100644 --- a/build.gradle +++ b/build.gradle @@ -40,7 +40,7 @@ afterEvaluate { tasks.configureReobfTaskForReobfJarJar.mustRunAfter(tasks.compileJava) } -// Mod Detailss +// Mod Details version = "${mod_version}" group = 'com.petrolpark.destroy' archivesBaseName = "destroy-${minecraft_version}" @@ -150,6 +150,28 @@ repositories { maven { // Blueprint url = "https://maven.jaackson.me" } + + maven { // Architectury + url = "https://maven.architectury.dev" + content { + includeGroup "dev.architectury" + } + } + maven { // KubeJS and Rhino + url = "https://maven.saps.dev/minecraft" + content { + includeGroup "dev.latvian.mods" + } + } + + maven { // EMI + name = "TerraformersMC" + url = "https://maven.terraformersmc.com/" + } + + maven { // MixinSquared (may god have mercy) + url = "https://maven.bawnorton.com/releases" + } } configurations { @@ -195,7 +217,7 @@ dependencies { // JEI compileOnly fg.deobf("mezz.jei:jei-${minecraft_version}-common-api:${jei_version}") compileOnly fg.deobf("mezz.jei:jei-${minecraft_version}-forge-api:${jei_version}") - compileOnly fg.deobf("mezz.jei:jei-${minecraft_version}-forge:${jei_version}") + runtimeOnly fg.deobf("mezz.jei:jei-${minecraft_version}-forge:${jei_version}") // Farmer's Delight compileOnly fg.deobf("curse.maven:farmers-delight-398521:${farmersdelight_version}") @@ -211,12 +233,34 @@ dependencies { implementation fg.deobf("com.rbasamoyai:ritchiesprojectilelib:1.0.0-369e88d+1.20.1-forge") implementation fg.deobf("com.rbasamoyai:createbigcannons:${cbc_version}") + // Supplementaries + implementation fg.deobf("maven.modrinth:moonlight:forge_1.20-2.13.71") + implementation fg.deobf("maven.modrinth:supplementaries:1.20-3.1.18") + // Embeddium - compileOnly fg.deobf("maven.modrinth:embeddium:${embeddium_version}+mc${minecraft_version}") - + implementation fg.deobf("maven.modrinth:embeddium:${embeddium_version}+mc${minecraft_version}") + + // Jade + runtimeOnly fg.deobf("maven.modrinth:jade:${jade_version}") + + // KubeJS + runtimeOnly fg.deobf("dev.latvian.mods:rhino-forge:${rhino_version}") + runtimeOnly fg.deobf("dev.latvian.mods:kubejs-forge:${kubejs_version}") + runtimeOnly fg.deobf("dev.architectury:architectury-forge:${architectury_version}") + + implementation fg.deobf("maven.modrinth:sophisticated-core:1.20.1-1.2.23.902") + runtimeOnly fg.deobf("maven.modrinth:sophisticated-backpacks:1.20.1-3.23.6.1211") + // ANNOTATION PROCESSORS + // MixinSquared's annotationProcessor MUST be registered BEFORE Mixin's one. + compileOnly(annotationProcessor("com.github.bawnorton.mixinsquared:mixinsquared-common:${mixin_squared_version}")) + implementation(jarJar("com.github.bawnorton.mixinsquared:mixinsquared-forge:${mixin_squared_version}")) {jarJar.ranged(it, "[${mixin_squared_version},)")} + annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" + + compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:${mixin_extras_version}")) + implementation(jarJar("io.github.llamalad7:mixinextras-forge:${mixin_extras_version}")) {jarJar.ranged(it, "[${mixin_extras_version},)")} } jar { diff --git a/gradle.properties b/gradle.properties index a0c10858f..65510a691 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs = -Xmx3G org.gradle.daemon = false # Destroy info -mod_version = 0.1.1 +mod_version = 0.1.1-snapshot-i+1 minecraft_version = 1.20.1 forge_version = 47.3.7 @@ -11,6 +11,8 @@ forgegradle_version = 6.0.26 cursegradle_version = 1.4.0 mixingradle_version = 0.7-SNAPSHOT mixin_version = 0.8.5 +mixin_extras_version = 0.4.1 +mixin_squared_version = 0.2.0 librarian_version = 1.+ parchment_version = 2023.09.03 @@ -21,10 +23,16 @@ flywheel_version = 0.6.11-13 registrate_version = MC1.20-1.3.3 # Optional mod dependency info -jei_version = 15.12.3.55 +jei_version = 15.20.0.106 farmersdelight_version = 4638874 blueprint_version = 7.0.0 spark_version = 4587309 cbc_version = 5.5.0+mc.1.20.1-forge curios_version = 5.9.1 embeddium_version = 0.3.30 + +jade_version = 11.12.3+forge +kubejs_version = 2001.6.5-build.18 +rhino_version = 2001.2.3-build.10 +architectury_version = 9.2.14 +emi_version = 1.1.20+1.20.1 \ No newline at end of file diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties deleted file mode 100644 index 858feb7e3..000000000 --- a/gradle/gradle-daemon-jvm.properties +++ /dev/null @@ -1,2 +0,0 @@ -#This file is generated by updateDaemonJvm -toolchainVersion=17 diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 7bb1320aa..cc85900ed 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -20,7 +20,6 @@ "destroy:tree_tap", "destroy:vat_controller", "destroy:vat_side", - "destroy:vat_controller", "destroy:blacklight", "destroy:carbon_fiber_block", "destroy:fluorite_block", diff --git a/src/main/java/com/petrolpark/destroy/DestroyAdvancementTrigger.java b/src/main/java/com/petrolpark/destroy/DestroyAdvancementTrigger.java index 0c91f121f..91322b9d5 100644 --- a/src/main/java/com/petrolpark/destroy/DestroyAdvancementTrigger.java +++ b/src/main/java/com/petrolpark/destroy/DestroyAdvancementTrigger.java @@ -34,9 +34,9 @@ public enum DestroyAdvancementTrigger { COLORIMETER, COMPLETE_SEISMOGRAPH, CUT_ONIONS, - DISTILL("distill", "distillations"), + DISTILL("distill", "distillation"), CHARGE_WITH_DYNAMO("charge_with_dynamo", "dynamo_charging"), - ELECTROLYZE_WITH_DYNAMO("electrolyze_with_dynamo", "electrolyze_with_dynamo"), + ELECTROLYZE_WITH_DYNAMO("electrolyze_with_dynamo", "dynamo_electrolysis"), ETHYLANTHRAQUINONE, EXTRUDE, FILL_SEISMOGRAPH, diff --git a/src/main/java/com/petrolpark/destroy/DestroyBlockEntityTypes.java b/src/main/java/com/petrolpark/destroy/DestroyBlockEntityTypes.java index 95e0c5647..c5fb81901 100644 --- a/src/main/java/com/petrolpark/destroy/DestroyBlockEntityTypes.java +++ b/src/main/java/com/petrolpark/destroy/DestroyBlockEntityTypes.java @@ -7,6 +7,7 @@ import com.petrolpark.destroy.content.logistics.siphon.SiphonRenderer; import com.petrolpark.destroy.content.oil.pumpjack.PumpjackBlockEntity; import com.petrolpark.destroy.content.oil.pumpjack.PumpjackCamBlockEntity; +import com.petrolpark.destroy.content.oil.pumpjack.PumpjackInstance; import com.petrolpark.destroy.content.oil.pumpjack.PumpjackRenderer; import com.petrolpark.destroy.content.processing.ageing.AgeingBarrelBlockEntity; import com.petrolpark.destroy.content.processing.ageing.AgeingBarrelRenderer; @@ -24,15 +25,17 @@ import com.petrolpark.destroy.content.processing.glassblowing.BlowpipeBlockEntity; import com.petrolpark.destroy.content.processing.glassblowing.BlowpipeBlockEntityRenderer; import com.petrolpark.destroy.content.processing.sieve.MechanicalSieveBlockEntity; +import com.petrolpark.destroy.content.processing.sieve.MechanicalSieveInstance; import com.petrolpark.destroy.content.processing.sieve.MechanicalSieveRenderer; import com.petrolpark.destroy.content.processing.treetap.TreeTapBlockEntity; +import com.petrolpark.destroy.content.processing.treetap.TreeTapInstance; import com.petrolpark.destroy.content.processing.treetap.TreeTapRenderer; import com.petrolpark.destroy.content.processing.trypolithography.keypunch.KeypunchBlockEntity; +import com.petrolpark.destroy.content.processing.trypolithography.keypunch.KeypunchInstance; import com.petrolpark.destroy.content.processing.trypolithography.keypunch.KeypunchRenderer; import com.petrolpark.destroy.content.redstone.programmer.RedstoneProgrammerBlockEntity; import com.petrolpark.destroy.content.redstone.programmer.RedstoneProgrammerBlockEntityRenderer; import com.petrolpark.destroy.content.sandcastle.SandCastleBlockEntity; -import com.petrolpark.destroy.core.block.entity.instance.HorizontalShaftlessCogwheelInstance; import com.petrolpark.destroy.core.chemistry.storage.ElementTankBlockEntity; import com.petrolpark.destroy.core.chemistry.storage.ElementTankRenderer; import com.petrolpark.destroy.core.chemistry.storage.SimpleMixtureTankBlockEntity.SimplePlaceableMixtureTankBlockEntity; @@ -138,7 +141,7 @@ public class DestroyBlockEntityTypes { public static final BlockEntityEntry KEYPUNCH = REGISTRATE .blockEntity("keypunch", KeypunchBlockEntity::new) - .instance(() -> HorizontalShaftlessCogwheelInstance::new) + .instance(() -> KeypunchInstance::new) .validBlocks(DestroyBlocks.KEYPUNCH) .renderer(() -> KeypunchRenderer::new) .register(); @@ -151,6 +154,7 @@ public class DestroyBlockEntityTypes { public static final BlockEntityEntry MECHANICAL_SIEVE = REGISTRATE .blockEntity("mechanical_sieve", MechanicalSieveBlockEntity::new) + .instance(() -> MechanicalSieveInstance::new) .validBlock(DestroyBlocks.MECHANICAL_SIEVE) .renderer(() -> MechanicalSieveRenderer::new) .register(); @@ -163,7 +167,7 @@ public class DestroyBlockEntityTypes { public static final BlockEntityEntry PUMPJACK = REGISTRATE .blockEntity("pumpjack", PumpjackBlockEntity::new) - //.instance(() -> PumpjackInstance::new, false) Can't use instancing because that can't render cutout for some reason + .instance(() -> PumpjackInstance::new) .validBlocks(DestroyBlocks.PUMPJACK) .renderer(() -> PumpjackRenderer::new) .register(); @@ -198,6 +202,7 @@ public class DestroyBlockEntityTypes { public static final BlockEntityEntry TREE_TAP = REGISTRATE .blockEntity("tree_tap", TreeTapBlockEntity::new) + .instance(() -> TreeTapInstance::new) .validBlock(DestroyBlocks.TREE_TAP) .renderer(() -> TreeTapRenderer::new) .register(); diff --git a/src/main/java/com/petrolpark/destroy/DestroyBlocks.java b/src/main/java/com/petrolpark/destroy/DestroyBlocks.java index 4e87c445f..963d8bf41 100644 --- a/src/main/java/com/petrolpark/destroy/DestroyBlocks.java +++ b/src/main/java/com/petrolpark/destroy/DestroyBlocks.java @@ -203,7 +203,7 @@ public class DestroyBlocks { .properties(p -> p .mapColor(MapColor.SNOW) ).item(MixedExplosiveBlockItem::new) - .onRegister(registerPrimeableBombDispenserBehaviour()) + .onRegister(item -> DispenserBlock.registerBehavior(item, ((MixedExplosiveBlock)item.getBlock()).new CustomExplosiveMixDispenseBehaviour())) .build() .register(); diff --git a/src/main/java/com/petrolpark/destroy/DestroyClient.java b/src/main/java/com/petrolpark/destroy/DestroyClient.java index a02a5cc16..c9ecfcf58 100644 --- a/src/main/java/com/petrolpark/destroy/DestroyClient.java +++ b/src/main/java/com/petrolpark/destroy/DestroyClient.java @@ -1,5 +1,6 @@ package com.petrolpark.destroy; +import com.petrolpark.Petrolpark; import com.petrolpark.destroy.client.DestroyItemDisplayContexts; import com.petrolpark.destroy.client.DestroyPartials; import com.petrolpark.destroy.client.DestroyParticleTypes; @@ -9,6 +10,7 @@ import com.petrolpark.destroy.client.FogHandler; import com.petrolpark.destroy.core.extendedinventory.ExtendedInventoryClientHandler; +import com.petrolpark.item.decay.DecayingItemHandler; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @@ -24,6 +26,9 @@ public class DestroyClient { public static void clientInit(final FMLClientSetupEvent event) { event.enqueueWork(() -> { // Work which must be done on main thread DestroyItemProperties.register(); + + // TODO: This is supposed to be done by the Petrolpark library, remove this once this is properly fixed + Petrolpark.DECAYING_ITEM_HANDLER.set(new DecayingItemHandler.ClientDecayingItemHandler()); }); DestroyPonderTags.register(); DestroyPonderIndex.register(); diff --git a/src/main/java/com/petrolpark/destroy/chemistry/legacy/LegacyMixture.java b/src/main/java/com/petrolpark/destroy/chemistry/legacy/LegacyMixture.java index b0b1e3076..8f4b9010f 100644 --- a/src/main/java/com/petrolpark/destroy/chemistry/legacy/LegacyMixture.java +++ b/src/main/java/com/petrolpark/destroy/chemistry/legacy/LegacyMixture.java @@ -420,7 +420,7 @@ public void heat(float energyDensity) { temperatureChange = nextHigherBoilingPoint.getFirst() - temperature; // Only increase the temperature by enough to get to the next BP temperature += temperatureChange; // Raise the Mixture to the boiling point - energyDensity -= temperatureChange * getVolumetricHeatCapacity(); // Energy leftover once the Mixture has been raised to the boiling point + energyDensity -= temperatureChange * volumetricHeatCapacity; // Energy leftover once the Mixture has been raised to the boiling point LegacySpecies molecule = nextHigherBoilingPoint.getSecond(); float liquidConcentration = getConcentrationOf(molecule) * (1f - states.get(molecule)); // The moles per bucket of liquid Molecules @@ -448,7 +448,7 @@ public void heat(float energyDensity) { temperatureChange = nextLowerBoilingPoint.getFirst() - temperature; // Only decrease the temperature by enough to get to the next condensation point temperature += temperatureChange; // Decrease the Mixture to the boiling point - energyDensity -= temperatureChange * getVolumetricHeatCapacity(); // Additional energy once the Mixture has been lowered to the condensation point + energyDensity -= temperatureChange * volumetricHeatCapacity; // Additional energy once the Mixture has been lowered to the condensation point LegacySpecies molecule = nextLowerBoilingPoint.getSecond(); float gasConcentration = getConcentrationOf(molecule) * states.get(molecule); @@ -654,7 +654,7 @@ public Phases separatePhases(double initialVolume) { // Add Reaction Results to new Mixtures for (Entry entry : reactionResults.entrySet()) { double resultMoles = entry.getValue() * initialVolume; - double newTotalVolume = newLiquidVolume * newGasVolume; + double newTotalVolume = newLiquidVolume + newGasVolume; liquidMixture.reactionResults.put(entry.getKey(), (float)(resultMoles / newTotalVolume)); // A cancelled-out expression for (resultMoles / liquidVolume) * (liquidVolume / (liquidVolume + gasVolume)). Essentially we just divvy out the results based on the volumes of the two phases gasMixture.reactionResults.put(entry.getKey(), (float)(resultMoles / newTotalVolume)); }; @@ -723,18 +723,36 @@ protected void incrementReactionResults(LegacyReaction reaction, float molesPerB * @param heatingPower The power being supplied to this Basin by the {@link com.petrolpark.destroy.core.chemistry.vat.IVatHeaterBlock heater} below it. * @param outsideTemperature The {@link com.petrolpark.destroy.core.pollution.Pollution#getLocalTemperature temperature} outside the Basin. */ - public ReactionInBasinResult reactInBasin(int volume, List availableStacks, float heatingPower, float outsideTemperature) { + public ReactionInBasinResult reactInBasin(int volume, List availableStacks, float heatingTemperature, float outsideTemperature) { float volumeInLiters = (float)volume / Constants.MILLIBUCKETS_PER_LITER; int ticks = 0; + // Bottom face receives heat, other faces dissipate heat into the environment + // The bottom face is more conductive than the other faces, this is balanced in such a way that a kindled Blaze Burner + // reaches roughly 130°C and a superheated Blaze Burner reaches roughly 360°C, hot enough to boil mercury + float averageTemperature = (1.35f * heatingTemperature + 4.65f * outsideTemperature) / 6f; + ReactionContext context = new ReactionContext(availableStacks, 0f, false); dissolveItems(context, volumeInLiters); // Dissolve all Items - while (!equilibrium && ticks < 600) { // React the Mixture - float energyChange = heatingPower / TICKS_PER_SECOND; - energyChange += (outsideTemperature - temperature) * 100f / TICKS_PER_SECOND; // Fourier's Law (sort of), the Basin has a fixed conductance of 100 andthe divide by 20 is for 20 ticks per second - if (Math.abs(energyChange) > 0.0001f) { - heat(1000 * energyChange / volume); // 1000 converts getFluidAmount() in mB to Buckets + while (ticks < 600) { // React the Mixture + // Fourier's Law (sort of), the Basin has a fixed conductance and the divide by 20 is for 20 ticks per second + // The Basin is given unrealistically high conductance to help make it more reliable by ensuring that the + // contained Mixture reaches its target temperature quickly. + float temperatureDifference = averageTemperature - temperature; + float energyChange = temperatureDifference * 300000f / TICKS_PER_SECOND; + float predictedMixtureTemperatureChange = Math.abs(energyChange / (volumeInLiters * getVolumetricHeatCapacity())); + + if (predictedMixtureTemperatureChange > 0.001f) { + // Prevent temperature from exploding to infinity due to the high conductance and time step + // This is a certified Euler moment and I'm too lazy to switch over to a fancier integrator for the moment + if (predictedMixtureTemperatureChange > Math.abs(temperatureDifference)) + energyChange *= 0.99f * Math.abs(temperatureDifference) / predictedMixtureTemperatureChange; + + heat(energyChange / volumeInLiters); + } else if(equilibrium) { + break; }; + reactForTick(context, 1); ticks++; }; @@ -768,7 +786,6 @@ public Map getCompletedResults(double volumeInLiters) { // Decrease the amount of Reaction that has happened reactionResults.replace(result, molesPerLiterOfReaction - numberOfResult * result.getRequiredMoles() / (float)volumeInLiters); - results.put(result, numberOfResult); }; // reactionResults.keySet().removeIf(result -> { // Remove any one-off Results and Results which have run out diff --git a/src/main/java/com/petrolpark/destroy/chemistry/legacy/LegacyMolecularStructure.java b/src/main/java/com/petrolpark/destroy/chemistry/legacy/LegacyMolecularStructure.java index de6be89a8..b772d0434 100644 --- a/src/main/java/com/petrolpark/destroy/chemistry/legacy/LegacyMolecularStructure.java +++ b/src/main/java/com/petrolpark/destroy/chemistry/legacy/LegacyMolecularStructure.java @@ -1,14 +1,6 @@ package com.petrolpark.destroy.chemistry.legacy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.Map.Entry; import javax.annotation.Nullable; @@ -85,7 +77,7 @@ public class LegacyMolecularStructure implements Cloneable { private String optimumFROWNSCode; private LegacyMolecularStructure() { - structure = new HashMap>(); + structure = new LinkedHashMap>(); groups = new ArrayList<>(); topology = Topology.LINEAR; sideChains = new ArrayList<>(); @@ -606,7 +598,7 @@ public LegacyMolecularStructure addCarbonyl() { * @return This Formula */ public LegacyMolecularStructure addAllHydrogens() { - Map> newStructure = new HashMap>(structure); // Create a shallow copy, as the original structure can't be modified while being iterated over + Map> newStructure = new LinkedHashMap>(structure); // Create a shallow copy, as the original structure can't be modified while being iterated over // Replace all empty side chains with Hydrogen, if necessary if (topology != Topology.LINEAR) { @@ -797,6 +789,7 @@ private static Branch getMaximumBranchWithHighestMass(Map { return getMaximumBranch(a2, structure).getMassOfLongestChain().compareTo(getMaximumBranch(a1, structure).getMassOfLongestChain()); // Put in descending order of chain length }); + Collections.sort(terminalAtoms, (a1, a2) -> { return Branch.getMassForComparisonInSerialization(a1).compareTo(Branch.getMassForComparisonInSerialization(a2)); }); @@ -885,7 +878,7 @@ public LegacyMolecularStructure shallowCopy() { try { LegacyMolecularStructure newFormula = (LegacyMolecularStructure) super.clone(); - newFormula.structure = new HashMap<>(structure.size()); + newFormula.structure = new LinkedHashMap<>(structure.size()); newFormula.structure = shallowCopyStructure(structure); // Shallow copy the Structure newFormula.groups = new ArrayList<>(groups); // Shallow copy the Groups newFormula.topology = this.topology; // Shallow copy the Topology @@ -930,7 +923,7 @@ public Branch getRenderBranch() { * @see LegacyMolecularStructure#shallowCopy The wrapper for this Method */ private static Map> shallowCopyStructure(Map> structureToCopy) { - Map> newStructure = new HashMap<>(); + Map> newStructure = new LinkedHashMap<>(); for (LegacyAtom atom : structureToCopy.keySet()) { List oldBonds = structureToCopy.get(atom); List newBonds = new ArrayList<>(); @@ -1194,7 +1187,7 @@ private static BondType trailingBondType(String symbol) { * @return The original structure, now with its non-acidic hydrogen Atoms removed */ private static Map> stripHydrogens(Map> structure) { - Map> newStructure = new HashMap<>(); + Map> newStructure = new LinkedHashMap<>(); for (Entry> entry : structure.entrySet()) { LegacyAtom atom = entry.getKey(); List bondsToInclude = new ArrayList<>(); diff --git a/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyMolecules.java b/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyMolecules.java index eeb4134db..f69ed5e52 100644 --- a/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyMolecules.java +++ b/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyMolecules.java @@ -617,13 +617,6 @@ public final class DestroyMolecules { .hypothetical() .translationKey("amide") .build(), - - GENERIC_AMINE = builder() - .id("generic_amine") - .structure(LegacyMolecularStructure.deserialize("destroy:linear:RC(R)(R)N")) - .hypothetical() - .translationKey("amine") - .build(), GENERIC_BORANE = builder() .id("generic_borane") diff --git a/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyReactions.java b/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyReactions.java index 6a2e89183..6558718e6 100644 --- a/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyReactions.java +++ b/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyReactions.java @@ -35,7 +35,7 @@ public class DestroyReactions { ACETYLENE_TRIMERIZATION = builder() .id("acetylene_trimerization") .addReactant(DestroyMolecules.ACETYLENE, 3) - .addSimpleItemTagCatalyst(AllTags.forgeItemTag("dusts/nickel"), 5f) + .addSimpleItemTagCatalyst(AllTags.forgeItemTag("dusts/nickel"), 1f) .addProduct(DestroyMolecules.BENZENE) .build(), @@ -125,7 +125,7 @@ public class DestroyReactions { BORAX_DISSOLUTION = builder() .id("borax_dissolution") .addReactant(DestroyMolecules.PROTON, 2, 1) - .addSimpleItemTagCatalyst(AllTags.forgeItemTag("raw_materials/borax"), 16f) + .addSimpleItemTagReactant(AllTags.forgeItemTag("raw_materials/borax"), 15f) .addCatalyst(DestroyMolecules.CHLORIDE, 1) .addProduct(DestroyMolecules.SODIUM_ION, 2) .addProduct(DestroyMolecules.WATER, 5) @@ -342,7 +342,7 @@ public class DestroyReactions { CYANAMIDE_ION_HYDROLYSIS = builder() .id("cyanamide_ion_hydrolysis") .addReactant(DestroyMolecules.CYANAMIDE_ION) - .addReactant(DestroyMolecules.WATER, 3, 1) + .addReactant(DestroyMolecules.WATER, 2, 1) .addProduct(DestroyMolecules.CYANAMIDE) .addProduct(DestroyMolecules.HYDROXIDE, 2) .build(), diff --git a/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyTopologies.java b/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyTopologies.java index 2778e8b1e..7877defbd 100644 --- a/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyTopologies.java +++ b/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/DestroyTopologies.java @@ -221,13 +221,13 @@ public class DestroyTopologies { .atom(LegacyElement.SULFUR, new Vec3(0d, 1.5d, 0d)) // 2 .withBondTo(1, BondType.SINGLE) .attach() - .atom(LegacyElement.SULFUR, new Vec3(0.75d, 1.25d, 0.6124d)) // 3 + .atom(LegacyElement.SULFUR, new Vec3(0.75d, 1.75d, 0.6124d)) // 3 .withBondTo(2, BondType.SINGLE) .attach() .atom(LegacyElement.SULFUR, new Vec3(1.5d, 1.5d, 0d)) // 4 .withBondTo(3, BondType.SINGLE) .attach() - .atom(LegacyElement.SULFUR, new Vec3(1.25d, 0.75d, 0.6124d)) // 5 + .atom(LegacyElement.SULFUR, new Vec3(1.75d, 0.75d, 0.6124d)) // 5 .withBondTo(4, BondType.SINGLE) .attach() .atom(LegacyElement.SULFUR, new Vec3(1.5d, 0d, 0d)) // 6 diff --git a/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/genericreaction/CyanamideAddition.java b/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/genericreaction/CyanamideAddition.java index 46034292f..dd62fc388 100644 --- a/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/genericreaction/CyanamideAddition.java +++ b/src/main/java/com/petrolpark/destroy/chemistry/legacy/index/genericreaction/CyanamideAddition.java @@ -31,6 +31,10 @@ public LegacyReaction generateReaction(GenericReactant re .addGroup(LegacyMolecularStructure.atom(LegacyElement.CARBON), false) .addAtom(LegacyElement.NITROGEN) .addAtom(LegacyElement.NITROGEN, BondType.DOUBLE); + + if(reactant.molecule.isHypothetical()) + structure.addAllHydrogens(); + return reactionBuilder() .addReactant(reactant.molecule) .addReactant(DestroyMolecules.CYANAMIDE) diff --git a/src/main/java/com/petrolpark/destroy/chemistry/legacy/reactionresult/PrecipitateReactionResult.java b/src/main/java/com/petrolpark/destroy/chemistry/legacy/reactionresult/PrecipitateReactionResult.java index fb2bdf8c6..61dd79305 100644 --- a/src/main/java/com/petrolpark/destroy/chemistry/legacy/reactionresult/PrecipitateReactionResult.java +++ b/src/main/java/com/petrolpark/destroy/chemistry/legacy/reactionresult/PrecipitateReactionResult.java @@ -8,6 +8,7 @@ import com.petrolpark.destroy.chemistry.legacy.LegacyReaction; import com.petrolpark.destroy.chemistry.legacy.ReactionResult; import com.petrolpark.destroy.core.chemistry.vat.VatControllerBlockEntity; +import com.petrolpark.item.decay.IDecayingItem; import com.simibubi.create.content.processing.basin.BasinBlockEntity; import net.minecraft.world.item.ItemStack; @@ -38,7 +39,9 @@ public void onBasinReaction(Level level, BasinBlockEntity basin) { @Override public void onVatReaction(Level level, VatControllerBlockEntity vatController) { - ItemHandlerHelper.insertItemStacked(vatController.inventory, precipitate.get(), false); + ItemStack result = precipitate.get(); + IDecayingItem.startDecay(result); + ItemHandlerHelper.insertItemStacked(vatController.inventory, result, false); }; @Override diff --git a/src/main/java/com/petrolpark/destroy/client/DestroyLang.java b/src/main/java/com/petrolpark/destroy/client/DestroyLang.java index 56f78b360..b59a4244e 100644 --- a/src/main/java/com/petrolpark/destroy/client/DestroyLang.java +++ b/src/main/java/com/petrolpark/destroy/client/DestroyLang.java @@ -172,7 +172,7 @@ public static List mixtureIngredientTooltip(CompoundTag fluidTag) { }; private static final float pressureMin = 0f; - private static final float pressureMax = 1000000f; + private static final float pressureMax = 4000000f; private static final float conductivityMin = 0f; private static final float conductivityMax = 100f; diff --git a/src/main/java/com/petrolpark/destroy/client/FogHandler.java b/src/main/java/com/petrolpark/destroy/client/FogHandler.java index 7490508cb..883ddf115 100644 --- a/src/main/java/com/petrolpark/destroy/client/FogHandler.java +++ b/src/main/java/com/petrolpark/destroy/client/FogHandler.java @@ -10,7 +10,9 @@ import com.simibubi.create.foundation.utility.animation.LerpedFloat; import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; +import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; +import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.FogType; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -26,8 +28,8 @@ public class FogHandler { private static final Color BROWN = new Color(0xFF4D2F19); - protected Color targetColor = new Color(0x00FFFFFF); - protected Color lastColor = new Color(0x00FFFFFF); + protected Color targetColor = Color.BLACK; + protected Color lastColor = Color.TRANSPARENT_BLACK; protected LerpedFloat colorMix = LerpedFloat.linear(); public void tick() { @@ -35,9 +37,13 @@ public void tick() { if (colorMix.getValue() >= 1d) lastColor = targetColor; }; - public void setTargetColor(Color color) { + public void setTargetColor(Color color, float partialTicks) { if (color.equals(targetColor)) return; - lastColor = Color.mixColors(lastColor, targetColor, colorMix.getValue()); + if (lastColor.equals(Color.TRANSPARENT_BLACK)) { + lastColor = color; + } else { + lastColor = getColor(partialTicks); + } targetColor = color; colorMix.setValue(0d); colorMix.chase(1d, 0.2d, Chaser.EXP); @@ -56,13 +62,26 @@ public static void onTick(TickEvent.ClientTickEvent event) { if (event.phase == TickEvent.Phase.START) DestroyClient.FOG_HANDLER.tick(); }; + /** + * {@link Camera#getFluidInCamera()} doesn't account for modded fluids so we need a more general check. + */ + private static FogType getFluidInCamera(Camera camera) { + Minecraft mc = Minecraft.getInstance(); + FluidState state = mc.level.getFluidState(camera.getBlockPosition()); + if (camera.getPosition().y < (double)((float)camera.getBlockPosition().getY() + state.getHeight(mc.level, camera.getBlockPosition()))) { + return FogType.WATER; + } + return camera.getFluidInCamera(); + }; + /** * Render fog according to the world's Smog Level. */ @SubscribeEvent public static void renderFog(RenderFog event) { if (!smogEnabled()) return; - if (event.getType() == FogType.NONE) { + + if (getFluidInCamera(event.getCamera()) == FogType.NONE) { Minecraft mc = Minecraft.getInstance(); float smog = (float)PollutionHelper.getPollution(mc.level, mc.player.blockPosition(), PollutionType.SMOG); event.scaleNearPlaneDistance(1f - (0.8f * smog / (float)PollutionType.SMOG.max)); @@ -77,11 +96,12 @@ public static void renderFog(RenderFog event) { @SubscribeEvent public static void colorFog(ComputeFogColor event) { if (!smogEnabled()) return; - if (event.getCamera().getFluidInCamera() == FogType.NONE) { + + if (getFluidInCamera(event.getCamera()) == FogType.NONE) { Minecraft mc = Minecraft.getInstance(); float smog = (float)PollutionHelper.getPollution(mc.level, mc.player.blockPosition(), PollutionType.SMOG); Color existing = new Color(event.getRed(), event.getGreen(), event.getBlue(), 1f); - DestroyClient.FOG_HANDLER.setTargetColor(Color.mixColors(existing, BROWN, 0.8f * smog / (float)PollutionType.SMOG.max)); + DestroyClient.FOG_HANDLER.setTargetColor(Color.mixColors(existing, BROWN, 0.8f * smog / (float)PollutionType.SMOG.max), AnimationTickHolder.getPartialTicks()); Color color = DestroyClient.FOG_HANDLER.getColor(AnimationTickHolder.getPartialTicks()); event.setRed(color.getRedAsFloat()); event.setGreen(color.getGreenAsFloat()); diff --git a/src/main/java/com/petrolpark/destroy/client/stackedtextbox/StackedTextBoxComponent.java b/src/main/java/com/petrolpark/destroy/client/stackedtextbox/StackedTextBoxComponent.java index dbbd20925..0f262ff38 100644 --- a/src/main/java/com/petrolpark/destroy/client/stackedtextbox/StackedTextBoxComponent.java +++ b/src/main/java/com/petrolpark/destroy/client/stackedtextbox/StackedTextBoxComponent.java @@ -5,6 +5,7 @@ import java.util.List; import com.petrolpark.destroy.MoveToPetrolparkLibrary; +import com.petrolpark.destroy.chemistry.legacy.LegacySpecies; import com.petrolpark.destroy.config.DestroyAllConfigs; import net.minecraft.client.Minecraft; @@ -56,10 +57,19 @@ public static class Molecule extends Plain { public Molecule(String value) { super(value); - String[] nameSpaceAndId = value.split(":"); - String key = nameSpaceAndId[0] + ".chemical." + nameSpaceAndId[1]; - String iupacKey = key + ".iupac"; - if (DestroyAllConfigs.CLIENT.chemistry.iupacNames.get() && I18n.exists(iupacKey)) key = iupacKey; + LegacySpecies sp = LegacySpecies.getMolecule(value); + String key; + + if(sp != null) + key = sp.getTranslationKey(DestroyAllConfigs.CLIENT.chemistry.iupacNames.get()); + else + { + String[] nameSpaceAndId = value.split(":"); + key = nameSpaceAndId[0] + ".chemical." + nameSpaceAndId[1]; + String iupacKey = key + ".iupac"; + if (DestroyAllConfigs.CLIENT.chemistry.iupacNames.get() && I18n.exists(iupacKey)) key = iupacKey; + } + String moleculeName = Component.translatable(key).getString(); setWords(moleculeName); }; diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/DestroyJEI.java b/src/main/java/com/petrolpark/destroy/compat/jei/DestroyJEI.java index 54a8e839b..18fd8f790 100644 --- a/src/main/java/com/petrolpark/destroy/compat/jei/DestroyJEI.java +++ b/src/main/java/com/petrolpark/destroy/compat/jei/DestroyJEI.java @@ -76,6 +76,7 @@ import mezz.jei.api.JeiPlugin; import mezz.jei.api.constants.RecipeTypes; import mezz.jei.api.forge.ForgeTypes; +import mezz.jei.api.helpers.IJeiHelpers; import mezz.jei.api.helpers.IPlatformFluidHelper; import mezz.jei.api.recipe.category.IRecipeCategory; import mezz.jei.api.recipe.vanilla.IJeiAnvilRecipe; @@ -87,7 +88,6 @@ import mezz.jei.api.registration.IRecipeRegistration; import mezz.jei.api.registration.ISubtypeRegistration; import mezz.jei.api.runtime.IJeiRuntime; -import mezz.jei.library.plugins.vanilla.anvil.AnvilRecipe; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; @@ -330,7 +330,7 @@ public void registerRecipes(IRecipeRegistration registration) { registration.addRecipes(RecipeTypes.CRAFTING, ExtendedDurationFireworkRocketRecipe.exampleRecipes()); // Anvil repairs - registration.addRecipes(RecipeTypes.ANVIL, getAnvilRepairs()); + registration.addRecipes(RecipeTypes.ANVIL, getAnvilRepairs(registration)); }; @Override @@ -437,7 +437,7 @@ protected void finalizeBuilding(mezz.jei.api.recipe.RecipeType type, CreateRe }; - private static List getAnvilRepairs() { + private static List getAnvilRepairs(IRecipeRegistration registration) { List> repairables = List.of( Pair.of(DestroyItems.HAZMAT_SUIT.get(), DestroyArmorMaterials.HAZMAT.getRepairIngredient()), Pair.of(DestroyItems.HAZMAT_LEGGINGS.get(), DestroyArmorMaterials.HAZMAT.getRepairIngredient()), @@ -449,14 +449,19 @@ private static List getAnvilRepairs() { Pair.of(DestroyItems.GOLD_LABORATORY_GOGGLES.get(), DestroyItems.GOLD_LABORATORY_GOGGLES.get().getRepairIngredient()) ); - return repairables.stream().map(pair -> makeRepairRecipe(new ItemStack(pair.getFirst()), pair.getSecond())).toList(); + return repairables.stream().map(pair -> makeRepairRecipe(registration, new ItemStack(pair.getFirst()), pair.getSecond())).toList(); }; - public static IJeiAnvilRecipe makeRepairRecipe(ItemStack input, Ingredient repairItem) { + public static IJeiAnvilRecipe makeRepairRecipe(IRecipeRegistration registration, ItemStack input, Ingredient repairItem) { ItemStack halfDurability = input.copy(); halfDurability.setDamageValue(halfDurability.getMaxDamage() / 2); ItemStack threeQuarterDurability = input.copy(); threeQuarterDurability.setDamageValue(threeQuarterDurability.getMaxDamage() * 3 / 4); - return new AnvilRecipe(Collections.singletonList(halfDurability), Arrays.asList(repairItem.getItems()), Collections.singletonList(threeQuarterDurability), null); + + return registration.getVanillaRecipeFactory().createAnvilRecipe( + Collections.singletonList(halfDurability), + Arrays.asList(repairItem.getItems()), + Collections.singletonList(threeQuarterDurability) + ); }; }; diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/MoleculeJEIIngredient.java b/src/main/java/com/petrolpark/destroy/compat/jei/MoleculeJEIIngredient.java index 3c293de07..e7db104b4 100644 --- a/src/main/java/com/petrolpark/destroy/compat/jei/MoleculeJEIIngredient.java +++ b/src/main/java/com/petrolpark/destroy/compat/jei/MoleculeJEIIngredient.java @@ -4,6 +4,7 @@ import javax.annotation.Nullable; +import com.mojang.blaze3d.vertex.PoseStack; import com.petrolpark.destroy.Destroy; import com.petrolpark.destroy.DestroyFluids; import com.petrolpark.destroy.DestroyItems; @@ -12,19 +13,27 @@ import com.petrolpark.destroy.chemistry.legacy.ReadOnlyMixture; import com.petrolpark.destroy.chemistry.legacy.index.DestroyMolecules; import com.petrolpark.destroy.chemistry.minecraft.MixtureFluid; +import com.petrolpark.destroy.compat.jei.render.MoleculeBatchRenderer; import com.petrolpark.destroy.config.DestroyAllConfigs; import com.petrolpark.destroy.core.chemistry.MoleculeDisplayItem; import com.petrolpark.destroy.core.chemistry.MoleculeDisplayItem.MoleculeTooltip; +import com.petrolpark.destroy.core.chemistry.MoleculeRenderer; import com.petrolpark.destroy.core.chemistry.storage.testtube.TestTubeItem; import mezz.jei.api.gui.builder.ITooltipBuilder; import mezz.jei.api.ingredients.IIngredientHelper; import mezz.jei.api.ingredients.IIngredientRenderer; import mezz.jei.api.ingredients.IIngredientType; +import mezz.jei.api.ingredients.rendering.BatchRenderElement; import mezz.jei.api.ingredients.subtypes.UidContext; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; @@ -103,11 +112,49 @@ public ItemStack getCheatItemStack(LegacySpecies ingredient) { public static final IIngredientRenderer RENDERER = new IIngredientRenderer() { + public static final ResourceLocation FONT_LOCATION = Destroy.asResource("charge"); + public static final Style FONT = Style.EMPTY.withFont(FONT_LOCATION); + private final MoleculeBatchRenderer.Cache batchRenderer = new MoleculeBatchRenderer.Cache(); + @Override public void render(GuiGraphics graphics, LegacySpecies ingredient) { - graphics.renderItem(MoleculeDisplayItem.with(ingredient), 0, 0); // TODO check positioning + if(DestroyAllConfigs.CLIENT.chemistry.fancyMoleculeRendering.get()) { + MoleculeRenderer renderer = ingredient.getRenderer(); + + MultiBufferSource.BufferSource buffer = graphics.bufferSource(); + PoseStack poseStack = graphics.pose(); + poseStack.pushPose(); + renderer.renderItem(0, 0, 16, 16, poseStack, buffer); + buffer.endBatch(); + + if (ingredient.getCharge() != 0) + { + String s = ingredient.getCharge() > 0 ? "+" : "-"; + int col = 0xFFFFFF; + + if (Math.abs(ingredient.getCharge()) > 1) + s = Math.abs(ingredient.getCharge()) + s; + + poseStack.pushPose(); + poseStack.translate(0, 0, 100); + Font fontRenderer = Minecraft.getInstance().font; + graphics.drawString(fontRenderer, FormattedCharSequence.forward(s, FONT), -1, -1, col, true); + poseStack.popPose(); + } + poseStack.popPose(); + } else { + graphics.renderItem(MoleculeDisplayItem.with(ingredient), 0, 0); // TODO check positioning + }; }; + @Override + public void renderBatch(GuiGraphics graphics, List> elements) { + if(DestroyAllConfigs.CLIENT.chemistry.fancyMoleculeRendering.get()) + batchRenderer.renderBatch(graphics, elements); + else + IIngredientRenderer.super.renderBatch(graphics, elements); + } + @Override public void getTooltip(ITooltipBuilder tooltip, LegacySpecies ingredient, TooltipFlag tooltipFlag) { tooltip.add(ingredient.getName(DestroyAllConfigs.CLIENT.chemistry.iupacNames.get())); diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedBlowpipe.java b/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedBlowpipe.java index 37c4264c0..e5ddd3053 100644 --- a/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedBlowpipe.java +++ b/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedBlowpipe.java @@ -1,6 +1,7 @@ package com.petrolpark.destroy.compat.jei.animation; import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import com.petrolpark.destroy.DestroyBlocks; @@ -8,9 +9,11 @@ import com.petrolpark.destroy.content.processing.glassblowing.BlowpipeBlockEntityRenderer; import com.petrolpark.destroy.content.processing.glassblowing.GlassblowingRecipe; import com.simibubi.create.compat.jei.category.animations.AnimatedKinetics; +import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.core.Direction; import net.minecraft.util.Brightness; @@ -38,7 +41,10 @@ public void draw(GlassblowingRecipe recipe, FluidStack fluid, GuiGraphics graphi .rotateY(180d) .translate(-0.5d, -0.5d, 0d); ms.pushPose(); - BlowpipeBlockEntityRenderer.render(recipe, fluid, Math.min((AnimationTickHolder.getRenderTime() % 120f) / 100f, 1f), ms, graphics.bufferSource(), Brightness.FULL_BRIGHT.pack(), OverlayTexture.NO_OVERLAY); + UIRenderHelper.flipForGuiRender(ms); + RenderSystem.disableDepthTest(); + BlowpipeBlockEntityRenderer.render(recipe, fluid, Math.min((AnimationTickHolder.getRenderTime() % 120f) / 100f, 1f), ms, graphics.bufferSource(), LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY); + RenderSystem.enableDepthTest(); ms.popPose(); ms.popPose(); diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedSieve.java b/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedSieve.java index a4f95e2a6..08fa08441 100644 --- a/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedSieve.java +++ b/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedSieve.java @@ -24,9 +24,9 @@ public void draw(GuiGraphics graphics, int xOffset, int yOffset) { ms.pushPose(); TransformStack.cast(ms) .translate(0d, -0.5d, 0.5d) - .rotateZ(90) - .rotateY(getCurrentAngle()) - .translateBack(0.5d, 0d, 0.5d); + .rotateY(90) + .rotateZ(getCurrentAngle()) + .translateBack(0.5d, -0.5d, 0d); blockElement(DestroyPartials.MECHANICAL_SIEVE_SHAFT) .render(graphics); ms.popPose(); diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedTreeTap.java b/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedTreeTap.java index 6cea73260..a7ab520bd 100644 --- a/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedTreeTap.java +++ b/src/main/java/com/petrolpark/destroy/compat/jei/animation/AnimatedTreeTap.java @@ -25,8 +25,7 @@ public void draw(GuiGraphics graphics, int xOffset, int yOffset) { blockElement(DestroyPartials.TREE_TAP_ARM) .rotateBlock(9f * Mth.sin(AnimationTickHolder.getRenderTime() / 4f), 0, 0) - .withRotationOffset(new Vec3(0, -4 / 16f, -1 / 16f)) - .atLocal(0f, - 12 / 16f, 7 / 16f) + .withRotationOffset(new Vec3(0, 0.5, 0.5)) .scale(scale) .render(graphics); diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/animation/JEIMoleculeRenderer.java b/src/main/java/com/petrolpark/destroy/compat/jei/animation/JEIMoleculeRenderer.java index 283d1bafe..958eb42d9 100644 --- a/src/main/java/com/petrolpark/destroy/compat/jei/animation/JEIMoleculeRenderer.java +++ b/src/main/java/com/petrolpark/destroy/compat/jei/animation/JEIMoleculeRenderer.java @@ -12,16 +12,6 @@ public JEIMoleculeRenderer(LegacySpecies molecule) { super(molecule); }; - @Override - public int getWidth() { - return width; - }; - - @Override - public int getHeight() { - return height; - }; - @Override public void draw(GuiGraphics graphics, int xOffset, int yOffset) { render(xOffset, yOffset, graphics); diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/category/FlameRetardantApplicationCategory.java b/src/main/java/com/petrolpark/destroy/compat/jei/category/FlameRetardantApplicationCategory.java index 9ace125b4..cd838111f 100644 --- a/src/main/java/com/petrolpark/destroy/compat/jei/category/FlameRetardantApplicationCategory.java +++ b/src/main/java/com/petrolpark/destroy/compat/jei/category/FlameRetardantApplicationCategory.java @@ -39,7 +39,8 @@ public FlameRetardantApplicationCategory(Info i @Override public void setRecipe(IRecipeLayoutBuilder builder, FlameRetardantApplicationRecipe recipe, IFocusGroup focuses) { boolean example = focuses.getFocuses(VanillaTypes.ITEM_STACK, RecipeIngredientRole.INPUT).findAny().isEmpty(); - List items = example ? exampleItems : focuses.getItemStackFocuses(RecipeIngredientRole.INPUT).map(IFocus::getTypedValue).map(ITypedIngredient::getIngredient).toList(); + List items = example ? exampleItems : focuses.getItemStackFocuses(RecipeIngredientRole.INPUT).map(IFocus::getTypedValue).map(ITypedIngredient::getIngredient) + .map(i -> i.copyWithCount(1)).toList(); builder.addSlot(RecipeIngredientRole.INPUT, 27, 51) .setBackground(getRenderedSlot(), -1, -1) diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/category/ReactionCategory.java b/src/main/java/com/petrolpark/destroy/compat/jei/category/ReactionCategory.java index 298bff3ba..79a09c1de 100644 --- a/src/main/java/com/petrolpark/destroy/compat/jei/category/ReactionCategory.java +++ b/src/main/java/com/petrolpark/destroy/compat/jei/category/ReactionCategory.java @@ -1,21 +1,19 @@ package com.petrolpark.destroy.compat.jei.category; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - +import java.util.*; + +import com.ibm.icu.text.DecimalFormat; +import com.petrolpark.destroy.chemistry.legacy.*; +import mezz.jei.api.gui.drawable.IDrawable; +import net.minecraft.client.gui.Font; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import org.joml.Vector2i; import com.petrolpark.client.rendering.PetrolparkGuiTexture; import com.petrolpark.compat.jei.JEITextureDrawable; import com.petrolpark.destroy.Destroy; import com.petrolpark.destroy.DestroyItems; -import com.petrolpark.destroy.chemistry.legacy.IItemReactant; -import com.petrolpark.destroy.chemistry.legacy.LegacySpecies; -import com.petrolpark.destroy.chemistry.legacy.LegacyReaction; import com.petrolpark.destroy.chemistry.legacy.reactionresult.PrecipitateReactionResult; import com.petrolpark.destroy.client.DestroyLang; import com.petrolpark.destroy.client.stackedtextbox.AbstractStackedTextBox; @@ -103,6 +101,16 @@ private static void tooManyMoleculesWarning(boolean reactants, LegacyReaction re Destroy.LOGGER.warn("Reaction '"+reaction.getFullId()+"' has too many " + (reactants ? "reactants" : "products") + " to fit on JEI."); }; + public static float getSpeciesWeightForSorting(LegacySpecies s) { + LegacyAtom atom = Collections.max(s.getAtoms(), Comparator.comparing(a -> a.getElement() == LegacyElement.R_GROUP ? a.rGroupNumber : -1)); + float weight = -s.getMass(); + + if(atom.getElement() == LegacyElement.R_GROUP) + weight -= 1000f - 100f * atom.rGroupNumber; + + return weight; + } + @Override public void setRecipe(IRecipeLayoutBuilder builder, T recipe, IFocusGroup focuses) { super.setRecipe(builder, recipe, focuses); @@ -113,11 +121,20 @@ public void setRecipe(IRecipeLayoutBuilder builder, T recipe, IFocusGroup focuse int numberOfReactants = getNumberOfReactants(reaction); if (numberOfReactants >= 6) tooManyMoleculesWarning(true, reaction); - for (LegacySpecies reactant : reaction.getReactants()) { + float molesPerItem = reaction.getMolesPerItem(); + if(molesPerItem == 0f) molesPerItem = 1f; + + Collection precipitates = reaction.hasResult() ? reaction.getResult().getAllPrecipitates() : Collections.emptyList(); + for (PrecipitateReactionResult precipitate : precipitates) { + molesPerItem = precipitate.getRequiredMoles(); + } + + for (LegacySpecies reactant : reaction.getReactants().stream().sorted(Comparator.comparing(ReactionCategory::getSpeciesWeightForSorting)).toList()) { if (i >= 6) continue; Vector2i pos = getReactantRenderPosition(i, numberOfReactants); builder.addSlot(RecipeIngredientRole.INPUT, pos.x, pos.y) .addIngredient(MoleculeJEIIngredient.TYPE, reactant) + .setOverlay(createOverlay(reaction.getReactantMolarRatio(reactant) * molesPerItem), 0, 0) .addRichTooltipCallback(ReactionTooltipHelper.reactantTooltip(reaction, reactant)) .setBackground(getRenderedSlot(), -1, -1); i++; @@ -135,8 +152,6 @@ public void setRecipe(IRecipeLayoutBuilder builder, T recipe, IFocusGroup focuse }; }; - Collection precipitates = reaction.hasResult() ? reaction.getResult().getAllPrecipitates() : Collections.emptyList(); - int j = 0; int numberOfProducts = reaction.getProducts().size() + precipitates.size(); @@ -153,10 +168,11 @@ public void setRecipe(IRecipeLayoutBuilder builder, T recipe, IFocusGroup focuse int l = numberOfProducts == 4 ? 2 : 3; - for (LegacySpecies product : reaction.getProducts()) { + for (LegacySpecies product : reaction.getProducts().stream().sorted(Comparator.comparing(ReactionCategory::getSpeciesWeightForSorting)).toList()) { if (j >= 6) continue; builder.addSlot(RecipeIngredientRole.OUTPUT, productsXOffset + (19 * (j % l)), productYOffset + (j / l) * 19) .addIngredient(MoleculeJEIIngredient.TYPE, product) + .setOverlay(createOverlay(reaction.getProductMolarRatio(product) * molesPerItem), 0, 0) .addRichTooltipCallback(ReactionTooltipHelper.productTooltip(reaction, product)) .setBackground(getRenderedSlot(), -1, -1); j++; @@ -175,7 +191,7 @@ public void setRecipe(IRecipeLayoutBuilder builder, T recipe, IFocusGroup focuse int m = 0; if (reaction.needsUV()) m++; // If there is UV catalyst, this is already drawn - for (LegacySpecies catalyst : reaction.getOrders().keySet()) { + for (LegacySpecies catalyst : reaction.getOrders().keySet().stream().sorted(Comparator.comparing(ReactionCategory::getSpeciesWeightForSorting)).toList()) { if (reaction.getReactants().contains(catalyst)) continue; Vector2i pos = getCatalystRenderPosition(m, numberOfCatalysts); builder.addSlot(RecipeIngredientRole.CATALYST, pos.x, pos.y) @@ -253,5 +269,37 @@ public void draw(T recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphic PetrolparkGuiTexture.JEI_LINE.render(graphics, 2, 85); (recipe.getReaction().displayAsReversible() ? PetrolparkGuiTexture.JEI_EQUILIBRIUM_ARROW : AllGuiTextures.JEI_ARROW).render(graphics, yOffset + 37, 46); }; - + + private static DecimalFormat df = new DecimalFormat("#.#"); + + public IDrawable createOverlay(float molarRatio) { + String s = molarRatio == 1f ? "" : df.format(molarRatio); + float scale = s.length() > 2 ? 0.75f : 1f; + + return new IDrawable() { + + @Override + public int getWidth() {return 16;} + + @Override + public int getHeight() {return 16;} + + @Override + public void draw(GuiGraphics graphics, int xOffset, int yOffset) { + if(s.isEmpty()) return; + + graphics.pose().pushPose(); + graphics.pose().translate(0, 0, 0); + graphics.pose().scale(scale, scale, 1); + + Font fontRenderer = Minecraft.getInstance().font; + graphics.drawString(fontRenderer, s, + (xOffset + getWidth()) / scale - fontRenderer.width(s) + 1, + (yOffset + getHeight()) / scale - 7, + 0xFFFFFF, true); + + graphics.pose().popPose(); + } + }; + } }; diff --git a/src/main/java/com/petrolpark/destroy/compat/jei/render/MoleculeBatchRenderer.java b/src/main/java/com/petrolpark/destroy/compat/jei/render/MoleculeBatchRenderer.java new file mode 100644 index 000000000..4e52849e4 --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/compat/jei/render/MoleculeBatchRenderer.java @@ -0,0 +1,94 @@ +package com.petrolpark.destroy.compat.jei.render; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.mojang.blaze3d.vertex.PoseStack; +import com.petrolpark.destroy.Destroy; +import com.petrolpark.destroy.chemistry.legacy.LegacySpecies; +import com.petrolpark.destroy.core.chemistry.MoleculeRenderer; +import mezz.jei.api.ingredients.rendering.BatchRenderElement; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; + +import java.util.ArrayList; +import java.util.List; + +public class MoleculeBatchRenderer { + + private final List molecules; + private final List moleculesWithCharge; + + public static final ResourceLocation FONT_LOCATION = Destroy.asResource("charge"); + public static final Style FONT = Style.EMPTY.withFont(FONT_LOCATION); + + public MoleculeBatchRenderer(Minecraft minecraft, List> elements) { + molecules = new ArrayList<>(); + moleculesWithCharge = new ArrayList<>(); + + for (BatchRenderElement element : elements) { + int charge = element.ingredient().getCharge(); + FormattedCharSequence chargeStr = null; + if (charge != 0) + { + String s = charge > 0 ? "+" : "-"; + if (Math.abs(charge) > 1) + s = Math.abs(charge) + s; + chargeStr = FormattedCharSequence.forward(s, FONT); + } + + BatchedMolecule m = new BatchedMolecule(element.ingredient().getRenderer(), element.x(), element.y(), chargeStr); + molecules.add(m); + if(chargeStr != null) moleculesWithCharge.add(m); + } + } + + public void render(GuiGraphics graphics, Minecraft minecraft) { + PoseStack poseStack = graphics.pose(); + poseStack.pushPose(); + + MultiBufferSource.BufferSource buffer = graphics.bufferSource(); + for (BatchedMolecule mol : molecules) { + MoleculeRenderer renderer = mol.renderer; + renderer.renderItem(mol.x, mol.y, 16, 16, poseStack, buffer); + } + buffer.endBatch(); + + for (BatchedMolecule mol : moleculesWithCharge) { + poseStack.pushPose(); + poseStack.translate(mol.x, mol.y, 100); + Font fontRenderer = Minecraft.getInstance().font; + graphics.drawString(fontRenderer, mol.charge, -1, -1, 0xFFFFFF, true); + poseStack.popPose(); + } + + poseStack.popPose(); + } + + private record BatchedMolecule(MoleculeRenderer renderer, int x, int y, FormattedCharSequence charge) {} + + public static class Cache { + private final LoadingCache>, MoleculeBatchRenderer> cache = + CacheBuilder.newBuilder() + .maximumSize(6) + .build(new CacheLoader<>() { + @Override + public MoleculeBatchRenderer load(List> elements) { + Minecraft minecraft = Minecraft.getInstance(); + return new MoleculeBatchRenderer(minecraft, elements); + } + }); + + public void renderBatch(GuiGraphics guiGraphics, List> elements) { + MoleculeBatchRenderer batchData = cache.getUnchecked(elements); + + Minecraft minecraft = Minecraft.getInstance(); + batchData.render(guiGraphics, minecraft); + } + } +} diff --git a/src/main/java/com/petrolpark/destroy/config/DestroyBlocksConfigs.java b/src/main/java/com/petrolpark/destroy/config/DestroyBlocksConfigs.java index 87737c335..291f5be5c 100644 --- a/src/main/java/com/petrolpark/destroy/config/DestroyBlocksConfigs.java +++ b/src/main/java/com/petrolpark/destroy/config/DestroyBlocksConfigs.java @@ -52,9 +52,14 @@ public class DestroyBlocksConfigs extends DestroyConfigBase { public final ConfigGroup vat = group(0, "vat", "Vat"); public final ConfigBool vatExplodesAtHighPressure = b(true, "vatExplodesAtHighPressure", "Whether Vats explode if the pressure exceeds the maximum of the weakest block."); public final ConfigInt simulationLevel = i(10, "simulationLevel", "How many times per tick reactions and thermodynamics are simulated.", "Increasing this may cause lag. Decreasing it can cause flickering in Vats."); - public final ConfigFloat blazeBurnerHeatingPower = f(15000000f, -Float.MAX_VALUE, Float.MAX_VALUE, "blazeBurnerHeatingPower", "The power supplied by kindled Blaze Burners to Vats and Basins"); + + /*public final ConfigFloat blazeBurnerHeatingPower = f(15000000f, -Float.MAX_VALUE, Float.MAX_VALUE, "blazeBurnerHeatingPower", "The power supplied by kindled Blaze Burners to Vats and Basins"); public final ConfigFloat blazeBurnerSuperHeatingPower = f(50000000f, -Float.MAX_VALUE, Float.MAX_VALUE, "blazeBurnerSuperHeatingPower", "The power supplied by superheating Blaze Burners to Vats and Basins"); - public final ConfigFloat coolerHeatingPower = f(-30000000f, -Float.MAX_VALUE, Float.MAX_VALUE, "coolerHeatingPower", "The power supplied by cooling Refrigerstraytors to Vats and Basins"); + public final ConfigFloat coolerHeatingPower = f(-30000000f, -Float.MAX_VALUE, Float.MAX_VALUE, "coolerHeatingPower", "The power supplied by cooling Refrigerstraytors to Vats and Basins");*/ + + public final ConfigFloat blazeBurnerHeatingTemperature = f(500f, -Float.MAX_VALUE, Float.MAX_VALUE, "blazeBurnerHeatingTemperature", "The difference in temperature between kindled Blaze Burners and the environment."); + public final ConfigFloat blazeBurnerSuperHeatingTemperature = f(1500f, -Float.MAX_VALUE, Float.MAX_VALUE, "blazeBurnerSuperHeatingTemperature", "The difference in temperature between superheating Blaze Burners and the environment"); + public final ConfigFloat coolerHeatingTemperature = f(-500f, -Float.MAX_VALUE, Float.MAX_VALUE, "coolerHeatingTemperature", "The difference in temperature between cooling Refrigerstraytors and the environment"); @Override public String getName() { diff --git a/src/main/java/com/petrolpark/destroy/config/DestroyClientChemistryConfigs.java b/src/main/java/com/petrolpark/destroy/config/DestroyClientChemistryConfigs.java index 2f1c3f872..9146fb4a1 100644 --- a/src/main/java/com/petrolpark/destroy/config/DestroyClientChemistryConfigs.java +++ b/src/main/java/com/petrolpark/destroy/config/DestroyClientChemistryConfigs.java @@ -6,6 +6,7 @@ public class DestroyClientChemistryConfigs extends DestroyConfigBase { public final ConfigBool iupacNames = b(false, "iupacNames", Comments.iupacNames, Comments.reloadRequired); public final ConfigEnum temperatureUnit = e(TemperatureUnit.DEGREES_CELCIUS, "temperatureUnit", Comments.temperatureUnit, Comments.reloadRequired); + public final ConfigBool fancyMoleculeRendering = b(true, "fancyMoleculeRendering", Comments.fancyMoleculeRendering); public final ConfigBool nerdMode = b(false, "nerdMode", Comments.nerdMode); @Override @@ -17,6 +18,7 @@ private static class Comments { static String iupacNames = "Show IUPAC systematic names rather than common names", temperatureUnit = "Units of temperature to display by default", + fancyMoleculeRendering = "Display molecules as their 3D representation in JEI", nerdMode = "Display additional technical details in some tooltips", reloadRequired = "[Reload may be required to take full effect]"; }; diff --git a/src/main/java/com/petrolpark/destroy/content/logistics/creativepump/CreativePumpBlockEntity.java b/src/main/java/com/petrolpark/destroy/content/logistics/creativepump/CreativePumpBlockEntity.java index 661c5f738..a77bfc495 100644 --- a/src/main/java/com/petrolpark/destroy/content/logistics/creativepump/CreativePumpBlockEntity.java +++ b/src/main/java/com/petrolpark/destroy/content/logistics/creativepump/CreativePumpBlockEntity.java @@ -9,13 +9,17 @@ import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard; import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter; import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.Components; +import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.infrastructure.config.AllConfigs; +import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -37,15 +41,20 @@ public void addBehaviours(List behaviours) { pumpSpeedBehaviour = new ScrollValueBehaviour(Component.translatable("block.destroy.creative_pump.speed"), this, new CreativePumpValueSlot()) { @Override public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) { - return new ValueSettingsBoard(label, max, 16, ImmutableList.of(Component.translatable("block.destroy.creative_pump.speed")), new ValueSettingsFormatter(ValueSettings::format)); + return new ValueSettingsBoard(label, max, 16, ImmutableList.of(Components.literal("\u2192").withStyle(ChatFormatting.BOLD)), new ValueSettingsFormatter(this::formatSettings)); + }; + + public MutableComponent formatSettings(ValueSettings settings) { + return Lang.number(Math.max(1, settings.value())).component(); }; } - .between(0, AllConfigs.server().kinetics.maxRotationSpeed.get()) + .between(1, AllConfigs.server().kinetics.maxRotationSpeed.get()) .withCallback(i -> { simulatedSpeed = i; - updatePressureChange(); + if (level != null && !level.isClientSide) + updatePressureChange(); }); - pumpSpeedBehaviour.setValue(simulatedSpeed); + pumpSpeedBehaviour.setValue(16); behaviours.add(pumpSpeedBehaviour); }; diff --git a/src/main/java/com/petrolpark/destroy/content/logistics/siphon/SiphonBlockEntity.java b/src/main/java/com/petrolpark/destroy/content/logistics/siphon/SiphonBlockEntity.java index 2df80a9fb..204ea83a0 100644 --- a/src/main/java/com/petrolpark/destroy/content/logistics/siphon/SiphonBlockEntity.java +++ b/src/main/java/com/petrolpark/destroy/content/logistics/siphon/SiphonBlockEntity.java @@ -46,7 +46,6 @@ public class SiphonBlockEntity extends SmartBlockEntity implements IHaveLabGoggl public ScrollValueBehaviour settings; public DestroyAdvancementBehaviour advancementBehaviour; - private boolean giveAdvancementWhenEmptied = false; public SiphonBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); @@ -71,14 +70,12 @@ public void addBehaviours(List behaviours) { protected void read(CompoundTag tag, boolean clientPacket) { super.read(tag, clientPacket); leftToDrain = tag.getInt("LeftToDrain"); - if (tag.contains("GiveAdvancementWhenEmptied", Tag.TAG_BYTE)) giveAdvancementWhenEmptied = tag.getBoolean("GiveAdvancementWhenEmptied"); }; @Override protected void write(CompoundTag tag, boolean clientPacket) { super.write(tag, clientPacket); tag.putInt("LeftToDrain", leftToDrain); - if (advancementBehaviour.getPlayer() != null) tag.putBoolean("GiveAdvanementWhenEmptied", giveAdvancementWhenEmptied); }; @Override @@ -111,8 +108,10 @@ public SiphonFluidHandler(IFluidHandler... handlers) { public FluidStack drain(int maxDrain, FluidAction action) { maxDrain = Math.min(maxDrain, leftToDrain); FluidStack drained = super.drain(maxDrain, action); - if (action.execute()) leftToDrain -= drained.getAmount(); - checkAdvancement(); + if (action.execute()) { + leftToDrain -= drained.getAmount(); + if(!drained.isEmpty()) checkAdvancement(); + } return drained; }; @@ -122,13 +121,15 @@ public FluidStack drain(FluidStack resource, FluidAction action) { if (toDrain.isEmpty()) return FluidStack.EMPTY; toDrain.setAmount(Math.min(resource.getAmount(), leftToDrain)); FluidStack drained = super.drain(toDrain, action); - if (action.execute()) leftToDrain -= drained.getAmount(); - checkAdvancement(); + if (action.execute()) { + leftToDrain -= drained.getAmount(); + if(!drained.isEmpty()) checkAdvancement(); + } return drained; }; private void checkAdvancement() { - if (giveAdvancementWhenEmptied && leftToDrain == 0) { + if (leftToDrain == 0) { advancementBehaviour.awardDestroyAdvancement(DestroyAdvancementTrigger.SIPHON); }; }; diff --git a/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackBlockEntity.java b/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackBlockEntity.java index a014467b9..e6a51df1e 100644 --- a/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackBlockEntity.java +++ b/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackBlockEntity.java @@ -149,6 +149,24 @@ public Float getTargetAngle() { return angle; }; + public float getRenderAngle() { + Float angle = getTargetAngle(); + if(angle == null) + { + BlockState blockState = getBlockState(); + Direction facing = PumpjackBlock.getFacing(blockState); + Direction.Axis axis = facing.getCounterClockWise().getAxis(); + BlockPos pos = getCamPos(); + double d = (((axis == Direction.Axis.X) ? 0 : pos.getX()) + ((axis == Direction.Axis.Y) ? 0 : pos.getY()) + + ((axis == Direction.Axis.Z) ? 0 : pos.getZ())) % 2; + angle = d == 0 ? 22.5f * Mth.PI / 180.f : 0f; + + if (axis.isHorizontal() && (facing.getAxis() == Axis.X ^ facing.getAxisDirection() == AxisDirection.NEGATIVE)) + angle *= -1; + } + return angle; + }; + @OnlyIn(Dist.CLIENT) public void playClientSound() { if (getTargetAngle() == null) return; @@ -164,14 +182,18 @@ public void playClientSound() { }; }; + public BlockPos getCamPos() { + Direction facing = PumpjackBlock.getFacing(getBlockState()); + return getBlockPos().relative(facing, 1); + } + @Nullable @SuppressWarnings("null") public PumpjackCamBlockEntity getCam() { PumpjackCamBlockEntity cam = source.get(); if (cam == null || cam.isRemoved() || !cam.canPower(getBlockPos())) { if (cam != null) source = new WeakReference<>(null); - Direction facing = PumpjackBlock.getFacing(getBlockState()); - BlockEntity anyCamAt = getLevel().getBlockEntity(getBlockPos().relative(facing, 1)); // It thinks getLevel() might be null + BlockEntity anyCamAt = getLevel().getBlockEntity(getCamPos()); // It thinks getLevel() might be null if (anyCamAt instanceof PumpjackCamBlockEntity newCam && newCam.canPower(getBlockPos())) { cam = newCam; source = new WeakReference<>(cam); diff --git a/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackInstance.java b/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackInstance.java index 7cf5fc22e..07d5d8fb1 100644 --- a/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackInstance.java +++ b/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackInstance.java @@ -8,6 +8,7 @@ import com.petrolpark.destroy.client.DestroyPartials; import com.simibubi.create.foundation.utility.AngleHelper; +import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.Mth; @@ -18,6 +19,8 @@ public class PumpjackInstance extends BlockEntityInstance i protected final ModelData beam; protected final ModelData pump; + private static final double beamRotation = Math.asin(5 / 17d); + public PumpjackInstance(MaterialManager materialManager, PumpjackBlockEntity blockEntity) { super(materialManager, blockEntity); @@ -31,7 +34,7 @@ public PumpjackInstance(MaterialManager materialManager, PumpjackBlockEntity blo .getModel(DestroyPartials.PUMPJACK_LINKAGE, blockState) .createInstance(); - beam = materialManager.defaultSolid() + beam = materialManager.defaultCutout() .material(Materials.TRANSFORMED) .getModel(DestroyPartials.PUMPJACK_BEAM, blockState) .createInstance(); @@ -44,14 +47,7 @@ public PumpjackInstance(MaterialManager materialManager, PumpjackBlockEntity blo @Override public void beginFrame() { - Float angle = blockEntity.getTargetAngle(); - if (angle == null) { - cam.setEmptyTransform(); - linkage.setEmptyTransform(); - beam.setEmptyTransform(); - pump.setEmptyTransform(); - return; - }; + float angle = blockEntity.getRenderAngle(); Direction facing = PumpjackBlock.getFacing(blockState); @@ -65,10 +61,10 @@ public void beginFrame() { .unCentre(); transformed(linkage, facing) - .translate(0d, -5 / 16d, 1d) + .translate(0d, -4.5 / 16d, 1d) .translate(0d, Mth.sin(angle) * 5 / 16d, -Mth.cos(angle) * 5 / 16d) .centre() - .rotateX(Mth.cos(angle) * 10d) + .rotateXRadians((Mth.cos(angle)) * beamRotation * 0.73d) .centre() .translate(0d, 0d, -1d) .unCentre() @@ -77,7 +73,7 @@ public void beginFrame() { transformed(beam, facing) .translate(0d, 1d, 0d) .centre() - .rotateX((Mth.sin(angle) - 1) * -18d) + .rotateXRadians((Mth.sin(angle)) * -beamRotation) .centre() .translate(0d, -1d, 0d) .unCentre() diff --git a/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackRenderer.java b/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackRenderer.java index 67bef0f74..18a17a914 100644 --- a/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackRenderer.java +++ b/src/main/java/com/petrolpark/destroy/content/oil/pumpjack/PumpjackRenderer.java @@ -1,9 +1,11 @@ package com.petrolpark.destroy.content.oil.pumpjack; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.core.PartialModel; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.petrolpark.destroy.client.DestroyPartials; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; import com.simibubi.create.foundation.render.CachedBufferer; import com.simibubi.create.foundation.render.SuperByteBuffer; @@ -12,6 +14,7 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.Mth; import net.minecraft.world.level.block.state.BlockState; @@ -24,10 +27,9 @@ public PumpjackRenderer(BlockEntityRendererProvider.Context context) {} @Override protected void renderSafe(PumpjackBlockEntity pumpjack, float partialTicks, PoseStack ms, MultiBufferSource bufferSource, int light, int overlay) { - //if (Backend.canUseInstancing(pumpjack.getLevel())) return; Can't use instancing because it can't render cutout for some reason + if (Backend.canUseInstancing(pumpjack.getLevel())) return; - Float angle = pumpjack.getTargetAngle(); - if (angle == null) angle = 0f; + float angle = pumpjack.getRenderAngle(); BlockState blockState = pumpjack.getBlockState(); Direction facing = PumpjackBlock.getFacing(blockState); diff --git a/src/main/java/com/petrolpark/destroy/content/processing/cooler/CoolerBlockEntity.java b/src/main/java/com/petrolpark/destroy/content/processing/cooler/CoolerBlockEntity.java index 6fc238a96..dc96d453e 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/cooler/CoolerBlockEntity.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/cooler/CoolerBlockEntity.java @@ -2,6 +2,7 @@ import java.util.List; +import com.petrolpark.destroy.chemistry.api.util.Constants; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -49,6 +50,8 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import com.petrolpark.destroy.chemistry.api.util.Constants; + public class CoolerBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation { private static final int TANK_CAPACITY = 1000; @@ -99,7 +102,7 @@ private void consumeFluid() { totalMolesPerBucket += concentration; if (molecule.hasTag(DestroyMolecules.Tags.REFRIGERANT)) { totalRefrigerantMolesPerBucket += concentration; - coolingPower += DestroyAllConfigs.SERVER.blocks.coolerEfficiency.getF() * concentration * amount * molecule.getMolarHeatCapacity() / 100; + coolingPower += DestroyAllConfigs.SERVER.blocks.coolerEfficiency.getF() * concentration * amount * molecule.getMolarHeatCapacity() * 10 / Constants.MILLIBUCKETS_PER_LITER; }; }; @@ -107,7 +110,7 @@ private void consumeFluid() { } else if (fluidStack.getFluid().is(Fluids.COOLANT.tag)) { - coolingPower += fluidStack.getAmount(); // One bucket of coolant = 50 seconds of coling + coolingPower += fluidStack.getAmount(); // One bucket of coolant = 50 seconds of cooling } if (coolingPower > 0f) { diff --git a/src/main/java/com/petrolpark/destroy/content/processing/dynamo/DynamoCogInstance.java b/src/main/java/com/petrolpark/destroy/content/processing/dynamo/DynamoCogInstance.java index 75196fd0c..d671f3e58 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/dynamo/DynamoCogInstance.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/dynamo/DynamoCogInstance.java @@ -15,12 +15,6 @@ public DynamoCogInstance(MaterialManager modelManager, KineticBlockEntity blockE super(modelManager, blockEntity); }; - @Override - public void updateLight() { - super.updateLight(); - relight(pos); - }; - @Override protected Instancer getModel() { BlockState state = blockEntity.getBlockState(); diff --git a/src/main/java/com/petrolpark/destroy/content/processing/glassblowing/BlowpipeBlockEntityRenderer.java b/src/main/java/com/petrolpark/destroy/content/processing/glassblowing/BlowpipeBlockEntityRenderer.java index a9e489997..50b1dca48 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/glassblowing/BlowpipeBlockEntityRenderer.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/glassblowing/BlowpipeBlockEntityRenderer.java @@ -73,7 +73,7 @@ public static void render(GlassblowingRecipe recipe, FluidStack fluid, float pro }; for (int j = 0; j < shapes; j++) { - DestroyFluidRenderer.renderFluidBoxWithAlpha(fluid, - radii[j], -radii[j], ends[j] - 1/ 128f, radii[j], radii[j], ends[j+1] + 1 / 128f, buffer, ms, light, fluidOpacity); + DestroyFluidRenderer.renderFluidBoxWithAlpha(fluid, - radii[j] - 1/ 512f, -radii[j] - 1/ 128f, ends[j] - 1/ 512f, radii[j] + 1 / 512f, radii[j] + 1 / 128f, ends[j+1] + 1 / 512f, buffer, ms, light, fluidOpacity); }; }; diff --git a/src/main/java/com/petrolpark/destroy/content/processing/glassblowing/BlowpipeItem.java b/src/main/java/com/petrolpark/destroy/content/processing/glassblowing/BlowpipeItem.java index 2cf95234f..ecae331a2 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/glassblowing/BlowpipeItem.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/glassblowing/BlowpipeItem.java @@ -205,7 +205,12 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slotI tag.putBoolean("Blowing", false); }; - if (increaseProgress && progress < BlowpipeBlockEntity.BLOWING_DURATION) tag.putInt("Progress", progress + 1); + if (increaseProgress && progress < BlowpipeBlockEntity.BLOWING_DURATION) { + tag.putInt("Progress", progress + 1); + if(progress < BlowpipeBlockEntity.BLOWING_DURATION && progress + 1 >= BlowpipeBlockEntity.BLOWING_DURATION && entity instanceof Player player) { + DestroyAdvancementTrigger.BLOWPIPE.award(level, player); + } + } }; @Override @@ -227,9 +232,6 @@ public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livi tag.putInt("Progress", 0); tag.putInt("LastProgress", 0); tag.put("Tank", new FluidTank(BlowpipeBlockEntity.TANK_CAPACITY).writeToNBT(new CompoundTag())); // Empty the Tank - if (livingEntity instanceof Player player) { - DestroyAdvancementTrigger.BLOWPIPE.award(level, player); - }; }; return stack; }; diff --git a/src/main/java/com/petrolpark/destroy/content/processing/sieve/MechanicalSieveInstance.java b/src/main/java/com/petrolpark/destroy/content/processing/sieve/MechanicalSieveInstance.java new file mode 100644 index 000000000..600151505 --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/content/processing/sieve/MechanicalSieveInstance.java @@ -0,0 +1,83 @@ +package com.petrolpark.destroy.content.processing.sieve; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.petrolpark.destroy.client.DestroyPartials; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; +import com.simibubi.create.foundation.utility.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; + +public class MechanicalSieveInstance extends SingleRotatingInstance implements DynamicInstance { + + protected final ModelData sieve; + protected final ModelData linkages; + + public MechanicalSieveInstance(MaterialManager materialManager, MechanicalSieveBlockEntity blockEntity) { + super(materialManager, blockEntity); + + sieve = materialManager.defaultCutout() + .material(Materials.TRANSFORMED) + .getModel(DestroyPartials.MECHANICAL_SIEVE, blockState) + .createInstance(); + + linkages = materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(DestroyPartials.MECHANICAL_SIEVE_LINKAGES, blockState) + .createInstance(); + + updateAnimation(); + } + + @Override + public void beginFrame() { + updateAnimation(); + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, sieve, linkages); + } + + @Override + public void remove() { + super.remove(); + sieve.delete(); + linkages.delete(); + } + + private void updateAnimation() { + Direction.Axis axis = KineticBlockEntityRenderer.getRotationAxisOf(blockEntity); + float angle = KineticBlockEntityRenderer.getAngleForTe(blockEntity, blockEntity.getBlockPos(), axis); + Direction facing = blockState.getValue(MechanicalSieveBlock.X) ? Direction.EAST : Direction.SOUTH; + + float offset = (float)(Mth.sin(angle) * 2 / 16d); + + sieve.loadIdentity() + .translate(getInstancePosition()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .unCentre() + .translate(offset, 0d , 0d); + + linkages.loadIdentity() + .translate(getInstancePosition()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .translate(offset, 0d , 0d) + .rotateZRadians(-angle) + .unCentre(); + } + + @Override + protected Instancer getModel() { + Direction facing = blockState.getValue(MechanicalSieveBlock.X) ? Direction.EAST : Direction.SOUTH; + return getRotatingMaterial().getModel(DestroyPartials.MECHANICAL_SIEVE_SHAFT, blockState, facing); + } +} diff --git a/src/main/java/com/petrolpark/destroy/content/processing/sieve/MechanicalSieveRenderer.java b/src/main/java/com/petrolpark/destroy/content/processing/sieve/MechanicalSieveRenderer.java index 4084cf72f..8b4c2a2d3 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/sieve/MechanicalSieveRenderer.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/sieve/MechanicalSieveRenderer.java @@ -1,5 +1,6 @@ package com.petrolpark.destroy.content.processing.sieve; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -25,6 +26,8 @@ public MechanicalSieveRenderer(Context context) { @Override protected void renderSafe(MechanicalSieveBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + if (Backend.canUseInstancing(be.getLevel())) return; + BlockState state = be.getBlockState(); boolean x = state.getValue(MechanicalSieveBlock.X); VertexConsumer vc = buffer.getBuffer(RenderType.cutoutMipped()); @@ -56,7 +59,7 @@ protected void renderSafe(MechanicalSieveBlockEntity be, float partialTicks, Pos @Override protected SuperByteBuffer getRotatedModel(MechanicalSieveBlockEntity be, BlockState state) { - return CachedBufferer.partialFacingVertical(DestroyPartials.MECHANICAL_SIEVE_SHAFT, state, state.getValue(MechanicalSieveBlock.X) ? Direction.EAST : Direction.SOUTH); + return CachedBufferer.partialFacing(DestroyPartials.MECHANICAL_SIEVE_SHAFT, state, state.getValue(MechanicalSieveBlock.X) ? Direction.EAST : Direction.SOUTH); }; }; diff --git a/src/main/java/com/petrolpark/destroy/content/processing/treetap/TreeTapInstance.java b/src/main/java/com/petrolpark/destroy/content/processing/treetap/TreeTapInstance.java new file mode 100644 index 000000000..f02998c6a --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/content/processing/treetap/TreeTapInstance.java @@ -0,0 +1,62 @@ +package com.petrolpark.destroy.content.processing.treetap; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.jozufozu.flywheel.core.materials.oriented.OrientedData; +import com.petrolpark.destroy.client.DestroyPartials; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.base.ShaftInstance; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING; + +public class TreeTapInstance extends ShaftInstance implements DynamicInstance { + + protected final ModelData arm; + + public TreeTapInstance(MaterialManager materialManager, TreeTapBlockEntity blockEntity) { + super(materialManager, blockEntity); + + arm = materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(DestroyPartials.TREE_TAP_ARM, blockState) + .createInstance(); + + updateAnimation(); + } + + @Override + public void beginFrame() { + updateAnimation(); + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, arm); + } + + @Override + public void remove() { + super.remove(); + arm.delete(); + } + + private void updateAnimation() { + Direction facing = blockState.getValue(TreeTapBlock.HORIZONTAL_FACING); + + arm.loadIdentity() + .translate(getInstancePosition()) + .centre() + .rotate(9f * Mth.sin(KineticBlockEntityRenderer.getAngleForTe(blockEntity, blockEntity.getBlockPos(), facing.getClockWise().getAxis())), facing.getClockWise().getAxis()) + .rotateToFace(facing.getOpposite()) + .unCentre(); + } +} diff --git a/src/main/java/com/petrolpark/destroy/content/processing/treetap/TreeTapRenderer.java b/src/main/java/com/petrolpark/destroy/content/processing/treetap/TreeTapRenderer.java index 09e7c6b92..98d25a0b6 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/treetap/TreeTapRenderer.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/treetap/TreeTapRenderer.java @@ -1,5 +1,6 @@ package com.petrolpark.destroy.content.processing.treetap; +import com.jozufozu.flywheel.backend.Backend; import com.mojang.blaze3d.vertex.PoseStack; import com.petrolpark.destroy.client.DestroyPartials; import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; @@ -21,7 +22,7 @@ public TreeTapRenderer(Context context) { @Override protected void renderSafe(TreeTapBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - //if (Backend.canUseInstancing(be.getLevel())) return; + if (Backend.canUseInstancing(be.getLevel())) return; BlockState state = be.getBlockState(); Direction facing = state.getValue(TreeTapBlock.HORIZONTAL_FACING); @@ -31,7 +32,6 @@ protected void renderSafe(TreeTapBlockEntity be, float partialTicks, PoseStack m .rotate(9f * Mth.sin(getAngleForTe(be, be.getBlockPos(), facing.getClockWise().getAxis())), facing.getClockWise().getAxis()) .rotateToFace(facing.getOpposite()) .unCentre() - .translate(0f, 12 / 16f, 7 / 16f) .light(light) .renderInto(ms, buffer.getBuffer(RenderType.solid())); diff --git a/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/CircuitMaskItem.java b/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/CircuitMaskItem.java index b1b144da5..6732de738 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/CircuitMaskItem.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/CircuitMaskItem.java @@ -14,6 +14,7 @@ import com.simibubi.create.foundation.item.render.SimpleCustomRenderer; import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; import net.minecraft.nbt.CompoundTag; @@ -94,9 +95,14 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slotI }; @Override + @OnlyIn(Dist.CLIENT) public void appendHoverText(ItemStack stack, Level level, List tooltipComponents, TooltipFlag isAdvanced) { super.appendHoverText(stack, level, tooltipComponents, isAdvanced); if (stack.getOrCreateTag().contains("HideContaminants")) return; + + if(level == null) // Fixes a crash caused by Jade + level = Minecraft.getInstance().level; + List previousPunchers = getContaminants(stack); tooltipComponents.add(Component.literal(" ")); tooltipComponents.add(DestroyLang.translate("tooltip.circuit_mask.punched_by", previousPunchers.size()).style(ChatFormatting.GRAY).component()); diff --git a/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/keypunch/KeypunchInstance.java b/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/keypunch/KeypunchInstance.java new file mode 100644 index 000000000..a0bcafdb2 --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/keypunch/KeypunchInstance.java @@ -0,0 +1,65 @@ +package com.petrolpark.destroy.content.processing.trypolithography.keypunch; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.petrolpark.destroy.client.DestroyPartials; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogInstance; +import com.simibubi.create.foundation.render.AllMaterialSpecs; +import com.simibubi.create.foundation.utility.AnimationTickHolder; + +public class KeypunchInstance extends EncasedCogInstance implements DynamicInstance { + + protected final ModelData piston; + + public KeypunchInstance(MaterialManager materialManager, KeypunchBlockEntity blockEntity) { + super(materialManager, blockEntity, false); + + piston = materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(DestroyPartials.KEYPUNCH_PISTON, blockState) + .createInstance(); + + updateAnimation(); + } + + @Override + public void beginFrame() { + updateAnimation(); + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, piston); + } + + @Override + public void remove() { + super.remove(); + piston.delete(); + } + + @Override + protected Instancer getCogModel() { + return materialManager.defaultSolid() + .material(AllMaterialSpecs.ROTATING) + .getModel(AllPartialModels.SHAFTLESS_COGWHEEL, blockEntity.getBlockState()); + } + + private void updateAnimation() { + KeypunchBlockEntity be = (KeypunchBlockEntity)blockEntity; + CircuitPunchingBehaviour behaviour = be.punchingBehaviour; + float renderedHeadOffset = behaviour.getRenderedPistonOffset(AnimationTickHolder.getPartialTicks()); + + int pistonPos = be.getActualPosition(); + + piston.loadIdentity() + .translate(getInstancePosition()) + .translate((4 + 2 * (pistonPos % 4)) / 16f, - (6.1f + (renderedHeadOffset * 12.5f)) / 16f, (4 + 2 * (pistonPos / 4)) / 16f); + } +} diff --git a/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/keypunch/KeypunchRenderer.java b/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/keypunch/KeypunchRenderer.java index 4b73a9f5d..5781ffe12 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/keypunch/KeypunchRenderer.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/keypunch/KeypunchRenderer.java @@ -1,5 +1,6 @@ package com.petrolpark.destroy.content.processing.trypolithography.keypunch; +import com.jozufozu.flywheel.backend.Backend; import com.mojang.blaze3d.vertex.PoseStack; import com.petrolpark.destroy.client.DestroyPartials; import com.simibubi.create.AllPartialModels; @@ -25,6 +26,9 @@ public boolean shouldRenderOffScreen(KeypunchBlockEntity be) { @Override protected void renderSafe(KeypunchBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + if (Backend.canUseInstancing(be.getLevel())) return; + BlockState blockState = be.getBlockState(); CircuitPunchingBehaviour behaviour = be.punchingBehaviour; float renderedHeadOffset = behaviour.getRenderedPistonOffset(partialTicks); @@ -34,8 +38,6 @@ protected void renderSafe(KeypunchBlockEntity be, float partialTicks, PoseStack headRender.translate((4 + 2 * (pistonPos % 4)) / 16f, - (6.1f + (renderedHeadOffset * 12.5f)) / 16f, (4 + 2 * (pistonPos / 4)) / 16f) .light(light) .renderInto(ms, buffer.getBuffer(RenderType.solid())); - - super.renderSafe(be, partialTicks, ms, buffer, light, overlay); }; @Override diff --git a/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/recipe/CircuitPatternIngredient.java b/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/recipe/CircuitPatternIngredient.java index e3729c410..4f76cc4ad 100644 --- a/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/recipe/CircuitPatternIngredient.java +++ b/src/main/java/com/petrolpark/destroy/content/processing/trypolithography/recipe/CircuitPatternIngredient.java @@ -50,6 +50,9 @@ public boolean isSimple() { return false; }; + @Override + public boolean isEmpty() { return false; }; + @Override public IIngredientSerializer getSerializer() { return SERIALIZER; diff --git a/src/main/java/com/petrolpark/destroy/content/product/fireretardant/FireproofingHelper.java b/src/main/java/com/petrolpark/destroy/content/product/fireretardant/FireproofingHelper.java index 025dbed52..3907321a7 100644 --- a/src/main/java/com/petrolpark/destroy/content/product/fireretardant/FireproofingHelper.java +++ b/src/main/java/com/petrolpark/destroy/content/product/fireretardant/FireproofingHelper.java @@ -53,8 +53,8 @@ public static ItemStack fillItem(Level world, int requiredAmount, ItemStack stac .map(SingleFluidRecipe.class::cast) .filter(r -> r.getRequiredFluid().test(availableFluid)) .map(r -> { - availableFluid.shrink(100); - ItemStack result = stack.copy(); + availableFluid.shrink(requiredAmount); + ItemStack result = stack.copyWithCount(1); stack.shrink(1); apply(world, result); return result; diff --git a/src/main/java/com/petrolpark/destroy/content/tool/swissarmyknife/SwissArmyKnifeItem.java b/src/main/java/com/petrolpark/destroy/content/tool/swissarmyknife/SwissArmyKnifeItem.java index 8485d9b22..a07e0af1d 100644 --- a/src/main/java/com/petrolpark/destroy/content/tool/swissarmyknife/SwissArmyKnifeItem.java +++ b/src/main/java/com/petrolpark/destroy/content/tool/swissarmyknife/SwissArmyKnifeItem.java @@ -3,6 +3,7 @@ import java.util.EnumMap; import java.util.Map; import java.util.Set; +import java.util.WeakHashMap; import java.util.function.Consumer; import java.util.function.Supplier; @@ -17,8 +18,6 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; import net.minecraft.tags.BlockTags; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -35,7 +34,6 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.CampfireBlock; import net.minecraft.world.level.block.PumpkinBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; @@ -53,20 +51,50 @@ public class SwissArmyKnifeItem extends DiggerItem { private static int timeUntilToolPutAway = 20; - @Nullable - public static Tool selectedTool = null; - public SwissArmyKnifeItem(float attackDamageModifier, float attackSpeedModifier, Tier tier, Properties properties) { super(attackDamageModifier, attackSpeedModifier, tier, BlockTags.MINEABLE_WITH_PICKAXE, properties); // The tag supplied here is ignored }; + @OnlyIn(Dist.CLIENT) + public static class ClientState { + private static Map states = new WeakHashMap<>(); + + @Nullable + public Tool selectedTool = null; + public Tool lastSelectedTool = null; + public int animTimer = 0; + + public Map chasers; + + public ClientState() { + chasers = new EnumMap<>(Tool.class); + for (Tool tool : Tool.values()) { + chasers.put(tool, LerpedFloat.angular().chase(0d, 0.4d, Chaser.EXP)); + }; + }; + + public void tick() { + chasers.values().forEach(chaser -> chaser.tickChaser()); + + if(selectedTool != lastSelectedTool) { + animTimer++; + if(animTimer >= 8) { + animTimer = 0; + lastSelectedTool = selectedTool; + chasers.forEach((entry, value) -> value.chase(entry == selectedTool ? 1d : 0d, 0.4d, Chaser.EXP)); + }; + }; + }; + }; + + @OnlyIn(Dist.CLIENT) @Override public void inventoryTick(ItemStack stack, Level level, Entity entity, int slotId, boolean isSelected) { - Map chasers = getChasers(stack); - chasers.values().forEach(LerpedFloat::tickChaser); - putChasers(stack, chasers); - if (level.isClientSide()) { - if (getTool(stack) != selectedTool) DestroyMessages.sendToServer(new SwissArmyKnifeToolC2SPacket(selectedTool)); + if (level.isClientSide() && entity == Minecraft.getInstance().player) { + ClientState clientState = getClientState(Minecraft.getInstance().player); + if (getTool(stack) != clientState.selectedTool) { + DestroyMessages.sendToServer(new SwissArmyKnifeToolC2SPacket(clientState.selectedTool)); + }; }; }; @@ -125,16 +153,22 @@ public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack }; @Override - @OnlyIn(Dist.CLIENT) - public void initializeClient(Consumer consumer) { - consumer.accept(SimpleCustomRenderer.create(this, new SwissArmyKnifeItemRenderer())); - }; + @OnlyIn(Dist.CLIENT) + public void initializeClient(Consumer consumer) { + consumer.accept(SimpleCustomRenderer.create(this, new SwissArmyKnifeItemRenderer())); + }; @OnlyIn(Dist.CLIENT) public static void clientPlayerTick() { Minecraft minecraft = Minecraft.getInstance(); + + ClientState.states.keySet().removeIf(entity -> !(entity.getItemInHand(InteractionHand.MAIN_HAND).getItem() instanceof SwissArmyKnifeItem || entity.getItemInHand(InteractionHand.OFF_HAND).getItem() instanceof SwissArmyKnifeItem)); + ClientState.states.forEach((entity, state) -> state.tick()); + LocalPlayer player = minecraft.player; if (player == null) return; + + ClientState clientState = getClientState(player); Tool newTool; boolean switchTool = false; if (!(player.getItemInHand(InteractionHand.MAIN_HAND).getItem() instanceof SwissArmyKnifeItem) && !(player.getItemInHand(InteractionHand.OFF_HAND).getItem() instanceof SwissArmyKnifeItem)) { @@ -149,10 +183,10 @@ public static void clientPlayerTick() { timeUntilToolPutAway = 20; }; }; - switchTool |= newTool != null && newTool != selectedTool; + switchTool |= newTool != null && newTool != clientState.selectedTool; if (switchTool) { DestroyMessages.sendToServer(new SwissArmyKnifeToolC2SPacket(newTool)); - selectedTool = newTool; + clientState.selectedTool = newTool; }; }; @@ -175,7 +209,7 @@ public static Tool getTool(Level level, HitResult ray, boolean shiftDown) { if (shiftDown || tool == null) { if (state.getBlock() instanceof PumpkinBlock) tool = Tool.SHEARS; if (AxeItem.getAxeStrippingState(state) != null) tool = Tool.AXE; - if (ShovelItem.FLATTENABLES.containsKey(state.getBlock()) || (state.getBlock() instanceof CampfireBlock && state.getValue(CampfireBlock.LIT))) tool = Tool.SHOVEL; + if (ShovelItem.FLATTENABLES.containsKey(state.getBlock())) tool = Tool.SHOVEL; if (HoeItem.TILLABLES.containsKey(state.getBlock())) tool = Tool.HOE; }; } else if (ray instanceof EntityHitResult ehr) { @@ -197,36 +231,11 @@ public static Tool getTool(ItemStack stack) { public static void putTool(ItemStack stack, @Nullable Tool tool) { stack.removeTagKey("ActiveTool"); if (tool != null) stack.getOrCreateTag().putInt("ActiveTool", tool.ordinal()); - Map chasers = getChasers(stack); - chasers.entrySet().forEach(entry -> entry.getValue().chase(entry.getKey() == tool ? 1d : 0d, 0.4d, Chaser.EXP)); - putChasers(stack, chasers); - }; - - public static Map getChasers(ItemStack stack) { - EnumMap map = new EnumMap<>(Tool.class); - int ordinal = 0; - if (!stack.getOrCreateTag().contains("ToolAnimations", Tag.TAG_LIST)) return Tool.ALL_RETRACTED; - for (Tag t : stack.getOrCreateTag().getList("ToolAnimations", Tag.TAG_COMPOUND)) { - CompoundTag tag = (CompoundTag)t; - LerpedFloat toolAngle = LerpedFloat.angular().chase(tag.getFloat("Target"), 0.4d, Chaser.EXP); - toolAngle.setValue(tag.getFloat("Value")); - map.put(Tool.values()[ordinal], toolAngle); - ordinal++; - }; - return map; - }; - - public static void putChasers(ItemStack stack, Map chasers) { - ListTag list = new ListTag(); - for (Tool tool : Tool.values()) { - CompoundTag tag = new CompoundTag(); - LerpedFloat toolAngle = chasers.get(tool); - if (toolAngle == null) toolAngle = LerpedFloat.angular().chase(0d, 0.4d, Chaser.EXP); - tag.putFloat("Target", toolAngle.getChaseTarget()); - tag.putFloat("Value", toolAngle.getValue()); - list.add(tag); - }; - stack.getOrCreateTag().put("ToolAnimations", list); + }; + + @OnlyIn(Dist.CLIENT) + public static ClientState getClientState(LivingEntity entity) { + return ClientState.states.computeIfAbsent(entity, e -> new ClientState()); }; public static enum Tool { @@ -249,5 +258,5 @@ public static enum Tool { this.exampleTool = exampleTool; }; }; - -}; + +}; \ No newline at end of file diff --git a/src/main/java/com/petrolpark/destroy/content/tool/swissarmyknife/SwissArmyKnifeItemRenderer.java b/src/main/java/com/petrolpark/destroy/content/tool/swissarmyknife/SwissArmyKnifeItemRenderer.java index 5cd3ce77a..235229d74 100644 --- a/src/main/java/com/petrolpark/destroy/content/tool/swissarmyknife/SwissArmyKnifeItemRenderer.java +++ b/src/main/java/com/petrolpark/destroy/content/tool/swissarmyknife/SwissArmyKnifeItemRenderer.java @@ -11,6 +11,7 @@ import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.animation.LerpedFloat; import net.minecraft.client.Minecraft; @@ -28,11 +29,23 @@ public class SwissArmyKnifeItemRenderer extends CustomRenderedItemModelRenderer protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, ItemDisplayContext transformType, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { Minecraft mc = Minecraft.getInstance(); ItemRenderer itemRenderer = mc.getItemRenderer(); - if (transformType == ItemDisplayContext.FIRST_PERSON_RIGHT_HAND || transformType == ItemDisplayContext.FIRST_PERSON_LEFT_HAND || transformType == ItemDisplayContext.THIRD_PERSON_RIGHT_HAND || transformType == ItemDisplayContext.THIRD_PERSON_LEFT_HAND) { + + // animation only works for the local player for now + LivingEntity owner = null; + if(transformType == ItemDisplayContext.FIRST_PERSON_RIGHT_HAND || transformType == ItemDisplayContext.FIRST_PERSON_LEFT_HAND || transformType == ItemDisplayContext.THIRD_PERSON_RIGHT_HAND || transformType == ItemDisplayContext.THIRD_PERSON_LEFT_HAND) { + /*if(mc.player.getMainHandItem() == stack || mc.player.getOffhandItem() == stack) + owner = mc.player;*/ + + // eh + owner = mc.player; + } + + if (owner != null) { boolean firstPerson = (transformType == ItemDisplayContext.FIRST_PERSON_RIGHT_HAND || transformType == ItemDisplayContext.FIRST_PERSON_LEFT_HAND); - Map chasers = SwissArmyKnifeItem.getChasers(stack); + Map chasers = SwissArmyKnifeItem.getClientState(owner).chasers; + float pt = AnimationTickHolder.getPartialTicks(); ms.pushPose(); if (!firstPerson) { @@ -60,7 +73,7 @@ protected void render(ItemStack stack, CustomRenderedItemModel model, PartialIte if (toolAngle != null) { TransformStack.cast(ms) .translate(5 / 16f, -5 / 16f, 0f) - .rotateZ(179 * (1 - toolAngle.getValue()) * (tool == RenderedTool.LOWER_SHEARS ? 1f : -1f)) + .rotateZ(179 * (1 - toolAngle.getValue(pt)) * (tool == RenderedTool.LOWER_SHEARS ? 1f : -1f)) .translateBack(5 / 16f, -5 / 16f, 0f); }; itemRenderer.renderStatic(renderedTool, ItemDisplayContext.NONE, light, OverlayTexture.NO_OVERLAY, ms, buffer, mc.level, 0); @@ -107,5 +120,5 @@ public static float getItemProperty(ItemStack stack, @Nullable ClientLevel level }; - -}; + +}; \ No newline at end of file diff --git a/src/main/java/com/petrolpark/destroy/core/bettervaluesettings/BetterValueSettingsScreen.java b/src/main/java/com/petrolpark/destroy/core/bettervaluesettings/BetterValueSettingsScreen.java index 2b0ff7430..853ebc748 100644 --- a/src/main/java/com/petrolpark/destroy/core/bettervaluesettings/BetterValueSettingsScreen.java +++ b/src/main/java/com/petrolpark/destroy/core/bettervaluesettings/BetterValueSettingsScreen.java @@ -38,7 +38,7 @@ public BetterValueSettingsScreen(BlockPos pos, Direction sideAccessed, Interacti protected void saveAndClose(double mouseX, double mouseY) { ValueSettings closest = getClosestCoordinate((int) mouseX, (int) mouseY); AllPackets.getChannel() - .sendToServer(new ValueSettingsPacket(pos, closest.row(), closest.value(), hand, sideAccessed, + .sendToServer(new ValueSettingsPacket(pos, closest.row(), closest.value(), null, sideAccessed, AllKeys.ctrlDown())); onClose(); }; diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/MoleculeRenderer.java b/src/main/java/com/petrolpark/destroy/core/chemistry/MoleculeRenderer.java index d1bf4e0a6..0e2d97944 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/MoleculeRenderer.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/MoleculeRenderer.java @@ -1,19 +1,35 @@ package com.petrolpark.destroy.core.chemistry; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; +import com.jozufozu.flywheel.core.model.ModelUtil; +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.vertex.*; +import com.mojang.math.Axis; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.phys.AABB; +import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.client.model.IModelBuilder; +import net.minecraftforge.client.model.pipeline.QuadBakingVertexConsumer; +import net.minecraftforge.client.textures.UnitTextureAtlasSprite; import org.joml.Math; import org.joml.Quaternionf; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; import com.petrolpark.destroy.chemistry.legacy.LegacyAtom; import com.petrolpark.destroy.chemistry.legacy.LegacySpecies; import com.petrolpark.destroy.chemistry.legacy.LegacyBond.BondType; @@ -33,30 +49,14 @@ public class MoleculeRenderer { protected String moleculeID; - /** - * The distance from 0 to the highest X value of any rendered object. - */ - protected int width; - /** - * The distance from 0 to the highest Y value of any rendered object. - */ - protected int height; - /** - * How far below X = 0 this rendered Molecule extends. - */ - protected int xOffset; - /** - * How far above Y = 0 this rendered Molecule extends (remember positive Y is down). - */ - protected int yOffset; - /** - * How far behind Z = 0 this rendered Molecule extends - */ - protected int zOffset; + protected AABB bb; protected static final double SCALE = 23d; protected static final double BOND_LENGTH = SCALE / 2; + //protected SuperByteBuffer model; + protected BakedModel model; + /** * The list of Atoms and Bonds to render, and their locations. * This is ordered from back to front. @@ -65,11 +65,7 @@ public class MoleculeRenderer { public MoleculeRenderer(LegacySpecies molecule) { moleculeID = molecule.getFullID(); - width = 0; - height = 0; - xOffset = 5; - yOffset = 0; - zOffset = 0; + bb = new AABB(Vec3.ZERO, Vec3.ZERO); RENDERED_OBJECTS = new ArrayList<>(); // Monatomic Molecules @@ -132,23 +128,26 @@ public MoleculeRenderer(LegacySpecies molecule) { // Rescale the Renderer to fit every Atom for (Pair pair : RENDERED_OBJECTS) { - width = Math.max(width, (int)pair.getFirst().x); - height = Math.max(height, (int)pair.getFirst().y); - // Set the X and Y offsets to the positive of the most negative respective coordinate of any rendered object present - xOffset = -(int)Math.min(-xOffset, pair.getFirst().x); - yOffset = -(int)Math.min(-yOffset, pair.getFirst().y); - zOffset = -(int)Math.min(-zOffset, pair.getFirst().z); + bb = bb.minmax(new AABB(pair.getFirst(), pair.getFirst())); + }; + + // Bake all rendered objects into a single model + IModelBuilder builder = IModelBuilder.of(false, true, true, ItemTransforms.NO_TRANSFORMS, ItemOverrides.EMPTY, + UnitTextureAtlasSprite.INSTANCE, RenderTypeGroup.EMPTY); + QuadBakingVertexConsumer buffer = new QuadBakingVertexConsumer(builder::addUnculledFace); + buffer.setTintIndex(-1); + for (Pair pair : RENDERED_OBJECTS) { + pair.getSecond().renderInto(buffer, pair.getFirst()); }; - width += xOffset; - height += yOffset; + model = builder.build(); }; public int getWidth() { - return width; + return (int)bb.getXsize(); }; public int getHeight() { - return height; + return (int)bb.getYsize(); }; /** @@ -157,13 +156,36 @@ public int getHeight() { public void render(int xPosition, int yPosition, GuiGraphics graphics) { PoseStack poseStack = graphics.pose(); poseStack.pushPose(); - poseStack.translate(xPosition + ((float)width / 2f), yPosition + yOffset, -200); - TransformStack.cast(poseStack) - .rotateY(AnimationTickHolder.getRenderTime()); // Rotation - poseStack.translate(-((float)width) / 2f + xOffset, 0f, 0f); - for (Pair pair : RENDERED_OBJECTS) { - pair.getSecond().render(graphics, pair.getFirst()); - }; + Vec3 center = bb.getCenter(); + poseStack.translate(center.x - bb.minX + xPosition, center.y - bb.minY + yPosition, -200); + poseStack.mulPose(Axis.YP.rotationDegrees(AnimationTickHolder.getRenderTime())); + poseStack.translate(-center.x, -center.y, -center.z); + + UIRenderHelper.flipForGuiRender(poseStack); + Lighting.setupFor3DItems(); + Minecraft.getInstance().getItemRenderer().renderModelLists(model, ItemStack.EMPTY, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, + poseStack, graphics.bufferSource().getBuffer(Sheets.cutoutBlockSheet())); + graphics.flush(); + + poseStack.popPose(); + }; + + public void renderItem(int xPosition, int yPosition, int width, int height, PoseStack poseStack, MultiBufferSource.BufferSource buffer) { + float scale = java.lang.Math.min(0.5f, java.lang.Math.min((width+2)/(getWidth()+1f), (height+2)/(getHeight()+1f))); + + poseStack.pushPose(); + Vec3 center = bb.getCenter(); + poseStack.translate(xPosition + width/2, yPosition + height/2, 50); + poseStack.mulPose(Axis.XP.rotationDegrees(-10)); + poseStack.mulPose(Axis.YP.rotationDegrees(AnimationTickHolder.getRenderTime())); + poseStack.scale(scale, scale, scale); + poseStack.translate(-center.x, -center.y, -center.z); + + UIRenderHelper.flipForGuiRender(poseStack); + Lighting.setupFor3DItems(); + Minecraft.getInstance().getItemRenderer().renderModelLists(model, ItemStack.EMPTY, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, + poseStack, buffer.getBuffer(Sheets.cutoutBlockSheet())); + poseStack.popPose(); }; @@ -214,7 +236,7 @@ public void generateBranch(Branch branch, Vec3 startLocation, Vec3 direction, Ve Branch sideBranch = sideBranchAndBondType.getKey(); Vec3 newPlane = confinedGeometry.getZig().cross(sideZag); RENDERED_OBJECTS.add(Pair.of(location.add(sideZag.scale(0.5d * BOND_LENGTH)), BondRenderInstance.fromZig(sideBranchAndBondType.getValue(), sideZag))); - generateBranch(sideBranch, location.add(sideZag.scale(BOND_LENGTH)), MathsHelper.rotate(sideZag, newPlane, 90d), newPlane, sideZag, false); + generateBranch(sideBranch, location.add(sideZag.scale(BOND_LENGTH)), MathsHelper.rotate(sideZag, newPlane, 90d), newPlane, sideZag, true); j++; }; @@ -357,6 +379,7 @@ public static double distanceFromPointToLine(Vec3 point, Vec3 linePoint, Vec3 li protected static interface IRenderableMoleculePart { public void render(GuiGraphics graphics, Vec3 location); + public void renderInto(VertexConsumer builder, Vec3 location); }; protected static record BondRenderInstance(BondType type, Quaternionf rotation) implements IRenderableMoleculePart { @@ -372,7 +395,10 @@ public static BondRenderInstance fromZig(BondType type, Vec3 zig) { Vec3 z = zig.normalize(); Vec3 axis = bond.cross(z); Quaternionf q = new Quaternionf(axis.x(), axis.y(), axis.z(), (float)bond.dot(z) + (float)Math.sqrt(bond.lengthSqr() * z.lengthSqr())); - return new BondRenderInstance(type, new Quaternionf(q.normalize())); + if(!q.normalize().isFinite()) + q = new Quaternionf(0f, 0f, 0f, 1f); // identity + + return new BondRenderInstance(type, q); }; @Override @@ -388,6 +414,24 @@ public void render(GuiGraphics graphics, Vec3 location) { .render(graphics, 0, 0); poseStack.popPose(); }; + + @Override + public void renderInto(VertexConsumer builder, Vec3 location) { + PoseStack poseStack = new PoseStack(); + + // Models need to be flipped on the Y axis when rendered in the GUI in order to appear upright + // Molecules were originally rendered piece by piece, with each piece being flipped individually + // Now that molecules are baked into a single model, the Y coordinates need to be flipped so each + // piece appears in the correct position once the entire model is flipped again + poseStack.translate(location.x, -location.y, location.z); + TransformStack.cast(poseStack) + .multiply(new Quaternionf(-rotation.x, rotation.y, -rotation.z, rotation.w)); // flip rotation around Y axis + poseStack.scale((float)SCALE, (float)SCALE, (float)SCALE); + + Minecraft.getInstance().getBlockRenderer().getModelRenderer() + .renderModel(poseStack.last(), builder, Blocks.AIR.defaultBlockState(), type().getPartial().get(), 1, 1, 1, + 0, OverlayTexture.NO_OVERLAY, ModelUtil.VIRTUAL_DATA, RenderType.solid()); + }; }; protected static record AtomRenderInstance(LegacyAtom atom) implements IRenderableMoleculePart { @@ -403,5 +447,17 @@ public void render(GuiGraphics graphics, Vec3 location) { .render(graphics, 0, 0); poseStack.popPose(); }; + + @Override + public void renderInto(VertexConsumer builder, Vec3 location) { + PoseStack poseStack = new PoseStack(); + + poseStack.translate(location.x, -location.y, location.z); + poseStack.scale((float)SCALE, (float)SCALE, (float)SCALE); + + Minecraft.getInstance().getBlockRenderer().getModelRenderer() + .renderModel(poseStack.last(), builder, Blocks.AIR.defaultBlockState(), atom.getPartial().get(), 1, 1, 1, + 0, OverlayTexture.NO_OVERLAY, ModelUtil.VIRTUAL_DATA, RenderType.solid()); + }; }; }; diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/basinreaction/ReactionInBasinRecipe.java b/src/main/java/com/petrolpark/destroy/core/chemistry/basinreaction/ReactionInBasinRecipe.java index ccbe7e2dd..ea4778986 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/basinreaction/ReactionInBasinRecipe.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/basinreaction/ReactionInBasinRecipe.java @@ -59,8 +59,8 @@ public static ReactionInBasinRecipe create(Collection availableFluid Level level = basin.getLevel(); BlockPos pos = basin.getBlockPos(); - float heatingPower = IVatHeaterBlock.getHeatingPower(level, pos.below(), Direction.UP); float outsideTemperature = Pollution.getLocalTemperature(level, pos); + float heatingTemperature = outsideTemperature + IVatHeaterBlock.getRelativeTemperature(level, pos.below(), Direction.UP); ExtendedBasinBehaviour behaviour = basin.getBehaviour(ExtendedBasinBehaviour.TYPE); boolean shouldUpdateBasin = false; @@ -101,7 +101,7 @@ public static ReactionInBasinRecipe create(Collection availableFluid tryReact: if (canReact) { // TODO modify temp according to Heat Level LegacyMixture mixture = LegacyMixture.mix(mixtures); - ReactionInBasinResult result = mixture.reactInBasin(totalAmount, availableItemsCopy, heatingPower, outsideTemperature); // Mutably react the Mixture and change the Item Stacks + ReactionInBasinResult result = mixture.reactInBasin(totalAmount, availableItemsCopy, heatingTemperature, outsideTemperature); // Mutably react the Mixture and change the Item Stacks // If equilibrium was not disturbed, don't do anything else if (result.ticks() == 0) { @@ -109,7 +109,7 @@ public static ReactionInBasinRecipe create(Collection availableFluid break tryReact; }; - Phases phases = mixture.separatePhases(result.amount()); + Phases phases = mixture.separatePhases(totalAmount); // Add the resultant Mixture to the results for this Recipe FluidStack outputMixtureStack = MixtureFluid.of((int)Math.round(phases.liquidVolume()), phases.liquidMixture()); @@ -145,7 +145,10 @@ public static ReactionInBasinRecipe create(Collection availableFluid gatherReactionResults(result.reactionResults(), reactionResults, builder); // Gather all behaviour.setReactionResults(reactionResults); // Schedule the Reaction Results to occur once the Mixing has finished - behaviour.evaporatedFluid = MixtureFluid.of((int)Math.round(phases.gasVolume()), phases.gasMixture()); + if(phases.gasMixture().getTotalConcentration() > 0f) + behaviour.evaporatedFluid = MixtureFluid.of((int)Math.round(phases.gasVolume()), phases.gasMixture()); + else + behaviour.evaporatedFluid = FluidStack.EMPTY; shouldUpdateBasin = true; }; diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/storage/PlaceableMixtureTankBlock.java b/src/main/java/com/petrolpark/destroy/core/chemistry/storage/PlaceableMixtureTankBlock.java index 97c2b4700..38e71cb86 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/storage/PlaceableMixtureTankBlock.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/storage/PlaceableMixtureTankBlock.java @@ -56,7 +56,7 @@ public ItemStack getFilledItemStack(BlockEntity be) { if (be != null && asItem() instanceof IMixtureStorageItem mixtureItem) { ItemStack stack = new ItemStack(asItem()); return be.getCapability(ForgeCapabilities.FLUID_HANDLER).map(fluidHandler -> { - mixtureItem.setContents(stack, fluidHandler.drain(mixtureItem.getCapacity(stack), FluidAction.EXECUTE)); + mixtureItem.setContents(stack, fluidHandler.drain(mixtureItem.getCapacity(stack), FluidAction.SIMULATE)); return stack; }).orElse(ItemStack.EMPTY); }; diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/storage/PlaceableMixtureTankItem.java b/src/main/java/com/petrolpark/destroy/core/chemistry/storage/PlaceableMixtureTankItem.java index 96f8e025e..c439d41cd 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/storage/PlaceableMixtureTankItem.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/storage/PlaceableMixtureTankItem.java @@ -51,6 +51,12 @@ public boolean canAttackBlock(BlockState state, Level level, BlockPos pos, Playe @Override public InteractionResult place(BlockPlaceContext context) { + if(context.getPlayer() != null && context.getPlayer().getAbilities().instabuild) { + context.getPlayer().getAbilities().instabuild = false; + InteractionResult res = super.place(context); + context.getPlayer().getAbilities().instabuild = true; + return res; + } return IPickUpPutDownBlock.removeItemFromInventory(context, super.place(context)); }; diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/IVatHeaterBlock.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/IVatHeaterBlock.java index 6429afa9e..7bed5fa26 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/IVatHeaterBlock.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/IVatHeaterBlock.java @@ -13,36 +13,36 @@ * Interface for Blocks which can heat or cool a {@link Vat}. */ public interface IVatHeaterBlock { - + /** - * Get the power (in watts) the given Block State supplies or withdraws from a {@link Vat}. + * Get the temperature (in kelvin) of the given Block State relative to ambient temperature. * @param level * @param blockState * @param blockPos * @param face The face of the Block State touching the Vat * @return Positive value for heaters, negative value for coolers */ - float getHeatingPower(Level level, BlockState blockState, BlockPos blockPos, Direction face); + float getRelativeTemperature(Level level, BlockState blockState, BlockPos blockPos, Direction face); - public static float getHeatingPower(Level level, BlockPos blockPos, Direction face) { + static float getRelativeTemperature(Level level, BlockPos blockPos, Direction face) { BlockState state = level.getBlockState(blockPos); if (state.isAir()) return 0f; // IVatHeaters if (state.getBlock() instanceof IVatHeaterBlock heater) { - return heater.getHeatingPower(level, state, blockPos, face); + return heater.getRelativeTemperature(level, state, blockPos, face); }; // Blaze Burners, Coolers, etc. if (state.hasProperty(BlazeBurnerBlock.HEAT_LEVEL) && face == Direction.UP) { HeatLevel heatLevel = state.getValue(BlazeBurnerBlock.HEAT_LEVEL); if (heatLevel == HeatLevel.KINDLED) { - return DestroyAllConfigs.SERVER.blocks.blazeBurnerHeatingPower.getF(); + return DestroyAllConfigs.SERVER.blocks.blazeBurnerHeatingTemperature.getF(); } else if (heatLevel == HeatLevel.SEETHING) { - return DestroyAllConfigs.SERVER.blocks.blazeBurnerSuperHeatingPower.getF(); + return DestroyAllConfigs.SERVER.blocks.blazeBurnerSuperHeatingTemperature.getF(); } else if ("FROSTING".equals(heatLevel.name())) { - return DestroyAllConfigs.SERVER.blocks.coolerHeatingPower.getF(); + return DestroyAllConfigs.SERVER.blocks.coolerHeatingTemperature.getF(); }; }; diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatControllerBlockEntity.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatControllerBlockEntity.java index 66b5f8b8f..8fb3ca9eb 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatControllerBlockEntity.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatControllerBlockEntity.java @@ -10,11 +10,7 @@ import javax.annotation.Nullable; -import com.petrolpark.destroy.DestroyAdvancementTrigger; -import com.petrolpark.destroy.DestroyBlockEntityTypes; -import com.petrolpark.destroy.DestroyBlocks; -import com.petrolpark.destroy.DestroyFluids; -import com.petrolpark.destroy.DestroyRecipeTypes; +import com.petrolpark.destroy.*; import com.petrolpark.destroy.chemistry.api.util.Constants; import com.petrolpark.destroy.chemistry.legacy.LegacyMixture; import com.petrolpark.destroy.chemistry.legacy.LegacyMixture.ReactionContext; @@ -27,6 +23,7 @@ import com.petrolpark.destroy.core.block.entity.ISpecialWhenHoveredBlockEntity; import com.petrolpark.destroy.core.chemistry.MixtureContentsDisplaySource; import com.petrolpark.destroy.core.chemistry.recipe.MixtureConversionRecipe; +import com.petrolpark.destroy.core.chemistry.vat.material.VatMaterial; import com.petrolpark.destroy.core.chemistry.vat.VatFluidTankBehaviour.VatTankSegment.VatFluidTank; import com.petrolpark.destroy.core.chemistry.vat.VatSideBlockEntity.DisplayType; import com.petrolpark.destroy.core.data.advancement.DestroyAdvancementBehaviour; @@ -89,16 +86,22 @@ public class VatControllerBlockEntity extends SmartBlockEntity implements IHaveL * This Mixture belongs to an imaginary Fluid Stack with a size equal to the capacity of the Vat. */ protected LegacyMixture cachedMixture; - /** - * The power (in W) being supplied to this Vat. This can be positive (if the Vat is - * being heated) or negative (if it is being cooled). - */ - protected float heatingPower; + /** * The amount of UV being supplied to this Vat. */ protected float UVPower; + /** + * The temperature of the walls of the Vat (not its contents) + */ + protected float vatTemperature; + + /** + * The average temperature outside the Vat relative to ambient temperature + */ + protected float averageOutsideRelativeTemperature; + /* * As the client side doesn't have access to the cached Mixture, store the pressure, temperature, and whether it is boiling or at equilibrium */ @@ -193,21 +196,66 @@ public void tick() { boolean shouldUpdateFluidMixture = false; Vat vat = getVatOptional().get(); if (tankBehaviour.isEmpty()) return; - double fluidAmount = getCapacity() / Constants.MILLIBUCKETS_PER_LITER; // Converts getFluidAmount() in mB to liters + float fluidAmount = (float)getCapacity() / Constants.MILLIBUCKETS_PER_LITER; // Converts getFluidAmount() in mB to liters int cyclesPerTick = getSimulationLevel(); // Heating - for (int cycle = 0; cycle < cyclesPerTick; cycle++) { - float energyChange = heatingPower; - energyChange += (Pollution.getLocalTemperature(getLevel(), getBlockPos()) - cachedMixture.getTemperature()) * vat.getConductance(); // Fourier's Law (sort of), the divide by 20 is for 20 ticks per second - energyChange /= 20 * cyclesPerTick; - if (Math.abs(energyChange / (fluidAmount * cachedMixture.getVolumetricHeatCapacity())) > 0.001f && fluidAmount != 0d) { // Only bother heating if the temperature change will be somewhat significant - cachedMixture.heat(energyChange / (float)fluidAmount); - cachedMixture.disturbEquilibrium(); - } else { - break; + float ambientTemperature = Pollution.getLocalTemperature(getLevel(), getBlockPos()); + float averageTemperature = Math.max(0f, ambientTemperature + averageOutsideRelativeTemperature); + + int vatSideVolume = vat.getSideBlockPositions().size(); + + // The volumetric heat capacity of one Vat block in joules per bucket-kelvin (1 block = 1 bucket) + // Assume all Vat materials have the same heat capacity for now + float vatSideHeatCapacity = 3000f * 10f; + + // 10 is an arbitrary number and I'm not entirely sure where it's coming from but I find that without it, Vats don't transfer enough energy + // to their liquid contents to raise their temperature within a reasonable amount of time. + // Maybe I missed some important detail, or something's wrong with the way conductance is calculated, or maybe this is completely realistic and it only feels + // weird in game because it's easy to forget you're heating liquid through 1 meter of solid metal. Either way, gameplay before realism. + float vatConductance = vat.getConductance()*10f; + + boolean settled = false; + + for (int cycle = 0; cycle < cyclesPerTick && !settled ; cycle++) { + settled = true; + + // Conduct heat between the Vat's walls and its surroundings + float energyChangeExternal = (averageTemperature - vatTemperature) * vatConductance; // Fourier's Law (sort of), the divide by 20 is for 20 ticks per second + energyChangeExternal /= 20 * cyclesPerTick; + + float energyChangeInternal = 0f; + + // Conduct heat between the Vat's walls and its contents + if(fluidAmount > 0d) + { + energyChangeInternal = (vatTemperature - cachedMixture.getTemperature()) * vatConductance; + energyChangeInternal /= 20 * cyclesPerTick; + + // Prevent temperature from exploding to infinity when conductance is very high (e.g. copper vat) + // (can't be bothered to do proper integration this is just a test anyway) + float predictedMixtureTemperatureChange = Math.abs(energyChangeInternal / (fluidAmount * cachedMixture.getVolumetricHeatCapacity())); + float temperatureDifference = Math.abs(vatTemperature - cachedMixture.getTemperature()); + + // Only bother heating if the temperature change will be somewhat significant + if (temperatureDifference > 0.001f || predictedMixtureTemperatureChange > 0.001f) + { + if (predictedMixtureTemperatureChange > temperatureDifference) + energyChangeInternal *= 0.99f * temperatureDifference / predictedMixtureTemperatureChange; + + cachedMixture.heat(energyChangeInternal / fluidAmount); + cachedMixture.disturbEquilibrium(); + settled = false; + } }; + + // Temperature change = Energy change / (Volume * Volumetric heat capacity) + float vatTemperatureChange = (energyChangeExternal - energyChangeInternal) / (vatSideVolume * vatSideHeatCapacity); + if (Math.abs(vatTemperatureChange) > 0.001f) { + vatTemperature += vatTemperatureChange; + settled = false; + } }; // Take all Items out of the Inventory @@ -231,12 +279,12 @@ public void tick() { cachedMixture.reactForTick(context, getSimulationLevel()); shouldUpdateFluidMixture = true; - if (!cachedMixture.isAtEquilibrium()) advancementBehaviour.awardDestroyAdvancement(DestroyAdvancementTrigger.USE_VAT); - }; + // Put all Items back in the Inventory + for (ItemStack itemStack : availableItemStacks) { + ItemHandlerHelper.insertItemStacked(inventory, itemStack, false); + }; - // Put all Items back in the Inventory - for (ItemStack itemStack : availableItemStacks) { - ItemHandlerHelper.insertItemStacked(inventory, itemStack, false); + if (!cachedMixture.isAtEquilibrium()) advancementBehaviour.awardDestroyAdvancement(DestroyAdvancementTrigger.USE_VAT); }; if (shouldUpdateFluidMixture) { @@ -249,7 +297,7 @@ public void tick() { // Releasing gas if there is an open vent VatSideBlockEntity openVent = getOpenVent(); - if (openVent != null && !getGasTank().isEmptyOrFullOfAir()) { + if (openVent != null && !getGasTank().wasFlushed()) { PollutionHelper.pollute(getLevel(), openVent.getBlockPos().relative(openVent.direction), 10, flush()); updateCachedMixture(); }; @@ -282,8 +330,12 @@ public static int getSimulationLevel() { protected void read(CompoundTag tag, boolean clientPacket) { super.read(tag, clientPacket); - heatingPower = tag.getFloat("HeatingPower"); UVPower = tag.getFloat("UVPower"); + averageOutsideRelativeTemperature = tag.getFloat("AverageOutsideRelativeTemperature"); + if(tag.contains("VatTemperature")) + vatTemperature = tag.getFloat("VatTemperature"); + else + vatTemperature = getLevel() == null ? 289f : Pollution.getLocalTemperature(getLevel(), getBlockPos()); // Initialize default temperature if we're loading from a previous version // Vat if (tag.contains("Vat", Tag.TAG_COMPOUND)) { @@ -314,8 +366,9 @@ protected void read(CompoundTag tag, boolean clientPacket) { protected void write(CompoundTag tag, boolean clientPacket) { super.write(tag, clientPacket); - tag.putFloat("HeatingPower", heatingPower); tag.putFloat("UVPower", UVPower); + tag.putFloat("AverageOutsideRelativeTemperature", averageOutsideRelativeTemperature); + tag.putFloat("VatTemperature", vatTemperature); // Vat if (vat.isPresent()) { @@ -445,6 +498,7 @@ public boolean tryMakeVat() { }); vat = Optional.of(newVat.get()); + vatTemperature = Pollution.getLocalTemperature(getLevel(), getBlockPos()); finalizeVatConstruction(); updateCachedMixture(); flush(); @@ -453,6 +507,21 @@ public boolean tryMakeVat() { return true; }; + public void recomputeHeatSources() { + if (!hasLevel() || getLevel().isClientSide() || !vat.isPresent()) return; + + float newRelativeTemperature = (float)vat.get().getSideBlockPositions().stream().mapToDouble(pos -> + getLevel().getBlockEntity(pos, DestroyBlockEntityTypes.VAT_SIDE.get()) + .map(vatSide -> IVatHeaterBlock.getRelativeTemperature(getLevel(), pos.relative(vatSide.direction), vatSide.direction.getOpposite()) + * VatMaterial.getMaterial(vatSide.getMaterial()).get().thermalConductivity()) + .orElse(0f)).sum() / vat.get().getConductance(); + + if(newRelativeTemperature != averageOutsideRelativeTemperature) { + averageOutsideRelativeTemperature = newRelativeTemperature; + sendData(); + } + } + private void finalizeVatConstruction() { tankBehaviour.allowExtraction(); // Enable extraction from the Vat now it actually exists tankBehaviour.setCapacity(vat.get().getCapacity()); @@ -496,8 +565,8 @@ public void deleteVat(BlockPos posDestroyed) { }); }; }); - heatingPower = 0f; UVPower = 0f; + averageOutsideRelativeTemperature = 0f; cachedMixture = new LegacyMixture(); vat = Optional.empty(); @@ -588,11 +657,6 @@ public float getRenderedFluidLevel(float partialTicks) { } }; - public void changeHeatingPower(float powerChange) { - heatingPower += powerChange; - sendData(); - }; - public void changeUVPower(float UVChange) { UVPower += UVChange; if (cachedMixture != null) cachedMixture.disturbEquilibrium(); @@ -623,10 +687,15 @@ public float getPercent() { @SuppressWarnings("null") public float getTemperature() { if (getLevel().isClientSide()) return temperature.getChaseTarget(); // It thinks getLevel() might be null (it's not) - if (getVatOptional().isEmpty() || cachedMixture == null) return Pollution.getLocalTemperature(getLevel(), getBlockPos()); + if (getVatOptional().isEmpty() || cachedMixture == null) return vatTemperature; return cachedMixture.getTemperature(); }; + @SuppressWarnings("null") + public float getVatTemperature() { + return vatTemperature; + }; + /** * Get the pressure above room pressure of the gas in this Vat (in Pa). */ @@ -635,7 +704,7 @@ public float getPressure() { if (getLevel().isClientSide()) return pressure.getChaseTarget(); // It thinks getLevel() might be null (it's not) if (!getVatOptional().isPresent()) return 0f; if (getGasTank().isEmpty()) { - return getLiquidTank().getFluidAmount() == getLiquidTank().getCapacity() ? 0f : AIR_PRESSURE; // Return 0 for a vacuum, and normal air pressure for a full Vat + return getLiquidTank().getFluidAmount() == getLiquidTank().getCapacity() ? 0f : -AIR_PRESSURE; // Return 0 for a vacuum, and normal air pressure for a full Vat }; return LegacyReaction.GAS_CONSTANT * 1000f * getTemperature() * ReadOnlyMixture.readNBT(ReadOnlyMixture::new, getGasTank().getFluid().getOrCreateChildTag("Mixture")).getTotalConcentration() - AIR_PRESSURE; }; @@ -790,12 +859,18 @@ protected FluidStack drainGasTank(int amount, FluidAction action) { protected FluidStack drainGasTankWithMolarDensity(int amount, double molarDensity, FluidAction action) { if (vatControllerGetter.get() == null || vatControllerGetter.get().getGasTankContents().isEmpty()) return FluidStack.EMPTY; LegacyMixture mixture = LegacyMixture.readNBT(vatControllerGetter.get().getGasTankContents().getOrCreateChildTag("Mixture")); + double scaleFactor = mixture.getTotalConcentration() / molarDensity; - FluidStack lostFluid = drainGasTank((int)Math.ceil(scaleFactor * amount), action); // Round up - mixture.scale((float)scaleFactor); - double drainedAmount = (double)lostFluid.getAmount() / scaleFactor; - FluidStack stack = MixtureFluid.of((int)Math.ceil(drainedAmount), mixture); - return stack; + int amountToDrain = Math.min((int)Math.ceil(scaleFactor * amount), amount); // Round up + FluidStack lostFluid = drainGasTank(amountToDrain, action); + + int drainedAmount = amount; + + // Don't bother scaling the mixture when simulating because this messes with Create's fluid networks + if(action.execute()) + mixture.scale((float)drainedAmount / lostFluid.getAmount()); + + return MixtureFluid.of(drainedAmount, mixture); }; protected void updateVatGasVolume(FluidStack drained, FluidAction action) { diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatFluidTankBehaviour.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatFluidTankBehaviour.java index 984485eb3..29e595788 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatFluidTankBehaviour.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatFluidTankBehaviour.java @@ -117,7 +117,7 @@ public ReadOnlyMixture getCombinedReadOnlyMixture() { }; for (Entry entry : moleculesAndMoles.entrySet()) { - mixture.addMolecule(entry.getKey(), entry.getValue() / totalVolume); //TODO use different volume as this makes things slow + mixture.addMolecule(entry.getKey(), entry.getValue()); }; return mixture; @@ -254,6 +254,10 @@ public boolean isEmptyOrFullOfAir() { return isEmpty() || flushed; }; + public boolean wasFlushed() { + return flushed; + }; + @Override public boolean isFluidValid(int tank, FluidStack stack) { return DestroyFluids.isMixture(stack); diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatScreen.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatScreen.java index 79504ed8d..857dd3ed5 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatScreen.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatScreen.java @@ -172,7 +172,7 @@ protected void updateMoleculeList() { switch (selectedView) { case BOTH: { mixture = blockEntity.getCombinedReadOnlyMixture(); - amount = blockEntity.getVatOptional().map(Vat::getCapacity).orElse(0); + amount = (int)Constants.MILLIBUCKETS_PER_LITER; break; } case GAS: { fluid = blockEntity.getGasTankContents(); diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatSideBlock.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatSideBlock.java index fe2a04fb5..6aa96605f 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatSideBlock.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatSideBlock.java @@ -19,6 +19,7 @@ import com.simibubi.create.foundation.blockEntity.SmartBlockEntityTicker; import com.simibubi.create.foundation.gui.ScreenOpener; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; @@ -72,7 +73,7 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player return onBlockEntityUse(level, pos, be -> { if (!(be instanceof VatSideBlockEntity vbe)) return InteractionResult.PASS; if (vbe.getDisplayType().quantityObserved.isPresent()) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> openScreen(vbe)); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> openScreen(vbe, player)); return InteractionResult.SUCCESS; }; return InteractionResult.PASS; @@ -80,8 +81,9 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player }; @OnlyIn(Dist.CLIENT) - public void openScreen(VatSideBlockEntity vbe) { - ScreenOpener.open(new RedstoneMonitorVatSideScreen(vbe)); + public void openScreen(VatSideBlockEntity vbe, Player player) { + if (player instanceof LocalPlayer) + ScreenOpener.open(new RedstoneMonitorVatSideScreen(vbe)); }; @Override diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatSideBlockEntity.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatSideBlockEntity.java index bcc098b53..efc9d4c55 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatSideBlockEntity.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/VatSideBlockEntity.java @@ -116,7 +116,6 @@ protected AABB createRenderBoundingBox() { @Override public void addBehaviours(List behaviours) { inputBehaviour = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.TYPE, this, 1, BUFFER_TANK_CAPACITY, false) - .whenFluidUpdates(this::tryInsertFluidInVat) .forbidExtraction(); behaviours.add(inputBehaviour); //fluidCapability = LazyOptional.empty(); // Temporarily set this to an empty optional @@ -233,7 +232,6 @@ protected void read(CompoundTag tag, boolean clientPacket) { }; controllerPosition = NbtUtils.readBlockPos(tag.getCompound("ControllerPosition")).offset(getBlockPos()); displayType = DisplayType.values()[tag.getInt("DisplayType")]; - oldPower = tag.getFloat("OldHeatingPower"); oldUV = tag.getFloat("OldUVPower"); if (tag.contains("InitializationTicks", Tag.TAG_INT)) initializationTicks = tag.getInt("InitializationTicks"); else initializationTicks = 0; if (clientPacket) { @@ -241,6 +239,13 @@ protected void read(CompoundTag tag, boolean clientPacket) { spoutingFluid = FluidStack.loadFluidStackFromNBT(tag.getCompound("SpoutingFluid")); ventOpenness.chase(displayType == DisplayType.OPEN_VENT ? 1f : 0f, 0.3f, Chaser.EXP); }; + + if(!redstoneMonitor.quantityObserved.isPresent() && getDisplayType().quantityObserved.isPresent()) { + redstoneMonitor.quantityObserved = getDisplayType().quantityObserved.map(f -> () -> { + VatControllerBlockEntity vc = getController(); + return vc == null ? 0.f : f.apply(vc); + }); + } redstoneMonitor.withLabel(getDisplayType().quantityLabel); }; @@ -250,7 +255,6 @@ protected void write(CompoundTag tag, boolean clientPacket) { if (direction != null) tag.putInt("Side", direction.ordinal()); if (controllerPosition != null) tag.put("ControllerPosition", NbtUtils.writeBlockPos(controllerPosition.subtract(getBlockPos()))); tag.putInt("DisplayType", displayType.ordinal()); - tag.putFloat("OldHeatingPower", oldPower); tag.putFloat("OldUVPower", oldUV); if (initializationTicks > 0) tag.putInt("InitializationTicks", initializationTicks); if (clientPacket) { @@ -325,12 +329,6 @@ public void setPowerFromAdjacentBlock(BlockPos heaterOrLampPos) { VatControllerBlockEntity vatController = getController(); if (vatController == null) return; - float newPower = IVatHeaterBlock.getHeatingPower(getLevel(), heaterOrLampPos, direction.getOpposite()); - if (newPower != oldPower) { - vatController.changeHeatingPower(newPower - oldPower); - oldPower = newPower; - }; - float newUVPower = 0f; if (VatMaterial.getMaterial(getMaterial()).map(VatMaterial::transparent).orElse(false)) { newUVPower = IUVLampBlock.getUVPower(getLevel(), heaterOrLampPos, direction.getOpposite()); @@ -342,7 +340,7 @@ public void setPowerFromAdjacentBlock(BlockPos heaterOrLampPos) { vatController.changeUVPower(newUVPower - oldUV); oldUV = newUVPower; }; - + vatController.recomputeHeatSources(); sendData(); }; @@ -515,7 +513,8 @@ public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneak if (getDisplayType().showsTemperature) { TemperatureUnit unit = DestroyAllConfigs.CLIENT.chemistry.temperatureUnit.get(); DestroyLang.translate("tooltip.vat.temperature", unit.of(controller.getTemperature(), df)).style(ChatFormatting.WHITE).forGoggles(tooltip); - if (DestroyAllConfigs.CLIENT.chemistry.nerdMode.get()) DestroyLang.translate("tooltip.vat.power", df.format(controller.heatingPower / 1000f)).forGoggles(tooltip); + DestroyLang.translate("tooltip.vat.temperature.outer", unit.of(controller.getVatTemperature(), df)).style(ChatFormatting.WHITE).forGoggles(tooltip); + //if (DestroyAllConfigs.CLIENT.chemistry.nerdMode.get()) DestroyLang.translate("tooltip.vat.power", df.format(controller.heatingPower / 1000f)).forGoggles(tooltip); } else if (getDisplayType().showsPressure) { Vat vat = getVatOptional().get(); DestroyLang.translate("tooltip.vat.pressure.header").style(ChatFormatting.WHITE).forGoggles(tooltip); diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/AbstractQuantityObservingScreen.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/AbstractQuantityObservingScreen.java index 63072d0c4..a2c4f2524 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/AbstractQuantityObservingScreen.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/AbstractQuantityObservingScreen.java @@ -3,6 +3,7 @@ import java.util.List; import com.mojang.blaze3d.platform.InputConstants; +import com.petrolpark.destroy.DestroyMessages; import com.petrolpark.destroy.client.DestroyGuiTextures; import com.petrolpark.destroy.client.DestroyLang; import com.simibubi.create.foundation.gui.AbstractSimiScreen; @@ -38,7 +39,7 @@ protected int getTitleX() { return 16; }; - protected abstract void onThresholdChange(boolean upper, float newValue); + protected abstract void updateThresholds(float lower, float upper); @Override protected void init() { @@ -60,6 +61,7 @@ protected void init() { lowerBound.mouseClicked(0, 0, 0); lowerBound.active = false; lowerBound.setTooltip(Tooltip.create(DestroyLang.translate("tooltip.vat.menu.quantity_observed.minimum").component())); + lowerBound.setValue(""+quantityBehaviour.lowerThreshold); upperBound = new EditBox(minecraft.font, guiLeft + 171, guiTop + getEditBoxY(), 70, 10, Component.literal(""+quantityBehaviour.lowerThreshold)); upperBound.setBordered(false); @@ -68,6 +70,7 @@ protected void init() { upperBound.mouseClicked(0, 0, 0); upperBound.active = false; upperBound.setTooltip(Tooltip.create(DestroyLang.translate("tooltip.vat.menu.quantity_observed.maximum").component())); + upperBound.setValue(""+quantityBehaviour.upperThreshold); addRenderableWidgets(lowerBound, upperBound); }; @@ -80,19 +83,24 @@ public void tick() { box.setCursorPosition(box.getValue().length()); box.setHighlightPos(box.getCursorPosition()); - // Attempt to update the Vat Side with the given number - boolean upper = box == upperBound; - float oldValue = upper ? quantityBehaviour.upperThreshold : quantityBehaviour.lowerThreshold; - try { - float value = Float.valueOf(box.getValue()); - if (value != oldValue) onThresholdChange(upper, value); - } catch (NumberFormatException e) { - box.setValue(""+oldValue); - }; + // TODO: validate values }; }; }; + @Override + public void onClose() { + lowerBound.setFocused(false); + upperBound.setFocused(false); + tick(); + + try { + updateThresholds(Float.valueOf(lowerBound.getValue()), Float.valueOf(upperBound.getValue())); + } catch (NumberFormatException e) {} + + super.onClose(); + } + @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (getFocused() instanceof EditBox && (keyCode == InputConstants.KEY_RETURN || keyCode == InputConstants.KEY_NUMPADENTER)) for (EditBox box : List.of(lowerBound, upperBound)) { diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneMonitorVatSideScreen.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneMonitorVatSideScreen.java index 84d68f004..84aa7efe6 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneMonitorVatSideScreen.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneMonitorVatSideScreen.java @@ -20,8 +20,8 @@ protected int getEditBoxY() { }; @Override - protected void onThresholdChange(boolean upper, float newValue) { - DestroyMessages.sendToServer(new RedstoneQuantityMonitorThresholdChangeC2SPacket(upper, newValue, vatSide.getBlockPos())); - }; + protected void updateThresholds(float lower, float upper) { + DestroyMessages.sendToServer(new RedstoneQuantityMonitorThresholdChangeC2SPacket(lower, upper, vatSide.getBlockPos())); + } }; diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneQuantityMonitorBehaviour.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneQuantityMonitorBehaviour.java index c96e3d681..9a26191fb 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneQuantityMonitorBehaviour.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneQuantityMonitorBehaviour.java @@ -7,6 +7,8 @@ import javax.annotation.Nonnull; +import com.petrolpark.destroy.Destroy; +import com.petrolpark.destroy.core.chemistry.vat.observation.colorimeter.ColorimeterBlockEntity; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; @@ -26,6 +28,7 @@ public class RedstoneQuantityMonitorBehaviour extends BlockEntityBehaviour { public float lowerThreshold; public float upperThreshold; protected int oldStrength; + protected boolean isFirstTick; protected IntConsumer strengthChangeCallback = i -> {}; @@ -34,6 +37,11 @@ public RedstoneQuantityMonitorBehaviour(SmartBlockEntity be) { quantityObserved = Optional.empty(); }; + @Override + public void initialize() { + isFirstTick = true; + } + public RedstoneQuantityMonitorBehaviour withLabel(Function label) { this.label = label; return this; @@ -45,8 +53,7 @@ public RedstoneQuantityMonitorBehaviour onStrengthChanged(IntConsumer callback) }; public int getStrength() { - if (quantityObserved.isPresent()) return oldStrength; - return 0; + return oldStrength; }; public void update() { @@ -60,6 +67,11 @@ public Component getLabelledQuantity() { @Override public void tick() { + if(isFirstTick) { + isFirstTick = false; + return; + } + int strength = 0; if (quantityObserved.isPresent()) strength = (int)(Mth.clamp((quantityObserved.get().get() - lowerThreshold) / (upperThreshold - lowerThreshold), 0f, 1f) * 15f); if (strength != oldStrength) { @@ -72,21 +84,17 @@ public void tick() { @Override public void read(CompoundTag nbt, boolean clientPacket) { super.read(nbt, clientPacket); - if (quantityObserved.isPresent()) { - oldStrength = nbt.getInt("OldRedstoneStrength"); - lowerThreshold = nbt.getFloat("LowerObservedQuantityThreshold"); - upperThreshold = nbt.getFloat("UpperObservedQuantityThreshold"); - }; + oldStrength = nbt.getInt("OldRedstoneStrength"); + lowerThreshold = nbt.getFloat("LowerObservedQuantityThreshold"); + upperThreshold = nbt.getFloat("UpperObservedQuantityThreshold"); }; @Override public void write(CompoundTag nbt, boolean clientPacket) { super.write(nbt, clientPacket); - if (quantityObserved.isPresent()) { - nbt.putInt("OldRedstoneStrength", oldStrength); - nbt.putFloat("LowerObservedQuantityThreshold", lowerThreshold); - nbt.putFloat("UpperObservedQuantityThreshold", upperThreshold); - }; + nbt.putInt("OldRedstoneStrength", oldStrength); + nbt.putFloat("LowerObservedQuantityThreshold", lowerThreshold); + nbt.putFloat("UpperObservedQuantityThreshold", upperThreshold); }; @Override diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneQuantityMonitorThresholdChangeC2SPacket.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneQuantityMonitorThresholdChangeC2SPacket.java index 266fcd0bd..0a7ad8f7b 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneQuantityMonitorThresholdChangeC2SPacket.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/RedstoneQuantityMonitorThresholdChangeC2SPacket.java @@ -12,26 +12,26 @@ public class RedstoneQuantityMonitorThresholdChangeC2SPacket extends C2SPacket { - public final boolean upper; - public final float value; + public final float lower; + public final float upper; public final BlockPos pos; - public RedstoneQuantityMonitorThresholdChangeC2SPacket(boolean upper, float value, BlockPos pos) { + public RedstoneQuantityMonitorThresholdChangeC2SPacket(float lower, float upper, BlockPos pos) { + this.lower = lower; this.upper = upper; - this.value = value; this.pos = pos; }; public RedstoneQuantityMonitorThresholdChangeC2SPacket(FriendlyByteBuf buffer) { - upper = buffer.readBoolean(); - value = buffer.readFloat(); + lower = buffer.readFloat(); + upper = buffer.readFloat(); pos = buffer.readBlockPos(); }; @Override public void toBytes(FriendlyByteBuf buffer) { - buffer.writeBoolean(upper); - buffer.writeFloat(value); + buffer.writeFloat(lower); + buffer.writeFloat(upper); buffer.writeBlockPos(pos); }; @@ -42,8 +42,8 @@ public boolean handle(Supplier supplier) { ServerPlayer sender = context.getSender(); RedstoneQuantityMonitorBehaviour behaviour = BlockEntityBehaviour.get(sender.level(), pos, RedstoneQuantityMonitorBehaviour.TYPE); if (behaviour != null) { - if (upper) behaviour.upperThreshold = value; - else behaviour.lowerThreshold = value; + behaviour.lowerThreshold = lower; + behaviour.upperThreshold = upper; behaviour.notifyUpdate(); }; }); diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterBlock.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterBlock.java index 18a567cbf..fc4422345 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterBlock.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterBlock.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Set; +import com.petrolpark.destroy.Destroy; import com.petrolpark.destroy.DestroyBlockEntityTypes; import com.petrolpark.destroy.DestroyFluids; import com.petrolpark.destroy.chemistry.legacy.LegacySpecies; @@ -13,11 +14,15 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.redstone.thresholdSwitch.ThresholdSwitchBlockEntity; import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.gui.ScreenOpener; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; @@ -79,14 +84,15 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player if (DestroyFluids.isMixture(fluid)) species.addAll(ReadOnlyMixture.readNBT(ReadOnlyMixture::new, fluid.getOrCreateChildTag("Mixture")).getContents(false)); }; - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> openScreen(be, species)); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> openScreen(be, species, player)); return InteractionResult.SUCCESS; }); }; @OnlyIn(Dist.CLIENT) - public void openScreen(ColorimeterBlockEntity be, Set species) { - ScreenOpener.open(new ColorimeterScreen(be, new ArrayList<>(species))); + public void openScreen(ColorimeterBlockEntity be, Set species, Player player) { + if(player instanceof LocalPlayer) + ScreenOpener.open(new ColorimeterScreen(be, new ArrayList<>(species))); }; @Override @@ -101,8 +107,8 @@ public int getSignal(BlockState state, BlockGetter level, BlockPos pos, Directio }; @Override - public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) { - withBlockEntityDo(level, pos, ColorimeterBlockEntity::updateVat); + public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos neighborPos, boolean isMoving) { + withBlockEntityDo(level, pos, cbe -> cbe.onNeighborChanged(neighborPos)); }; @Override diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterBlockEntity.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterBlockEntity.java index ee7e75148..42e28f640 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterBlockEntity.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterBlockEntity.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Optional; +import com.petrolpark.destroy.Destroy; import com.petrolpark.destroy.DestroyAdvancementTrigger; import com.petrolpark.destroy.DestroyBlockEntityTypes; import com.petrolpark.destroy.DestroyFluids; @@ -16,20 +17,24 @@ import com.petrolpark.destroy.core.chemistry.vat.material.VatMaterial; import com.petrolpark.destroy.core.chemistry.vat.observation.RedstoneQuantityMonitorBehaviour; import com.petrolpark.destroy.core.data.advancement.DestroyAdvancementBehaviour; +import com.simibubi.create.api.event.BlockEntityBehaviourEvent; import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; import com.simibubi.create.content.redstone.displayLink.source.DisplaySource; import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; +import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.Lang; +import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fluids.FluidStack; public class ColorimeterBlockEntity extends SmartBlockEntity { @@ -45,33 +50,48 @@ public class ColorimeterBlockEntity extends SmartBlockEntity { public RedstoneQuantityMonitorBehaviour redstoneMonitor; protected DestroyAdvancementBehaviour advancementBehaviour; + protected boolean updateVatNextTick; public ColorimeterBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); }; + public void initialize() { + super.initialize(); + updateVatNextTick = true; + } + @Override public void addBehaviours(List behaviours) { + advancementBehaviour = new DestroyAdvancementBehaviour(this, DestroyAdvancementTrigger.COLORIMETER); + behaviours.add(advancementBehaviour); + redstoneMonitor = new RedstoneQuantityMonitorBehaviour(this) .withLabel(f -> DestroyLang.translate("tooltip.colorimeter.menu.current_concentration", df.format(f)).component()) .onStrengthChanged(strength -> getLevel().setBlockAndUpdate(getBlockPos(), getBlockState().setValue(ColorimeterBlock.POWERED, strength != 0))); behaviours.add(redstoneMonitor); - - advancementBehaviour = new DestroyAdvancementBehaviour(this, DestroyAdvancementTrigger.COLORIMETER); - behaviours.add(advancementBehaviour); }; - + @Override public void tick() { super.tick(); if (molecule != null && getVatOptional().isPresent()) advancementBehaviour.awardDestroyAdvancement(DestroyAdvancementTrigger.COLORIMETER); + + if(updateVatNextTick) + { + updateVatNextTick = false; + updateVat(); + } }; @Override protected void read(CompoundTag tag, boolean clientPacket) { super.read(tag, clientPacket); - setMolecule(LegacySpecies.getMolecule(tag.getString("Molecule"))); - if (tag.contains("ObservingGas")) observingGas = true; + + if(clientPacket && (Minecraft.getInstance().screen instanceof ColorimeterScreen cs) && cs.colorimeter == this) + return; + + configure(LegacySpecies.getMolecule(tag.getString("Molecule")), tag.contains("ObservingGas")); }; @Override @@ -84,6 +104,7 @@ protected void write(CompoundTag tag, boolean clientPacket) { public void configure(LegacySpecies observedMolecule, boolean observingGas) { this.observingGas = observingGas; setMolecule(observedMolecule); + updateVatNextTick = true; }; public LegacySpecies getMolecule() { @@ -92,7 +113,6 @@ public LegacySpecies getMolecule() { public void setMolecule(LegacySpecies molecule) { this.molecule = molecule; - updateVat(); notifyUpdate(); }; @@ -105,6 +125,11 @@ public Optional getVatOptional() { }); }; + public void onNeighborChanged(BlockPos neighborPos) { + if(neighborPos.equals(getBlockPos().relative(getBlockState().getValue(ColorimeterBlock.FACING)))) + updateVatNextTick = true; + } + public void updateVat() { Optional vat = getVatOptional(); if (molecule != null && vat.isPresent()) { @@ -120,7 +145,7 @@ public void updateVat() { }; redstoneMonitor.quantityObserved = Optional.empty(); }; - + public static class ColorimeterDisplaySource extends DisplaySource { private static final DecimalFormat df = new DecimalFormat(); diff --git a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterScreen.java b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterScreen.java index 63dbd3cb0..25421ca92 100644 --- a/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterScreen.java +++ b/src/main/java/com/petrolpark/destroy/core/chemistry/vat/observation/colorimeter/ColorimeterScreen.java @@ -42,8 +42,8 @@ public ColorimeterScreen(ColorimeterBlockEntity colorimeter, List species = colorimeter.getMolecule(); speciesIndex = 0; this.availableSpecies = availableSpecies; - availableSpecies.remove(species); - availableSpecies.add(speciesIndex, species); // Put the selected species first + + speciesIndex = availableSpecies.indexOf(species); observingGas = colorimeter.observingGas; }; @@ -99,13 +99,13 @@ private void configureClientColorimeter() { }; @Override - protected void onThresholdChange(boolean upper, float newValue) { - DestroyMessages.sendToServer(new RedstoneQuantityMonitorThresholdChangeC2SPacket(upper, newValue, colorimeter.getBlockPos())); - }; + protected void updateThresholds(float lower, float upper) { + DestroyMessages.sendToServer(new RedstoneQuantityMonitorThresholdChangeC2SPacket(lower, upper, colorimeter.getBlockPos())); + } @Override public void onClose() { - if (species != colorimeter.getMolecule() || observingGas != colorimeter.observingGas) DestroyMessages.sendToServer(new ConfigureColorimeterC2SPacket(observingGas, species, colorimeter.getBlockPos())); + DestroyMessages.sendToServer(new ConfigureColorimeterC2SPacket(observingGas, species, colorimeter.getBlockPos())); super.onClose(); }; diff --git a/src/main/java/com/petrolpark/destroy/core/event/DestroyCommonEvents.java b/src/main/java/com/petrolpark/destroy/core/event/DestroyCommonEvents.java index 6b5926665..45861131c 100644 --- a/src/main/java/com/petrolpark/destroy/core/event/DestroyCommonEvents.java +++ b/src/main/java/com/petrolpark/destroy/core/event/DestroyCommonEvents.java @@ -480,15 +480,6 @@ public static final void onPlayerRightClickBlock(PlayerInteractEvent.RightClickB }; }; - // Consuming certain Items, even if in Creative - if (!AllBlocks.DEPLOYER.has(state) && event.getItemStack().getItem() instanceof BlockItem blockItem && blockItem.getBlock() instanceof IPickUpPutDownBlock) { - InteractionResult result = stack.useOn(new UseOnContext(player, event.getHand(), event.getHitVec())); - if (result.consumesAction() && player instanceof ServerPlayer serverPlayer) CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(serverPlayer, pos, stack); - event.setCancellationResult(result); - if (result != InteractionResult.PASS) event.setCanceled(true); - return; - }; - // Fireproof Flint and Steel if (stack.getItem() == Items.FLINT_AND_STEEL && FireproofingHelper.isFireproof(player.level().registryAccess(), stack)) { DestroyAdvancementTrigger.FIREPROOF_FLINT_AND_STEEL.award(player.level(), player); diff --git a/src/main/java/com/petrolpark/destroy/core/explosion/SmartExplosion.java b/src/main/java/com/petrolpark/destroy/core/explosion/SmartExplosion.java index 7591f0fa1..2c20e6e9e 100644 --- a/src/main/java/com/petrolpark/destroy/core/explosion/SmartExplosion.java +++ b/src/main/java/com/petrolpark/destroy/core/explosion/SmartExplosion.java @@ -262,7 +262,7 @@ public ExplosionResult getExplosionResult() { */ public void explodeBlock(BlockPos pos) { BlockState state = level.getBlockState(pos); - if (level instanceof ServerLevel serverLevel) { + if (level instanceof ServerLevel serverLevel && state.canDropFromExplosion(level, pos, this)) { BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null; LootParams.Builder builder = new LootParams.Builder(serverLevel) .withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos)) diff --git a/src/main/java/com/petrolpark/destroy/core/explosion/mixedexplosive/MixedExplosiveBlock.java b/src/main/java/com/petrolpark/destroy/core/explosion/mixedexplosive/MixedExplosiveBlock.java index 4450669cf..23845f49c 100644 --- a/src/main/java/com/petrolpark/destroy/core/explosion/mixedexplosive/MixedExplosiveBlock.java +++ b/src/main/java/com/petrolpark/destroy/core/explosion/mixedexplosive/MixedExplosiveBlock.java @@ -7,13 +7,19 @@ import com.petrolpark.destroy.DestroyBlocks; import com.petrolpark.destroy.DestroyEntityTypes; import com.petrolpark.destroy.core.explosion.PrimeableBombBlock; +import com.petrolpark.destroy.core.explosion.PrimedBombEntity; import com.petrolpark.destroy.core.explosion.SmartExplosion; import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockSource; import net.minecraft.core.Direction; +import net.minecraft.core.dispenser.OptionalDispenseItemBehavior; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -22,11 +28,15 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.DispenserBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.BlockHitResult; @@ -34,6 +44,8 @@ import net.minecraft.world.phys.Vec3; import net.minecraftforge.network.NetworkHooks; +import javax.annotation.Nullable; + public class MixedExplosiveBlock extends PrimeableBombBlock implements IBE { public MixedExplosiveBlock(Properties properties) { @@ -42,18 +54,19 @@ public MixedExplosiveBlock(Properties properties) { @Override public void onCaughtFire(BlockState state, Level level, BlockPos pos, Direction face, LivingEntity igniter) { - withBlockEntityDo(level, pos, be -> { - MixedExplosiveInventory inv = be.getExplosiveInventory(); - if (inv.isEmpty()) return; - ExplosiveProperties properties = inv.getExplosiveProperties(); - if (properties.fulfils(ExplosiveProperties.NO_FUSE)) { - level.removeBlock(pos, false); - if (level instanceof ServerLevel serverLevel) SmartExplosion.explode(serverLevel, CustomExplosiveMixExplosion.create(level, inv, igniter, Vec3.atCenterOf(pos))); - } else if (properties.fulfils(ExplosiveProperties.CAN_EXPLODE)) { - super.onCaughtFire(state, level, pos, face, igniter); - level.removeBlock(pos, false); - }; - }); + new MixedExplosivePrimer(level, pos, state) + .setIgniter(igniter) + .setIgnitionFace(face) + .prime(); + }; + + @Override + public void onBlockExploded(BlockState state, Level level, BlockPos pos, Explosion explosion) { + new MixedExplosivePrimer(level, pos, state) + .setIgniter(explosion.getIndirectSourceEntity()) + .setTriggeredByExplosion(true) + .prime(); + level.setBlock(pos, Blocks.AIR.defaultBlockState(), 3); }; @Override @@ -73,6 +86,11 @@ public boolean isRandomlyTicking(BlockState state) { return true; }; + @Override + public boolean canDropFromExplosion(BlockState state, BlockGetter level, BlockPos pos, Explosion explosion) { + return level.getBlockEntity(pos) instanceof MixedExplosiveBlockEntity be && be.getExplosiveInventory().getExplosiveProperties().fulfils(ExplosiveProperties.CAN_EXPLODE); + }; + @Override public void randomTick(BlockState pState, ServerLevel pLevel, BlockPos pPos, RandomSource pRandom) { withBlockEntityDo(pLevel, pPos, be -> { @@ -139,6 +157,85 @@ public BlockEntityType getBlockEntityType() return DestroyBlockEntityTypes.CUSTOM_EXPLOSIVE_MIX.get(); }; + public static class MixedExplosivePrimer { + private Level level; + private BlockPos pos; + private BlockState state; + private int color = 0xFFFFFF; + private MixedExplosiveInventory inv = null; + private Component customName = null; + private boolean triggeredByExplosion = false; + private LivingEntity igniter = null; + private Direction face = null; + + public MixedExplosivePrimer(Level level, BlockPos pos, BlockState state) { + this.level = level; + this.pos = pos; + this.state = state; + + if(level.getBlockEntity(pos) instanceof MixedExplosiveBlockEntity be) { + color = be.getColor(); + inv = be.getExplosiveInventory(); + customName = be.getCustomName(); + }; + }; + + public MixedExplosivePrimer(Level level, BlockPos pos, ItemStack itemStack) { + this.level = level; + this.pos = pos; + this.state = null; + + if(itemStack.getItem() instanceof MixedExplosiveBlockItem item) { + color = item.getColor(itemStack); + inv = item.getExplosiveInventory(itemStack); + customName = itemStack.getDisplayName(); + }; + }; + + public MixedExplosivePrimer setTriggeredByExplosion(boolean b) { + triggeredByExplosion = b; + return this; + }; + + public MixedExplosivePrimer setIgniter(LivingEntity e) { + igniter = e; + return this; + }; + + public MixedExplosivePrimer setIgnitionFace(Direction d) { + face = d; + return this; + }; + + public boolean prime() { + if (inv == null || inv.isEmpty()) return false; + + ExplosiveProperties properties = inv.getExplosiveProperties(); + if (properties.fulfils(ExplosiveProperties.CAN_EXPLODE)) { + if(level instanceof ServerLevel) { + MixedExplosiveEntity entity = new MixedExplosiveEntity(level, pos, state, igniter, color, inv); + entity.setCustomName(customName); + level.addFreshEntity(entity); + if(properties.fulfils(ExplosiveProperties.NO_FUSE)) { + entity.setFuse(1); + } else if(triggeredByExplosion) { + int i = entity.getFuse(); + entity.setFuse((short)(level.random.nextInt(i / 4) + i / 8)); + } else { + level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0f, 1.0f); + } + level.gameEvent(igniter, GameEvent.PRIME_FUSE, pos); + }; + if(state != null) + level.removeBlock(pos, false); + return true; + }; + + return false; + }; + }; + + // This actually doesn't get used anymore public static class CustomExplosiveMixEntityFactory implements PrimedBombEntityFactory { @Override @@ -151,5 +248,17 @@ public MixedExplosiveEntity create(Level level, BlockPos pos, BlockState state, }; }; + + public class CustomExplosiveMixDispenseBehaviour extends OptionalDispenseItemBehavior { + + @Override + protected ItemStack execute(BlockSource blockSource, ItemStack stack) { + Level level = blockSource.getLevel(); + BlockPos pos = blockSource.getPos().relative(blockSource.getBlockState().getValue(DispenserBlock.FACING)); + if(new MixedExplosivePrimer(level, pos, stack).prime()) + stack.shrink(1); + return stack; + }; + }; }; diff --git a/src/main/java/com/petrolpark/destroy/core/fluid/GeniusFluidTankBehaviour.java b/src/main/java/com/petrolpark/destroy/core/fluid/GeniusFluidTankBehaviour.java index 9903694c5..5b592bba7 100644 --- a/src/main/java/com/petrolpark/destroy/core/fluid/GeniusFluidTankBehaviour.java +++ b/src/main/java/com/petrolpark/destroy/core/fluid/GeniusFluidTankBehaviour.java @@ -12,6 +12,7 @@ import com.simibubi.create.foundation.fluid.SmartFluidTank; import net.minecraft.nbt.Tag; +import net.minecraft.world.level.material.Fluids; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; @@ -87,6 +88,17 @@ public int fill(FluidStack resource, FluidAction action) { return filled; }; + @Override + public FluidStack drain(int maxDrain, FluidAction action) + { + FluidStack stack = super.drain(maxDrain, action); + // Replace the held fluid with an empty fluid stack if we completely emptied this tank + // This clears mixture data and allows empty containers of the same type to stack + if(fluid.isEmpty() && fluid.getRawFluid() != Fluids.EMPTY) + setFluid(FluidStack.EMPTY); + return stack; + } + }; }; diff --git a/src/main/java/com/petrolpark/destroy/core/pollution/PollutionHelper.java b/src/main/java/com/petrolpark/destroy/core/pollution/PollutionHelper.java index e92996fd8..0dfca2efe 100644 --- a/src/main/java/com/petrolpark/destroy/core/pollution/PollutionHelper.java +++ b/src/main/java/com/petrolpark/destroy/core/pollution/PollutionHelper.java @@ -151,7 +151,8 @@ public static void pollute(Level level, BlockPos blockPos, float multiplier, int List nearbyEntities = level.getEntities(null, new AABB(blockPos).inflate(2)).stream().filter(e -> e instanceof LivingEntity).map(e -> (LivingEntity)e).toList(); for (FluidStack fluidStack : List.of(fluidStacks)) { pollute(level, blockPos, multiplier, fluidStack); - if (particleWeight == 1 || level.getRandom().nextInt(particleWeight) == 0); DestroyMessages.sendToAllClients(new EvaporatingFluidS2CPacket(blockPos, fluidStack)); + if (particleWeight == 1 || level.getRandom().nextInt(particleWeight) == 0) + DestroyMessages.sendToAllClients(new EvaporatingFluidS2CPacket(blockPos, fluidStack)); for (LivingEntity entity : nearbyEntities) { ChemistryHazardHelper.damage(level, entity, fluidStack, true); }; diff --git a/src/main/java/com/petrolpark/destroy/core/pollution/pollutometer/PollutometerBlockEntity.java b/src/main/java/com/petrolpark/destroy/core/pollution/pollutometer/PollutometerBlockEntity.java index 8de2d1f98..76f3e2d28 100644 --- a/src/main/java/com/petrolpark/destroy/core/pollution/pollutometer/PollutometerBlockEntity.java +++ b/src/main/java/com/petrolpark/destroy/core/pollution/pollutometer/PollutometerBlockEntity.java @@ -28,7 +28,7 @@ public class PollutometerBlockEntity extends SmartBlockEntity { public PollutometerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); - pollutionType = PollutionType.RADIOACTIVITY; + pollutionType = PollutionType.GREENHOUSE; }; @Override diff --git a/src/main/java/com/petrolpark/destroy/core/recipe/ingredient/fluid/SaltFluidIngredient.java b/src/main/java/com/petrolpark/destroy/core/recipe/ingredient/fluid/SaltFluidIngredient.java index 70834c20c..48dde9cf1 100644 --- a/src/main/java/com/petrolpark/destroy/core/recipe/ingredient/fluid/SaltFluidIngredient.java +++ b/src/main/java/com/petrolpark/destroy/core/recipe/ingredient/fluid/SaltFluidIngredient.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.List; +import com.google.common.math.IntMath; import com.google.gson.JsonObject; import com.petrolpark.destroy.chemistry.legacy.LegacyMixture; import com.petrolpark.destroy.chemistry.legacy.LegacySpecies; @@ -41,7 +42,11 @@ public void addNBT(CompoundTag fluidTag) { @Override protected boolean testMixture(LegacyMixture mixture) { - return mixture.hasUsableMolecule(cation, minConcentration * cation.getCharge(), maxConcentration * cation.getCharge(), (molecule) -> molecule == anion) && mixture.hasUsableMolecule(anion, minConcentration * -anion.getCharge(), maxConcentration * -anion.getCharge(), (molecule) -> molecule == cation); + int gcd = IntMath.gcd(cation.getCharge(), -anion.getCharge()); + float cationMultiplier = (float)-anion.getCharge() / gcd; + float anionMultiplier = (float)cation.getCharge() / gcd; + return mixture.hasUsableMolecule(cation, minConcentration * cationMultiplier, maxConcentration * cationMultiplier, (molecule) -> molecule == anion) + && mixture.hasUsableMolecule(anion, minConcentration * anionMultiplier, maxConcentration * anionMultiplier, (molecule) -> molecule == cation); }; @Override diff --git a/src/main/java/com/petrolpark/destroy/mixin/AbstractContainerMenuMixin.java b/src/main/java/com/petrolpark/destroy/mixin/AbstractContainerMenuMixin.java index 557617e26..97fd360fb 100644 --- a/src/main/java/com/petrolpark/destroy/mixin/AbstractContainerMenuMixin.java +++ b/src/main/java/com/petrolpark/destroy/mixin/AbstractContainerMenuMixin.java @@ -22,6 +22,8 @@ public abstract class AbstractContainerMenuMixin implements DelayedSlotPopulatio @Shadow public abstract Slot getSlot(int pSlotId); @Shadow + public abstract boolean isValidSlotIndex(int pSlotIndex); + @Shadow private ItemStack carried; @Shadow private int stateId; @@ -38,7 +40,7 @@ public void populateDelayedSlots() { @Overwrite public void setItem(int pSlotId, int pStateId, ItemStack pStack) { - if (pSlotId >= slots.size()) { + if (!isValidSlotIndex(pSlotId)) { delayedSlotStacks.put(pSlotId, pStack); } else { getSlot(pSlotId).set(pStack); @@ -50,7 +52,7 @@ public void setItem(int pSlotId, int pStateId, ItemStack pStack) { public void initializeContents(int pStateId, List pItems, ItemStack pCarried) { for (int i = 0; i < pItems.size(); ++i) { ItemStack stack = pItems.get(i); - if (i >= slots.size()) { + if (!isValidSlotIndex(i)) { delayedSlotStacks.put(i, stack); } else { getSlot(i).set(stack); @@ -61,5 +63,5 @@ public void initializeContents(int pStateId, List pItems, ItemStack p }; - + }; diff --git a/src/main/java/com/petrolpark/destroy/mixin/FluidNetworkMixin.java b/src/main/java/com/petrolpark/destroy/mixin/FluidNetworkMixin.java index 633a2f821..525d7ed1e 100644 --- a/src/main/java/com/petrolpark/destroy/mixin/FluidNetworkMixin.java +++ b/src/main/java/com/petrolpark/destroy/mixin/FluidNetworkMixin.java @@ -1,47 +1,33 @@ package com.petrolpark.destroy.mixin; -import java.util.Iterator; - +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import com.petrolpark.destroy.DestroyFluids; -import com.petrolpark.destroy.mixin.accessor.FluidNetworkAccessor; import com.simibubi.create.content.fluids.FluidNetwork; -import com.simibubi.create.content.fluids.PipeConnection; -import com.simibubi.create.content.fluids.PipeConnection.Flow; -import com.simibubi.create.foundation.utility.BlockFace; -import com.simibubi.create.foundation.utility.Pair; import net.minecraftforge.fluids.FluidStack; @Mixin(FluidNetwork.class) public class FluidNetworkMixin { - - /** - * Similar to {@link com.petrolpark.destroy.mixin.PipeConnectionMixin here}, we don't want a Fluid Network to reset transferring Fluid if all that has changed - * is one Mixture becoming another. - */ - @Inject( - method = "Lcom/simibubi/create/content/fluids/FluidNetwork;tick()V", - at = @At( - value = "INVOKE", - target = "Ljava/util/Iterator;remove()V", - ordinal = 1 - ), - cancellable = true, - locals = LocalCapture.CAPTURE_FAILSOFT, - remap = false - + @WrapOperation( + method="Lcom/simibubi/create/content/fluids/FluidNetwork;tick()V", + at=@At( + value="INVOKE", + ordinal=0, + target="Lnet/minecraftforge/fluids/FluidStack;isFluidEqual(Lnet/minecraftforge/fluids/FluidStack;)Z" + ), + remap=false ) - public void inTick(CallbackInfo ci, int cycle, boolean shouldContinue, Iterator> iterator, Pair pair, BlockFace blockFace, PipeConnection pipeConnection, Flow flow) { - FluidStack fluid = ((FluidNetworkAccessor)this).getFluid(); - if (DestroyFluids.isMixture(fluid) && DestroyFluids.isMixture(flow.fluid)) { - ((FluidNetworkAccessor)this).setFluid(flow.fluid); - ci.cancel(); - }; - }; + private boolean considerMixturesEqual(FluidStack fluid, FluidStack other, Operation original) { + if(original.call(fluid, other)) + return true; + else if(DestroyFluids.isMixture(fluid) && DestroyFluids.isMixture(other)) { + return true; + } + + return false; + } }; diff --git a/src/main/java/com/petrolpark/destroy/mixin/FluidPropagatorMixin.java b/src/main/java/com/petrolpark/destroy/mixin/FluidPropagatorMixin.java index a4f27da97..366e5e6b5 100644 --- a/src/main/java/com/petrolpark/destroy/mixin/FluidPropagatorMixin.java +++ b/src/main/java/com/petrolpark/destroy/mixin/FluidPropagatorMixin.java @@ -1,27 +1,26 @@ package com.petrolpark.destroy.mixin; -import com.petrolpark.destroy.DestroyBlocks; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.pump.PumpBlock; import com.tterrag.registrate.util.entry.BlockEntry; import net.minecraft.world.level.block.state.BlockState; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(FluidPropagator.class) public class FluidPropagatorMixin { - - @Redirect( - method = "Lcom/simibubi/create/content/fluids/FluidPropagator;propagateChangedPipe(Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V", - at = @At( - value = "INVOKE", - target = "Lcom/tterrag/registrate/util/entry/BlockEntry;has(Lnet/minecraft/world/level/block/state/BlockState;)Z", - remap = false + @WrapOperation( + method="Lcom/simibubi/create/content/fluids/FluidPropagator;propagateChangedPipe(Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V", + at=@At( + value="INVOKE", + target="Lcom/tterrag/registrate/util/entry/BlockEntry;has(Lnet/minecraft/world/level/block/state/BlockState;)Z", + remap=false ), remap=false ) - @SuppressWarnings("rawtypes") - private static boolean matchOtherPumps(BlockEntry instance, BlockState state) { - return instance.has(state) || DestroyBlocks.CREATIVE_PUMP.has(state); - }; + private static boolean matchOtherPumps(BlockEntry instance, BlockState state, Operation original) { + return (state.getBlock() instanceof PumpBlock) || original.call(instance, state); + } } diff --git a/src/main/java/com/petrolpark/destroy/mixin/FluidTransportBehaviourMixin.java b/src/main/java/com/petrolpark/destroy/mixin/FluidTransportBehaviourMixin.java new file mode 100644 index 000000000..5fafbd27a --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/mixin/FluidTransportBehaviourMixin.java @@ -0,0 +1,71 @@ +package com.petrolpark.destroy.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.petrolpark.destroy.DestroyFluids; +import com.petrolpark.destroy.chemistry.legacy.LegacyMixture; +import com.petrolpark.destroy.chemistry.minecraft.MixtureFluid; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.Map; + +@Mixin(FluidTransportBehaviour.class) +public class FluidTransportBehaviourMixin { + private ThreadLocal accumulatedAvailableFluid = new ThreadLocal<>(); + + @WrapOperation( + method = "tick()V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraftforge/fluids/FluidStack;isFluidEqual(Lnet/minecraftforge/fluids/FluidStack;)Z", + remap = false + ), + remap = false + ) + private boolean considerMixturesEqual(FluidStack fluid, FluidStack other, Operation original) { + if(original.call(fluid, other)) + return true; + else if(DestroyFluids.isMixture(fluid) && DestroyFluids.isMixture(other)) { + return true; + } + + return false; + } + + @ModifyVariable( + method = "tick()V", + name = "availableFlow", + at = @At("STORE"), + remap = false + ) + private FluidStack accumulateAvailableFluidStack(FluidStack providedFluid) { + if(providedFluid.isEmpty()) { + // If providedFluid is empty, we just initialized availableFlow + accumulatedAvailableFluid.set(FluidStack.EMPTY); + } else if(DestroyFluids.isMixture(providedFluid)) { + if(accumulatedAvailableFluid.get().isEmpty()) { + // First Mixture input, remember it and carry on as normal + accumulatedAvailableFluid.set(providedFluid); + return providedFluid; + } else { + // If this pipe segments has multiple Mixture inputs, mix them together + // This is purely visual for the sake of displaying flowing liquids in transparent pipes + LegacyMixture existingMixture = LegacyMixture.readNBT(accumulatedAvailableFluid.get().getOrCreateTag().getCompound("Mixture")); + LegacyMixture addedMixture = LegacyMixture.readNBT(providedFluid.getOrCreateTag().getCompound("Mixture")); + int existingAmount = accumulatedAvailableFluid.get().getAmount(); + int addedAmount = providedFluid.getAmount(); + LegacyMixture newMixture = LegacyMixture.mix(Map.of(existingMixture, existingAmount/1000d, addedMixture, addedAmount/1000d)); + + accumulatedAvailableFluid.set(MixtureFluid.of(existingAmount + addedAmount, newMixture)); + return accumulatedAvailableFluid.get(); + } + } + + // Not a Mixture input, carry on as normal + return providedFluid; + } +} diff --git a/src/main/java/com/petrolpark/destroy/mixin/MountedFluidStorageMixin.java b/src/main/java/com/petrolpark/destroy/mixin/MountedFluidStorageMixin.java new file mode 100644 index 000000000..54f62c1e9 --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/mixin/MountedFluidStorageMixin.java @@ -0,0 +1,52 @@ +package com.petrolpark.destroy.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.simibubi.create.content.contraptions.MountedFluidStorage; +import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.foundation.fluid.SmartFluidTank; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import com.petrolpark.destroy.core.fluid.GeniusFluidTankBehaviour.GeniusFluidTank; + +import java.util.function.Consumer; + +@Mixin(MountedFluidStorage.class) +public abstract class MountedFluidStorageMixin { + @Inject( + method = "Lcom/simibubi/create/content/contraptions/MountedFluidStorage;createMountedTank(Lnet/minecraft/world/level/block/entity/BlockEntity;)Lcom/simibubi/create/foundation/fluid/SmartFluidTank;", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private void createGeniusMountedTank(BlockEntity be, CallbackInfoReturnable cir) { + if(be instanceof FluidTankBlockEntity tank) { + cir.setReturnValue(new GeniusFluidTank( + tank.getTotalTankSize() * FluidTankBlockEntity.getCapacityMultiplier(), + this::invokeOnFluidStackChanged)); + } + } + + @WrapOperation( + method = "Lcom/simibubi/create/content/contraptions/MountedFluidStorage;deserialize(Lnet/minecraft/nbt/CompoundTag;)Lcom/simibubi/create/content/contraptions/MountedFluidStorage;", + at = @At( + value = "NEW", + target = "com/simibubi/create/foundation/fluid/SmartFluidTank" + ), + remap = false + ) + private static SmartFluidTank deserializeGeniusMountedTank(int capacity, Consumer updateCallback, Operation original) { + return new GeniusFluidTank(capacity, updateCallback); + } + + @Invoker( + value = "onFluidStackChanged", + remap = false + ) + public abstract void invokeOnFluidStackChanged(FluidStack stack); +} diff --git a/src/main/java/com/petrolpark/destroy/mixin/MultiPlayerGameModeMixin.java b/src/main/java/com/petrolpark/destroy/mixin/MultiPlayerGameModeMixin.java new file mode 100644 index 000000000..2662321b0 --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/mixin/MultiPlayerGameModeMixin.java @@ -0,0 +1,47 @@ +package com.petrolpark.destroy.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.petrolpark.destroy.core.block.IPickUpPutDownBlock; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.BlockHitResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(MultiPlayerGameMode.class) +public class MultiPlayerGameModeMixin { + private static boolean currentItemStackIgnoresCreative = false; + + @Inject( + method = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;performUseItemOn(Lnet/minecraft/client/player/LocalPlayer;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;useOn(Lnet/minecraft/world/item/context/UseOnContext;)Lnet/minecraft/world/InteractionResult;", + ordinal = 0 + ) + ) + private void checkCurrentItemStack(LocalPlayer pPlayer, InteractionHand pHand, BlockHitResult pResult, CallbackInfoReturnable cir) { + currentItemStackIgnoresCreative = pPlayer.getItemInHand(pHand).getItem() instanceof BlockItem blockItem && blockItem.getBlock() instanceof IPickUpPutDownBlock; + } + + @WrapOperation( + method = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;performUseItemOn(Lnet/minecraft/client/player/LocalPlayer;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;setCount(I)V" + ) + ) + private void dontRevertItemStack(ItemStack instance, int pCount, Operation original) { + if(currentItemStackIgnoresCreative) + currentItemStackIgnoresCreative = false; + else + original.call(instance, pCount); + } +} diff --git a/src/main/java/com/petrolpark/destroy/mixin/PipeConnectionMixin.java b/src/main/java/com/petrolpark/destroy/mixin/PipeConnectionMixin.java index ed103e932..5ebde69aa 100644 --- a/src/main/java/com/petrolpark/destroy/mixin/PipeConnectionMixin.java +++ b/src/main/java/com/petrolpark/destroy/mixin/PipeConnectionMixin.java @@ -3,9 +3,14 @@ import java.util.Optional; import java.util.function.Predicate; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.petrolpark.destroy.Destroy; +import com.petrolpark.destroy.chemistry.legacy.LegacyMixture; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @@ -23,45 +28,56 @@ @Mixin(PipeConnection.class) public class PipeConnectionMixin { - + private ThreadLocal> retainedNetwork = new ThreadLocal<>(); + private ThreadLocal shouldUpdateData = new ThreadLocal<>(); + + @Inject( + method= "manageFlows(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraftforge/fluids/FluidStack;Ljava/util/function/Predicate;)Z", + at=@At("HEAD"), + remap=false + ) + private void manageFlows_onStart(Level world, BlockPos pos, FluidStack internalFluid, Predicate extractionPredicate, CallbackInfoReturnable cir) { + retainedNetwork.set(((PipeConnectionAccessor)this).getNetwork()); + shouldUpdateData.set(false); + } + + @Inject( + method= "manageFlows(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraftforge/fluids/FluidStack;Ljava/util/function/Predicate;)Z", + at=@At("RETURN"), + cancellable = true, + remap=false + ) + private void manageFlows_onReturn(Level world, BlockPos pos, FluidStack internalFluid, Predicate extractionPredicate, CallbackInfoReturnable cir) { + // Returning true from PipeConnection.manageFlows causes its data to be sent from the server to the client. + // We want that to happen whenever the Mixture carried by this connection changes. + if(shouldUpdateData.get()) + cir.setReturnValue(true); + } + /** - * Usually if a Fluid Network is trying to pull from a Tank and is animating the Fluid moving through the Pipes, it will + * Usually if a Fluid Network is trying to pull from a Tank and is animating the Fluid moving through the Pipes, it will * reset if the Fluid Stack changes. This stops this behaviour if the Fluid being transferred happens to be a Mixture, as * these change a lot. We don't want to try restarting the flow every tick. - * @param world - * @param pos - * @param internalFluid - * @param extractionPredicate - * @param cir */ - @Inject( - method = "Lcom/simibubi/create/content/fluids/PipeConnection;manageFlows(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraftforge/fluids/FluidStack;Ljava/util/function/Predicate;)Z", - at = @At( - value = "INVOKE", - target = "empty", - ordinal = 1 - ), - cancellable = true, - locals = LocalCapture.CAPTURE_FAILSOFT, - remap = false + @WrapOperation( + method= "manageFlows(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraftforge/fluids/FluidStack;Ljava/util/function/Predicate;)Z", + at=@At( + value="INVOKE", + target="Lnet/minecraftforge/fluids/FluidStack;isFluidEqual(Lnet/minecraftforge/fluids/FluidStack;)Z" + ), + remap=false ) - public void inManageFlows(Level world, BlockPos pos, FluidStack internalFluid, Predicate extractionPredicate, CallbackInfoReturnable cir, Optional retainedNetwork) { - Flow flow = ((PipeConnectionAccessor)this).getFlow().get(); - FlowSource source = ((PipeConnectionAccessor)this).getSource().get(); - - FluidStack provided = flow.inbound ? source.provideFluid(extractionPredicate) : internalFluid; - if (((PipeConnection)(Object)this).hasPressure() && DestroyFluids.isMixture(provided) && DestroyFluids.isMixture(flow.fluid)) { // Only update the Fluid if we have Fluid and should be moving it - flow.fluid = provided; - Optional network = retainedNetwork; - if (network.isPresent()) { - ((FluidNetworkAccessor)network.get()).setFluid(provided.copy()); - ((PipeConnectionAccessor)this).setNetwork(network); - }; + private boolean considerMixturesEqual(FluidStack fluid, FluidStack other, Operation original) { + if(original.call(fluid, other)) + return true; + else if(DestroyFluids.isMixture(fluid) && DestroyFluids.isMixture(other)) { + ((PipeConnectionAccessor)this).getFlow().get().fluid = fluid; + if(retainedNetwork.get().isPresent()) + ((FluidNetworkAccessor)retainedNetwork.get().get()).setFluid(fluid); + shouldUpdateData.set(true); + return true; + } - ((PipeConnection)(Object)this).manageFlows(world, pos, internalFluid, extractionPredicate); - - cir.setReturnValue(true); // Let the client know an update has occured - cir.cancel(); - }; - }; + return false; + } }; diff --git a/src/main/java/com/petrolpark/destroy/mixin/PortableStorageInterfaceMovementMixin.java b/src/main/java/com/petrolpark/destroy/mixin/PortableStorageInterfaceMovementMixin.java new file mode 100644 index 000000000..45b0f3714 --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/mixin/PortableStorageInterfaceMovementMixin.java @@ -0,0 +1,34 @@ +package com.petrolpark.destroy.mixin; + +import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PortableStorageInterfaceMovement.class) +public class PortableStorageInterfaceMovementMixin { + /** + * This isn't related to Destroy whatsoever but my farms keep getting stuck and + * it's pissing me off so fuck it, I'm doing it here. + */ + @Inject( + method = "Lcom/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceMovement;tick(Lcom/simibubi/create/content/contraptions/behaviour/MovementContext;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/nbt/CompoundTag;contains(Ljava/lang/String;)Z", + remap = true + ), + remap = false, + cancellable = true + ) + private void fixStalledInterface(MovementContext context, CallbackInfo ci) { + // If the PSI has no working position set, unstall it. + // I haven't found the actual root cause for this but I suspect it happens when the chunk gets unloaded right before a PSI disengages. + if(!context.data.contains("WorkingPos")) { + ((PortableStorageInterfaceMovement)(Object)this).cancelStall(context); + ci.cancel(); + } + } +} diff --git a/src/main/java/com/petrolpark/destroy/mixin/ServerPlayerGameModeMixin.java b/src/main/java/com/petrolpark/destroy/mixin/ServerPlayerGameModeMixin.java new file mode 100644 index 000000000..09c45eae3 --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/mixin/ServerPlayerGameModeMixin.java @@ -0,0 +1,48 @@ +package com.petrolpark.destroy.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.petrolpark.destroy.core.block.IPickUpPutDownBlock; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ServerPlayerGameMode.class) +public class ServerPlayerGameModeMixin { + private static boolean currentItemStackIgnoresCreative = false; + + @Inject( + method = "Lnet/minecraft/server/level/ServerPlayerGameMode;useItemOn(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;useOn(Lnet/minecraft/world/item/context/UseOnContext;)Lnet/minecraft/world/InteractionResult;", + ordinal = 0 + ) + ) + private void checkCurrentItemStack(ServerPlayer pPlayer, Level pLevel, ItemStack pStack, InteractionHand pHand, BlockHitResult pHitResult, CallbackInfoReturnable cir) { + currentItemStackIgnoresCreative = pStack.getItem() instanceof BlockItem blockItem && blockItem.getBlock() instanceof IPickUpPutDownBlock; + } + + @WrapOperation( + method = "Lnet/minecraft/server/level/ServerPlayerGameMode;useItemOn(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;setCount(I)V" + ) + ) + private void dontRevertItemStack(ItemStack instance, int pCount, Operation original) { + if(currentItemStackIgnoresCreative) + currentItemStackIgnoresCreative = false; + else + original.call(instance, pCount); + } +} diff --git a/src/main/java/com/petrolpark/destroy/mixin/ValueSettingsPacketMixin.java b/src/main/java/com/petrolpark/destroy/mixin/ValueSettingsPacketMixin.java index 1114f6ab3..6bbf50a2f 100644 --- a/src/main/java/com/petrolpark/destroy/mixin/ValueSettingsPacketMixin.java +++ b/src/main/java/com/petrolpark/destroy/mixin/ValueSettingsPacketMixin.java @@ -33,6 +33,7 @@ protected void applySettings(ServerPlayer player, SmartBlockEntity be) { continue; if (hand != null) { valueSettingsBehaviour.onShortInteract(player, hand, side); + return; }; if (valueSettingsBehaviour instanceof BetterValueSettingsBehaviour smartValueSettingsBehaviour) { smartValueSettingsBehaviour.acceptAccessInformation(hand, side); diff --git a/src/main/java/com/petrolpark/destroy/mixin/compat/supplementaries/SoftFluidStackImplMixin.java b/src/main/java/com/petrolpark/destroy/mixin/compat/supplementaries/SoftFluidStackImplMixin.java new file mode 100644 index 000000000..a7c1e9c1c --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/mixin/compat/supplementaries/SoftFluidStackImplMixin.java @@ -0,0 +1,22 @@ +package com.petrolpark.destroy.mixin.compat.supplementaries; + +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import net.mehvahdjukaar.moonlight.api.fluids.SoftFluidStack; +import net.mehvahdjukaar.moonlight.api.fluids.forge.SoftFluidStackImpl; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(SoftFluidStackImpl.class) +public class SoftFluidStackImplMixin { + @WrapMethod( + method = "Lnet/mehvahdjukaar/moonlight/api/fluids/forge/SoftFluidStackImpl;toForgeFluid(Lnet/mehvahdjukaar/moonlight/api/fluids/SoftFluidStack;)Lnet/minecraftforge/fluids/FluidStack;", + remap = false + ) + private static FluidStack toForgeFluid(SoftFluidStack softFluid, Operation original) { + FluidStack stack = original.call(softFluid); + if(softFluid.hasTag() && softFluid.getTag().contains("Mixture")) + stack.getOrCreateTag().put("Mixture", softFluid.getTag().getCompound("Mixture")); + return stack; + } +} diff --git a/src/main/java/com/petrolpark/destroy/mixin/compat/supplementaries/SpongeInteractionMixin.java b/src/main/java/com/petrolpark/destroy/mixin/compat/supplementaries/SpongeInteractionMixin.java new file mode 100644 index 000000000..214ac3c36 --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/mixin/compat/supplementaries/SpongeInteractionMixin.java @@ -0,0 +1,30 @@ +package com.petrolpark.destroy.mixin.compat.supplementaries; + +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.petrolpark.destroy.core.pollution.PollutionHelper; +import net.mehvahdjukaar.moonlight.api.fluids.forge.SoftFluidStackImpl; +import net.mehvahdjukaar.supplementaries.common.block.faucet.FluidOffer; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(targets = "net/mehvahdjukaar/supplementaries/common/block/faucet/SpongeInteraction") +public class SpongeInteractionMixin { + @WrapMethod( + method = "fill", + remap = false + ) + public Integer fill(Level level, BlockPos pos, BlockState target, FluidOffer offer, Operation original) { + Integer result = original.call(level, pos, target, offer); + if(result != null && result.intValue() > 0) { + // Voiding fluids by pouring them onto a sponge releases them into the atmosphere + FluidStack fluidStack = SoftFluidStackImpl.toForgeFluid(offer.fluid().copyWithCount(result.intValue())); + PollutionHelper.pollute(level, pos, 1.f, 1, fluidStack); + }; + return result; + } +} diff --git a/src/main/java/com/petrolpark/destroy/mixin/patch/ContaminantMixin.java b/src/main/java/com/petrolpark/destroy/mixin/patch/ContaminantMixin.java new file mode 100644 index 000000000..15b9ce9ac --- /dev/null +++ b/src/main/java/com/petrolpark/destroy/mixin/patch/ContaminantMixin.java @@ -0,0 +1,28 @@ +package com.petrolpark.destroy.mixin.patch; + +import com.petrolpark.PetrolparkRegistries; +import com.petrolpark.contamination.Contaminant; +import net.minecraft.resources.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(Contaminant.class) +public class ContaminantMixin { + @Shadow + protected ResourceLocation rl; + + /** + * @author _Kilburn + * @reason Temporarily patching this here so I don't have to maintain a separate fork of the Library. It's not pretty but it'll have to do for now. + */ + @Overwrite(remap=false) + public ResourceLocation getLocation() { + if (this.rl == null) { + this.rl = PetrolparkRegistries.getDataRegistry(PetrolparkRegistries.Keys.CONTAMINANT).getKey((Contaminant)(Object)this); + } + + return this.rl; + } + +} diff --git a/src/main/java/com/petrolpark/destroy/mixin/plugin/DestroyMixinPlugin.java b/src/main/java/com/petrolpark/destroy/mixin/plugin/DestroyMixinPlugin.java index b0d05dc37..a80168e6c 100644 --- a/src/main/java/com/petrolpark/destroy/mixin/plugin/DestroyMixinPlugin.java +++ b/src/main/java/com/petrolpark/destroy/mixin/plugin/DestroyMixinPlugin.java @@ -1,5 +1,6 @@ package com.petrolpark.destroy.mixin.plugin; +import com.bawnorton.mixinsquared.canceller.MixinCancellerRegistrar; import com.petrolpark.compat.CompatMods; import com.petrolpark.mixin.plugin.PetrolparkMixinPlugin; @@ -14,6 +15,10 @@ protected String getMixinPackage() { public void onLoad(String mixinPackage) { // TFMG mixins requireMultipleMods("AdvancedDistillationCategoryMixin", CompatMods.TFMG, CompatMods.JEI); + + // Fixes a compatibility issue with TFMG caused by the way it registers its own custom pumps + // Not a permanent solution (hopefully) + MixinCancellerRegistrar.register((targetClassNames, mixinClassName) -> mixinClassName.equals("com.drmangotea.tfmg.mixins.FluidPropagatorMixin")); }; }; diff --git a/src/main/resources/assets/destroy/font/charge.json b/src/main/resources/assets/destroy/font/charge.json new file mode 100644 index 000000000..a984cc670 --- /dev/null +++ b/src/main/resources/assets/destroy/font/charge.json @@ -0,0 +1,10 @@ +{ + "providers": [ + { + "type": "bitmap", + "file": "destroy:font/charge.png", + "ascent": 7, + "chars": ["0123456789+-"] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/destroy/lang/en_gb.json b/src/main/resources/assets/destroy/lang/en_gb.json index 9bd7781b5..88725fa29 100644 --- a/src/main/resources/assets/destroy/lang/en_gb.json +++ b/src/main/resources/assets/destroy/lang/en_gb.json @@ -1294,7 +1294,7 @@ "destroy.reaction.hydrogen_combustion": "[destroy:hydrogen] Combustion", "destroy.reaction.hydrogen_combustion.description": "The highly {exothermic, destroy:exothermic} {oxidation, destroy:oxidation} of [destroy:hydrogen].", "destroy.reaction.hydrogen_cyanide_dissociation": "[destroy:hydrogen_cyanide] Dissociation", - "destroy.reaction.hydrogen_cyanide_dissociation.description": "Hydrogen cyanide is a weak acid that does not easily dissociate in water. It can be coaxed into doing so by reacting it with a {destroy:base}.", + "destroy.reaction.hydrogen_cyanide_dissociation.description": "Hydrogen cyanide is a weak acid that does not easily dissociate in water. It can be coaxed into doing so by reacting it with a {base, destroy:base}.", "destroy.reaction.hydrogen_iodide_synthesis": "[destroy:hydrogen_iodide] Synthesis", "destroy.reaction.hydrogen_iodide_synthesis.description": "A method for the production of [destroy:hydrogen_iodide].", "destroy.reaction.hydroxide_neutralization": "Neutralisation", @@ -1302,7 +1302,7 @@ "destroy.reaction.hypochlorite_formation": "[destroy:hypochlorite] Formation", "destroy.reaction.hypochlorite_formation.description": "The {disproportionation, destroy:disproportionation} of [destroy:chlorine] with sodium hydroxide.", "destroy.reaction.hypochlorous_acid_dissociation": "[destroy:hypochlorous_acid] Dissociation", - "destroy.reaction.hypochlorous_acid_dissociation.description": "Hypochlorous Acid is a weak acid that does not easily dissociate in water. It can be coaxed into doing so by reacting it with a {destroy:base}.", + "destroy.reaction.hypochlorous_acid_dissociation.description": "Hypochlorous Acid is a weak acid that does not easily dissociate in water. It can be coaxed into doing so by reacting it with a {base, destroy:base}.", "destroy.reaction.iodide_displacement": "[destroy:iodide] Displacement", "destroy.reaction.iodide_displacement.description": "The {oxidation, destroy:oxidation} of [destroy:iodide] and {reduction, destroy:reduction} of [destroy:chlorine].", "destroy.reaction.iodine_dissolution": "[destroy:iodine] Solution", @@ -1390,7 +1390,7 @@ "destroy.reaction.sulfur_trioxide_hydration": "[destroy:sulfur_trioxide] Hydration", "destroy.reaction.sulfur_trioxide_hydration.description": "The {hydration, destroy:hydrolysis} of [destroy:sulfur_trioxide] to make [destroy:sulfuric_acid], which is the ultimate product from combining [destroy:sulfur], [destroy:oxygen] and [destroy:water].", "destroy.reaction.tatp": "Acetone Peroxide Synthesis", - "destroy.reaction.tatp.description": "A dangerous way of producing an explosive, which has injured many an amatuer chemist.", + "destroy.reaction.tatp.description": "A dangerous way of producing an explosive, which has injured many an amateur chemist.", "destroy.reaction.tetraborate_equilibrium": "[destroy:tetrahydroxy_tetraborate] Equilibrium", "destroy.reaction.tetraborate_equilibrium.description": "The interconversion of various boron oxides in solution.", "destroy.reaction.tetraethyllead_synthesis": "[destroy:tetraethyllead] Synthesis", diff --git a/src/main/resources/assets/destroy/lang/en_us.json b/src/main/resources/assets/destroy/lang/en_us.json index 60ea2773f..14fd34f47 100644 --- a/src/main/resources/assets/destroy/lang/en_us.json +++ b/src/main/resources/assets/destroy/lang/en_us.json @@ -139,9 +139,9 @@ "block.destroy.beaker.tooltip": "BEAKER", "block.destroy.beaker.tooltip.summary": "A vessel which can store and transport _medium_ amount of Mixture. Can be _placed_ and easily picked up.", "block.destroy.beaker.tooltip.condition1": "When Right-Clicked", - "block.destroy.beaker.tooltip.behaviour1": "_Empties_ the Beaker into the targeted recepticle.", + "block.destroy.beaker.tooltip.behaviour1": "_Empties_ the Beaker into the targeted receptacle.", "block.destroy.beaker.tooltip.condition2": "When Left-Clicked", - "block.destroy.beaker.tooltip.behaviour2": "_Fills_ the Beaker from the targeted recepticle.", + "block.destroy.beaker.tooltip.behaviour2": "_Fills_ the Beaker from the targeted receptacle.", "block.destroy.blacklight": "Blacklight", "block.destroy.blowpipe": "Blowpipe", "block.destroy.borosilicate_glass": "Borosilicate Glass", @@ -205,9 +205,9 @@ "block.destroy.measuring_cylinder.filled": "Measuring Cylinder of %1$s", "block.destroy.measuring_cylinder.tooltip.summary": "A vessel which can transfer _exact_ amounts of Mixture.", "block.destroy.measuring_cylinder.tooltip.condition1": "When Right-Clicked and Held", - "block.destroy.measuring_cylinder.tooltip.behaviour1": "_Empties_ a specific amount into the targeted recepticle.", + "block.destroy.measuring_cylinder.tooltip.behaviour1": "_Empties_ a specific amount into the targeted receptacle.", "block.destroy.measuring_cylinder.tooltip.condition2": "When Left-Clicked and Held", - "block.destroy.measuring_cylinder.tooltip.behaviour2": "_Fills_ a specific amount from the targeted recepticle.", + "block.destroy.measuring_cylinder.tooltip.behaviour2": "_Fills_ a specific amount from the targeted receptacle.", "block.destroy.mechanical_sieve": "Mechanical Sieve", "block.destroy.mercury_periodic_table_block": "Mercury Element Block", "block.destroy.molten_borosilicate_glass": "Molten Borosilicate Glass", @@ -229,7 +229,7 @@ "block.destroy.picric_acid_block": "Picric Acid Block", "block.destroy.picric_acid_block.tooltip": "PICRIC_ACID_BLOCK", "block.destroy.picric_acid_block.tooltip.summary": "This _powerful explosive_ can even detonate _underwater_.", - "block.destroy.platinum_block": "Block of Plywood", + "block.destroy.platinum_block": "Block of Platinum", "block.destroy.platinum_periodic_table_block": "Platinum Element Block", "block.destroy.plywood": "Plywood", "block.destroy.pollutometer": "Pollutometer", @@ -249,9 +249,9 @@ "block.destroy.round_bottomed_flask.filled": "Round-Bottomed Flask of %1$s", "block.destroy.round_bottomed_flask.tooltip.summary": "A vessel which can store and transport _medium_ amount of Mixture. Can be _placed_ and easily picked up.", "block.destroy.round_bottomed_flask.tooltip.condition1": "When Right-Clicked", - "block.destroy.round_bottomed_flask.tooltip.behaviour1": "_Empties_ the Flask into the targeted recepticle.", + "block.destroy.round_bottomed_flask.tooltip.behaviour1": "_Empties_ the Flask into the targeted receptacle.", "block.destroy.round_bottomed_flask.tooltip.condition2": "When Left-Clicked", - "block.destroy.round_bottomed_flask.tooltip.behaviour2": "_Fills_ the Flask from the targeted recepticle.", + "block.destroy.round_bottomed_flask.tooltip.behaviour2": "_Fills_ the Flask from the targeted receptacle.", "block.destroy.sandcastle": "Sandcastle", "block.destroy.siphon": "Redstone Siphon", "block.destroy.siphon.drain_amount": "Amount to Drain", @@ -623,8 +623,8 @@ "destroy.display_source.colorimeter.species_name.dont_include": "No Molecule name", "destroy.display_source.mixture.temperature_unit": "Temperature Unit", "destroy.display_source.mixture.temperature_unit.kelvin": "Kelvins", - "destroy.display_source.mixture.temperature_unit.celcius": "Degrees Celcius", - "destroy.display_source.mixture.temperature_unit.farenheit": "Degrees Farenheit", + "destroy.display_source.mixture.temperature_unit.celcius": "Degrees Celsius", + "destroy.display_source.mixture.temperature_unit.farenheit": "Degrees Fahrenheit", "destroy.display_source.mixture.molecule_name_type": "Molecule Names", "destroy.display_source.mixture.molecule_name_type.iupac": "IUPAC Names", "destroy.display_source.mixture.molecule_name_type.common": "Common Names", @@ -1174,7 +1174,7 @@ "destroy.reaction.hydrogen_combustion": "[destroy:hydrogen] Combustion", "destroy.reaction.hydrogen_combustion.description": "The highly {exothermic, destroy:exothermic} {oxidation, destroy:oxidation} of [destroy:hydrogen].", "destroy.reaction.hydrogen_cyanide_dissociation": "[destroy:hydrogen_cyanide] Dissociation", - "destroy.reaction.hydrogen_cyanide_dissociation.description": "Hydrogen cyanide is a weak acid that does not easily dissociate in water. It can be coaxed into doing so by reacting it with a {destroy:base}.", + "destroy.reaction.hydrogen_cyanide_dissociation.description": "[destroy:hydrogen_cyanide] is a weak acid that does not easily dissociate in water. It can be coaxed into doing so by reacting it with a {base, destroy:base}.", "destroy.reaction.hydrogen_iodide_synthesis": "[destroy:hydrogen_iodide] Synthesis", "destroy.reaction.hydrogen_iodide_synthesis.description": "A method for the production of [destroy:hydrogen_iodide].", "destroy.reaction.hydroxide_neutralization": "Neutralization", @@ -1182,7 +1182,7 @@ "destroy.reaction.hypochlorite_formation": "[destroy:hypochlorite] Formation", "destroy.reaction.hypochlorite_formation.description": "The {disproportionation, destroy:disproportionation} of [destroy:chlorine] with sodium hydroxide.", "destroy.reaction.hypochlorous_acid_dissociation": "[destroy:hypochlorous_acid] Dissociation", - "destroy.reaction.hypochlorous_acid_dissociation.description": "Hypochlorous Acid is a weak acid that does not easily dissociate in water. It can be coaxed into doing so by reacting it with a {destroy:base}.", + "destroy.reaction.hypochlorous_acid_dissociation.description": "[destroy:hypochlorous_acid] is a weak acid that does not easily dissociate in water. It can be coaxed into doing so by reacting it with a {base, destroy:base}.", "destroy.reaction.iodide_displacement": "[destroy:iodide] Displacement", "destroy.reaction.iodide_displacement.description": "The {oxidation, destroy:oxidation} of [destroy:iodide] and {reduction, destroy:reduction} of [destroy:chlorine].", "destroy.reaction.iodine_dissolution": "[destroy:iodine] Solution", @@ -1270,7 +1270,7 @@ "destroy.reaction.sulfur_trioxide_hydration": "[destroy:sulfur_trioxide] Hydration", "destroy.reaction.sulfur_trioxide_hydration.description": "The {hydration, destroy:hydrolysis} of [destroy:sulfur_trioxide] to make [destroy:sulfuric_acid], which is the ultimate product from combining [destroy:sulfur], [destroy:oxygen] and [destroy:water].", "destroy.reaction.tatp": "Acetone Peroxide Synthesis", - "destroy.reaction.tatp.description": "A dangerous way of producing an explosive, which has injured many an amatuer chemist.", + "destroy.reaction.tatp.description": "A dangerous way of producing an explosive, which has injured many an amateur chemist.", "destroy.reaction.tetraborate_equilibrium": "[destroy:tetrahydroxy_tetraborate] Equilibrium", "destroy.reaction.tetraborate_equilibrium.description": "The interconversion of various boron oxides in solution.", "destroy.reaction.tetraethyllead_synthesis": "[destroy:tetraethyllead] Synthesis", @@ -1466,6 +1466,7 @@ "destroy.tooltip.vat.pressure.max": "Maximum: %1$skPa (%2$s)", "destroy.tooltip.vat.power": "Power Supplied: %1$skW", "destroy.tooltip.vat.temperature": "Vat Temperature: %1$s", + "destroy.tooltip.vat.temperature.outer": "Wall Temperature: %1$s", "destroy.tooltip.vat.reacting.header": "Reacting", "destroy.tooltip.vat.reacting": "The Mixture in this Vat is constantly changing. It will be difficult to extract it.", "destroy.tooltip.vat_material.conductivity": "Conductivity:", @@ -1891,9 +1892,9 @@ "item.destroy.test_tube.tooltip": "TEST_TUBE", "item.destroy.test_tube.tooltip.summary": "A vessel that can contain a _small_ amount of _liquid_ Mixture.", "item.destroy.test_tube.tooltip.condition1": "When Right-Clicked", - "item.destroy.test_tube.tooltip.behaviour1": "_Empties_ the Test Tube into the targeted recepticle.", + "item.destroy.test_tube.tooltip.behaviour1": "_Empties_ the Test Tube into the targeted receptacle.", "item.destroy.test_tube.tooltip.condition2": "When Left-Clicked", - "item.destroy.test_tube.tooltip.behaviour2": "_Fills_ the Test Tube from the targeted recepticle.", + "item.destroy.test_tube.tooltip.behaviour2": "_Fills_ the Test Tube from the targeted receptacle.", "item.destroy.thermite_brownie": "Thermite Brownie", "item.destroy.thermite_brownie.tooltip": "THERMITE_BROWNIE", "item.destroy.thermite_brownie.tooltip.summary": "This brownie is even spicier than normal. Your _Blaze Burners_ love them.", diff --git a/src/main/resources/assets/destroy/models/block/mechanical_sieve/shaft.json b/src/main/resources/assets/destroy/models/block/mechanical_sieve/shaft.json index ba6d4f821..2224684fb 100644 --- a/src/main/resources/assets/destroy/models/block/mechanical_sieve/shaft.json +++ b/src/main/resources/assets/destroy/models/block/mechanical_sieve/shaft.json @@ -8,31 +8,30 @@ }, "elements": [ { - "from": [6, 14, 6], - "to": [10, 16, 10], + "from": [6, 6, 14], + "to": [10, 10, 16], "rotation": {"angle": 0, "axis": "x", "origin": [8, 8, 8]}, "faces": { - "north": {"uv": [6, 14, 10, 16], "rotation": 180, "texture": "#0"}, - "east": {"uv": [6, 0, 10, 2], "rotation": 180, "texture": "#0"}, - "south": {"uv": [6, 14, 10, 16], "texture": "#0"}, - "west": {"uv": [6, 0, 10, 2], "texture": "#0"}, - "up": {"uv": [8, 0, 6, 2], "texture": "#2"}, - "down": {"uv": [6, 0, 8, 2], "rotation": 180, "texture": "#2"} + "north": {"uv": [6, 0, 8, 2], "texture": "#2"}, + "east": {"uv": [6, 0, 10, 2], "rotation": 90, "texture": "#0"}, + "south": {"uv": [8, 0, 6, 2], "texture": "#2"}, + "west": {"uv": [6, 0, 10, 2], "rotation": 90, "texture": "#0"}, + "up": {"uv": [6, 14, 10, 16], "texture": "#0"}, + "down": {"uv": [6, 14, 10, 16], "texture": "#0"} } }, { - "from": [6, 0, 6], - "to": [10, 2, 10], + "from": [6, 6, 0], + "to": [10, 10, 2], "rotation": {"angle": 0, "axis": "x", "origin": [8, 8, 8]}, "faces": { - "north": {"uv": [6, 0, 10, 2], "rotation": 180, "texture": "#0"}, - "east": {"uv": [6, 0, 10, 2], "rotation": 180, "texture": "#0"}, - "south": {"uv": [6, 0, 10, 2], "texture": "#0"}, - "west": {"uv": [6, 0, 10, 2], "texture": "#0"}, - "up": {"uv": [8, 0, 6, 2], "texture": "#2"}, - "down": {"uv": [6, 0, 8, 2], "rotation": 180, "texture": "#2"} + "north": {"uv": [6, 0, 8, 2], "texture": "#2"}, + "east": {"uv": [6, 0, 10, 2], "rotation": 90, "texture": "#0"}, + "south": {"uv": [8, 0, 6, 2], "texture": "#2"}, + "west": {"uv": [6, 0, 10, 2], "rotation": 90, "texture": "#0"}, + "up": {"uv": [6, 0, 10, 2], "texture": "#0"}, + "down": {"uv": [6, 0, 10, 2], "texture": "#0"} } } - ], - "display": {} + ] } \ No newline at end of file diff --git a/src/main/resources/assets/destroy/models/block/tree_tap/arm.json b/src/main/resources/assets/destroy/models/block/tree_tap/arm.json index c9a955592..322355143 100644 --- a/src/main/resources/assets/destroy/models/block/tree_tap/arm.json +++ b/src/main/resources/assets/destroy/models/block/tree_tap/arm.json @@ -10,9 +10,9 @@ "elements": [ { "name": "Pinky", - "from": [4, 11, -1.95], - "to": [6, 15, 3.05], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 0, 0]}, + "from": [4, 23, 5.05], + "to": [6, 27, 10.05], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 7]}, "faces": { "north": {"uv": [0, 0, 2, 4], "rotation": 180, "texture": "#1"}, "east": {"uv": [0, 0, 4, 5], "rotation": 90, "texture": "#1"}, @@ -24,9 +24,9 @@ }, { "name": "Middle", - "from": [6, 12, -2], - "to": [8, 16, 3], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 0, 0]}, + "from": [6, 24, 5], + "to": [8, 28, 10], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 7]}, "faces": { "north": {"uv": [0, 0, 2, 4], "rotation": 180, "texture": "#1"}, "east": {"uv": [4, 8, 0, 13], "rotation": 90, "texture": "#1"}, @@ -38,9 +38,9 @@ }, { "name": "Index", - "from": [8, 14, -2], - "to": [10, 16, 6], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 0, 0]}, + "from": [8, 26, 5], + "to": [10, 28, 13], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 7]}, "faces": { "north": {"uv": [0, 0, 2, 2], "texture": "#1"}, "east": {"uv": [2, 1, 4, 9], "rotation": 270, "texture": "#1"}, @@ -52,9 +52,9 @@ }, { "name": "Thumb", - "from": [8, 12, -2], - "to": [12, 14, 1], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 0, 0]}, + "from": [8, 24, 5], + "to": [12, 26, 8], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 7]}, "faces": { "north": {"uv": [2, 0, 0, 4], "rotation": 90, "texture": "#1"}, "east": {"uv": [0, 1, 2, 4], "rotation": 270, "texture": "#1"}, @@ -66,9 +66,9 @@ }, { "name": "Palm", - "from": [5, 10, -2], - "to": [11, 12, 1], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 0, 0]}, + "from": [5, 22, 5], + "to": [11, 24, 8], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 7]}, "faces": { "north": {"uv": [1, 2, 3, 8], "rotation": 90, "texture": "#1"}, "east": {"uv": [1, 4, 3, 7], "rotation": 90, "texture": "#1"}, @@ -80,9 +80,9 @@ }, { "name": "Wrist", - "from": [6, 9, -1.95], - "to": [10.05, 12, 2], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 0, 0]}, + "from": [6, 21, 5.05], + "to": [10.05, 24, 9], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 7]}, "faces": { "north": {"uv": [3, 0, 6, 4], "rotation": 90, "texture": "#0"}, "east": {"uv": [4, 0, 7, 4], "rotation": 90, "texture": "#0"}, @@ -94,9 +94,9 @@ }, { "name": "Cuff", - "from": [5, 7, -3], - "to": [11, 9, 3], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 0, 0]}, + "from": [5, 19, 4], + "to": [11, 21, 10], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 7]}, "faces": { "north": {"uv": [0, 14, 6, 16], "rotation": 180, "texture": "#2"}, "east": {"uv": [0, 14, 6, 16], "rotation": 180, "texture": "#2"}, @@ -108,9 +108,9 @@ }, { "name": "Arm", - "from": [6, -2, -2], - "to": [10, 7, 2], - "rotation": {"angle": 0, "axis": "x", "origin": [8, 0, 0]}, + "from": [6, 10, 5], + "to": [10, 19, 9], + "rotation": {"angle": 0, "axis": "x", "origin": [8, 12, 7]}, "faces": { "north": {"uv": [0, 0, 4, 9], "texture": "#2"}, "east": {"uv": [0, 0, 4, 9], "texture": "#2"}, @@ -158,7 +158,7 @@ "groups": [ { "name": "Hand", - "origin": [8, 8, 8], + "origin": [8, 20, 15], "color": 0, "children": [0, 1, 2, 3, 4, 5, 6, 7] } diff --git a/src/main/resources/assets/destroy/textures/font/charge.png b/src/main/resources/assets/destroy/textures/font/charge.png new file mode 100644 index 000000000..e8354fe5b Binary files /dev/null and b/src/main/resources/assets/destroy/textures/font/charge.png differ diff --git a/src/main/resources/data/destroy/advancements/chrome.json b/src/main/resources/data/destroy/advancements/chrome.json index ba71aa746..abf597af4 100644 --- a/src/main/resources/data/destroy/advancements/chrome.json +++ b/src/main/resources/data/destroy/advancements/chrome.json @@ -1,24 +1,25 @@ { "parent": "destroy:urinate", "criteria": { - "hold": { + "hold_ingot": { "trigger": "minecraft:inventory_changed", "conditions": { "items": [ - { - "item": "destroy:nether_crocoite" - }, - { - "tag": "forge:raw_materials/chromium" - }, { "tag": "forge:ingots/chromium" - }, - { - "item": "destroy:crushed_raw_chromium" } ] } + }, + "hold_nugget": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:nuggets/chromium" + } + ] + } } }, "display": { @@ -35,7 +36,7 @@ }, "requirements": [ [ - "hold" + "hold_ingot", "hold_nugget" ] ] } \ No newline at end of file diff --git a/src/main/resources/data/destroy/advancements/plastic.json b/src/main/resources/data/destroy/advancements/plastic.json index 70a1768d1..e9ee1b479 100644 --- a/src/main/resources/data/destroy/advancements/plastic.json +++ b/src/main/resources/data/destroy/advancements/plastic.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "destroy:plastic" + "tag": "destroy:plastics" } ] } diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/borosilicate_glass.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/borosilicate_glass.json index 3ab2fa116..b7ce57f7c 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/borosilicate_glass.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/borosilicate_glass.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 300000, + "max_pressure_difference": 1200000, "conductivity": 15, "transparent": true, "blocks": [ diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/copper_casing.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/copper_casing.json index 5ce450860..f0ef29b79 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/copper_casing.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/copper_casing.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 500000, + "max_pressure_difference": 2000000, "conductivity": 400, "transparent": false, "blocks": [ diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/fiberglass.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/fiberglass.json index b44660147..ba705f70f 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/fiberglass.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/fiberglass.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 350000, + "max_pressure_difference": 1400000, "conductivity": 17, "transparent": false, "blocks": [ diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/insulated_stainless_steel.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/insulated_stainless_steel.json index 571e40c58..28fde0ac1 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/insulated_stainless_steel.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/insulated_stainless_steel.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 800000, + "max_pressure_difference": 3200000, "conductivity": 20, "transparent": false, "blocks": [ diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/iron.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/iron.json index 2dfa31f69..d6f6bb0db 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/iron.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/iron.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 250000, + "max_pressure_difference": 1000000, "conductivity": 50, "transparent": false, "blocks": [ diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/netherite_block.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/netherite_block.json index fb6c2dc7b..2126c56fd 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/netherite_block.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/netherite_block.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 1200000, + "max_pressure_difference": 4800000, "conductivity": 70, "transparent": false, "blocks": [ diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/stainless_steel.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/stainless_steel.json index aafee6572..c88839723 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/stainless_steel.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/stainless_steel.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 1000000, + "max_pressure_difference": 4000000, "conductivity": 35, "transparent": false, "blocks": [ diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/tinted_glass.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/tinted_glass.json index 345148708..f9136bd0d 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/tinted_glass.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/tinted_glass.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 100000, + "max_pressure_difference": 400000, "conductivity": 18, "transparent": false, "blocks": [ diff --git a/src/main/resources/data/destroy/destroy_compat/vat_materials/weak_glass.json b/src/main/resources/data/destroy/destroy_compat/vat_materials/weak_glass.json index 07a742fdf..f258c4fdc 100644 --- a/src/main/resources/data/destroy/destroy_compat/vat_materials/weak_glass.json +++ b/src/main/resources/data/destroy/destroy_compat/vat_materials/weak_glass.json @@ -1,5 +1,5 @@ { - "max_pressure_difference": 100000, + "max_pressure_difference": 400000, "conductivity": 30, "transparent": true, "blocks": [ diff --git a/src/main/resources/data/supplementaries/tags/blocks/faucet_connection_blacklist.json b/src/main/resources/data/supplementaries/tags/blocks/faucet_connection_blacklist.json new file mode 100644 index 000000000..650310eb6 --- /dev/null +++ b/src/main/resources/data/supplementaries/tags/blocks/faucet_connection_blacklist.json @@ -0,0 +1,8 @@ +{ + "replace": false, + "values": [ + {"id":"destroy:beaker","required":false}, + {"id":"destroy:measuring_cylinder","required":false}, + {"id":"destroy:round_bottomed_flask","required":false} + ] +} \ No newline at end of file diff --git a/src/main/resources/data/supplementaries/blackboard_white.json b/src/main/resources/data/supplementaries/tags/items/blackboard_white.json similarity index 100% rename from src/main/resources/data/supplementaries/blackboard_white.json rename to src/main/resources/data/supplementaries/tags/items/blackboard_white.json diff --git a/src/main/resources/destroy.mixins.json b/src/main/resources/destroy.mixins.json index 89a2be060..e4c685d71 100644 --- a/src/main/resources/destroy.mixins.json +++ b/src/main/resources/destroy.mixins.json @@ -1,5 +1,5 @@ { - "required": "true", + "required": true, "package": "com.petrolpark.destroy.mixin", "compatibilityLevel": "JAVA_17", "refmap": "destroy.refmap.json", @@ -27,6 +27,9 @@ "compat.jei.MixingCategoryMixin", "compat.jei.PackingCategoryMixin", "compat.tfmg.AdvancedDistillationCategoryMixin", + "compat.supplementaries.SoftFluidStackImplMixin", + "compat.supplementaries.SpongeInteractionMixin", + "patch.ContaminantMixin", "AbstractContainerMenuMixin", "AirCurrentMixin", "BasinBlockEntityMixin", @@ -40,6 +43,7 @@ "FluidNetworkMixin", "FluidPropagatorMixin", "FluidTankBlockEntityMixin", + "FluidTransportBehaviourMixin", "GenericItemFillingMixin", "GhostItemMenuMixin", "HeatConditionMixin", @@ -48,13 +52,17 @@ "ItemEntityMixin", "LevelSettingsMixin", "MechanicalMixerBlockEntityMixin", + "MountedFluidStorageMixin", + "MultiPlayerGameModeMixin", "PipeConnectionMixin", "PlayerMixin", "PonderTagScreenMixin", + "PortableStorageInterfaceMovementMixin", "SchematicannonInventoryMixin", "SequencedAssemblyRecipeMixin", "ServerGamePacketListenerImplMixin", "ServerLevelMixin", + "ServerPlayerGameModeMixin", "SoundEntryBuilderMixin", "SplashingTypeMixin", "SpoutBlockMixin",