From 216aaf26c7437d922136b1801e1e603c962a38cc Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Sat, 23 Sep 2023 22:58:09 -0700 Subject: [PATCH 01/27] migrate from Forge to Neo --- .gitignore | 2 + Phosphophyllite | 2 +- Quartz | 2 +- build.gradle | 293 +++++++++-------------- gradle.properties | 6 +- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 61574 bytes gradle/wrapper/gradle-wrapper.properties | 5 +- settings.gradle | 17 ++ src/main/resources/META-INF/mods.toml | 10 +- 9 files changed, 146 insertions(+), 191 deletions(-) diff --git a/.gitignore b/.gitignore index 28e36be1..ed2ac11b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ logs # Files from Forge MDK forge*changelog.txt + +publishlocal \ No newline at end of file diff --git a/Phosphophyllite b/Phosphophyllite index dba020e7..be830c6e 160000 --- a/Phosphophyllite +++ b/Phosphophyllite @@ -1 +1 @@ -Subproject commit dba020e7170b01437c2dca0e66b0213b671b41b5 +Subproject commit be830c6e3f1fabf7883d39fb92f44b7a725461cd diff --git a/Quartz b/Quartz index 27d9b244..9611fdfd 160000 --- a/Quartz +++ b/Quartz @@ -1 +1 @@ -Subproject commit 27d9b244859b9d0ca9ad51099a50c38df75d1500 +Subproject commit 9611fdfd43a56dab23a4da6d225b87c92fdc33fa diff --git a/build.gradle b/build.gradle index dd4d9bf6..c89ee9cc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,24 +1,11 @@ -buildscript { - repositories { - // These repositories are only for Gradle plugins, put any other repositories in the repository block further below - maven { url = 'https://maven.minecraftforge.net' } - maven { url = 'https://maven.parchmentmc.org' } - mavenCentral() - } - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true - classpath 'org.parchmentmc:librarian:1.+' - } +plugins { + id 'eclipse' + id 'idea' + id 'maven-publish' + id 'net.neoforged.gradle' version '[6.0.18,6.2)' + id 'org.spongepowered.mixin' version '0.7.+' + id 'org.parchmentmc.librarian.forgegradle' version '1.+' } -apply plugin: 'net.minecraftforge.gradle' -apply plugin: 'org.parchmentmc.librarian.forgegradle' -// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. -apply plugin: 'eclipse' -apply plugin: 'maven-publish' - -java.toolchain.languageVersion = JavaLanguageVersion.of(17) - -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) evaluationDependsOnChildren() @@ -27,35 +14,30 @@ if (!"${postfixVersion}".isEmpty()) { version += "-${postfixVersion}" } -group = 'net.roguelogix.biggerreactors' -archivesBaseName = "biggerreactors-${mc_version}" +group = "net.roguelogix.${mod_id}" +base { + archivesName = "${mod_id}-${mc_version}" +} + +java.toolchain.languageVersion = JavaLanguageVersion.of(17) +println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { - mappings channel: "${mapping_channel}", version: "${mapping_version}" - // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. + mappings channel: mapping_channel, version: mapping_version + copyIdeResources = true accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - // Default run configurations. - // These can be tweaked, removed, or duplicated as needed. runs { - client { - workingDirectory project.file('run') - - //This fixes Mixin application problems from other mods because their refMaps are SRG-based, but we're in a MCP env - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" + // applies to all the run configs below + configureEach { + workingDirectory project.file("run/${it.name}") - // Recommended logging data for a userdev environment - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - arg "-mixin.config=phosphophyllite.mixins.json" - arg "-mixin.config=quartz.mixins.json" - - // Recommended logging level for the console + property 'forge.logging.markers', 'SCAN,REGISTRIES' property 'forge.logging.console.level', 'debug' mods { - BiggerReactors { + "${mod_id}" { source sourceSets.main } Quartz { @@ -67,72 +49,37 @@ minecraft { } } - server { - workingDirectory project.file('run') - - //This fixes Mixin application problems from other mods because their refMaps are SRG-based, but we're in a MCP env - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - - // Recommended logging data for a userdev environment - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + client { + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + property 'forge.enabledGameTestNamespaces', mod_id + } - // Recommended logging level for the console - property 'forge.logging.console.level', 'debug' + server { + property 'forge.enabledGameTestNamespaces', mod_id + args '--nogui' + } - mods { - BiggerReactors { - source sourceSets.main - } - Quartz { - source project(':Quartz').sourceSets.main - } - Phosphophyllite { - source project(':Phosphophyllite').sourceSets.main - } - } + gameTestServer { + property 'forge.enabledGameTestNamespaces', mod_id } data { - workingDirectory project.file('run') - - // Recommended logging data for a userdev environment - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - - // Recommended logging level for the console - property 'forge.logging.console.level', 'debug' - -// args '--mod', 'examplemod', '--all', '--output', file('src/generated/resources/') - - mods { - BiggerReactors { - source sourceSets.main - } - Quartz { - source project(':Quartz').sourceSets.main - } - Phosphophyllite { - source project(':Phosphophyllite').sourceSets.main - } - } + args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') } } } -configurations { - library - implementation.extendsFrom library -} -minecraft.runs.all { - lazyToken('minecraft_classpath') { - configurations.library.copyRecursive().resolve().collect { it.absolutePath }.join(File.pathSeparator) - } +// Include resources generated by data generators. +sourceSets.main.resources { srcDir 'src/generated/resources' } + +mixin { + config 'quartz.mixins.json' + config 'phosphophyllite.mixins.json' } repositories { maven { - name = "CurseForge" - url = "https://minecraft.curseforge.com/api/maven/" + url = "https://www.cursemaven.com" } maven { // location of the maven that hosts JEI files since January 2023 @@ -140,15 +87,11 @@ repositories { url = "https://maven.blamejared.com/" } maven { - url = "https://www.cursemaven.com" - } - maven { - url 'https://modmaven.k-4u.nl/' - } - maven { + // mekanism url 'https://modmaven.dev/' } maven { + // computer craft url 'https://squiddev.cc/maven/' content { includeGroup("cc.tweaked") @@ -158,10 +101,7 @@ repositories { } dependencies { - // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed - // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. - // The userdev artifact is a special name and will get all sorts of transformations applied to it. - minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" + minecraft "net.neoforged:forge:${mc_version}-${neo_version}" compileOnly project(':Phosphophyllite') compileOnly project(':Quartz') @@ -190,45 +130,11 @@ dependencies { // runtimeOnly fg.deobf('curse.maven:WorldStripper-250603:3545856') // runtimeOnly fg.deobf('curse.maven:CW-399558:3926815') - compileOnly "org.lwjgl:lwjgl-opencl:3.3.1" -} - -jar { - manifest { - attributes([ - "Specification-Title" : "BiggerReactors", - "Specification-Version" : "1", - "Implementation-Title" : project.name, - "Implementation-Version" : "${version}", - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") - ]) + minecraftLibrary("org.lwjgl:lwjgl-opencl:3.3.1") { + transitive(false) } } -publish.dependsOn('reobfJar') - -//task generateModeratorCsv(type: net.roguelogix.Json5ToCsvTask) { -// records = ["type", "location", "absorption", "efficiency", "moderation", "conductivity"] -// jsonInputs = fileTree(dir: "src/main/resources/data/biggerreactors/ebcr/moderators/", include: "**/*.json*") -// csvOutput = file("$buildDir/data/moderators.csv") -//} -// -//task generateCoilCsv(type: net.roguelogix.Json5ToCsvTask) { -// records = ["type", "location", "efficiency", "extractionRate", "bonus"] -// jsonInputs = fileTree(dir: "src/main/resources/data/biggerreactors/ebest/coils/", include: "**/*.json*") -// csvOutput = file("$buildDir/data/coils.csv") -//} -// -//task generateModeratorWikimedia(type: net.roguelogix.CsvToWikimediaTask, dependsOn: generateModeratorCsv) { -// csvInput = generateModeratorCsv.outputs.files[0] -// txtOutput = file("$buildDir/data/moderators.txt") -//} -// -//task generateCoilWikimedia(type: net.roguelogix.CsvToWikimediaTask, dependsOn: generateCoilCsv) { -// csvInput = generateCoilCsv.outputs.files[0] -// txtOutput = file("$buildDir/data/coils.txt") -//} - gradle.projectsEvaluated { var phosVersionRange = project.project(":Phosphophyllite").property("compatibility").toString().split(',') var phosMinVersion = phosVersionRange[0].substring(1) @@ -246,60 +152,87 @@ gradle.projectsEvaluated { println("::set-output name=phos_version_range::" + phosRequirementString) println("::set-output name=quartz_version_range::" + quartzRequirementString) - - def resource_targets = ["META-INF/mods.toml", "pack.mcmeta"] - def into_targets = ["$rootDir/out/production/resources/", "$rootDir/out/production/${project.name}.main/", "$rootDir/bin/main/"] - def properties = [ - version : version, - fmlVersion : forge_version.substring(0, forge_version.indexOf('.')), - forgeVersion : forge_version, - mcVersion : mc_version, - phosVersionRange: project.project(":Phosphophyllite").property("compatibility").toString(), - quartzVersionRange: project.project(":Quartz").property("compatibility").toString() - ] - processResources { - duplicatesStrategy = 'INCLUDE' - inputs.properties properties - - def spec = copySpec { - from(sourceSets.main.resources) { - include resource_targets - expand properties - } - } - - with spec - into_targets.each { - def file = file(it) - if (file.exists()) { - copy { - with spec - into file - } - } + tasks.withType(ProcessResources).configureEach { + var replaceProperties = [ + minecraft_version : mc_version, + neo_version : neo_version, + loader_version : neo_version.substring(0, neo_version.indexOf('.')), + version : version, + phos_version_range : project.project(":Phosphophyllite").property("compatibility").toString(), + quartz_version_range: project.project(":Quartz").property("compatibility").toString(), + ] + inputs.properties replaceProperties + + filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { + expand replaceProperties + [project: project] } + } +} - from(sourceSets.main.resources) { - exclude resource_targets - } +tasks.named('jar', Jar).configure { + manifest { + attributes([ + 'Specification-Title' : mod_id, + 'Specification-Vendor' : "BiggerSeries", + 'Specification-Version' : '1', // We are version 1 of ourselves + 'Implementation-Title' : project.name, + 'Implementation-Version' : project.jar.archiveVersion, + 'Implementation-Vendor' : "BiggerSeries", + 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ]) } } -task sourcesJar(type: Jar) { - classifier = 'sources' +tasks.named('publish').configure { + dependsOn 'reobfJar' + mustRunAfter 'reobfJar' +} + +tasks.register('sourcesJar', Jar) { + archiveClassifier = 'sources' from sourceSets.main.allSource } -def reobfFile = file("$buildDir/reobfJar/output.jar") -def reobfArtifact = artifacts.add('default', reobfFile) { - type 'jar' - builtBy 'reobfJar' + +artifacts { + archives jar + archives sourcesJar } publishing { publications { - mavenJava(MavenPublication) { - artifact reobfArtifact + register('mavenJava', MavenPublication) { + artifact jar artifact sourcesJar } } + repositories { + maven { + url "file://${project.projectDir}/publishlocal" + } + } +} + +// NeoGradle is dumb, and generates the run configs incorrectly, this fixes them +tasks.register('zzz_copyRunConfigsToTmpDir', Copy) { + from '.idea/runConfigurations' + into '.idea/runConfigurations1' +} + +tasks.register('zzz_depeteTmpDir', Delete) { + delete '.idea/runConfigurations1' +} + +tasks.register('_createIntellijRunsThatWork', Copy) { + dependsOn 'genIntellijRuns' + mustRunAfter 'genIntellijRuns' + dependsOn 'zzz_copyRunConfigsToTmpDir' + mustRunAfter 'zzz_copyRunConfigsToTmpDir' + + from '.idea/runConfigurations1' + into '.idea/runConfigurations' + filter { String line -> line.replace("out/production/classes", "build/classes/java/main") } + filter { String line -> line.replace("out/production/resources", "build/resources/main") } + filter { String line -> line.replace("copyIntellijResources", "prepareRunClientCompile") } + + finalizedBy 'zzz_depeteTmpDir' } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 2ccc35da..5dd26a35 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.daemon=false mc_version=1.20.1 mapping_channel=parchment mapping_version=2023.07.09-1.20.1 -forge_version=47.1.0 +neo_version=47.1.76 cc_mc_version=1.20.1 cc_version=1.106.1 @@ -15,4 +15,6 @@ jei_version=15.2.0.22 majorVersion=0 minorVersion=6 patchVersion=0 -postfixVersion=beta.10.1 \ No newline at end of file +postfixVersion=beta.10.1 + +mod_id=biggerreactors \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644 GIT binary patch delta 36524 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%0DGK?7GHTj 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 VwlMN}`%er%aGR6olj~j${vQ;P=LY}) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661e..c898b7af 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 477d5a9a..384993b3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,19 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { + name = 'NeoForged' + url = 'https://maven.neoforged.net/releases' + } + maven { + url = 'https://maven.parchmentmc.org' + } + } +} + +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' +} + include 'Phosphophyllite' include 'Quartz' \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 8b486ac8..5321a912 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[${fmlVersion},)" +loaderVersion="[${loader_version},)" license="LGPL v2.1" issueTrackerURL="https://github.com/BiggerSeries/BiggerReactors/issues/" @@ -22,25 +22,25 @@ Official continuation of Big Reactors [[dependencies.biggerreactors]] modId="forge" mandatory=true - versionRange="[${forgeVersion},)" + versionRange="[${neo_version},)" ordering="NONE" side="BOTH" [[dependencies.biggerreactors]] modId="minecraft" mandatory=true - versionRange="[${mcVersion}]" + versionRange="[${minecraft_version}]" ordering="NONE" side="BOTH" [[dependencies.biggerreactors]] modId="phosphophyllite" mandatory=true - versionRange="${phosVersionRange}" + versionRange="${phos_version_range}" ordering="NONE" side="BOTH" [[dependencies.biggerreactors]] modId="quartz" mandatory=true - versionRange="${quartzVersionRange}" + versionRange="${quartz_version_range}" ordering="NONE" side="BOTH" From c7a8e966ce1d611419f268b7f09a1b6a581f5b8a Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Sat, 23 Sep 2023 23:02:50 -0700 Subject: [PATCH 02/27] use publish task for publish action --- .github/workflows/publish.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index de5f46b3..e7bb13b5 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -17,8 +17,7 @@ jobs: - uses: actions/checkout@v2 - run: git submodule update --init --recursive - id: mainbuild - run: ./gradlew build - - run: ./gradlew publishToMavenLocal + run: ./gradlew :publish - run: mkdir jars - run: mv build/libs/biggerreactors-* jars/ - uses: actions/upload-artifact@v2 From 75c16a2591a2ff41e3e23182092c7c34479eded7 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Sun, 24 Sep 2023 18:14:42 -0700 Subject: [PATCH 03/27] add VK dep for Quartz at dev time --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index c89ee9cc..5872a569 100644 --- a/build.gradle +++ b/build.gradle @@ -133,6 +133,9 @@ dependencies { minecraftLibrary("org.lwjgl:lwjgl-opencl:3.3.1") { transitive(false) } + minecraftLibrary ("org.lwjgl:lwjgl-vulkan:3.3.1"){ + transitive(false) + } } gradle.projectsEvaluated { From 7c08080203bb2aad77f3b7d9392117c39ff1edcf Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Mon, 2 Oct 2023 20:30:33 -0700 Subject: [PATCH 04/27] fix datagen after Neo migration --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5872a569..ff91782e 100644 --- a/build.gradle +++ b/build.gradle @@ -64,7 +64,7 @@ minecraft { } data { - args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + args '--mod', mod_id, '--all', '--existing-mod', 'biggerreactors', '--existing-mod', 'phosphophyllite', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') } } } From 23400b68877abf9a000a920dca514d8936c21f41 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Mon, 2 Oct 2023 20:39:11 -0700 Subject: [PATCH 05/27] add SimulationConfiguration also remove special exception types to allow it to load without Forge's deps --- Phosphophyllite | 2 +- .../reactor/ReactorMultiblockController.java | 5 +- .../simulation/SimulationConfiguration.java | 84 +++++++++++++++++++ .../simulation/SimulationDescription.java | 26 ++---- .../simulation/accellerated/ocl/CLUtil.java | 7 ++ .../ocl/SingleQueueOpenCL12Simulation.java | 17 ++-- .../base/BaseReactorSimulation.java | 45 +++++----- .../reactor/simulation/base/Battery.java | 9 +- .../reactor/simulation/base/CoolantTank.java | 8 +- .../cpu/FullPassReactorSimulation.java | 42 +++++----- .../cpu/TimeSlicedReactorSimulation.java | 32 +++---- .../reactor/util/ReactorTransitionTank.java | 5 +- 12 files changed, 183 insertions(+), 99 deletions(-) create mode 100644 src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java diff --git a/Phosphophyllite b/Phosphophyllite index be830c6e..df0f9a90 160000 --- a/Phosphophyllite +++ b/Phosphophyllite @@ -1 +1 @@ -Subproject commit be830c6e3f1fabf7883d39fb92f44b7a725461cd +Subproject commit df0f9a90916d3e56233748a6100e8c90fe41dbf2 diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java index 9d76f3a0..bcf468ea 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java @@ -18,6 +18,7 @@ import net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorFuelRod; import net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorManifold; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.IReactorSimulation; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationDescription; import net.roguelogix.biggerreactors.multiblocks.reactor.state.ReactorActivity; import net.roguelogix.biggerreactors.multiblocks.reactor.state.ReactorState; @@ -428,7 +429,6 @@ protected void onValidationPassed() { simulationDescription.setControlRod(rodPos.getX() - start.x, rodPos.getZ() - start.z, true); } simulationDescription.setPassivelyCooled(coolantPorts.isEmpty()); - simulationDescription.setAmbientTemperature(293.15); var airProperties = ReactorModeratorRegistry.blockModeratorProperties(Blocks.AIR); if (airProperties == null) { airProperties = ReactorModeratorRegistry.ModeratorProperties.EMPTY_MODERATOR; @@ -439,7 +439,8 @@ protected void onValidationPassed() { simulationData = simulation.save(); } final var simulationBuilder = new SimulationDescription.Builder(Config.CONFIG.mode == Config.Mode.EXPERIMENTAL, Config.CONFIG.Reactor.useFullPassSimulation, Config.CONFIG.Reactor.allowOffThreadSimulation, Config.CONFIG.Reactor.allowMultiThreadSimulation, Config.CONFIG.Reactor.allowAcceleratedSimulation); - simulation = simulationBuilder.build(simulationDescription); + final var simulationConfiguration = new SimulationConfiguration(Config.CONFIG.Reactor, 293.15); + simulation = simulationBuilder.build(simulationDescription, simulationConfiguration); if (simulationData != null) { simulation.load(simulationData); } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java new file mode 100644 index 00000000..d09a9514 --- /dev/null +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java @@ -0,0 +1,84 @@ +package net.roguelogix.biggerreactors.multiblocks.reactor.simulation; + +import net.roguelogix.biggerreactors.Config; + +public record SimulationConfiguration( + double ambientTemperature, + double fuelUsageMultiplier, + double outputMultiplier, + double passiveOutputMultiplier, + double activeOutputMultiplier, + long fuelRodFuelCapacity, + double fuelFertilityMinimumDecay, + double fuelFertilityDecayDenominator, + double fuelFertilityDecayDenominatorInactiveMultiplier, + double casingHeatTransferRFMKT, + double fuelToStackRFKTMultiplier, + double stackToCoolantRFMKT, + double stackToAmbientRFMKT, + long passiveBatteryPerExternalBlock, + double passiveCoolingTransferEfficiency, + long coolantTankCapacityPerFuelRod, + double stackRFM3K, + double rodRFM3K, + double fuelReactivity, + double fissionEventsPerFuelUnit, + double RFPerRadiationUnit, + double fuelPerRadiationUnit, + double fuelHardnessDivisor, + double fuelAbsorptionCoefficient, + double fuelModerationFactor, + double radIntensityScalingMultiplier, + double radIntensityScalingRateExponentMultiplier, + double radIntensityScalingShiftMultiplier, + double radPenaltyShiftMultiplier, + double radPenaltyRateMultiplier, + double fuelAbsorptionScalingMultiplier, + double fuelAbsorptionScalingShiftMultiplier, + double fuelAbsorptionScalingRateExponentMultiplier, + double fuelRadScalingMultiplier + // TODO: find a way to do this too, maybe + // these aren't reloadable values at all + // SimUtil actually uses these very early in startup +// double irradiationDistance +// double simulationRays +) { + + public SimulationConfiguration(Config.Reactor reactorConfig, double ambientTemperature) { + this(ambientTemperature, + reactorConfig.FuelUsageMultiplier, + reactorConfig.OutputMultiplier, + reactorConfig.PassiveOutputMultiplier, + reactorConfig.ActiveOutputMultiplier, + reactorConfig.PerFuelRodCapacity, + reactorConfig.FuelFertilityMinimumDecay, + reactorConfig.FuelFertilityDecayDenominator, + reactorConfig.FuelFertilityDecayDenominatorInactiveMultiplier, + reactorConfig.CasingHeatTransferRFMKT, + reactorConfig.FuelToStackRFKTMultiplier, + reactorConfig.StackToCoolantRFMKT, + reactorConfig.StackToAmbientRFMKT, + reactorConfig.PassiveBatteryPerExternalBlock, + reactorConfig.PassiveCoolingTransferEfficiency, + reactorConfig.CoolantTankAmountPerFuelRod, + reactorConfig.CaseFEPerUnitVolumeKelvin, + reactorConfig.RodFEPerUnitVolumeKelvin, + reactorConfig.FuelReactivity, + reactorConfig.FissionEventsPerFuelUnit, + reactorConfig.FEPerRadiationUnit, + reactorConfig.FuelPerRadiationUnit, + reactorConfig.FuelHardnessDivisor, + reactorConfig.FuelAbsorptionCoefficient, + reactorConfig.FuelModerationFactor, + reactorConfig.RadIntensityScalingMultiplier, + reactorConfig.RadIntensityScalingRateExponentMultiplier, + reactorConfig.RadIntensityScalingShiftMultiplier, + reactorConfig.RadPenaltyShiftMultiplier, + reactorConfig.RadPenaltyRateMultiplier, + reactorConfig.FuelAbsorptionScalingMultiplier, + reactorConfig.FuelAbsorptionScalingShiftMultiplier, + reactorConfig.FuelAbsorptionScalingRateExponentMultiplier, + reactorConfig.fuelRadScalingMultiplier + ); + } +} diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java index d843cd53..2a888c41 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java @@ -41,8 +41,6 @@ public SimulationDescription(@Nonnull PhosphophylliteCompound compound) { boolean[][] controlRodLocations = null; int controlRodCount = 0; boolean passivelyCooled = false; - double ambientTemperature = 273.15; - public void setSize(int x, int y, int z) { if (x <= 0 || y <= 0 || z <= 0) { throw new IllegalArgumentException("all sizes must be greater than zero"); @@ -123,36 +121,32 @@ public void setPassivelyCooled(boolean passivelyCooled) { this.passivelyCooled = passivelyCooled; } - public void setAmbientTemperature(double ambientTemperature) { - this.ambientTemperature = ambientTemperature; - } - public record Builder(boolean experimental, boolean fullPass, boolean allowOffThread, boolean allowMultiThread, boolean allowAccelerated) { - public IReactorSimulation build(SimulationDescription description) { + public IReactorSimulation build(SimulationDescription description, SimulationConfiguration configuration) { description.ensureValid(); if (experimental) { - return new SingleQueueOpenCL12Simulation(description); + return new SingleQueueOpenCL12Simulation(description, configuration); } if (!fullPass) { - return new TimeSlicedReactorSimulation(description); + return new TimeSlicedReactorSimulation(description, configuration); } var rodMultiple = description.controlRodCount / Config.CONFIG.Reactor.ModeSpecific.ControlRodBatchSize; if (allowAccelerated && rodMultiple >= 16) { if (CLUtil.available) { - return new SingleQueueOpenCL12Simulation(description); + return new SingleQueueOpenCL12Simulation(description, configuration); } } if (allowMultiThread && rodMultiple >= 2) { - return new FullPassReactorSimulation.MultiThreaded(description, false); + return new FullPassReactorSimulation.MultiThreaded(description, configuration, false); } if (allowOffThread) { - return new FullPassReactorSimulation.MultiThreaded(description, true); + return new FullPassReactorSimulation.MultiThreaded(description, configuration,true); } - return new FullPassReactorSimulation(description); + return new FullPassReactorSimulation(description, configuration); } } @@ -212,10 +206,6 @@ public boolean isManifoldAt(int x, int y, int z) { return manifoldLocations[x][y][z]; } - public double ambientTemperature(){ - return ambientTemperature; - } - @Override @Nullable public PhosphophylliteCompound save() { @@ -269,7 +259,6 @@ public PhosphophylliteCompound save() { compound.put("controlRodLocations", controlRodLocations); compound.put("defaultModeratorProperties", defaultModeratorProperties.toROBNMap()); compound.put("passivelyCooled", passivelyCooled); - compound.put("ambientTemperature", ambientTemperature); return compound; } @@ -376,6 +365,5 @@ public void load(@Nonnull PhosphophylliteCompound compound) { setDefaultIModeratorProperties(new ReactorModeratorRegistry.ModeratorProperties(absorption, heatEfficiency, moderation, heatConductivity)); } setPassivelyCooled(compound.getBoolean("passivelyCooled")); - setAmbientTemperature(compound.getDouble("ambientTemperature")); } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/ocl/CLUtil.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/ocl/CLUtil.java index cf061b51..6b05d565 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/ocl/CLUtil.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/ocl/CLUtil.java @@ -1,5 +1,6 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.ocl; +import io.netty.buffer.ByteBuf; import it.unimi.dsi.fastutil.longs.LongArrayList; import net.roguelogix.biggerreactors.Config; import net.roguelogix.phosphophyllite.registry.OnModLoad; @@ -211,6 +212,7 @@ private static void onModLoad() { var devicesLB = devicesBB.asLongBuffer(); var intBuffer = stack.mallocInt(1); var longBuffer = stack.mallocLong(1); + var pointerBuffer = stack.mallocPointer(1); LOGGER.info("Getting devices"); for (int i = 0; i < deviceCount.get(0); i++) { long device = devicesLB.get(i); @@ -222,6 +224,11 @@ private static void onModLoad() { largestSizeMultiple1 = sizeMultiple; } clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, longBuffer, null); + clGetDeviceInfo(device, CL_DEVICE_NAME, (ByteBuffer) null, pointerBuffer); + var stringBuffer = stack.malloc((int) pointerBuffer.get(0)); + clGetDeviceInfo(device, CL_DEVICE_NAME, stringBuffer, pointerBuffer); + var GPUname = MemoryUtil.memUTF8(stringBuffer); + LOGGER.info("GPU Name: " + GPUname); maxWorkGroupSizes.add(longBuffer.get(0)); } LOGGER.info("Creating program"); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/ocl/SingleQueueOpenCL12Simulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/ocl/SingleQueueOpenCL12Simulation.java index 80c346f1..b9cca315 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/ocl/SingleQueueOpenCL12Simulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/ocl/SingleQueueOpenCL12Simulation.java @@ -1,8 +1,7 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.ocl; -import net.roguelogix.biggerreactors.Config; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationDescription; -import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base.ModeratorCache; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base.SimUtil; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.cpu.FullPassReactorSimulation; import org.lwjgl.PointerBuffer; @@ -52,8 +51,8 @@ public class SingleQueueOpenCL12Simulation extends FullPassReactorSimulation { private final PointerBuffer rayReductionGlobalWorkSize = clUtil.allocPointer(3); - public SingleQueueOpenCL12Simulation(SimulationDescription simulationDescription) { - super(simulationDescription); + public SingleQueueOpenCL12Simulation(SimulationDescription simulationDescription, SimulationConfiguration configuration) { + super(simulationDescription, configuration); try (var stack = MemoryStack.stackPush()) { final var returnCode = stack.mallocInt(1); @@ -197,7 +196,7 @@ public SingleQueueOpenCL12Simulation(SimulationDescription simulationDescription argLongBuffer.put(0, controlRodInsertionsBuffer); clSetKernelArg(simKernel, 7, argLongBuffer); // localInsertions - clSetKernelArg(simKernel, 8, (long) (Math.pow(Config.CONFIG.Reactor.IrradiationDistance * 2 + 1, 2) * 4)); + clSetKernelArg(simKernel, 8, (long) (Math.pow(net.roguelogix.biggerreactors.Config.CONFIG.Reactor.IrradiationDistance * 2 + 1, 2) * 4)); // rodRayInfosGlobal argLongBuffer.put(0, rodRayInfoBuffer); @@ -271,7 +270,7 @@ protected void startNextRadiate() { reactorInfoIB.put(2, z); reactorInfoFB.put(3, (float) fuelAbsorptionTemperatureCoefficient); reactorInfoFB.put(4, (float) initialHardness); - reactorInfoFB.put(5, (float) Config.CONFIG.Reactor.FEPerRadiationUnit); + reactorInfoFB.put(5, (float) configuration.RFPerRadiationUnit()); reactorInfoFB.put(6, (float) FuelAbsorptionCoefficient); reactorInfoFB.put(7, (float) FuelModerationFactor); reactorInfoFB.put(8, (float) fuelHardnessMultiplier); @@ -290,7 +289,7 @@ protected double radiate() { checkReturnCode(clEnqueueReadBuffer(queue, rayResultsBuffer, true, 0, rayResultsFB, null, null)); - fuelRFAdded *= Config.CONFIG.Reactor.FEPerRadiationUnit; + fuelRFAdded *= configuration.RFPerRadiationUnit(); collectResults(); @@ -299,8 +298,8 @@ protected double radiate() { caseRFAdded /= controlRods.length; if (!Double.isNaN(fuelRadAdded)) { - if (Config.CONFIG.Reactor.fuelRadScalingMultiplier != 0) { - fuelRadAdded *= Config.CONFIG.Reactor.fuelRadScalingMultiplier * (Config.CONFIG.Reactor.PerFuelRodCapacity / Math.max(1.0, (double) fuelTank().totalStored())); + if (configuration.fuelRadScalingMultiplier() != 0) { + fuelRadAdded *= configuration.fuelRadScalingMultiplier() * (configuration.fuelRodFuelCapacity() / Math.max(1.0, (double) fuelTank().totalStored())); } fuelFertility += fuelRadAdded; } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java index 5bc9c66f..36007b47 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java @@ -1,6 +1,6 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base; -import net.roguelogix.biggerreactors.Config; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.IReactorSimulation; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationDescription; import net.roguelogix.biggerreactors.registries.ReactorModeratorRegistry; @@ -40,7 +40,10 @@ public abstract class BaseReactorSimulation implements IReactorSimulation { protected double fuelFertility = 1; - protected BaseReactorSimulation(SimulationDescription simulationDescription) { + protected final SimulationConfiguration configuration; + + protected BaseReactorSimulation(SimulationDescription simulationDescription, SimulationConfiguration configuration) { + this.configuration = configuration; x = simulationDescription.x(); y = simulationDescription.y(); z = simulationDescription.z(); @@ -66,13 +69,13 @@ protected BaseReactorSimulation(SimulationDescription simulationDescription) { final ReactorModeratorRegistry.IModeratorProperties manifoldSignalingProperties; if (simulationDescription.passivelyCooled()) { - output = battery = new Battery((((long) (x + 2) * (y + 2) * (z + 2)) - ((long) x * y * z)) * Config.CONFIG.Reactor.PassiveBatteryPerExternalBlock); + output = battery = new Battery((((long) (x + 2) * (y + 2) * (z + 2)) - ((long) x * y * z)) * configuration.passiveBatteryPerExternalBlock(), configuration); coolantTank = null; manifoldSignalingProperties = new ReactorModeratorRegistry.ModeratorProperties(defaultModeratorProperties); } else { - long perSideCapacity = controlRods.length * y * Config.CONFIG.Reactor.CoolantTankAmountPerFuelRod; - perSideCapacity += simulationDescription.manifoldCount() * Config.CONFIG.Reactor.CoolantTankAmountPerFuelRod; - output = coolantTank = new CoolantTank(perSideCapacity, simulationDescription.defaultModeratorProperties()); + long perSideCapacity = controlRods.length * y * configuration.coolantTankCapacityPerFuelRod(); + perSideCapacity += simulationDescription.manifoldCount() * configuration.coolantTankCapacityPerFuelRod(); + output = coolantTank = new CoolantTank(perSideCapacity, simulationDescription.defaultModeratorProperties(), configuration); battery = null; manifoldSignalingProperties = coolantTank; } @@ -95,7 +98,7 @@ protected BaseReactorSimulation(SimulationDescription simulationDescription) { } } - fuelTank = new FuelTank(Config.CONFIG.Reactor.PerFuelRodCapacity * controlRods.length * y); + fuelTank = new FuelTank(configuration.fuelRodFuelCapacity() * controlRods.length * y); double fuelToCasingRFKT = 0; int fuelToManifoldSurfaceArea = 0; @@ -103,7 +106,7 @@ protected BaseReactorSimulation(SimulationDescription simulationDescription) { for (int i = 0; i < y; i++) { for (Vector2ic direction : SimUtil.cardinalDirections) { if (controlRod.x + direction.x() < 0 || controlRod.x + direction.x() >= x || controlRod.z + direction.y() < 0 || controlRod.z + direction.y() >= z) { - fuelToCasingRFKT += Config.CONFIG.Reactor.CasingHeatTransferRFMKT; + fuelToCasingRFKT += configuration.casingHeatTransferRFMKT(); continue; } ReactorModeratorRegistry.IModeratorProperties properties = moderatorProperties[controlRod.x + direction.x()][i][controlRod.z + direction.y()]; @@ -119,7 +122,7 @@ protected BaseReactorSimulation(SimulationDescription simulationDescription) { } } } - fuelToCasingRFKT *= Config.CONFIG.Reactor.FuelToStackRFKTMultiplier; + fuelToCasingRFKT *= configuration.fuelToStackRFKTMultiplier(); double stackToCoolantSystemRFKT = 2 * (x * y + x * z + z * y); @@ -151,26 +154,26 @@ protected BaseReactorSimulation(SimulationDescription simulationDescription) { } } } - stackToCoolantSystemRFKT *= Config.CONFIG.Reactor.StackToCoolantRFMKT; + stackToCoolantSystemRFKT *= configuration.stackToCoolantRFMKT(); if (simulationDescription.passivelyCooled()) { - stackToCoolantSystemRFKT *= Config.CONFIG.Reactor.PassiveCoolingTransferEfficiency; + stackToCoolantSystemRFKT *= configuration.passiveCoolingTransferEfficiency(); } - this.casingToAmbientRFKT = 2 * ((x + 2) * (y + 2) + (x + 2) * (z + 2) + (z + 2) * (y + 2)) * Config.CONFIG.Reactor.StackToAmbientRFMKT; + this.casingToAmbientRFKT = 2 * ((x + 2) * (y + 2) + (x + 2) * (z + 2) + (z + 2) * (y + 2)) * configuration.stackToAmbientRFMKT(); this.fuelToCasingRFKT = fuelToCasingRFKT; this.fuelToManifoldSurfaceArea = fuelToManifoldSurfaceArea; this.stackToCoolantSystemRFKT = stackToCoolantSystemRFKT; - fuelHeat.setRfPerKelvin(controlRods.length * y * Config.CONFIG.Reactor.RodFEPerUnitVolumeKelvin); - stackHeat.setRfPerKelvin(x * y * z * Config.CONFIG.Reactor.RodFEPerUnitVolumeKelvin); + fuelHeat.setRfPerKelvin(controlRods.length * y * configuration.rodRFM3K()); + stackHeat.setRfPerKelvin(x * y * z * configuration.stackRFM3K()); ambientHeat.setInfinite(true); - ambientHeat.setTemperature(simulationDescription.ambientTemperature()); - stackHeat.setTemperature(simulationDescription.ambientTemperature()); - fuelHeat.setTemperature(simulationDescription.ambientTemperature()); + ambientHeat.setTemperature(configuration.ambientTemperature()); + stackHeat.setTemperature(configuration.ambientTemperature()); + fuelHeat.setTemperature(configuration.ambientTemperature()); if (battery != null) { - battery.setTemperature(simulationDescription.ambientTemperature()); + battery.setTemperature(configuration.ambientTemperature()); } } @@ -185,14 +188,14 @@ public void tick(boolean active) { { // decay fertility, RadiationHelper.tick in old BR, this is copied, mostly - double denominator = Config.CONFIG.Reactor.FuelFertilityDecayDenominator; + double denominator = configuration.fuelFertilityDecayDenominator(); if (!active) { // Much slower decay when off - denominator *= Config.CONFIG.Reactor.FuelFertilityDecayDenominatorInactiveMultiplier; + denominator *= configuration.fuelFertilityDecayDenominatorInactiveMultiplier(); } // Fertility decay, at least 0.1 rad/t, otherwise halve it every 10 ticks - fuelFertility = Math.max(0f, fuelFertility - Math.max(Config.CONFIG.Reactor.FuelFertilityMinimumDecay, fuelFertility / denominator)); + fuelFertility = Math.max(0f, fuelFertility - Math.max(configuration.fuelFertilityMinimumDecay(), fuelFertility / denominator)); } fuelHeat.transferWith(stackHeat, fuelToCasingRFKT + fuelToManifoldSurfaceArea * (coolantTank == null ? defaultModeratorProperties : coolantTank).heatConductivity()); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/Battery.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/Battery.java index 50104024..a6df48c0 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/Battery.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/Battery.java @@ -1,6 +1,6 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base; -import net.roguelogix.biggerreactors.Config; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.IReactorSimulation; import net.roguelogix.phosphophyllite.serialization.IPhosphophylliteSerializable; import net.roguelogix.phosphophyllite.serialization.PhosphophylliteCompound; @@ -10,6 +10,8 @@ import javax.annotation.Nullable; public class Battery extends HeatBody implements IReactorSimulation.IBattery, IPhosphophylliteSerializable { + + private final SimulationConfiguration configuration; private final long capacity; private long stored; private long generatedLastTick; @@ -18,7 +20,8 @@ public class Battery extends HeatBody implements IReactorSimulation.IBattery, IP setInfinite(true); } - public Battery(long capacity) { + public Battery(long capacity, SimulationConfiguration configuration) { + this.configuration = configuration; this.capacity = capacity; } @@ -30,7 +33,7 @@ public double transferWith(HeatBody other, double rfkt) { double rfTransferred = (newTemp - other.temperature()) * other.rfPerKelvin(); - generatedLastTick = (long) (-rfTransferred * Config.CONFIG.Reactor.OutputMultiplier * Config.CONFIG.Reactor.PassiveOutputMultiplier); + generatedLastTick = (long) (-rfTransferred * configuration.outputMultiplier() * configuration.passiveOutputMultiplier()); stored += generatedLastTick; if (stored > capacity) { stored = capacity; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/CoolantTank.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/CoolantTank.java index 3d206e74..98fa0bd9 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/CoolantTank.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/CoolantTank.java @@ -1,6 +1,6 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base; -import net.roguelogix.biggerreactors.Config; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.IReactorSimulation; import net.roguelogix.biggerreactors.registries.FluidTransitionRegistry; import net.roguelogix.biggerreactors.registries.ReactorModeratorRegistry; @@ -12,6 +12,7 @@ import javax.annotation.Nullable; public class CoolantTank extends HeatBody implements IReactorSimulation.ICoolantTank, ReactorModeratorRegistry.IModeratorProperties, IPhosphophylliteSerializable { + private final SimulationConfiguration configuration; private final long perSideCapacity; private long liquidAmount = 0; @@ -26,7 +27,8 @@ public class CoolantTank extends HeatBody implements IReactorSimulation.ICoolant private long transitionedLastTick; private long rfTransferredLastTick; - CoolantTank(long perSideCapacity, ReactorModeratorRegistry.IModeratorProperties defaultModeratorProperties) { + CoolantTank(long perSideCapacity, ReactorModeratorRegistry.IModeratorProperties defaultModeratorProperties, SimulationConfiguration configuration) { + this.configuration = configuration; this.perSideCapacity = perSideCapacity; this.defaultModeratorProperties = defaultModeratorProperties; this.setInfinite(true); @@ -70,7 +72,7 @@ public double absorbRF(double rf) { rf = Math.abs(rf); - final double transitionMultiplier = Config.CONFIG.Reactor.OutputMultiplier * Config.CONFIG.Reactor.ActiveOutputMultiplier; + final double transitionMultiplier = configuration.outputMultiplier() * configuration.activeOutputMultiplier(); final double effectiveLatentHeat = transitionProperties.latentHeat() * transitionMultiplier; long toTransition = (long) (rf / effectiveLatentHeat); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java index cffd6e24..5d855f7d 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java @@ -1,13 +1,11 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.cpu; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -//import jdk.incubator.vector.DoubleVector; -//import jdk.incubator.vector.VectorOperators; -import net.roguelogix.biggerreactors.Config; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationDescription; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base.BaseReactorSimulation; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base.ModeratorCache; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base.SimUtil; -import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationDescription; import net.roguelogix.biggerreactors.registries.ReactorModeratorRegistry; import net.roguelogix.phosphophyllite.threading.Event; import net.roguelogix.phosphophyllite.threading.Queues; @@ -21,8 +19,8 @@ public class FullPassReactorSimulation extends BaseReactorSimulation { protected final byte[] moderatorIndices; protected final double[] initialIntensties; - public FullPassReactorSimulation(SimulationDescription simulationDescription) { - super(simulationDescription); + public FullPassReactorSimulation(SimulationDescription simulationDescription, SimulationConfiguration configuration) { + super(simulationDescription, configuration); final ObjectArrayList moderators = new ObjectArrayList<>(); moderators.add(CONTROL_ROD_MODERATOR); @@ -129,33 +127,33 @@ protected void setupIrradiationTick() { moderatorCaches.forEach(ModeratorCache::update); // Base value for radiation production penalties. 0-1, caps at about 3000C; - final double radiationPenaltyBase = Math.exp(-Config.CONFIG.Reactor.RadPenaltyShiftMultiplier * Math.exp(-0.001 * Config.CONFIG.Reactor.RadPenaltyRateMultiplier * (fuelHeat.temperature() - 273.15))); + final double radiationPenaltyBase = Math.exp(-configuration.radPenaltyShiftMultiplier() * Math.exp(-0.001 * configuration.radPenaltyRateMultiplier() * (fuelHeat.temperature() - 273.15))); // Raw amount - what's actually in the tanks // Effective amount - how final long baseFuelAmount = fuelTank.fuel() + (fuelTank.waste() / 100); // Intensity = how strong the radiation is, hardness = how energetic the radiation is (penetration) - final double rawRadIntensity = (double) baseFuelAmount * Config.CONFIG.Reactor.FissionEventsPerFuelUnit; + final double rawRadIntensity = (double) baseFuelAmount * configuration.fissionEventsPerFuelUnit(); // Scale up the "effective" intensity of radiation, to provide an incentive for bigger reactors in general. // Scale up a second time based on scaled amount in each fuel rod. Provides an incentive for making reactors that aren't just pancakes. - final double scaledRadIntensity = Math.pow((Math.pow((rawRadIntensity), Config.CONFIG.Reactor.FuelReactivity) / controlRods.length), Config.CONFIG.Reactor.FuelReactivity) * controlRods.length; + final double scaledRadIntensity = Math.pow((Math.pow((rawRadIntensity), configuration.fuelReactivity()) / controlRods.length), configuration.fuelReactivity()) * controlRods.length; // Radiation hardness starts at 20% and asymptotically approaches 100% as heat rises. // This will make radiation harder and harder to capture. initialHardness = Math.min(1.0, 0.2f + (0.8 * radiationPenaltyBase)); - final double rawIntensity = (1f + (-Config.CONFIG.Reactor.RadIntensityScalingMultiplier * Math.exp(-10f * Config.CONFIG.Reactor.RadIntensityScalingShiftMultiplier * Math.exp(-0.001f * Config.CONFIG.Reactor.RadIntensityScalingRateExponentMultiplier * (fuelHeat.temperature() - 273.15))))); - fuelAbsorptionTemperatureCoefficient = (1.0 - (Config.CONFIG.Reactor.FuelAbsorptionScalingMultiplier * Math.exp(-10 * Config.CONFIG.Reactor.FuelAbsorptionScalingShiftMultiplier * Math.exp(-0.001 * Config.CONFIG.Reactor.FuelAbsorptionScalingRateExponentMultiplier * (fuelHeat.temperature() - 273.15))))); + final double rawIntensity = (1f + (-configuration.radIntensityScalingMultiplier() * Math.exp(-10f * configuration.radIntensityScalingShiftMultiplier() * Math.exp(-0.001f * configuration.radIntensityScalingRateExponentMultiplier() * (fuelHeat.temperature() - 273.15))))); + fuelAbsorptionTemperatureCoefficient = (1.0 - (configuration.fuelAbsorptionScalingMultiplier() * Math.exp(-10 * configuration.fuelAbsorptionScalingShiftMultiplier() * Math.exp(-0.001 * configuration.fuelAbsorptionScalingRateExponentMultiplier() * (fuelHeat.temperature() - 273.15))))); // final double controlRodModifier = 1.0 / controlRods.length; - final double FuelUsageMultiplier = Config.CONFIG.Reactor.FuelUsageMultiplier; - final double FuelPerRadiationUnit = Config.CONFIG.Reactor.FuelPerRadiationUnit; - FuelAbsorptionCoefficient = Config.CONFIG.Reactor.FuelAbsorptionCoefficient; - FuelModerationFactor = Config.CONFIG.Reactor.FuelModerationFactor; - fuelHardnessMultiplier = 1 / Config.CONFIG.Reactor.FuelHardnessDivisor; + final double FuelUsageMultiplier = configuration.fuelUsageMultiplier(); + final double FuelPerRadiationUnit = configuration.fuelPerRadiationUnit(); + FuelAbsorptionCoefficient = configuration.fuelAbsorptionCoefficient(); + FuelModerationFactor = configuration.fuelModerationFactor(); + fuelHardnessMultiplier = 1 / configuration.fuelHardnessDivisor(); rayMultiplier = 1.0 / (double) (SimUtil.rays.size() * y); double rawFuelUsage = 0; @@ -194,7 +192,7 @@ protected void collectIrradiationResult(IrradiationResult result) { } protected double realizeIrradiationTick() { - final double FEPerRadiationUnit = Config.CONFIG.Reactor.FEPerRadiationUnit; + final double FEPerRadiationUnit = configuration.RFPerRadiationUnit(); caseRFAdded *= FEPerRadiationUnit; fuelRFAdded *= FEPerRadiationUnit; @@ -203,8 +201,8 @@ protected double realizeIrradiationTick() { caseRFAdded /= controlRods.length; if (!Double.isNaN(fuelRadAdded)) { - if (Config.CONFIG.Reactor.fuelRadScalingMultiplier != 0) { - fuelRadAdded *= Config.CONFIG.Reactor.fuelRadScalingMultiplier * (Config.CONFIG.Reactor.PerFuelRodCapacity / Math.max(1.0, (double) fuelTank().totalStored())); + if (configuration.fuelRadScalingMultiplier() != 0) { + fuelRadAdded *= configuration.fuelRadScalingMultiplier() * (configuration.fuelRodFuelCapacity() / Math.max(1.0, (double) fuelTank().totalStored())); } fuelFertility += fuelRadAdded; } @@ -350,12 +348,12 @@ public static class MultiThreaded extends FullPassReactorSimulation { private Event doneEvent; private final Runnable mainRunnable = () -> runIrradiationRequest(fullPassIrradiationRequest); - public MultiThreaded(SimulationDescription simulationDescription, boolean singleThread) { - super(simulationDescription); + public MultiThreaded(SimulationDescription simulationDescription, SimulationConfiguration configuration, boolean singleThread) { + super(simulationDescription, configuration); if (!singleThread) { final var cacheArray = this.moderatorCaches.toArray(new ModeratorCache[0]); - final int batchSize = Config.CONFIG.Reactor.ModeSpecific.ControlRodBatchSize; + final int batchSize = net.roguelogix.biggerreactors.Config.CONFIG.Reactor.ModeSpecific.ControlRodBatchSize; final int batches = controlRods.length / batchSize + ((controlRods.length % batchSize == 0) ? 0 : 1); irradiationRequestRunnables = new Runnable[batches]; irradiationRequests = new IrradiationRequest[batches]; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/TimeSlicedReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/TimeSlicedReactorSimulation.java index fa191f8c..6afb0153 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/TimeSlicedReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/TimeSlicedReactorSimulation.java @@ -1,6 +1,6 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.cpu; -import net.roguelogix.biggerreactors.Config; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base.BaseReactorSimulation; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base.SimUtil; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationDescription; @@ -16,8 +16,8 @@ public class TimeSlicedReactorSimulation extends BaseReactorSimulation { private int currentRod = 0; private int rodOffset = 0; - public TimeSlicedReactorSimulation(SimulationDescription simulationDescription) { - super(simulationDescription); + public TimeSlicedReactorSimulation(SimulationDescription simulationDescription, SimulationConfiguration configuration) { + super(simulationDescription, configuration); Collections.shuffle(Arrays.asList(controlRods), new Random()); } @@ -38,26 +38,26 @@ protected double radiate() { currentRod %= controlRods.length; // Base value for radiation production penalties. 0-1, caps at about 3000C; - final double radiationPenaltyBase = Math.exp(-Config.CONFIG.Reactor.RadPenaltyShiftMultiplier * Math.exp(-0.001 * Config.CONFIG.Reactor.RadPenaltyRateMultiplier * (fuelHeat.temperature() - 273.15))); + final double radiationPenaltyBase = Math.exp(-configuration.radPenaltyShiftMultiplier() * Math.exp(-0.001 * configuration.radPenaltyRateMultiplier() * (fuelHeat.temperature() - 273.15))); // Raw amount - what's actually in the tanks // Effective amount - how final long baseFuelAmount = fuelTank.fuel() + (fuelTank.waste() / 100); // Intensity = how strong the radiation is, hardness = how energetic the radiation is (penetration) - final double rawRadIntensity = (double) baseFuelAmount * Config.CONFIG.Reactor.FissionEventsPerFuelUnit; + final double rawRadIntensity = (double) baseFuelAmount * configuration.fissionEventsPerFuelUnit(); // Scale up the "effective" intensity of radiation, to provide an incentive for bigger reactors in general. // Scale up a second time based on scaled amount in each fuel rod. Provides an incentive for making reactors that aren't just pancakes. - final double scaledRadIntensity = Math.pow((Math.pow((rawRadIntensity), Config.CONFIG.Reactor.FuelReactivity) / controlRods.length), Config.CONFIG.Reactor.FuelReactivity) * controlRods.length; + final double scaledRadIntensity = Math.pow((Math.pow((rawRadIntensity), configuration.fuelReactivity()) / controlRods.length), configuration.fuelReactivity()) * controlRods.length; // Radiation hardness starts at 20% and asymptotically approaches 100% as heat rises. // This will make radiation harder and harder to capture. final double initialHardness = Math.min(1.0, 0.2f + (0.8 * radiationPenaltyBase)); - final double rawIntensity = (1f + (-Config.CONFIG.Reactor.RadIntensityScalingMultiplier * Math.exp(-10f * Config.CONFIG.Reactor.RadIntensityScalingShiftMultiplier * Math.exp(-0.001f * Config.CONFIG.Reactor.RadIntensityScalingRateExponentMultiplier * (fuelHeat.temperature() - 273.15))))); - final double fuelAbsorptionTemperatureCoefficient = (1.0 - (Config.CONFIG.Reactor.FuelAbsorptionScalingMultiplier * Math.exp(-10 * Config.CONFIG.Reactor.FuelAbsorptionScalingShiftMultiplier * Math.exp(-0.001 * Config.CONFIG.Reactor.FuelAbsorptionScalingRateExponentMultiplier * (fuelHeat.temperature() - 273.15))))); - final double fuelHardnessMultiplier = 1 / Config.CONFIG.Reactor.FuelHardnessDivisor; + final double rawIntensity = (1f + (-configuration.radIntensityScalingMultiplier() * Math.exp(-10f * configuration.radIntensityScalingShiftMultiplier() * Math.exp(-0.001f * configuration.radIntensityScalingRateExponentMultiplier() * (fuelHeat.temperature() - 273.15))))); + final double fuelAbsorptionTemperatureCoefficient = (1.0 - (configuration.fuelAbsorptionScalingMultiplier() * Math.exp(-10 * configuration.fuelAbsorptionScalingShiftMultiplier() * Math.exp(-0.001 * configuration.fuelAbsorptionScalingRateExponentMultiplier() * (fuelHeat.temperature() - 273.15))))); + final double fuelHardnessMultiplier = 1 / configuration.fuelHardnessDivisor(); double rawFuelUsage = 0; @@ -65,11 +65,11 @@ protected double radiate() { double fuelRadAdded = 0; double caseRFAdded = 0; - final var FuelPerRadiationUnit = Config.CONFIG.Reactor.FuelPerRadiationUnit; - final var FEPerRadiationUnit = Config.CONFIG.Reactor.FEPerRadiationUnit; - final var FuelUsageMultiplier = Config.CONFIG.Reactor.FuelUsageMultiplier; - final var FuelAbsorptionCoefficient = Config.CONFIG.Reactor.FuelAbsorptionCoefficient; - final var FuelModerationFactor = Config.CONFIG.Reactor.FuelModerationFactor; + final var FuelPerRadiationUnit = configuration.fuelPerRadiationUnit(); + final var FEPerRadiationUnit = configuration.RFPerRadiationUnit(); + final var FuelUsageMultiplier = configuration.fuelUsageMultiplier(); + final var FuelAbsorptionCoefficient = configuration.fuelAbsorptionCoefficient(); + final var FuelModerationFactor = configuration.fuelModerationFactor(); SimUtil.ControlRod rod = controlRods[currentRod]; @@ -144,8 +144,8 @@ protected double radiate() { } if (!Double.isNaN(fuelRadAdded)) { - if (Config.CONFIG.Reactor.fuelRadScalingMultiplier != 0) { - fuelRadAdded *= Config.CONFIG.Reactor.fuelRadScalingMultiplier * (Config.CONFIG.Reactor.PerFuelRodCapacity / Math.max(1.0, (double) fuelTank().totalStored())); + if (configuration.fuelRadScalingMultiplier() != 0) { + fuelRadAdded *= configuration.fuelRadScalingMultiplier() * (configuration.fuelRodFuelCapacity() / Math.max(1.0, (double) fuelTank().totalStored())); } fuelFertility += fuelRadAdded; } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/util/ReactorTransitionTank.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/util/ReactorTransitionTank.java index 2081a1bf..d3cac21e 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/util/ReactorTransitionTank.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/util/ReactorTransitionTank.java @@ -9,7 +9,6 @@ import net.roguelogix.biggerreactors.util.FluidTransitionTank; import net.roguelogix.phosphophyllite.util.HeatBody; import net.roguelogix.phosphophyllite.util.NonnullDefault; -import org.apache.commons.lang3.NotImplementedException; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -33,12 +32,12 @@ public long maxTransitionedLastTick() { @Override public double transferWith(HeatBody body, double rfkt) { - throw new NotImplementedException(""); + throw new IllegalArgumentException(""); } @Override public double absorbRF(double rf) { - throw new NotImplementedException(""); + throw new IllegalArgumentException(""); } public ReactorTransitionTank(IReactorSimulation.ICoolantTank internalTank) { From 053805efbd1c5b853cf3ce11655c9d1af9926d2b Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Mon, 2 Oct 2023 21:19:25 -0700 Subject: [PATCH 06/27] allow SimulationConfiguration construction from a JSON map --- .../simulation/SimulationConfiguration.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java index d09a9514..8710bb06 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java @@ -2,6 +2,8 @@ import net.roguelogix.biggerreactors.Config; +import java.util.Map; + public record SimulationConfiguration( double ambientTemperature, double fuelUsageMultiplier, @@ -44,6 +46,10 @@ public record SimulationConfiguration( // double simulationRays ) { + public SimulationConfiguration(double ambientTemperature) { + this(Config.CONFIG.Reactor, ambientTemperature); + } + public SimulationConfiguration(Config.Reactor reactorConfig, double ambientTemperature) { this(ambientTemperature, reactorConfig.FuelUsageMultiplier, @@ -81,4 +87,43 @@ public SimulationConfiguration(Config.Reactor reactorConfig, double ambientTempe reactorConfig.fuelRadScalingMultiplier ); } + + public SimulationConfiguration(Map jsonMap) { + this( + (double) jsonMap.get("ambientTemperature"), + (double) jsonMap.get("fuelUsageMultiplier"), + (double) jsonMap.get("outputMultiplier"), + (double) jsonMap.get("passiveOutputMultiplier"), + (double) jsonMap.get("activeOutputMultiplier"), + (long) jsonMap.get("fuelRodFuelCapacity"), + (double) jsonMap.get("fuelFertilityMinimumDecay"), + (double) jsonMap.get("fuelFertilityDecayDenominator"), + (double) jsonMap.get("fuelFertilityDecayDenominatorInactiveMultiplier"), + (double) jsonMap.get("casingHeatTransferRFMKT"), + (double) jsonMap.get("fuelToStackRFKTMultiplier"), + (double) jsonMap.get("stackToCoolantRFMKT"), + (double) jsonMap.get("stackToAmbientRFMKT"), + (long) jsonMap.get("passiveBatteryPerExternalBlock"), + (double) jsonMap.get("passiveCoolingTransferEfficiency"), + (long) jsonMap.get("coolantTankCapacityPerFuelRod"), + (double) jsonMap.get("stackRFM3K"), + (double) jsonMap.get("rodRFM3K"), + (double) jsonMap.get("fuelReactivity"), + (double) jsonMap.get("fissionEventsPerFuelUnit"), + (double) jsonMap.get("RFPerRadiationUnit"), + (double) jsonMap.get("fuelPerRadiationUnit"), + (double) jsonMap.get("fuelHardnessDivisor"), + (double) jsonMap.get("fuelAbsorptionCoefficient"), + (double) jsonMap.get("fuelModerationFactor"), + (double) jsonMap.get("radIntensityScalingMultiplier"), + (double) jsonMap.get("radIntensityScalingRateExponentMultiplier"), + (double) jsonMap.get("radIntensityScalingShiftMultiplier"), + (double) jsonMap.get("radPenaltyShiftMultiplier"), + (double) jsonMap.get("radPenaltyRateMultiplier"), + (double) jsonMap.get("fuelAbsorptionScalingMultiplier"), + (double) jsonMap.get("fuelAbsorptionScalingShiftMultiplier"), + (double) jsonMap.get("fuelAbsorptionScalingRateExponentMultiplier"), + (double) jsonMap.get("fuelRadScalingMultiplier") + ); + } } From d45b33b689173d83ce2c51f73dc4b2072b5584f3 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Mon, 2 Oct 2023 21:22:37 -0700 Subject: [PATCH 07/27] move passivelyCooled to configuration --- .../reactor/ReactorMultiblockController.java | 3 +-- .../reactor/simulation/SimulationConfiguration.java | 10 ++++++---- .../reactor/simulation/SimulationDescription.java | 11 ----------- .../simulation/base/BaseReactorSimulation.java | 4 ++-- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java index bcf468ea..ec01572d 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java @@ -428,7 +428,6 @@ protected void onValidationPassed() { BlockPos rodPos = controlRods.get(i).getBlockPos(); simulationDescription.setControlRod(rodPos.getX() - start.x, rodPos.getZ() - start.z, true); } - simulationDescription.setPassivelyCooled(coolantPorts.isEmpty()); var airProperties = ReactorModeratorRegistry.blockModeratorProperties(Blocks.AIR); if (airProperties == null) { airProperties = ReactorModeratorRegistry.ModeratorProperties.EMPTY_MODERATOR; @@ -439,7 +438,7 @@ protected void onValidationPassed() { simulationData = simulation.save(); } final var simulationBuilder = new SimulationDescription.Builder(Config.CONFIG.mode == Config.Mode.EXPERIMENTAL, Config.CONFIG.Reactor.useFullPassSimulation, Config.CONFIG.Reactor.allowOffThreadSimulation, Config.CONFIG.Reactor.allowMultiThreadSimulation, Config.CONFIG.Reactor.allowAcceleratedSimulation); - final var simulationConfiguration = new SimulationConfiguration(Config.CONFIG.Reactor, 293.15); + final var simulationConfiguration = new SimulationConfiguration(Config.CONFIG.Reactor, 293.15, coolantPorts.isEmpty()); simulation = simulationBuilder.build(simulationDescription, simulationConfiguration); if (simulationData != null) { simulation.load(simulationData); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java index 8710bb06..f8584b3a 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java @@ -6,6 +6,7 @@ public record SimulationConfiguration( double ambientTemperature, + boolean passivelyCooled, double fuelUsageMultiplier, double outputMultiplier, double passiveOutputMultiplier, @@ -46,12 +47,12 @@ public record SimulationConfiguration( // double simulationRays ) { - public SimulationConfiguration(double ambientTemperature) { - this(Config.CONFIG.Reactor, ambientTemperature); + public SimulationConfiguration(double ambientTemperature, boolean passivelyCooled) { + this(Config.CONFIG.Reactor, ambientTemperature, passivelyCooled); } - public SimulationConfiguration(Config.Reactor reactorConfig, double ambientTemperature) { - this(ambientTemperature, + public SimulationConfiguration(Config.Reactor reactorConfig, double ambientTemperature, boolean passivelyCooled) { + this(ambientTemperature, passivelyCooled, reactorConfig.FuelUsageMultiplier, reactorConfig.OutputMultiplier, reactorConfig.PassiveOutputMultiplier, @@ -91,6 +92,7 @@ public SimulationConfiguration(Config.Reactor reactorConfig, double ambientTempe public SimulationConfiguration(Map jsonMap) { this( (double) jsonMap.get("ambientTemperature"), + (boolean) jsonMap.get("passivelyCooled"), (double) jsonMap.get("fuelUsageMultiplier"), (double) jsonMap.get("outputMultiplier"), (double) jsonMap.get("passiveOutputMultiplier"), diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java index 2a888c41..a38dce05 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java @@ -40,7 +40,6 @@ public SimulationDescription(@Nonnull PhosphophylliteCompound compound) { @Nullable boolean[][] controlRodLocations = null; int controlRodCount = 0; - boolean passivelyCooled = false; public void setSize(int x, int y, int z) { if (x <= 0 || y <= 0 || z <= 0) { throw new IllegalArgumentException("all sizes must be greater than zero"); @@ -117,10 +116,6 @@ public void setManifold(int x, int y, int z, boolean manifold) { manifoldLocations[x][y][z] = manifold; } - public void setPassivelyCooled(boolean passivelyCooled) { - this.passivelyCooled = passivelyCooled; - } - public record Builder(boolean experimental, boolean fullPass, boolean allowOffThread, boolean allowMultiThread, boolean allowAccelerated) { public IReactorSimulation build(SimulationDescription description, SimulationConfiguration configuration) { @@ -187,10 +182,6 @@ public boolean isControlRodAt(int x, int z) { return controlRodLocations[x][z]; } - public boolean passivelyCooled() { - return passivelyCooled; - } - public int manifoldCount() { return manifoldCount; } @@ -258,7 +249,6 @@ public PhosphophylliteCompound save() { compound.put("manifoldLocations", manifoldLocations); compound.put("controlRodLocations", controlRodLocations); compound.put("defaultModeratorProperties", defaultModeratorProperties.toROBNMap()); - compound.put("passivelyCooled", passivelyCooled); return compound; } @@ -364,6 +354,5 @@ public void load(@Nonnull PhosphophylliteCompound compound) { } setDefaultIModeratorProperties(new ReactorModeratorRegistry.ModeratorProperties(absorption, heatEfficiency, moderation, heatConductivity)); } - setPassivelyCooled(compound.getBoolean("passivelyCooled")); } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java index 36007b47..982ed4e3 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java @@ -68,7 +68,7 @@ protected BaseReactorSimulation(SimulationDescription simulationDescription, Sim } final ReactorModeratorRegistry.IModeratorProperties manifoldSignalingProperties; - if (simulationDescription.passivelyCooled()) { + if (configuration.passivelyCooled()) { output = battery = new Battery((((long) (x + 2) * (y + 2) * (z + 2)) - ((long) x * y * z)) * configuration.passiveBatteryPerExternalBlock(), configuration); coolantTank = null; manifoldSignalingProperties = new ReactorModeratorRegistry.ModeratorProperties(defaultModeratorProperties); @@ -156,7 +156,7 @@ protected BaseReactorSimulation(SimulationDescription simulationDescription, Sim } stackToCoolantSystemRFKT *= configuration.stackToCoolantRFMKT(); - if (simulationDescription.passivelyCooled()) { + if (configuration.passivelyCooled()) { stackToCoolantSystemRFKT *= configuration.passiveCoolingTransferEfficiency(); } From 5e9231197f9eb5fd598c1acb59f97e50568c51ce Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Tue, 3 Oct 2023 08:21:44 -0700 Subject: [PATCH 08/27] mark simulation save as NotNull --- .../multiblocks/reactor/simulation/IReactorSimulation.java | 7 +++++++ .../reactor/simulation/base/BaseReactorSimulation.java | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java index 58c4268a..45a2fb7c 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java @@ -5,8 +5,11 @@ import net.roguelogix.phosphophyllite.debug.DebugInfo; import net.roguelogix.phosphophyllite.debug.IDebuggable; import net.roguelogix.phosphophyllite.serialization.IPhosphophylliteSerializable; +import net.roguelogix.phosphophyllite.serialization.PhosphophylliteCompound; import net.roguelogix.phosphophyllite.util.NonnullDefault; +import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @@ -43,6 +46,10 @@ default boolean isAsync() { return false; } + @NotNull + @Override + PhosphophylliteCompound save(); + interface ControlRod { double insertion(); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java index 982ed4e3..83a7e149 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java @@ -7,6 +7,7 @@ import net.roguelogix.phosphophyllite.debug.DebugInfo; import net.roguelogix.phosphophyllite.serialization.PhosphophylliteCompound; import net.roguelogix.phosphophyllite.util.HeatBody; +import org.jetbrains.annotations.NotNull; import org.joml.Vector2ic; import org.joml.Vector3ic; @@ -264,7 +265,7 @@ public double ambientTemperature() { return ambientHeat.temperature(); } - @Nullable + @NotNull @Override public PhosphophylliteCompound save() { var compound = new PhosphophylliteCompound(); From aa2fd222d234ed6f28a90cfae57acb3de937da55 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Tue, 3 Oct 2023 08:22:17 -0700 Subject: [PATCH 09/27] allow registries to be loaded without Neo deps --- .../biggerreactors/registries/FluidTransitionRegistry.java | 3 +-- .../biggerreactors/registries/ReactorModeratorRegistry.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java b/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java index 5b9e7341..cd997c13 100644 --- a/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java +++ b/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java @@ -10,7 +10,6 @@ import net.roguelogix.phosphophyllite.config.ConfigValue; import net.roguelogix.phosphophyllite.data.DatapackLoader; import net.roguelogix.phosphophyllite.robn.ROBNObject; -import org.apache.commons.lang3.NotImplementedException; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @@ -44,7 +43,7 @@ default Map toROBNMap() { @Override default void fromROBNMap(Map map) { - throw new NotImplementedException(""); + throw new IllegalArgumentException(""); } } diff --git a/src/main/java/net/roguelogix/biggerreactors/registries/ReactorModeratorRegistry.java b/src/main/java/net/roguelogix/biggerreactors/registries/ReactorModeratorRegistry.java index 4a8a3784..e4ce915f 100644 --- a/src/main/java/net/roguelogix/biggerreactors/registries/ReactorModeratorRegistry.java +++ b/src/main/java/net/roguelogix/biggerreactors/registries/ReactorModeratorRegistry.java @@ -26,7 +26,6 @@ import net.roguelogix.phosphophyllite.registry.OnModLoad; import net.roguelogix.phosphophyllite.robn.ROBNObject; import net.roguelogix.phosphophyllite.serialization.PhosphophylliteCompound; -import org.apache.commons.lang3.NotImplementedException; import java.util.HashMap; import java.util.List; @@ -57,7 +56,7 @@ default Map toROBNMap() { @Override default void fromROBNMap(Map map) { - throw new NotImplementedException(""); + throw new IllegalArgumentException(""); } } From 5af46ad86137aadeea48c774355560ed5a5dc782 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Thu, 19 Oct 2023 12:19:43 -0700 Subject: [PATCH 10/27] add Vulkan backed simulation --- Phosphophyllite | 2 +- Quartz | 2 +- scripts/compileshaders.py | 47 ++ .../simulation/IReactorSimulation.java | 6 +- .../simulation/SimulationDescription.java | 15 +- .../accellerated/vk/Vk13Simulation.java | 603 ++++++++++++++++++ .../simulation/accellerated/vk/VkMemUtil.java | 322 ++++++++++ .../accellerated/vk/VkPipelines.java | 276 ++++++++ .../simulation/accellerated/vk/VkPools.java | 174 +++++ .../simulation/accellerated/vk/VkUtil.java | 462 ++++++++++++++ .../base/BaseReactorSimulation.java | 11 +- .../cpu/FullPassReactorSimulation.java | 24 +- .../simulation}/opencl/reactorsim.cl | 21 +- .../simulation/vk/glsl/raysim.comp | 242 +++++++ .../simulation/vk/glsl/raysimvec2.comp | 234 +++++++ .../simulation/vk/glsl/reduction.comp | 40 ++ .../simulation/vk/spv/raysim.comp.spv | Bin 0 -> 18596 bytes .../simulation/vk/spv/raysimvec2.comp.spv | Bin 0 -> 19808 bytes .../simulation/vk/spv/reduction.comp.spv | Bin 0 -> 3292 bytes 19 files changed, 2444 insertions(+), 37 deletions(-) create mode 100644 scripts/compileshaders.py create mode 100644 src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/Vk13Simulation.java create mode 100644 src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java create mode 100644 src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPipelines.java create mode 100644 src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPools.java create mode 100644 src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkUtil.java rename src/main/resources/{ => biggerreactors/simulation}/opencl/reactorsim.cl (89%) create mode 100644 src/main/resources/biggerreactors/simulation/vk/glsl/raysim.comp create mode 100644 src/main/resources/biggerreactors/simulation/vk/glsl/raysimvec2.comp create mode 100644 src/main/resources/biggerreactors/simulation/vk/glsl/reduction.comp create mode 100644 src/main/resources/biggerreactors/simulation/vk/spv/raysim.comp.spv create mode 100644 src/main/resources/biggerreactors/simulation/vk/spv/raysimvec2.comp.spv create mode 100644 src/main/resources/biggerreactors/simulation/vk/spv/reduction.comp.spv diff --git a/Phosphophyllite b/Phosphophyllite index df0f9a90..7371a6ba 160000 --- a/Phosphophyllite +++ b/Phosphophyllite @@ -1 +1 @@ -Subproject commit df0f9a90916d3e56233748a6100e8c90fe41dbf2 +Subproject commit 7371a6bab84271d10d80564bc757876c8b08235c diff --git a/Quartz b/Quartz index 9611fdfd..965eb12a 160000 --- a/Quartz +++ b/Quartz @@ -1 +1 @@ -Subproject commit 9611fdfd43a56dab23a4da6d225b87c92fdc33fa +Subproject commit 965eb12a6110ec0d6610f83522996617033e0588 diff --git a/scripts/compileshaders.py b/scripts/compileshaders.py new file mode 100644 index 00000000..194b6c0c --- /dev/null +++ b/scripts/compileshaders.py @@ -0,0 +1,47 @@ +import multiprocessing +import os +import sys + +def processFile(command): + print(command) + os.system(command) + pass + +def walkPath(inputDir, outputDir): + if not os.path.exists("glslc"): + return [] + inputs = os.listdir(inputDir) + if not os.path.exists(outputDir): + os.mkdir(outputDir) + inputs.sort() + folders = [] + commands = [] + for file in inputs: + fullFile = f"{inputDir}/{file}" + if os.path.isdir(fullFile): + folders.append(file) + continue + if not file.endswith(".comp"): + continue + outputFile = file + ".spv" + commands.append(f"./glslc -fshader-stage=comp ./{inputDir}/{file} -o ./{outputDir}/{outputFile} -I ./include") + pass + for folder in folders: + for command in walkPath(inputDir + "/" + folder, outputDir + "/" + folder): + commands.append(command) + pass + return commands + + +if __name__ == '__main__': + if os.path.abspath(".").endswith("scripts"): + os.chdir("..") + try: + allCommands = walkPath("src/main/resources/biggerreactors/simulation/vk/glsl", "src/main/resources/biggerreactors/simulation/vk/spv") + pool = multiprocessing.Pool(24) + pool.map(processFile, allCommands) + except Exception as e: + print(e.__str__()) + sys.exit(-1) + pass + pass diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java index 45a2fb7c..122706c9 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java @@ -2,14 +2,12 @@ import net.roguelogix.biggerreactors.registries.FluidTransitionRegistry; import net.roguelogix.biggerreactors.registries.ReactorModeratorRegistry; -import net.roguelogix.phosphophyllite.debug.DebugInfo; import net.roguelogix.phosphophyllite.debug.IDebuggable; import net.roguelogix.phosphophyllite.serialization.IPhosphophylliteSerializable; import net.roguelogix.phosphophyllite.serialization.PhosphophylliteCompound; import net.roguelogix.phosphophyllite.util.NonnullDefault; import org.jetbrains.annotations.NotNull; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @@ -46,6 +44,10 @@ default boolean isAsync() { return false; } + default boolean readyToTick() { + return true; + } + @NotNull @Override PhosphophylliteCompound save(); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java index a38dce05..27f5d5ac 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java @@ -3,6 +3,8 @@ import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.ocl.SingleQueueOpenCL12Simulation; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.ocl.CLUtil; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.Vk13Simulation; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkUtil; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.cpu.FullPassReactorSimulation; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.cpu.TimeSlicedReactorSimulation; import net.roguelogix.biggerreactors.registries.ReactorModeratorRegistry; @@ -121,21 +123,22 @@ public record Builder(boolean experimental, boolean fullPass, boolean allowOffTh public IReactorSimulation build(SimulationDescription description, SimulationConfiguration configuration) { description.ensureValid(); - if (experimental) { - return new SingleQueueOpenCL12Simulation(description, configuration); + if (experimental && VkUtil.available) { + return new Vk13Simulation(description, configuration); } if (!fullPass) { return new TimeSlicedReactorSimulation(description, configuration); } - var rodMultiple = description.controlRodCount / Config.CONFIG.Reactor.ModeSpecific.ControlRodBatchSize; - - if (allowAccelerated && rodMultiple >= 16) { + var fuelRods = description.controlRodCount * description.y; + if (allowAccelerated && fuelRods >= 8182) { if (CLUtil.available) { return new SingleQueueOpenCL12Simulation(description, configuration); } } - if (allowMultiThread && rodMultiple >= 2) { + + var controlRodBatches = description.controlRodCount / Config.CONFIG.Reactor.ModeSpecific.ControlRodBatchSize; + if (allowMultiThread && controlRodBatches >= 2) { return new FullPassReactorSimulation.MultiThreaded(description, configuration, false); } if (allowOffThread) { diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/Vk13Simulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/Vk13Simulation.java new file mode 100644 index 00000000..ba0eb167 --- /dev/null +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/Vk13Simulation.java @@ -0,0 +1,603 @@ +package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk; + +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationDescription; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.base.SimUtil; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.cpu.FullPassReactorSimulation; +import net.roguelogix.phosphophyllite.util.NonnullDefault; +import net.roguelogix.quartz.internal.util.PointerWrapper; +import org.lwjgl.BufferUtils; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.nio.LongBuffer; + +import static com.sun.jna.Native.LONG_SIZE; +import static com.sun.jna.Native.POINTER_SIZE; +import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkPools.allocCommandBuffer; +import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkPools.freeCommandBufferNow; +import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkUtil.*; +import static org.lwjgl.system.MemoryUtil.memGetAddress; +import static org.lwjgl.system.MemoryUtil.memPutAddress; +import static org.lwjgl.vulkan.VK13.*; + +@NonnullDefault +public class Vk13Simulation extends FullPassReactorSimulation { + + private final VkSemaphoreWaitInfo semaphoreWaitInfo = VkSemaphoreWaitInfo.create(); + private final LongBuffer semaphorePointer = BufferUtils.createLongBuffer(1); + private final LongBuffer semaphoreWaitValuePointer = BufferUtils.createLongBuffer(1); + private long nextWaitValue = 1; + + private final VkPools.DescriptorSet descriptorSet; + + private final PointerWrapper moderatorsWritePtr; + private final PointerWrapper controlRodWritePtr; + + private final VkCommandBuffer executeCommandBuffer; + private final PointerWrapper resultsReadPtr; + + public Vk13Simulation(SimulationDescription simulationDescription, SimulationConfiguration configuration) { + super(simulationDescription, configuration); + + final var SCOPE_OBJECT = new Object(); + final var SCOPE_CLEANINGS = new ReferenceArrayList(); + final var THIS_CLEANINGS = new ReferenceArrayList(); + VK_CLEANER.register(SCOPE_OBJECT, () -> SCOPE_CLEANINGS.forEach(Runnable::run)); + VK_CLEANER.register(this, () -> THIS_CLEANINGS.forEach(Runnable::run)); + + try (var stack = MemoryStack.stackPush()) { + var setupCommandBuffer = allocCommandBuffer(true); + SCOPE_CLEANINGS.add(() -> freeCommandBufferNow(setupCommandBuffer, true)); + var executeCommandBuffer = allocCommandBuffer(false); + THIS_CLEANINGS.add(() -> freeCommandBufferNow(executeCommandBuffer, false)); + + var semaphoreTypeCreateInfo = VkSemaphoreTypeCreateInfo.calloc(stack).sType$Default().semaphoreType(VK_SEMAPHORE_TYPE_TIMELINE).initialValue(0); + var semaphoreCreateInfo = VkSemaphoreCreateInfo.calloc(stack).sType$Default().pNext(semaphoreTypeCreateInfo); + checkVkResult(vkCreateSemaphore(VkUtil.device, semaphoreCreateInfo, null, semaphorePointer)); + semaphoreWaitInfo.sType$Default(); + semaphoreWaitInfo.semaphoreCount(1); + semaphoreWaitInfo.pSemaphores(semaphorePointer); + semaphoreWaitInfo.pValues(semaphoreWaitValuePointer); + final long semaphore = semaphorePointer.get(0); + THIS_CLEANINGS.add(() -> vkDestroySemaphore(VkUtil.device, semaphore, null)); + + descriptorSet = VkPools.allocDescriptorSet(); + + var descriptorUniformWrites = VkDescriptorBufferInfo.calloc(1, stack); + var descriptorBufferWrites = VkDescriptorBufferInfo.calloc(6, stack); + var descriptorWrite = VkWriteDescriptorSet.calloc(2, stack); + descriptorWrite.position(0).sType$Default(); + descriptorWrite.dstSet(descriptorSet.set()); + descriptorWrite.descriptorCount(6); + descriptorWrite.descriptorType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + descriptorWrite.dstBinding(1); + descriptorWrite.dstArrayElement(0); + descriptorWrite.pBufferInfo(descriptorBufferWrites); + descriptorWrite.position(1).sType$Default(); + descriptorWrite.dstSet(descriptorSet.set()); + descriptorWrite.descriptorCount(1); + descriptorWrite.descriptorType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + descriptorWrite.dstBinding(0); + descriptorWrite.dstArrayElement(0); + descriptorWrite.pBufferInfo(descriptorUniformWrites); + descriptorWrite.position(0); + + try (var __ = stack.push()) { + var beginInfo = VkCommandBufferBeginInfo.calloc(stack).sType$Default(); + beginInfo.flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkBeginCommandBuffer(setupCommandBuffer, beginInfo); + beginInfo.flags(0); + vkBeginCommandBuffer(executeCommandBuffer, beginInfo); + } + + { + var initialCopyStartBarrier = VkMemoryBarrier.calloc(1, stack).sType$Default(); + initialCopyStartBarrier.srcAccessMask(VK_ACCESS_HOST_WRITE_BIT); + initialCopyStartBarrier.dstAccessMask(VK_ACCESS_TRANSFER_READ_BIT); + vkCmdPipelineBarrier(setupCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, initialCopyStartBarrier, null, null); + } + + var bufferCreateInfo = VkBufferCreateInfo.calloc(stack).sType$Default(); + bufferCreateInfo.flags(0); + bufferCreateInfo.size(0); + bufferCreateInfo.usage(0); + bufferCreateInfo.sharingMode(VK_SHARING_MODE_EXCLUSIVE); + var bufferHandlePtr = stack.callocLong(1); + var bufferMemoryRequirements = VkMemoryRequirements.calloc(stack); + + // read/write each tick buffers + { + // the +8 is FuelAbsorptionTemperatureCoefficient and InitialHardness + final var moderatorsSize = (256 * 16L) + 16; + bufferCreateInfo.size(moderatorsSize); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long hostModeratorBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, hostModeratorBuffer, null)); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long gpuModeratorBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, gpuModeratorBuffer, null)); + + vkGetBufferMemoryRequirements(VkUtil.device, hostModeratorBuffer, bufferMemoryRequirements); + final var hostModeratorMemory = VkMemUtil.allocHost(bufferMemoryRequirements); + vkBindBufferMemory(VkUtil.device, hostModeratorBuffer, hostModeratorMemory.vkMemoryHandle(), hostModeratorMemory.offset()); + THIS_CLEANINGS.add(() -> VkMemUtil.freeHost(hostModeratorMemory)); + + vkGetBufferMemoryRequirements(VkUtil.device, gpuModeratorBuffer, bufferMemoryRequirements); + final var gpuModeratorMemory = VkMemUtil.allocGPU(bufferMemoryRequirements); + vkBindBufferMemory(VkUtil.device, gpuModeratorBuffer, gpuModeratorMemory.vkMemoryHandle(), gpuModeratorMemory.offset()); + THIS_CLEANINGS.add(() -> VkMemUtil.freeGPU(gpuModeratorMemory)); + + descriptorUniformWrites.position(0); + descriptorUniformWrites.buffer(gpuModeratorBuffer); + descriptorUniformWrites.offset(0); + descriptorUniformWrites.range(bufferCreateInfo.size()); + + moderatorsWritePtr = hostModeratorMemory.hostPtr(); + final var moderatorCopySize = bufferCreateInfo.size(); + + + final var controlRodBufferSize = x * z * 8L; + bufferCreateInfo.size(controlRodBufferSize); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long hostRodBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, hostRodBuffer, null)); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long gpuRodBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, gpuRodBuffer, null)); + + vkGetBufferMemoryRequirements(VkUtil.device, hostRodBuffer, bufferMemoryRequirements); + final var hostRodMemory = VkMemUtil.allocHost(bufferMemoryRequirements); + vkBindBufferMemory(VkUtil.device, hostRodBuffer, hostRodMemory.vkMemoryHandle(), hostRodMemory.offset()); + THIS_CLEANINGS.add(() -> VkMemUtil.freeHost(hostRodMemory)); + + vkGetBufferMemoryRequirements(VkUtil.device, gpuRodBuffer, bufferMemoryRequirements); + final var gpuRodMemory = VkMemUtil.allocGPU(bufferMemoryRequirements); + vkBindBufferMemory(VkUtil.device, gpuRodBuffer, gpuRodMemory.vkMemoryHandle(), gpuRodMemory.offset()); + THIS_CLEANINGS.add(() -> VkMemUtil.freeGPU(gpuRodMemory)); + + descriptorBufferWrites.position(0); + descriptorBufferWrites.buffer(gpuRodBuffer); + descriptorBufferWrites.offset(0); + descriptorBufferWrites.range(bufferCreateInfo.size()); + + controlRodWritePtr = hostRodMemory.hostPtr(); + final var rodCopySize = bufferCreateInfo.size(); + + var copyToGPUBarrier = VkBufferMemoryBarrier.calloc(2, stack); + copyToGPUBarrier.sType$Default(); + copyToGPUBarrier.buffer(hostModeratorBuffer); + copyToGPUBarrier.size(moderatorsSize); + copyToGPUBarrier.srcAccessMask(VK_ACCESS_HOST_WRITE_BIT); + copyToGPUBarrier.dstAccessMask(VK_ACCESS_TRANSFER_READ_BIT); + copyToGPUBarrier.position(1); + copyToGPUBarrier.sType$Default(); + copyToGPUBarrier.buffer(hostRodBuffer); + copyToGPUBarrier.size(controlRodBufferSize); + copyToGPUBarrier.srcAccessMask(VK_ACCESS_HOST_WRITE_BIT); + copyToGPUBarrier.dstAccessMask(VK_ACCESS_TRANSFER_READ_BIT); + copyToGPUBarrier.position(0); + vkCmdPipelineBarrier(executeCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, null, copyToGPUBarrier, null); + + var bufferCopy = VkBufferCopy.calloc(1, stack); + bufferCopy.srcOffset(0); + bufferCopy.dstOffset(0); + + bufferCopy.size(moderatorCopySize); + vkCmdCopyBuffer(executeCommandBuffer, hostModeratorBuffer, gpuModeratorBuffer, bufferCopy); + + bufferCopy.size(rodCopySize); + vkCmdCopyBuffer(executeCommandBuffer, hostRodBuffer, gpuRodBuffer, bufferCopy); + + copyToGPUBarrier.position(0); + copyToGPUBarrier.buffer(gpuModeratorBuffer); + copyToGPUBarrier.srcAccessMask(VK_ACCESS_TRANSFER_WRITE_BIT); + copyToGPUBarrier.dstAccessMask(VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT); + copyToGPUBarrier.position(1); + copyToGPUBarrier.buffer(gpuRodBuffer); + copyToGPUBarrier.srcAccessMask(VK_ACCESS_TRANSFER_WRITE_BIT); + copyToGPUBarrier.dstAccessMask(VK_ACCESS_SHADER_READ_BIT); + copyToGPUBarrier.position(0); + vkCmdPipelineBarrier(executeCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, null, copyToGPUBarrier, null); + + + } + final Runnable recordCopyBack; + { + final var burnResultsBufferSize = controlRods.length * 16L; + bufferCreateInfo.size(burnResultsBufferSize); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long hostBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, hostBuffer, null)); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long gpuBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, gpuBuffer, null)); + + vkGetBufferMemoryRequirements(VkUtil.device, hostBuffer, bufferMemoryRequirements); + final var hostMemory = VkMemUtil.allocHost(bufferMemoryRequirements); + vkBindBufferMemory(VkUtil.device, hostBuffer, hostMemory.vkMemoryHandle(), hostMemory.offset()); + THIS_CLEANINGS.add(() -> VkMemUtil.freeHost(hostMemory)); + + vkGetBufferMemoryRequirements(VkUtil.device, gpuBuffer, bufferMemoryRequirements); + final var gpuMemory = VkMemUtil.allocGPU(bufferMemoryRequirements); + vkBindBufferMemory(VkUtil.device, gpuBuffer, gpuMemory.vkMemoryHandle(), gpuMemory.offset()); + THIS_CLEANINGS.add(() -> VkMemUtil.freeGPU(gpuMemory)); + + var bufferCopy = VkBufferCopy.calloc(1, stack); + bufferCopy.srcOffset(0); + bufferCopy.dstOffset(0); + bufferCopy.size(bufferCreateInfo.size()); + // recording this needs to be deferred until after the main compute execution is recorded + recordCopyBack = () -> { + var copyBackBarrier = VkBufferMemoryBarrier.calloc(1, stack).sType$Default(); + + copyBackBarrier.buffer(gpuBuffer); + copyBackBarrier.size(bufferCopy.size()); + copyBackBarrier.srcAccessMask(VK_ACCESS_SHADER_WRITE_BIT); + copyBackBarrier.dstAccessMask(VK_ACCESS_TRANSFER_READ_BIT); + vkCmdPipelineBarrier(executeCommandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, null, copyBackBarrier, null); + + vkCmdCopyBuffer(executeCommandBuffer, gpuBuffer, hostBuffer, bufferCopy); + + copyBackBarrier.buffer(hostBuffer); + copyBackBarrier.srcAccessMask(VK_ACCESS_TRANSFER_WRITE_BIT); + copyBackBarrier.dstAccessMask(VK_ACCESS_HOST_READ_BIT); + vkCmdPipelineBarrier(executeCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, null, copyBackBarrier, null); + }; + + descriptorBufferWrites.position(5); + descriptorBufferWrites.buffer(gpuBuffer); + descriptorBufferWrites.offset(0); + descriptorBufferWrites.range(bufferCreateInfo.size()); + + resultsReadPtr = hostMemory.hostPtr(); + } + + // write once buffers + { + final var totalControlRodInfoSize = controlRods.length * 4; + bufferCreateInfo.size(totalControlRodInfoSize); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long hostBuffer = bufferHandlePtr.get(0); + SCOPE_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, hostBuffer, null)); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long gpuBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, gpuBuffer, null)); + + vkGetBufferMemoryRequirements(VkUtil.device, hostBuffer, bufferMemoryRequirements); + final var hostMemory = VkMemUtil.allocHost(bufferMemoryRequirements); + SCOPE_CLEANINGS.add(() -> VkMemUtil.freeHost(hostMemory)); + vkBindBufferMemory(VkUtil.device, hostBuffer, hostMemory.vkMemoryHandle(), hostMemory.offset()); + + vkGetBufferMemoryRequirements(VkUtil.device, gpuBuffer, bufferMemoryRequirements); + final var gpuMemory = VkMemUtil.allocGPU(bufferMemoryRequirements); + THIS_CLEANINGS.add(() -> VkMemUtil.freeGPU(gpuMemory)); + vkBindBufferMemory(VkUtil.device, gpuBuffer, gpuMemory.vkMemoryHandle(), gpuMemory.offset()); + + descriptorBufferWrites.position(1); + descriptorBufferWrites.buffer(gpuBuffer); + descriptorBufferWrites.offset(0); + descriptorBufferWrites.range(bufferCreateInfo.size()); + + var bufferCopy = VkBufferCopy.calloc(1, stack); + bufferCopy.srcOffset(0); + bufferCopy.dstOffset(0); + bufferCopy.size(bufferCreateInfo.size()); + vkCmdCopyBuffer(setupCommandBuffer, hostBuffer, gpuBuffer, bufferCopy); + + var hostControlRodPtr = hostMemory.hostPtr(); + + for (int i = 0; i < controlRods.length; i++) { + hostControlRodPtr.putShortIdx(i * 2L, (short) controlRods[i].x); + hostControlRodPtr.putShortIdx(i * 2L + 1, (short) controlRods[i].z); + } + } + + { + bufferCreateInfo.size((long) x * y * z); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long hostBuffer = bufferHandlePtr.get(0); + SCOPE_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, hostBuffer, null)); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long gpuBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, gpuBuffer, null)); + + vkGetBufferMemoryRequirements(VkUtil.device, hostBuffer, bufferMemoryRequirements); + final var hostMemory = VkMemUtil.allocHost(bufferMemoryRequirements); + SCOPE_CLEANINGS.add(() -> VkMemUtil.freeHost(hostMemory)); + vkBindBufferMemory(VkUtil.device, hostBuffer, hostMemory.vkMemoryHandle(), hostMemory.offset()); + + vkGetBufferMemoryRequirements(VkUtil.device, gpuBuffer, bufferMemoryRequirements); + final var gpuMemory = VkMemUtil.allocGPU(bufferMemoryRequirements); + THIS_CLEANINGS.add(() -> VkMemUtil.freeGPU(gpuMemory)); + vkBindBufferMemory(VkUtil.device, gpuBuffer, gpuMemory.vkMemoryHandle(), gpuMemory.offset()); + + descriptorBufferWrites.position(2); + descriptorBufferWrites.buffer(gpuBuffer); + descriptorBufferWrites.offset(0); + descriptorBufferWrites.range(bufferCreateInfo.size()); + + var bufferCopy = VkBufferCopy.calloc(1, stack); + bufferCopy.srcOffset(0); + bufferCopy.dstOffset(0); + bufferCopy.size(bufferCreateInfo.size()); + vkCmdCopyBuffer(setupCommandBuffer, hostBuffer, gpuBuffer, bufferCopy); + + var moderatorIndicesPtr = hostMemory.hostPtr(); + + int volume = x * y * z; + for (int i = 0; i < volume; i++) { + moderatorIndicesPtr.putByte(i, getModeratorIndex(i)); + } + } + + { + final var totalRayCount = SimUtil.rays.size(); + final var totalRaySize = totalRayCount * VkUtil.SIZEOF_RAY; + bufferCreateInfo.size(totalRaySize); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long hostBuffer = bufferHandlePtr.get(0); + SCOPE_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, hostBuffer, null)); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long gpuBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, gpuBuffer, null)); + + vkGetBufferMemoryRequirements(VkUtil.device, hostBuffer, bufferMemoryRequirements); + final var hostMemory = VkMemUtil.allocHost(bufferMemoryRequirements); + SCOPE_CLEANINGS.add(() -> VkMemUtil.freeHost(hostMemory)); + vkBindBufferMemory(VkUtil.device, hostBuffer, hostMemory.vkMemoryHandle(), hostMemory.offset()); + + vkGetBufferMemoryRequirements(VkUtil.device, gpuBuffer, bufferMemoryRequirements); + final var gpuMemory = VkMemUtil.allocGPU(bufferMemoryRequirements); + THIS_CLEANINGS.add(() -> VkMemUtil.freeGPU(gpuMemory)); + vkBindBufferMemory(VkUtil.device, gpuBuffer, gpuMemory.vkMemoryHandle(), gpuMemory.offset()); + + descriptorBufferWrites.position(3); + descriptorBufferWrites.buffer(gpuBuffer); + descriptorBufferWrites.offset(0); + descriptorBufferWrites.range(bufferCreateInfo.size()); + + var bufferCopy = VkBufferCopy.calloc(1, stack); + bufferCopy.srcOffset(0); + bufferCopy.dstOffset(0); + bufferCopy.size(bufferCreateInfo.size()); + vkCmdCopyBuffer(setupCommandBuffer, hostBuffer, gpuBuffer, bufferCopy); + + var hostRayPointer = hostMemory.hostPtr(); + + for (int i = 0; i < totalRayCount; i++) { + final var ray = SimUtil.rays.get(i); + final var rayOffset = i * 4 * MAX_RAY_STEPS; + for (int j = 0; j < ray.size(); j++) { + final var totalOffset = rayOffset + (j * 4L); + hostRayPointer.putFloatIdx(totalOffset, (float) ray.get(j).length); + hostRayPointer.putIntIdx(totalOffset + 1, ray.get(j).offset.x); + hostRayPointer.putIntIdx(totalOffset + 2, ray.get(j).offset.y); + hostRayPointer.putIntIdx(totalOffset + 3, ray.get(j).offset.z); + } + } + } + + // GPU only buffers + final Runnable recordReductionBarrier; + { + final var burnResultsBufferSize = controlRods.length * y * VkPipelines.zSizeForHeight(y) * 16L; + bufferCreateInfo.size(burnResultsBufferSize); + + bufferCreateInfo.usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + checkVkResult(vkCreateBuffer(VkUtil.device, bufferCreateInfo, null, bufferHandlePtr)); + final long gpuBuffer = bufferHandlePtr.get(0); + THIS_CLEANINGS.add(() -> vkDestroyBuffer(VkUtil.device, gpuBuffer, null)); + + vkGetBufferMemoryRequirements(VkUtil.device, gpuBuffer, bufferMemoryRequirements); + final var gpuMemory = VkMemUtil.allocGPU(bufferMemoryRequirements); + vkBindBufferMemory(VkUtil.device, gpuBuffer, gpuMemory.vkMemoryHandle(), gpuMemory.offset()); + THIS_CLEANINGS.add(() -> VkMemUtil.freeGPU(gpuMemory)); + + descriptorBufferWrites.position(4); + descriptorBufferWrites.buffer(gpuBuffer); + descriptorBufferWrites.offset(0); + descriptorBufferWrites.range(bufferCreateInfo.size()); + + recordReductionBarrier = () -> { + var stageToStageBarrier = VkBufferMemoryBarrier.calloc(1, stack).sType$Default(); + stageToStageBarrier.buffer(gpuBuffer); + stageToStageBarrier.size(burnResultsBufferSize); + stageToStageBarrier.srcAccessMask(VK_ACCESS_SHADER_WRITE_BIT); + stageToStageBarrier.dstAccessMask(VK_ACCESS_SHADER_READ_BIT); + vkCmdPipelineBarrier(executeCommandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, null, stageToStageBarrier, null); + }; + } + + + { + var initialCopyDoneBarrier = VkMemoryBarrier.calloc(1, stack).sType$Default(); + initialCopyDoneBarrier.srcAccessMask(VK_ACCESS_TRANSFER_WRITE_BIT); + initialCopyDoneBarrier.dstAccessMask(VK_ACCESS_SHADER_READ_BIT); + vkCmdPipelineBarrier(setupCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, initialCopyDoneBarrier, null, null); + } + + + vkUpdateDescriptorSets(device, descriptorWrite, null); + var simPipeline = VkPipelines.getSimPiplineForHeight(y); + vkCmdBindPipeline(executeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, simPipeline); + vkCmdPushConstants(executeCommandBuffer, VkPipelines.pipelineLayouts.firstLong(), VK_SHADER_STAGE_COMPUTE_BIT, 0, new int[]{x, z}); + vkCmdPushConstants(executeCommandBuffer, VkPipelines.pipelineLayouts.firstLong(), VK_SHADER_STAGE_COMPUTE_BIT, 8, new float[]{ + (float) configuration.RFPerRadiationUnit(), + (float) configuration.fuelAbsorptionCoefficient(), + (float) configuration.fuelModerationFactor(), + (float) (1.0 / configuration.fuelHardnessDivisor()), + } + ); + vkCmdBindDescriptorSets(executeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, VkPipelines.pipelineLayouts.firstLong(), 0, new long[]{descriptorSet.set()}, null); + vkCmdDispatch(executeCommandBuffer, controlRods.length, 1 /* group count is 1, global size is y*/, 1); + recordReductionBarrier.run(); + vkCmdBindDescriptorSets(executeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, VkPipelines.pipelineLayouts.secondLong(), 0, new long[]{descriptorSet.set()}, null); + vkCmdBindPipeline(executeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, VkPipelines.reductionPipeline); + vkCmdPushConstants(executeCommandBuffer, VkPipelines.pipelineLayouts.secondLong(), VK_SHADER_STAGE_COMPUTE_BIT, 0, new int[]{y * VkPipelines.zSizeForHeight(y)}); + vkCmdDispatch(executeCommandBuffer, controlRods.length, 1, 1); + recordCopyBack.run(); + + vkEndCommandBuffer(setupCommandBuffer); + vkEndCommandBuffer(executeCommandBuffer); + this.executeCommandBuffer = executeCommandBuffer; + + var commandBufferInfo = VkCommandBufferSubmitInfo.calloc(1, stack).sType$Default(); + commandBufferInfo.commandBuffer(setupCommandBuffer); + + var semaphoreSignalInfo = VkSemaphoreSubmitInfo.calloc(1, stack).sType$Default(); + semaphoreSignalInfo.semaphore(semaphorePointer.get(0)); + semaphoreSignalInfo.value(nextWaitValue); + semaphoreSignalInfo.stageMask(VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT); + + var submitInfo = VkSubmitInfo2.calloc(1, stack).sType$Default(); + submitInfo.pCommandBufferInfos(commandBufferInfo); + submitInfo.pSignalSemaphoreInfos(semaphoreSignalInfo); + + VkUtil.queueSubmit(submitInfo); + waitSemaphore(); + + if (VkPipelines.testSize != 0) { + THIS_CLEANINGS.add(() -> vkDestroyPipeline(device, simPipeline, null)); + } + } + } + + @Override + public boolean isAsync() { + return true; + } + + @Override + public boolean readyToTick() { + semaphoreWaitValuePointer.put(0, nextWaitValue); + return checkVkResult(vkWaitSemaphores(VkUtil.device, semaphoreWaitInfo, 0)) == VK_SUCCESS; + } + + private void waitSemaphore() { + semaphoreWaitValuePointer.put(0, nextWaitValue); + vkWaitSemaphores(VkUtil.device, semaphoreWaitInfo, -1); + } + + @Override + protected void finalize() throws Throwable { + waitSemaphore(); + } + + public void addSemaphoreToWaitInto(VkSemaphoreWaitInfo waitInfo, int index) { + var structAddress = waitInfo.address(); + var semaphoresPointer = memGetAddress(structAddress + VkSemaphoreWaitInfo.PSEMAPHORES); + var valuesPointer = memGetAddress(structAddress + VkSemaphoreWaitInfo.PVALUES); + memPutAddress(semaphoresPointer + ((long) index * POINTER_SIZE), semaphorePointer.get(0)); + memPutAddress(valuesPointer + ((long) index * LONG_SIZE), semaphoreWaitValuePointer.get(0)); + } + + @Override + protected void startNextRadiate() { + if (fuelTank.fuel() <= 0) { + return; + } + setupIrradiationTick(); + fullPassIrradiationRequest.updateCache(); + waitSemaphore(); + + moderatorsWritePtr.putFloatIdx(0L, (float) fuelAbsorptionTemperatureCoefficient); + moderatorsWritePtr.putFloatIdx(1L, (float) initialHardness); + + var moderators = moderatorsWritePtr.slice(16, moderatorsWritePtr.size() - 8); + for (int i = 0; i < moderatorCaches.size(); i++) { + var cache = moderatorCaches.get(i); + moderators.putFloatIdx(i * 4L, (float) cache.absorption); + moderators.putFloatIdx(i * 4L + 1, (float) cache.heatEfficiency); + moderators.putFloatIdx(i * 4L + 2, (float) cache.moderation); + } + + for (int i = 0; i < controlRods.length; i++) { + var controlRod = controlRods[i]; + int linearIndex = controlRod.x * z + controlRod.z; + controlRodWritePtr.putFloatIdx(linearIndex * 2L, (float) (controlRod.insertion * 0.01)); + controlRodWritePtr.putFloatIdx(linearIndex * 2L + 1, (float) initialIntensties[i]); + } + + nextWaitValue++; + semaphoreWaitValuePointer.put(0, nextWaitValue); + + try (var stack = MemoryStack.stackPush()) { + + var commandBufferInfo = VkCommandBufferSubmitInfo.calloc(1, stack).sType$Default(); + commandBufferInfo.commandBuffer(executeCommandBuffer); + + var semaphoreSignalInfo = VkSemaphoreSubmitInfo.calloc(1, stack).sType$Default(); + semaphoreSignalInfo.semaphore(semaphorePointer.get(0)); + semaphoreSignalInfo.value(nextWaitValue); + semaphoreSignalInfo.stageMask(VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT); + + var submitInfo = VkSubmitInfo2.calloc(1, stack).sType$Default(); + submitInfo.pCommandBufferInfos(commandBufferInfo); + submitInfo.pSignalSemaphoreInfos(semaphoreSignalInfo); + + VkUtil.queueSubmit(submitInfo); + } + } + + public double radiate() { + waitSemaphore(); + + for (long i = 0; i < controlRods.length; i++) { + fuelRFAdded += resultsReadPtr.getFloatIdx(i * 4) * rayMultiplier; + fuelRadAdded += resultsReadPtr.getFloatIdx(i * 4 + 1) * rayMultiplier; + caseRFAdded += resultsReadPtr.getFloatIdx(i * 4 + 2) * rayMultiplier; + } + + fuelRFAdded *= configuration.RFPerRadiationUnit(); + caseRFAdded *= configuration.RFPerRadiationUnit(); + + fuelRFAdded /= controlRods.length; + fuelRadAdded /= controlRods.length; + caseRFAdded /= controlRods.length; + + if (!Double.isNaN(fuelRadAdded)) { + if (configuration.fuelRadScalingMultiplier() != 0) { + fuelRadAdded *= configuration.fuelRadScalingMultiplier() * (configuration.fuelRodFuelCapacity() / Math.max(1.0, (double) fuelTank().totalStored())); + } + fuelFertility += fuelRadAdded; + } + if (!Double.isNaN(fuelRFAdded)) { + fuelHeat.absorbRF(fuelRFAdded); + } + if (!Double.isNaN(caseRFAdded)) { + stackHeat.absorbRF(caseRFAdded); + } + + fuelRFAdded = 0; + fuelRadAdded = 0; + caseRFAdded = 0; + + return rawFuelUsage; + } +} diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java new file mode 100644 index 00000000..c31c9f65 --- /dev/null +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java @@ -0,0 +1,322 @@ +package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk; + +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import net.roguelogix.phosphophyllite.util.NonnullDefault; +import net.roguelogix.quartz.internal.util.PointerWrapper; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.libc.LibCString; +import org.lwjgl.vulkan.VkMemoryAllocateInfo; +import org.lwjgl.vulkan.VkMemoryRequirements; +import org.lwjgl.vulkan.VkPhysicalDeviceMemoryProperties; + +import java.util.Collections; + +import static java.lang.Math.max; +import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkUtil.checkVkResult; +import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK13.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; +import static org.lwjgl.vulkan.VK13.vkGetPhysicalDeviceMemoryProperties; + +@NonnullDefault +public class VkMemUtil { + + // 1GiB + private static final long KiB = 1024; + private static final long MiB = 1024 * KiB; + private static final long GiB = 1024 * MiB; + private static final long VK_ALLOCATION_SIZE = GiB; + + private static class AllocationBlock { + + private record Info(long offset, long size) implements Comparable { + public Info(Info a, Info b) { + this(a.offset, a.size + b.size); + if (a.offset + a.size != b.offset) { + throw new IllegalStateException("Cannot combine non-consecutive alloc infos"); + } + } + + @Override + public int compareTo(Info info) { + return Long.compare(offset, info.offset); + } + + private Pair split(long size) { + if (size > this.size) { + throw new IllegalArgumentException("Cannot split allocation to larger size"); + } + if (size == this.size) { + return new Pair<>(new Info(this.offset, size), null); + } + return new Pair<>(new Info(this.offset, size), new Info(this.offset + size, this.size - size)); + } + } + + + private final ObjectArrayList freeAllocations = new ObjectArrayList<>() { + @Override + public boolean add(@Nullable Info allocation) { + if (allocation == null) { + return false; + } + int index = Collections.binarySearch(this, allocation); + if (index < 0) { + index = ~index; + super.add(index, allocation); + } else { + super.set(index, allocation); + } + return true; + } + }; + + private final long vkMemoryHandle; + private final long hostPtr; + private final long size; + + private AllocationBlock(long vkMemoryHandle, long hostPtr, long size) { + this.vkMemoryHandle = vkMemoryHandle; + this.hostPtr = hostPtr; + this.size = size; + freeAllocations.add(new Info(0, size)); + } + + public boolean canFit(long size, long alignment) { + for (Info freeAlloc : freeAllocations) { + final long nextValidAlignment = (freeAlloc.offset + (alignment - 1)) & (-alignment); + final long alignmentWaste = nextValidAlignment - freeAlloc.offset; + if (freeAlloc.size - alignmentWaste >= size) { + // fits + return true; + } + } + // dont fit + return false; + } + + public boolean owns(VkAllocation allocation) { + return allocation.vkMemoryHandle == this.vkMemoryHandle; + } + + public VkAllocation alloc(long size, long align) { + Info allocatedSpace = null; + for (Info freeAllocation : freeAllocations) { + var alloc = attemptAllocInSpace(freeAllocation, size, align); + if (alloc != null) { + allocatedSpace = alloc; + freeAllocations.remove(freeAllocation); + break; + } + } + if (allocatedSpace == null) { + throw new IllegalStateException("Failed to make allocation in block"); + } + PointerWrapper hostPtr = PointerWrapper.NULLPTR; + if (this.hostPtr != 0) { + hostPtr = new PointerWrapper(this.hostPtr + allocatedSpace.offset, size); + } + return new VkAllocation(this, vkMemoryHandle, allocatedSpace.offset, size, hostPtr); + } + + @Nullable + private Info attemptAllocInSpace(Info freeAlloc, long size, long alignment) { + // next value guaranteed to be at *most* one less than the next alignment, then bit magic because powers of two to round down without a divide + final long nextValidAlignment = (freeAlloc.offset + (alignment - 1)) & (-alignment); + final long alignmentWaste = nextValidAlignment - freeAlloc.offset; + if (freeAlloc.size - alignmentWaste < size) { + // wont fit, *neeeeeeeeeeeext* + return null; + } + boolean collapse = false; + if (alignmentWaste > 0) { + final var newAllocs = freeAlloc.split(alignmentWaste); + // not concurrent modification because this will always return + freeAllocations.add(newAllocs.getFirst()); + freeAlloc = newAllocs.getSecond(); + + int index = freeAllocations.indexOf(newAllocs.getFirst()); + collapseFreeAllocationWithNext(index - 1); + collapseFreeAllocationWithNext(index); + } + if (freeAlloc.size > size) { + final var newAllocs = freeAlloc.split(size); + // not concurrent modification because this will always return + freeAlloc = newAllocs.getFirst(); + freeAllocations.add(newAllocs.getSecond()); + int index = freeAllocations.indexOf(newAllocs.getSecond()); + collapseFreeAllocationWithNext(index - 1); + collapseFreeAllocationWithNext(index); + } + + return freeAlloc; + } + + public void free(VkAllocation allocation) { + if (!owns(allocation)) { + return; + } + var info = new Info(allocation.offset, allocation.size); + freeAllocations.add(info); + var index = freeAllocations.indexOf(info); + collapseFreeAllocationWithNext(index - 1); + collapseFreeAllocationWithNext(index); + } + + private boolean collapseFreeAllocationWithNext(int freeAllocationIndex) { + if (freeAllocationIndex < 0 || freeAllocationIndex >= freeAllocations.size() - 1) { + return false; + } + var allocA = freeAllocations.get(freeAllocationIndex); + var allocB = freeAllocations.get(freeAllocationIndex + 1); + if (allocA.offset + allocA.size == allocB.offset) { + // neighboring allocations, collapse them + freeAllocations.remove(freeAllocationIndex + 1); + freeAllocations.remove(freeAllocationIndex); + freeAllocations.add(new Info(allocA.offset, allocA.size + allocB.size)); + return true; + } + return false; + } + } + + private static final int hostMemoryType; + private static final int gpuMemoryType; + private static final int gpuMemoryProperties; + private static final ReferenceArrayList hostBlocks = new ReferenceArrayList<>(); + private static final ReferenceArrayList gpuBlocks = new ReferenceArrayList<>(); + + + static { + int hostType = -1; + int gpuType = -1; + boolean hostVisibleGPUMemory = false; + try (var stack = MemoryStack.stackPush()) { + var memoryProperties = VkPhysicalDeviceMemoryProperties.calloc(stack); + vkGetPhysicalDeviceMemoryProperties(VkUtil.device.getPhysicalDevice(), memoryProperties); + var memoryTypes = memoryProperties.memoryTypes(); + var typeCount = memoryProperties.memoryTypeCount(); + // earlier types preferred by implementation + for (int i = typeCount - 1; i >= 0; i--) { + var type = memoryTypes.get(i); + var propertyFlags = type.propertyFlags(); + if ((propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) { + if(!hostVisibleGPUMemory || (propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0){ + gpuType = i; + } + } + if ((propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0) { + hostType = i; + } + } + if (gpuType == -1) { + throw new IllegalStateException("Unable to find GPU memory"); + } + if (hostType == -1) { + throw new IllegalStateException("Unable to find GPU memory"); + } + hostMemoryType = hostType; + gpuMemoryType = gpuType; + gpuMemoryProperties = memoryTypes.get(gpuMemoryType).propertyFlags(); + } + } + + static void init() { + } + + static void terminate() { + for (AllocationBlock hostBlock : hostBlocks) { + vkFreeMemory(VkUtil.device, hostBlock.vkMemoryHandle, null); + } + for (AllocationBlock hostBlock : gpuBlocks) { + vkFreeMemory(VkUtil.device, hostBlock.vkMemoryHandle, null); + } + } + + public record VkAllocation(AllocationBlock block, long vkMemoryHandle, long offset, long size, PointerWrapper hostPtr) { + + } + + public static VkAllocation allocHost(VkMemoryRequirements memoryRequirements) { + if ((memoryRequirements.memoryTypeBits() & (1 << hostMemoryType)) == 0) { + throw new IllegalStateException("Cannot allocate on host"); + } + return allocHost(memoryRequirements.size(), memoryRequirements.alignment()); + } + + public static VkAllocation allocHost(long size, long alignment) { + var block = getBlockWithSpace(size, alignment, hostBlocks, hostMemoryType); + return block.alloc(size, alignment); + } + + public static void freeHost(@Nullable VkAllocation allocation) { + if (allocation == null) { + return; + } + for (AllocationBlock hostBlock : hostBlocks) { + if (hostBlock.owns(allocation)) { + hostBlock.free(allocation); + return; + } + } + } + + public static VkAllocation allocGPU(VkMemoryRequirements memoryRequirements) { + if ((memoryRequirements.memoryTypeBits() & (1 << gpuMemoryType)) == 0) { + throw new IllegalStateException("Cannot allocate on gpu"); + } + return allocGPU(memoryRequirements.size(), memoryRequirements.alignment()); + } + + public static VkAllocation allocGPU(long size, long alignment) { + var block = getBlockWithSpace(size, alignment, gpuBlocks, gpuMemoryType); + return block.alloc(size, alignment); + } + + public static void freeGPU(@Nullable VkAllocation allocation) { + if (allocation == null) { + return; + } + for (AllocationBlock hostBlock : gpuBlocks) { + if (hostBlock.owns(allocation)) { + hostBlock.free(allocation); + return; + } + } + } + + + private static AllocationBlock getBlockWithSpace(long size, long alignment, ReferenceArrayList list, int memoryType) { + for (AllocationBlock allocationBlock : list) { + if (allocationBlock.canFit(size, alignment)) { + return allocationBlock; + } + } + var newBlock = allocBlock(max(VK_ALLOCATION_SIZE, size), memoryType); + list.add(newBlock); + return newBlock; + } + + private static AllocationBlock allocBlock(long size, int memoryType) { + try (var stack = MemoryStack.stackPush()) { + var longReturn = stack.mallocLong(1); + var ptrReturn = stack.mallocPointer(1); + + var allocInfo = VkMemoryAllocateInfo.calloc(stack).sType$Default(); + allocInfo.allocationSize(size); + allocInfo.memoryTypeIndex(memoryType); + checkVkResult(vkAllocateMemory(VkUtil.device, allocInfo, null, longReturn)); + long memHandle = longReturn.get(0); + long memPtr = 0; +// if (memoryType == hostMemoryType || (gpuMemoryProperties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) { + if (memoryType == hostMemoryType) { + vkMapMemory(VkUtil.device, memHandle, 0, size, 0, ptrReturn); + memPtr = ptrReturn.get(0); + LibCString.nmemset(memPtr, 0, size); + } + return new AllocationBlock(memHandle, memPtr, size); + } + } +} diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPipelines.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPipelines.java new file mode 100644 index 00000000..32f25d85 --- /dev/null +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPipelines.java @@ -0,0 +1,276 @@ +package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk; + +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongLongImmutablePair; +import it.unimi.dsi.fastutil.longs.LongLongPair; +import net.roguelogix.biggerreactors.Config; +import net.roguelogix.phosphophyllite.util.NonnullDefault; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.vulkan.*; + +import java.nio.ByteBuffer; + +import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkUtil.checkVkResult; +import static org.lwjgl.vulkan.VK13.*; + +@NonnullDefault +public class VkPipelines { + + private static final long reductionShaderModule; + private static final long simShaderModule; + private static final long simvec2ShaderModule; + static final long descriptorLayout; + static final LongLongPair pipelineLayouts; + static final long reductionPipeline; + private static final long baseSimPipeline; + private static final LongArrayList simPipelines = new LongArrayList(); + + // best sizes benchmarked on a 5800u iGPU + private static final int[] zSizes = new int[]{ + 16, 16, 16, 16, + 16, 8, 8, 16, + 16, 8, 8, 8, + 8, 8, 8, 8, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 2, 2, + 2, 2, 2, 2, + 2, 2, 2, 2, + 2, 2, 2, 2, + 2, 2, 2, 2, + 2, 2, 2, 2, + }; + + static { + reductionShaderModule = createShaderModule(VkUtil.reductionSPV); + simShaderModule = createShaderModule(VkUtil.raySimSPV); + simvec2ShaderModule = createShaderModule(VkUtil.raySimVec2SPV); + descriptorLayout = createDescriptorLayout(); + pipelineLayouts = createPipelineLayouts(); + reductionPipeline = createReductionPipeline(); + baseSimPipeline = getSimPiplineForHeight(1); + } + + public static void init() { + + } + + public static void terminate() { + for (int i = 0; i < simPipelines.size(); i++) { + vkDestroyPipeline(VkUtil.device, simPipelines.getLong(i), null); + } + if (testSize != 0) { + vkDestroyPipeline(VkUtil.device, baseSimPipeline, null); + } + vkDestroyPipeline(VkUtil.device, reductionPipeline, null); + vkDestroyPipelineLayout(VkUtil.device, pipelineLayouts.firstLong(), null); + vkDestroyPipelineLayout(VkUtil.device, pipelineLayouts.secondLong(), null); + vkDestroyDescriptorSetLayout(VkUtil.device, descriptorLayout, null); + vkDestroyShaderModule(VkUtil.device, reductionShaderModule, null); + vkDestroyShaderModule(VkUtil.device, simShaderModule, null); + vkDestroyShaderModule(VkUtil.device, simvec2ShaderModule, null); + } + + private static long createShaderModule(ByteBuffer code) { + try (var stack = MemoryStack.stackPush()) { + + final var shaderModuleCreateInfo = VkShaderModuleCreateInfo.calloc(stack).sType$Default(); + shaderModuleCreateInfo.pCode(code); + final var longPtr = stack.mallocLong(1); + checkVkResult(vkCreateShaderModule(VkUtil.device, shaderModuleCreateInfo, null, longPtr)); + return longPtr.get(0); + } + } + + private static long createDescriptorLayout() { + try (var stack = MemoryStack.stackPush()) { + + final var bindings = VkDescriptorSetLayoutBinding.calloc(7, stack); + + bindings.position(0); + bindings.binding(); + bindings.descriptorType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + bindings.descriptorCount(1); + bindings.stageFlags(VK_SHADER_STAGE_COMPUTE_BIT); + + for (int i = 1; i < 7; i++) { + bindings.position(i); + bindings.binding(i); + bindings.descriptorType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + bindings.descriptorCount(1); + bindings.stageFlags(VK_SHADER_STAGE_COMPUTE_BIT); + } + bindings.position(0); + + + final var createInfo = VkDescriptorSetLayoutCreateInfo.calloc(stack).sType$Default(); + final var longPtr = stack.callocLong(1); + + createInfo.pBindings(bindings); + checkVkResult(vkCreateDescriptorSetLayout(VkUtil.device, createInfo, null, longPtr)); + return longPtr.get(0); + } + } + + private static LongLongPair createPipelineLayouts() { + try (var stack = MemoryStack.stackPush()) { + + final var descriptorLayouts = stack.mallocLong(1); + descriptorLayouts.put(0, descriptorLayout); + + final var raySimPushConstants = VkPushConstantRange.calloc(1, stack); + raySimPushConstants.offset(0); + raySimPushConstants.size(24); + raySimPushConstants.stageFlags(VK_SHADER_STAGE_COMPUTE_BIT); + + var raySimLayoutCreateInfo = VkPipelineLayoutCreateInfo.calloc(stack).sType$Default(); + raySimLayoutCreateInfo.pPushConstantRanges(raySimPushConstants); + raySimLayoutCreateInfo.pSetLayouts(descriptorLayouts); + + final var reductionPushConstants = VkPushConstantRange.calloc(1, stack); + reductionPushConstants.offset(0); + reductionPushConstants.size(4); + reductionPushConstants.stageFlags(VK_SHADER_STAGE_COMPUTE_BIT); + + var rayReductionLayoutCreateInfo = VkPipelineLayoutCreateInfo.calloc(stack).sType$Default(); + rayReductionLayoutCreateInfo.pPushConstantRanges(reductionPushConstants); + rayReductionLayoutCreateInfo.pSetLayouts(descriptorLayouts); + + var longPtr = stack.mallocLong(1); + + checkVkResult(vkCreatePipelineLayout(VkUtil.device, raySimLayoutCreateInfo, null, longPtr)); + long simLayout = longPtr.get(0); + + checkVkResult(vkCreatePipelineLayout(VkUtil.device, rayReductionLayoutCreateInfo, null, longPtr)); + long reductionLayout = longPtr.get(0); + + return new LongLongImmutablePair(simLayout, reductionLayout); + } + } + + private static long createReductionPipeline() { + try (var stack = MemoryStack.stackPush()) { + var createInfo = VkComputePipelineCreateInfo.calloc(1, stack).sType$Default(); + + var stage = createInfo.stage().sType$Default(); + stage.stage(VK_SHADER_STAGE_COMPUTE_BIT); + stage.module(reductionShaderModule); + // this is dumb, LWJGL doesnt have any way to pass the pointer directly + var name = MemoryUtil.memUTF8("main", true); + stage.pName(name); + + createInfo.layout(pipelineLayouts.secondLong()); + + var pipelineHandlePtr = stack.mallocLong(1); + int returnCode = vkCreateComputePipelines(VkUtil.device, VK_NULL_HANDLE, createInfo, null, pipelineHandlePtr); + MemoryUtil.memFree(name); + checkVkResult(returnCode); + return pipelineHandlePtr.get(0); + } + } + + public static int testSize = 0; + + public static int zSizeForHeight(int height) { + if(height > 1024){ + throw new IllegalArgumentException("Heights above 1024 not supported"); + } + int requestedSize = requestedZSizeForHeight(height); + while (requestedSize * height > 1024){ + requestedSize >>= 1; + } + return requestedSize; + } + + private static int requestedZSizeForHeight(int height){ + if (testSize != 0) { + return testSize; + } + if (height < zSizes.length) { + return zSizes[height]; + } + return 1; + } + + public static long getSimPiplineForHeight(int height) { + if (testSize == 0) { + if (height < simPipelines.size()) { + var pipeline = VkPipelines.simPipelines.getLong(height); + if (pipeline != 0) { + return pipeline; + } + } + } + simPipelines.size(height + 1); + + try (var stack = MemoryStack.stackPush()) { + var createInfo = VkComputePipelineCreateInfo.calloc(1, stack); + createInfo.sType$Default(); + if (height == 1) { + createInfo.flags(VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT); + } else { + createInfo.flags(VK_PIPELINE_CREATE_DERIVATIVE_BIT); + createInfo.basePipelineHandle(baseSimPipeline); + createInfo.basePipelineIndex(-1); + } + + var stage = createInfo.stage().sType$Default(); + stage.stage(VK_SHADER_STAGE_COMPUTE_BIT); +// stage.module((height & 1) == 0 ? simvec2ShaderModule : simShaderModule); + stage.module(simShaderModule); + // this is dumb, LWJGL doesnt have any way to pass the pointer directly + var name = MemoryUtil.memUTF8("main", true); + stage.pName(name); + + +// final var localYSize = (height & 1) == 0 ? height >> 1 : height; + final var localYSize = height; + final var localZSize = zSizeForHeight(height); + final var RayTTL = Config.CONFIG.Reactor.IrradiationDistance; + final var RodAreaSize = (2 * RayTTL) + 1; + final var RayPerBatch = Config.CONFIG.Reactor.SimulationRays / localZSize; + final var MaxRaySteps = VkUtil.MAX_RAY_STEPS; + + var specializationData = stack.calloc(6 * 4); // its all uints + var mapEntries = VkSpecializationMapEntry.calloc(5, stack); + + var specializationIntData = specializationData.asIntBuffer(); + specializationIntData.put(0, localYSize); + specializationIntData.put(1, localZSize); + specializationIntData.put(2, (int) RayTTL); + specializationIntData.put(3, (int) RodAreaSize); + specializationIntData.put(4, RayPerBatch); + specializationIntData.put(5, (int) MaxRaySteps); + + for (int i = 0; i < mapEntries.limit(); i++) { + mapEntries.position(i); + mapEntries.constantID(i); + mapEntries.offset(i * 4); + mapEntries.size(4); + } + mapEntries.position(0); + + var specializationInfo = VkSpecializationInfo.calloc(stack); + specializationInfo.pMapEntries(mapEntries); + specializationInfo.pData(specializationData); + stage.pSpecializationInfo(specializationInfo); + + createInfo.layout(pipelineLayouts.firstLong()); + + var pipelineHandlePtr = stack.mallocLong(1); + int returnCode = vkCreateComputePipelines(VkUtil.device, VK_NULL_HANDLE, createInfo, null, pipelineHandlePtr); + MemoryUtil.memFree(name); + checkVkResult(returnCode); + long pipeline = pipelineHandlePtr.get(0); + if (testSize == 0) { + simPipelines.set(height, pipelineHandlePtr.get(0)); + } + return pipeline; + } + } +} diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPools.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPools.java new file mode 100644 index 00000000..166986ed --- /dev/null +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPools.java @@ -0,0 +1,174 @@ +package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk; + +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkUtil.checkVkResult; +import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK13.VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; +import static org.lwjgl.vulkan.VK13.vkCreateCommandPool; + +public class VkPools { + + private static final long persistentCommandsPool; + private static final ReferenceArrayList freePersistentCommandBuffers = new ReferenceArrayList<>(); + private static final long singleIssueCommandsPool; + private static final ReferenceArrayList freeSingleIssueCommandBuffers = new ReferenceArrayList<>(); + private static final LongArrayList descriptorPools = new LongArrayList(); + + public record DescriptorSet(long set, long pool) { + public void free() { + freeDescriptorSet(this); + } + } + + private static final ReferenceArrayList freeDescriptorSets = new ReferenceArrayList(); + private static final ReferenceArrayList descriptorSetsToFree = new ReferenceArrayList(); + + static { + persistentCommandsPool = createCommandPool(false); + singleIssueCommandsPool = createCommandPool(true); + } + + private static long createCommandPool(boolean singleIssue) { + try (var stack = MemoryStack.stackPush()) { + + var createInfo = VkCommandPoolCreateInfo.calloc(stack).sType$Default(); + createInfo.flags(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + if (singleIssue) { + createInfo.flags(createInfo.flags() | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT); + } + createInfo.queueFamilyIndex(VkUtil.queueFamilyIndex); + + var handlePtr = stack.mallocLong(1); + checkVkResult(vkCreateCommandPool(VkUtil.device, createInfo, null, handlePtr)); + return handlePtr.get(0); + } + } + + private static long createDescriptorPool(int descriptorsPerSet) { + final int setsToAllocate = 8192; + try (var stack = MemoryStack.stackPush()) { + final var poolSizes = VkDescriptorPoolSize.calloc(1, stack); + poolSizes.type(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + poolSizes.descriptorCount(setsToAllocate * descriptorsPerSet); + + + var createInfo = VkDescriptorPoolCreateInfo.calloc(stack).sType$Default(); + createInfo.flags(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT); + createInfo.pPoolSizes(poolSizes); + createInfo.maxSets(setsToAllocate); + + var handlePtr = stack.mallocLong(1); + checkVkResult(vkCreateDescriptorPool(VkUtil.device, createInfo, null, handlePtr)); + return handlePtr.get(0); + } + } + + private static void allocPool() { + descriptorPools.add(createDescriptorPool(7)); + } + + static void init() { + allocPool(); + allocateMoreBuffers(true); + allocateMoreBuffers(false); + } + + static void terminate() { + vkDestroyCommandPool(VkUtil.device, persistentCommandsPool, null); + vkDestroyCommandPool(VkUtil.device, singleIssueCommandsPool, null); + for (int i = 0; i < descriptorPools.size(); i++) { + vkDestroyDescriptorPool(VkUtil.device, descriptorPools.getLong(i), null); + } + } + + private static void allocateMoreBuffers(boolean singleIssue) { + final var buffersToCreate = 32; + + var commandPool = singleIssue ? singleIssueCommandsPool : persistentCommandsPool; + var freeBuffers = singleIssue ? freeSingleIssueCommandBuffers : freePersistentCommandBuffers; + try (final var stack = MemoryStack.stackPush()) { + + final var allocInfo = VkCommandBufferAllocateInfo.calloc(stack); + allocInfo.sType(VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO); + allocInfo.commandPool(commandPool); + allocInfo.commandBufferCount(buffersToCreate); + allocInfo.level(VK_COMMAND_BUFFER_LEVEL_PRIMARY); + + final var pointerPtr = stack.mallocPointer(buffersToCreate); + checkVkResult(vkAllocateCommandBuffers(VkUtil.device, allocInfo, pointerPtr)); + for (int i = 0; i < buffersToCreate; i++) { + freeBuffers.add(new VkCommandBuffer(pointerPtr.get(i), VkUtil.device)); + } + } + } + + public static synchronized VkCommandBuffer allocCommandBuffer(boolean singleIssue) { + var freeBuffers = singleIssue ? freeSingleIssueCommandBuffers : freePersistentCommandBuffers; + if (freeBuffers.isEmpty()) { + allocateMoreBuffers(singleIssue); + } + return freeBuffers.pop(); + } + + public static synchronized void freeCommandBufferNow(VkCommandBuffer commandBuffer, boolean singleIssue) { + var freeBuffers = singleIssue ? freeSingleIssueCommandBuffers : freePersistentCommandBuffers; +// freeBuffers.add(commandBuffer); + var pool = singleIssue ? singleIssueCommandsPool : persistentCommandsPool; + vkFreeCommandBuffers(VkUtil.device, pool, commandBuffer); + } + + public static synchronized DescriptorSet allocDescriptorSet() { + try (final var stack = MemoryStack.stackPush()) { + final var setLayout = stack.mallocLong(1); + setLayout.put(0, VkPipelines.descriptorLayout); + + final var allocInfo = VkDescriptorSetAllocateInfo.callocStack(stack); + allocInfo.sType(VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO); + allocInfo.pSetLayouts(setLayout); + + final var longPtr = stack.mallocLong(1); + + boolean allocated = false; + long currentPool = VK_NULL_HANDLE; + for (int j = 0; j < 2; j++) { + for (int i = 0; i < descriptorPools.size(); i++) { + currentPool = descriptorPools.getLong(i); + allocInfo.descriptorPool(currentPool); + int code = vkAllocateDescriptorSets(VkUtil.device, allocInfo, longPtr); + if (code == VK_SUCCESS) { + allocated = true; + break; + } + } + if (allocated || descriptorSetsToFree.isEmpty()) { + break; + } + for (int i = 0; i < descriptorSetsToFree.size(); i++) { + // TODO: big calls, they can be passed more than one at a time + var set = descriptorSetsToFree.get(i); + longPtr.put(0, set.set); + vkFreeDescriptorSets(VkUtil.device, set.pool, longPtr); + } + } + if (!allocated) { + allocPool(); + currentPool = descriptorPools.getLong(descriptorPools.size() - 1); + allocInfo.descriptorPool(currentPool); + int code = vkAllocateDescriptorSets(VkUtil.device, allocInfo, longPtr); + if (code != VK_SUCCESS) { + throw new IllegalStateException("Unable to allocate descriptor in new pool"); + } + } + return new DescriptorSet(longPtr.get(0), currentPool); + } + } + + public static synchronized void freeDescriptorSet(DescriptorSet set) { + descriptorSetsToFree.add(set); + } + +} diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkUtil.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkUtil.java new file mode 100644 index 00000000..5220c42e --- /dev/null +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkUtil.java @@ -0,0 +1,462 @@ +package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import net.roguelogix.biggerreactors.Config; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.ocl.CLUtil; +import net.roguelogix.phosphophyllite.util.NonnullDefault; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.BufferUtils; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.Cleaner; +import java.nio.ByteBuffer; +import java.util.List; + +import static org.lwjgl.vulkan.VK13.*; + +@NonnullDefault +public class VkUtil { + + public static final long MAX_RAY_STEPS = Config.CONFIG.Reactor.IrradiationDistance * 2; + public static final long SIZEOF_RAY = 16 * MAX_RAY_STEPS; + + private static final Logger LOGGER = LogManager.getLogger("BiggerReactors/Reactor/Vulkan"); + public static final Cleaner VK_CLEANER = Cleaner.create(); + + public static final boolean available; + + public static final VkInstance instance; + public static final VkDevice device; + public static final ByteBuffer raySimSPV; + public static final ByteBuffer raySimVec2SPV; + public static final ByteBuffer reductionSPV; + public static final int queueFamilyIndex; + public static final List queues = new ReferenceArrayList<>(); + public static final IntArrayList availableQueueIndices = new IntArrayList(); + private static final ThreadLocal threadQueueIndex = ThreadLocal.withInitial(() -> -1); + + private static boolean roundRobinQueues = false; + private static int nextQueue = 0; + + static { + final int physicalDeviceIndex = 0; + final boolean enableValidationLayers = false; + + boolean initComplete = false; + @Nullable + VkInstance createdInstance = null; + VkDevice createdDevice = null; + ByteBuffer loadedRaysimSPV = null; + ByteBuffer loadedRaysimvec2SPV = null; + ByteBuffer loadedReductionSPV = null; + int familyIndex = -1; + + failedBreak: + try { + try { + LOGGER.info("Checking for LWJGL Vulkan classes"); + var instanceVersionSupported = VK.getInstanceVersionSupported(); + LOGGER.info("Classes found, attempting Vk init"); + if (instanceVersionSupported < VK_API_VERSION_1_3) { + LOGGER.info("Vulkan version too low"); + break failedBreak; + } + } catch (Throwable ignored) { // yes this will catch anything, thats the point + LOGGER.info("Failed to load LWJGL OpenCL Classes"); + break failedBreak; + } + + try (var stack = MemoryStack.stackPush()) { + var applicationInfo = VkApplicationInfo.calloc(stack); + applicationInfo.sType$Default(); + applicationInfo.apiVersion(VK_API_VERSION_1_3); + + var instanceCreateInfo = VkInstanceCreateInfo.calloc(stack); + instanceCreateInfo.sType$Default(); + instanceCreateInfo.pApplicationInfo(applicationInfo); + + if (enableValidationLayers) { + var namePtrs = stack.callocPointer(1); + stack.nASCII("VK_LAYER_KHRONOS_validation\0", true); + namePtrs.put(0, stack.getPointerAddress()); +// stack.nASCII("VK_LAYER_RENDERDOC_Capture\0", true); +// namePtrs.put(1, stack.getPointerAddress()); + instanceCreateInfo.ppEnabledLayerNames(namePtrs); + } + + var instancePtr = stack.callocPointer(1); + checkVkResult(vkCreateInstance(instanceCreateInfo, null, instancePtr)); + createdInstance = new VkInstance(instancePtr.get(0), instanceCreateInfo); + } + + VkPhysicalDevice physicalDevice; + try (var stack = MemoryStack.stackPush()) { + var intPtr = stack.callocInt(1); + vkEnumeratePhysicalDevices(createdInstance, intPtr, null); + if (intPtr.get(0) == 0) { + LOGGER.info("No physical devices available"); + break failedBreak; + } + var devicesPtr = stack.callocPointer(intPtr.get(0)); + vkEnumeratePhysicalDevices(createdInstance, intPtr, devicesPtr); + + + var deviceToUse = physicalDeviceIndex; + if (physicalDeviceIndex != 0 && intPtr.get(0) <= physicalDeviceIndex) { + LOGGER.warn("No physical device for index " + physicalDeviceIndex); + LOGGER.warn("Falling back to first device"); + deviceToUse = 0; + } + physicalDevice = new VkPhysicalDevice(devicesPtr.get(deviceToUse), createdInstance); + } + + try (var stack = MemoryStack.stackPush()) { + var intPtr = stack.callocInt(1); + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, intPtr, null); + var families = VkQueueFamilyProperties.calloc(intPtr.get(0), stack); + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, intPtr, families); + + var physicalDeviceProperties = VkPhysicalDeviceProperties.calloc(stack); + vkGetPhysicalDeviceProperties(physicalDevice, physicalDeviceProperties); + var vendorID = physicalDeviceProperties.vendorID(); + LOGGER.info("Device selected: " + physicalDeviceProperties.deviceNameString()); + if (physicalDeviceProperties.apiVersion() < VK_API_VERSION_1_3) { + LOGGER.info("Device API version too low"); + break failedBreak; + } + + VkQueueFamilyProperties familyToUse = null; + final int requiredFlags = VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; + // while more queues could be used in some cases, its easier to just use one + // even when using multiple queues, so long as its withing a single queue family queue transfers aren't needed + switch (vendorID) { + case 0x8086 -> { + // Intel, single queue and family that does everything + familyToUse = families.get(0); + familyIndex = 0; + } + case 0x1002 -> { + // AMD, at least two families, second one has 4 queues that can do compute + familyToUse = families.get(1); + familyIndex = 1; + if (familyToUse.queueCount() != 4 || (familyToUse.queueFlags() & requiredFlags) != requiredFlags) { + LOGGER.info("Unexpected AMD queue family properties"); + break failedBreak; + } + } + case 0x10DE -> { + // Nvidia, first family will have 16 queues + familyToUse = families.get(0); + familyIndex = 0; + if (familyToUse.queueCount() != 16 || (familyToUse.queueFlags() & requiredFlags) != requiredFlags) { + LOGGER.info("Unexpected Nvidia queue family properties"); + break failedBreak; + } + } + default -> { + // unknown vendor, just pick the first family that has compute + for (int i = 0; i < families.limit(); i++) { + final var family = families.get(i); + if ((family.queueFlags() & requiredFlags) == requiredFlags) { + familyToUse = family; + familyIndex = i; + break; + } + } + if (familyToUse == null) { + LOGGER.info("No compute queue family found"); + break failedBreak; + } + } + } + + LOGGER.info("Queue family " + familyIndex); + LOGGER.info("Queue count " + familyToUse.queueCount()); + + var queuePriorities = stack.callocFloat(familyToUse.queueCount()); + for (int i = 0; i < familyToUse.queueCount(); i++) { + queuePriorities.put(i, 1); + } + + var queueCreateInfos = VkDeviceQueueCreateInfo.calloc(1, stack); + queueCreateInfos.sType$Default(); + queueCreateInfos.queueFamilyIndex(familyIndex); + queueCreateInfos.pQueuePriorities(queuePriorities); + + // TODO: check for these features when selecting the device + { + var baseFeatures = VkPhysicalDeviceFeatures2.calloc(stack).sType$Default(); + var vk10Features = baseFeatures.features(); + var vk11Features = VkPhysicalDeviceVulkan11Features.calloc(stack).sType$Default(); + var vk12Features = VkPhysicalDeviceVulkan12Features.calloc(stack).sType$Default(); + var vk13Features = VkPhysicalDeviceVulkan13Features.calloc(stack).sType$Default(); + baseFeatures.pNext(vk11Features.address()); + vk11Features.pNext(vk12Features.address()); + vk12Features.pNext(vk13Features.address()); + vkGetPhysicalDeviceFeatures2(physicalDevice, baseFeatures); + + List missingFeatures = new ReferenceArrayList<>(); + if (!vk10Features.shaderInt16()) { + missingFeatures.add("shaderInt16"); + } + if (!vk11Features.storageBuffer16BitAccess()) { + missingFeatures.add("storageBuffer16BitAccess"); + } + if (!vk11Features.uniformAndStorageBuffer16BitAccess()) { + missingFeatures.add("uniformAndStorageBuffer16BitAccess"); + } + if (!vk12Features.timelineSemaphore()) { + missingFeatures.add("timelineSemaphore"); + } + if (!vk12Features.uniformAndStorageBuffer8BitAccess()) { + missingFeatures.add("uniformAndStorageBuffer8BitAccess"); + } + if (!vk12Features.shaderFloat16()) { + missingFeatures.add("shaderFloat16"); + } + if (!vk12Features.shaderInt8()) { + missingFeatures.add("shaderInt8"); + } + if (!vk13Features.synchronization2()) { + missingFeatures.add("synchronization2"); + } + if (!missingFeatures.isEmpty()) { + StringBuilder errorString = new StringBuilder("Device missing feature "); + for (String missingFeature : missingFeatures) { + errorString.append(missingFeature).append(", "); + } + LOGGER.info(errorString.toString()); + break failedBreak; + } + } + var baseFeatures = VkPhysicalDeviceFeatures2.calloc(stack).sType$Default(); + var vk10Features = baseFeatures.features(); + vk10Features.shaderInt16(true); + + var vk11Features = VkPhysicalDeviceVulkan11Features.calloc(stack).sType$Default(); + vk11Features.storageBuffer16BitAccess(true); + vk11Features.uniformAndStorageBuffer16BitAccess(true); + + var vk12Features = VkPhysicalDeviceVulkan12Features.calloc(stack).sType$Default(); + vk12Features.timelineSemaphore(true); + vk12Features.uniformAndStorageBuffer8BitAccess(true); + vk12Features.shaderFloat16(true); + vk12Features.shaderInt8(true); + + var vk13Features = VkPhysicalDeviceVulkan13Features.calloc(stack).sType$Default(); + vk13Features.synchronization2(true); + + var deviceCreateInfo = VkDeviceCreateInfo.calloc(stack).sType$Default(); + + deviceCreateInfo.pQueueCreateInfos(queueCreateInfos); + deviceCreateInfo.pNext(baseFeatures.address()); + baseFeatures.pNext(vk11Features.address()); + vk11Features.pNext(vk12Features.address()); + vk12Features.pNext(vk13Features.address()); + + var ptrReturn = stack.callocPointer(1); + checkVkResult(vkCreateDevice(physicalDevice, deviceCreateInfo, null, ptrReturn)); + createdDevice = new VkDevice(ptrReturn.get(0), physicalDevice, deviceCreateInfo); + + for (int i = 0; i < familyToUse.queueCount(); i++) { + vkGetDeviceQueue(createdDevice, familyIndex, i, ptrReturn); + queues.add(new VkQueue(ptrReturn.get(0), createdDevice)); + availableQueueIndices.add(i); + } + } + + loadedRaysimSPV = loadSPV("/biggerreactors/simulation/vk/spv/raysim.comp.spv"); + loadedRaysimvec2SPV = loadSPV("/biggerreactors/simulation/vk/spv/raysimvec2.comp.spv"); + loadedReductionSPV = loadSPV("/biggerreactors/simulation/vk/spv/reduction.comp.spv"); + + if (loadedRaysimSPV == null || loadedRaysimvec2SPV == null || loadedReductionSPV == null) { + break failedBreak; + } + + initComplete = true; + } catch (VulkanException e) { + e.printStackTrace(); + } + + + if (!initComplete) { + if (createdDevice != null) { + vkDeviceWaitIdle(createdDevice); + vkDestroyDevice(createdDevice, null); + createdDevice = null; + } + if (createdInstance != null) { + vkDestroyInstance(createdInstance, null); + createdInstance = null; + } + } + + //noinspection DataFlowIssue + instance = createdInstance; + //noinspection DataFlowIssue + device = createdDevice; + queueFamilyIndex = familyIndex; + //noinspection DataFlowIssue + raySimSPV = loadedRaysimSPV; + //noinspection DataFlowIssue + raySimVec2SPV = loadedRaysimvec2SPV; + //noinspection DataFlowIssue + reductionSPV = loadedReductionSPV; + + try { + if (initComplete) { + VkMemUtil.init(); + } + } catch (VulkanException e) { + initComplete = false; + e.printStackTrace(); + } + + available = initComplete; + +// if (enableValidationLayers) { +// System.out.println("RenderDocAttachWait"); +// try { +// System.in.read(); +// } catch (IOException e) { +// throw new RuntimeException(e); +// } +// } + } + + @Nullable + private static ByteBuffer loadSPV(String file) { + try (InputStream in = CLUtil.class.getResourceAsStream(file)) { + if (in == null) { + return null; + } + var bytes = in.readAllBytes(); + var byteBuf = BufferUtils.createByteBuffer(bytes.length); + byteBuf.put(0, bytes); + return byteBuf; + } catch (IOException e) { + return null; + } + } + + // @OnModLoad + public static void onModLoad() { + if (!available) { + return; + } + roundRobinQueues = true; + VkMemUtil.init(); + } + + // explicit init call + public static void init() { + if (!available) { + throw new IllegalStateException(); + } + roundRobinQueues = false; + VkMemUtil.init(); + VkPipelines.init(); + VkPools.init(); + } + + // TODO: on JVM shutdown this needs to be called + public static void terminate() { + if (!available) { + return; + } + // run GC passes so cleaners run + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + vkDeviceWaitIdle(device); + VkPools.terminate(); + VkPipelines.terminate(); + VkMemUtil.terminate(); + vkDestroyDevice(device, null); + vkDestroyInstance(instance, null); + } + + public static synchronized void acquireQueueForThread() { + if (!available) { + return; + } + var index = availableQueueIndices.removeInt(0); + threadQueueIndex.set(index); + } + + public static synchronized void releaseQueueForThread() { + if (!available) { + return; + } + availableQueueIndices.add((int) threadQueueIndex.get()); + threadQueueIndex.set(-1); + } + + public static class VulkanException extends RuntimeException { + public VulkanException(int returnCode) { + super("VK return code " + returnCode); + } + + public VulkanException(String message) { + super(message); + } + } + + @Contract + public static int checkVkResult(int returnCode) { + if (returnCode < 0) { + switch (returnCode) { + case VK_ERROR_OUT_OF_HOST_MEMORY -> throw new OutOfMemoryError("VK_ERROR_OUT_OF_HOST_MEMORY"); + case VK_ERROR_OUT_OF_DEVICE_MEMORY -> throw new VulkanException("VK_ERROR_OUT_OF_DEVICE_MEMORY"); + case VK_ERROR_INITIALIZATION_FAILED -> throw new VulkanException("VK_ERROR_INITIALIZATION_FAILED"); + case VK_ERROR_DEVICE_LOST -> throw new VulkanException("VK_ERROR_DEVICE_LOST"); + case VK_ERROR_MEMORY_MAP_FAILED -> throw new VulkanException("VK_ERROR_MEMORY_MAP_FAILED"); + case VK_ERROR_LAYER_NOT_PRESENT -> throw new VulkanException("VK_ERROR_LAYER_NOT_PRESENT"); + case VK_ERROR_EXTENSION_NOT_PRESENT -> throw new VulkanException("VK_ERROR_EXTENSION_NOT_PRESENT"); + case VK_ERROR_FEATURE_NOT_PRESENT -> throw new VulkanException("VK_ERROR_FEATURE_NOT_PRESENT"); + case VK_ERROR_INCOMPATIBLE_DRIVER -> throw new VulkanException("VK_ERROR_INCOMPATIBLE_DRIVER"); + case VK_ERROR_TOO_MANY_OBJECTS -> throw new VulkanException("VK_ERROR_TOO_MANY_OBJECTS"); + case VK_ERROR_FORMAT_NOT_SUPPORTED -> throw new VulkanException("VK_ERROR_FORMAT_NOT_SUPPORTED"); + case VK_ERROR_FRAGMENTED_POOL -> throw new VulkanException("VK_ERROR_FRAGMENTED_POOL"); + case -13 /* VK_ERROR_UNKNOWN */ -> throw new VulkanException("VK_ERROR_UNKNOWN"); + case VK_ERROR_OUT_OF_POOL_MEMORY -> throw new VulkanException("VK_ERROR_OUT_OF_POOL_MEMORY"); + case VK_ERROR_INVALID_EXTERNAL_HANDLE -> throw new VulkanException("VK_ERROR_INVALID_EXTERNAL_HANDLE"); + case -1000161000 /* VK_ERROR_FRAGMENTATION */ -> throw new VulkanException("VK_ERROR_FRAGMENTATION"); + case -1000257000 /* VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS */ -> throw new VulkanException("VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"); + default -> throw new VulkanException(returnCode); + } + + } + return returnCode; + } + + public static void queueSubmit(VkSubmitInfo2.Buffer submitInfos) { + final int queueIndex; + if (roundRobinQueues) { + queueIndex = nextQueue++; + nextQueue %= queues.size(); + } else { + queueIndex = threadQueueIndex.get(); + if (queueIndex == -1) { + throw new VulkanException("No queue aquired for thread"); + } + } + vkQueueSubmit2(queues.get(queueIndex), submitInfos, VK_NULL_HANDLE); + } +} diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java index 83a7e149..43f2ab29 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java @@ -43,6 +43,8 @@ public abstract class BaseReactorSimulation implements IReactorSimulation { protected final SimulationConfiguration configuration; + private boolean wasActiveLastTick = false; + protected BaseReactorSimulation(SimulationDescription simulationDescription, SimulationConfiguration configuration) { this.configuration = configuration; x = simulationDescription.x(); @@ -179,9 +181,9 @@ protected BaseReactorSimulation(SimulationDescription simulationDescription, Sim } @Override - public void tick(boolean active) { + public final void tick(boolean active) { double toBurn = 0; - if (active) { + if (wasActiveLastTick || (!isAsync() && active)) { toBurn = radiate(); } else { fuelTank.burn(0); @@ -203,10 +205,11 @@ public void tick(boolean active) { output.transferWith(stackHeat, stackToCoolantSystemRFKT); stackHeat.transferWith(ambientHeat, casingToAmbientRFKT); - if(active){ + if(active && isAsync()){ startNextRadiate(); - fuelTank.burn(toBurn); + wasActiveLastTick = true; } + fuelTank.burn(toBurn); } protected abstract double radiate(); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java index 5d855f7d..da483555 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java @@ -61,6 +61,12 @@ public FullPassReactorSimulation(SimulationDescription simulationDescription, Si initialIntensties = new double[controlRods.length]; fullPassIrradiationRequest = new IrradiationRequest(0, controlRods.length, this.moderatorCaches.toArray(new ModeratorCache[0]), y); + + FuelAbsorptionCoefficient = configuration.fuelAbsorptionCoefficient(); + FuelModerationFactor = configuration.fuelModerationFactor(); + fuelHardnessMultiplier = 1 / configuration.fuelHardnessDivisor(); + rayMultiplier = 1.0 / (double) (SimUtil.rays.size() * y); + } protected static class IrradiationRequest { @@ -97,10 +103,10 @@ protected static class IrradiationResult { } protected double fuelAbsorptionTemperatureCoefficient; - protected double FuelAbsorptionCoefficient; - protected double FuelModerationFactor; - protected double fuelHardnessMultiplier; - protected double rayMultiplier; + protected final double FuelAbsorptionCoefficient; + protected final double FuelModerationFactor; + protected final double fuelHardnessMultiplier; + protected final double rayMultiplier; protected double initialHardness; protected IrradiationRequest fullPassIrradiationRequest; @@ -151,11 +157,7 @@ protected void setupIrradiationTick() { final double FuelUsageMultiplier = configuration.fuelUsageMultiplier(); final double FuelPerRadiationUnit = configuration.fuelPerRadiationUnit(); - FuelAbsorptionCoefficient = configuration.fuelAbsorptionCoefficient(); - FuelModerationFactor = configuration.fuelModerationFactor(); - fuelHardnessMultiplier = 1 / configuration.fuelHardnessDivisor(); - rayMultiplier = 1.0 / (double) (SimUtil.rays.size() * y); - + double rawFuelUsage = 0; double fuelRFAdded = 0; @@ -348,6 +350,10 @@ public static class MultiThreaded extends FullPassReactorSimulation { private Event doneEvent; private final Runnable mainRunnable = () -> runIrradiationRequest(fullPassIrradiationRequest); + public MultiThreaded(SimulationDescription simulationDescription, SimulationConfiguration configuration) { + this(simulationDescription, configuration, false); + } + public MultiThreaded(SimulationDescription simulationDescription, SimulationConfiguration configuration, boolean singleThread) { super(simulationDescription, configuration); diff --git a/src/main/resources/opencl/reactorsim.cl b/src/main/resources/biggerreactors/simulation/opencl/reactorsim.cl similarity index 89% rename from src/main/resources/opencl/reactorsim.cl rename to src/main/resources/biggerreactors/simulation/opencl/reactorsim.cl index c70d8649..953b5f98 100644 --- a/src/main/resources/opencl/reactorsim.cl +++ b/src/main/resources/biggerreactors/simulation/opencl/reactorsim.cl @@ -141,18 +141,13 @@ kernel void raySim( local short2 controlRodPos; { - event_t rodPosCopy = async_work_group_copy(&controlRodPos, controlRodPositions + globalPos.x, 1, 0); - event_t reactorInfoCopy = async_work_group_copy((local char*) &reactorInfo, (global char*) (reactorInfoGlobal), sizeof(ReactorInfo), 0); + event_t firstCopy = async_work_group_copy(&controlRodPos, controlRodPositions + globalPos.x, 1, 0); + async_work_group_copy((local char*) &reactorInfo, (global char*) (reactorInfoGlobal), sizeof(ReactorInfo), firstCopy); - event_t events[ROD_AREA_WIDTH + 2]; - events[0] = async_work_group_copy((local char*) moderatorsLocal, (global char*) (moderatorsGlobal), sizeof(Moderator) * moderatorCount, 0); - events[1] = async_work_group_copy((local char*) &rodRayInfo, (global char*) (rodRayInfosGlobal + globalPos.x), sizeof(RodRayInfo), 0); + event_t secondCopy = async_work_group_copy((local char*) moderatorsLocal, (global char*) (moderatorsGlobal), sizeof(Moderator) * moderatorCount, 0); + async_work_group_copy((local char*) &rodRayInfo, (global char*) (rodRayInfosGlobal + globalPos.x), sizeof(RodRayInfo), secondCopy); - wait_group_events(1, &rodPosCopy); - wait_group_events(1, &reactorInfoCopy); - -// wait_group_events(1, &events[0]); -// wait_group_events(1, &events[1]); + wait_group_events(1, &firstCopy); int usedEvents = 2; for (int i = 0; i < ROD_AREA_WIDTH; ++i) { @@ -171,13 +166,11 @@ kernel void raySim( writeOffset += i * ROD_AREA_WIDTH; if (size != 0) { - events[usedEvents++] = async_work_group_copy(localInsertions + writeOffset, controlRodInsertions + readOffset, size, 0); -// wait_group_events(1, &events[usedEvents - 1]); + async_work_group_copy(localInsertions + writeOffset, controlRodInsertions + readOffset, size, secondCopy); } } - - wait_group_events(usedEvents, events); + wait_group_events(1, &secondCopy); } const int3 reactorPos = (int3)(controlRodPos.x, globalPos.y, controlRodPos.y); diff --git a/src/main/resources/biggerreactors/simulation/vk/glsl/raysim.comp b/src/main/resources/biggerreactors/simulation/vk/glsl/raysim.comp new file mode 100644 index 00000000..f9f984a9 --- /dev/null +++ b/src/main/resources/biggerreactors/simulation/vk/glsl/raysim.comp @@ -0,0 +1,242 @@ +#version 460 core +#extension GL_EXT_shader_8bit_storage : require +#extension GL_EXT_shader_16bit_storage : require +#extension GL_EXT_shader_explicit_arithmetic_types : require +//#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +#define MAXIMUM_MODERATOR_COUNT 256 // 8 bit uint +#define MAXIMUM_RAY_STEPS 8 +#define BARRIER memoryBarrierShared(); barrier() + +layout(local_size_x = 1, local_size_y_id = 0, local_size_z_id = 1) in; + +layout(constant_id = 2) const uint RayTTL = 4; +layout(constant_id = 3) const uint RodAreaSize = 9; +layout(constant_id = 4) const uint RaysPerBatch = 64; +// specialization doesnt work for this, at least, the validation layers seem to think it doesnt, so, thats nice + +struct Moderator { + float absorption; + float heatEfficiency; + float moderation; + float padding; +}; + +struct RayStep { + float stepLength; + int x, y, z; +}; + +struct Ray { + RayStep steps[MAXIMUM_RAY_STEPS]; +}; + +struct RayBurnInfo { + float fuelRFAdded; + float fuelRadAdded; + float caseRFAdded; + float padding; +}; + +#if __LINE__ > 0 +#define MERGE_(a, b) a##b +#define LABEL_(a) MERGE_(unique_name_, a) +#define UNIQUE_NAME LABEL_(__LINE__) +#else +#define UNIQUE_NAME NAME +#endif + +layout(push_constant, std430) uniform UNIQUE_NAME { + int xSize, zSize; + + float RFPerRadiationUnit; + float FuelAbsorptionCoefficient; + float FuelModerationFactor; + float FuelHardnessMultiplier; +} ReactorConstantInfo; + +layout(binding = 0, std140) uniform UNIQUE_NAME { + float FuelAbsorptionTemperatureCoefficient; + float InitialHardness; + float padding; + float padding1; + + Moderator moderators[MAXIMUM_MODERATOR_COUNT]; +} ReactorInfo; + +layout(binding = 1, std430) readonly buffer UNIQUE_NAME { + vec2 controlRodInfo[]; +}; + +layout(binding = 2, std430) readonly buffer UNIQUE_NAME { + u16vec2 controlRodPositions[]; +}; + +layout(binding = 3, std430) readonly buffer UNIQUE_NAME { + uint8_t moderatorIndices[]; +}; + +layout(binding = 4, std430) readonly buffer UNIQUE_NAME { + Ray rays[]; +}; + +layout(binding = 5, std430) writeonly buffer UNIQUE_NAME { + RayBurnInfo results[]; +}; + +shared float localInsertions[9][9]; +shared Moderator moderators[MAXIMUM_MODERATOR_COUNT]; +shared Ray currentRay[gl_WorkGroupSize.z]; +//shared RayBurnInfo immediateReduction[gl_WorkGroupSize.z][gl_WorkGroupSize.y]; + +bool isProvokingInvokation = false; +bool isProvokingForZ = false; + +void copyLocalResources(const u16vec2 controlRodPos); +RayBurnInfo raySim(const ivec3 reactorPos, const u16vec2 controlRodPosition, const float initialIntensity); + +void main() { + // same index across the workgroup + const u16vec2 controlRodPos = controlRodPositions[gl_GlobalInvocationID.x]; + isProvokingInvokation = gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0 && gl_LocalInvocationID.z == 0; + isProvokingForZ = gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0; + if (isProvokingInvokation) { + copyLocalResources(controlRodPos); + } + BARRIER; + + RayBurnInfo accumBurnInfo; + accumBurnInfo.fuelRFAdded = 0; + accumBurnInfo.fuelRadAdded = 0; + accumBurnInfo.caseRFAdded = 0; + + const uint batchBaseRay = RaysPerBatch * gl_LocalInvocationID.z; + const uint rodLinearIndex = controlRodPos.x * ReactorConstantInfo.xSize + controlRodPos.y; + const float initialIntensity = controlRodInfo[rodLinearIndex].y; + const ivec3 reactorPos = ivec3(controlRodPos.x, gl_GlobalInvocationID.y, controlRodPos.y); + + for (uint i = 0; i < RaysPerBatch; i++) { + const uint currentRayIndex = batchBaseRay + i; + if (isProvokingForZ) { + currentRay[gl_LocalInvocationID.z] = rays[currentRayIndex]; + } + BARRIER; + + RayBurnInfo rayBurnInfo = raySim(reactorPos, controlRodPos, initialIntensity); + + accumBurnInfo.fuelRFAdded += rayBurnInfo.fuelRFAdded; + accumBurnInfo.fuelRadAdded += rayBurnInfo.fuelRadAdded; + accumBurnInfo.caseRFAdded += rayBurnInfo.caseRFAdded; + } + + const uvec3 globalPos = gl_GlobalInvocationID; + const uvec3 globalSize = gl_WorkGroupSize * gl_NumWorkGroups; +// immediateReduction[gl_LocalInvocationID.z][gl_LocalInvocationID.y] = accumBurnInfo; +// BARRIER; +// if(gl_LocalInvocationID.z == 0){ +// RayBurnInfo finalWriteOut; +// finalWriteOut.fuelRFAdded = 0; +// finalWriteOut.fuelRadAdded = 0; +// finalWriteOut.caseRFAdded = 0; +// for (uint i = 0; i < gl_WorkGroupSize.z; i++) { +// RayBurnInfo rayBurnInfo = immediateReduction[i][gl_LocalInvocationID.y]; +// finalWriteOut.fuelRFAdded += rayBurnInfo.fuelRFAdded; +// finalWriteOut.fuelRadAdded += rayBurnInfo.fuelRadAdded; +// finalWriteOut.caseRFAdded += rayBurnInfo.caseRFAdded; +// } +// const uint fuelRodLinearIndex = (globalPos.x) * globalSize.y + globalPos.y; +// results[fuelRodLinearIndex].fuelRFAdded = finalWriteOut.fuelRFAdded; +// results[fuelRodLinearIndex].fuelRadAdded = finalWriteOut.fuelRadAdded; +// results[fuelRodLinearIndex].caseRFAdded = finalWriteOut.caseRFAdded; +// } + const uint fuelRodLinearIndex = ((globalPos.x) * globalSize.z + globalPos.z) * globalSize.y + globalPos.y; + // results[fuelRodLinearIndex] = accumBurnInfo; + results[fuelRodLinearIndex].fuelRFAdded = accumBurnInfo.fuelRFAdded; + results[fuelRodLinearIndex].fuelRadAdded = accumBurnInfo.fuelRadAdded; + results[fuelRodLinearIndex].caseRFAdded = accumBurnInfo.caseRFAdded; +} + +void copyLocalResources(const u16vec2 controlRodPos){ + for (uint i = 0; i < MAXIMUM_MODERATOR_COUNT; i++){ + moderators[i].absorption = ReactorInfo.moderators[i].absorption; + moderators[i].heatEfficiency = ReactorInfo.moderators[i].heatEfficiency; + moderators[i].moderation = ReactorInfo.moderators[i].moderation; + } + for (uint i = 0; i < RodAreaSize; i++) { + const uint readX = (controlRodPos.x - RayTTL) + i; + const uint xReadOffset = readX * ReactorConstantInfo.xSize; + for (uint j = 0; j < RodAreaSize; j++) { + const uint readZ = (controlRodPos.y - RayTTL) + j; + if (readX > ReactorConstantInfo.xSize || readZ > ReactorConstantInfo.zSize) { + localInsertions[i][j] = 0; + continue; + } + const uint xzReadOffset = xReadOffset + readZ; + localInsertions[i][j] = controlRodInfo[xzReadOffset].x; + } + } +} + +RayBurnInfo raySim(const ivec3 reactorPos, const u16vec2 controlRodPosition, const float initialIntensity) { + RayBurnInfo burnInfo; + burnInfo.caseRFAdded = 0; + burnInfo.fuelRFAdded = 0; + burnInfo.fuelRadAdded = 0; + float hardness = ReactorInfo.InitialHardness; + float intensity = initialIntensity; + + for (int i = 0; i < MAXIMUM_RAY_STEPS; i++) { + RayStep currentRayStep = currentRay[gl_LocalInvocationID.z].steps[i]; + if (currentRayStep.stepLength == 0.0) { + // if ((currentRayStep.x | currentRayStep.y | currentRayStep.z) == 0) { + break; + } + const int currentX = reactorPos.x + currentRayStep.x; + const int currentZ = reactorPos.z + currentRayStep.z; + if (currentX < 0 || currentX >= ReactorConstantInfo.xSize || currentZ < 0 || currentZ >= ReactorConstantInfo.zSize) { + // all work items in this workgroup will hit this at the same time + break; + } + const float stepLength = currentRayStep.stepLength; + const int currentY = reactorPos.y + currentRayStep.y; + const bool inRangeY = currentY >= 0 && currentY < (gl_WorkGroupSize.y * gl_NumWorkGroups.y); + const float NoOpMultiplier = float(inRangeY); + const int moderatorIndexIndex = ((((currentX * ReactorConstantInfo.zSize) + currentZ)) * int(gl_WorkGroupSize.y * gl_NumWorkGroups.y)) + (currentY * int(inRangeY)); + const uint moderatorIndex = moderatorIndices[moderatorIndexIndex]; + if(moderatorIndex != 0) { + // not a fuel rod + const Moderator moderator = moderators[moderatorIndex]; + const float radAbsorbed = (intensity * moderator.absorption * (1.0f - hardness) * stepLength); + intensity = max(0.0f, intensity - radAbsorbed); + // if i could get rid of this div, that would be great + hardness /= (((moderator.moderation) * stepLength) + 1.0f); + // hardness = 0; + burnInfo.caseRFAdded += moderator.heatEfficiency * radAbsorbed * NoOpMultiplier; + } else { + // not not fuel rod + + const uint rodX = currentRayStep.x + RayTTL; + const uint rodZ = currentRayStep.z + RayTTL; + const float controlRodInsertion = localInsertions[rodX][rodZ]; + + const float baseAbsorption = ReactorInfo.FuelAbsorptionTemperatureCoefficient * (1.0f - (hardness * ReactorConstantInfo.FuelHardnessMultiplier)); + + const float scaledAbsorption = baseAbsorption * ReactorConstantInfo.FuelAbsorptionCoefficient * stepLength; + + const float controlRodBonus = (1.0f - scaledAbsorption) * controlRodInsertion * 0.5f; + const float controlRodPenalty = scaledAbsorption * controlRodInsertion * 0.5f; + + const float radiationAbsorbed = (scaledAbsorption + controlRodBonus) * intensity; + const float fertilityAbsorbed = (scaledAbsorption - controlRodPenalty) * intensity; + + const float fuelModerationFactor = ReactorConstantInfo.FuelModerationFactor + (ReactorConstantInfo.FuelModerationFactor * controlRodInsertion + controlRodInsertion); + + intensity = max(0.0f, intensity - (radiationAbsorbed)); + hardness /= ((fuelModerationFactor - 1.0f) * stepLength) + 1.0f; + + burnInfo.fuelRFAdded += radiationAbsorbed * NoOpMultiplier; + burnInfo.fuelRadAdded += fertilityAbsorbed * NoOpMultiplier; + } + } + return burnInfo; +} \ No newline at end of file diff --git a/src/main/resources/biggerreactors/simulation/vk/glsl/raysimvec2.comp b/src/main/resources/biggerreactors/simulation/vk/glsl/raysimvec2.comp new file mode 100644 index 00000000..bbfacf9e --- /dev/null +++ b/src/main/resources/biggerreactors/simulation/vk/glsl/raysimvec2.comp @@ -0,0 +1,234 @@ +#version 460 core +#extension GL_EXT_shader_8bit_storage : require +#extension GL_EXT_shader_16bit_storage : require +#extension GL_EXT_shader_explicit_arithmetic_types : require +//#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +#define MAXIMUM_MODERATOR_COUNT 256// 8 bit uint +#define MAXIMUM_RAY_STEPS 8 +#define BARRIER memoryBarrierShared(); barrier() + +layout(local_size_x = 1, local_size_y_id = 0, local_size_z_id = 1) in; + +layout(constant_id = 2) const uint RayTTL = 4; +layout(constant_id = 3) const uint RodAreaSize = 9; +layout(constant_id = 4) const uint RaysPerBatch = 64; +// specialization doesnt work for this, at least, the validation layers seem to think it doesnt, so, thats nice + +struct Moderator { + float absorption; + float heatEfficiency; + float moderation; + float padding; +}; + +struct RayStep { + float stepLength; + int x, y, z; +}; + +struct Ray { + RayStep steps[MAXIMUM_RAY_STEPS]; +}; + +struct RayBurnInfo { + float fuelRFAdded; + float fuelRadAdded; + float caseRFAdded; + float padding; +}; + +#if __LINE__ > 0 +#define MERGE_(a, b) a##b +#define LABEL_(a) MERGE_(unique_name_, a) +#define UNIQUE_NAME LABEL_(__LINE__) +#else +#define UNIQUE_NAME NAME +#endif + +layout(push_constant, std430) uniform UNIQUE_NAME { + int xSize, zSize; + + float RFPerRadiationUnit; + float FuelAbsorptionCoefficient; + float FuelModerationFactor; + float FuelHardnessMultiplier; +} ReactorConstantInfo; + +layout(binding = 0, std140) uniform UNIQUE_NAME { + float FuelAbsorptionTemperatureCoefficient; + float InitialHardness; + float padding; + float padding1; + + Moderator moderators[MAXIMUM_MODERATOR_COUNT]; +} ReactorInfo; + +layout(binding = 1, std430) readonly buffer UNIQUE_NAME { + vec2 controlRodInfo[]; +}; + +layout(binding = 2, std430) readonly buffer UNIQUE_NAME { + u16vec2 controlRodPositions[]; +}; + +layout(binding = 3, std430) readonly buffer UNIQUE_NAME { + uint8_t moderatorIndices[]; +}; + +layout(binding = 4, std430) readonly buffer UNIQUE_NAME { + Ray rays[]; +}; + +layout(binding = 5, std430) writeonly buffer UNIQUE_NAME { + RayBurnInfo results[]; +}; + +shared float localInsertions[9][9]; +shared Moderator moderators[MAXIMUM_MODERATOR_COUNT]; +shared Ray currentRay; +shared RayStep currentRayStep; + +bool isProvokingInvokation = false; + +void copyLocalResources(const u16vec2 controlRodPos); +RayBurnInfo raySim(const ivec3 reactorPos, const u16vec2 controlRodPosition, const float initialIntensity); + +void main() { + // same index across the workgroup + const u16vec2 controlRodPos = controlRodPositions[gl_GlobalInvocationID.x]; + isProvokingInvokation = gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0 && gl_LocalInvocationID.z == 0; + if (isProvokingInvokation) { + copyLocalResources(controlRodPos); + } + BARRIER; + + RayBurnInfo accumBurnInfo; + accumBurnInfo.fuelRFAdded = 0; + accumBurnInfo.fuelRadAdded = 0; + accumBurnInfo.caseRFAdded = 0; + + const uint batchBaseRay = RaysPerBatch * gl_GlobalInvocationID.z; + const uint rodLinearIndex = controlRodPos.x * ReactorConstantInfo.xSize + controlRodPos.y; + const float initialIntensity = controlRodInfo[rodLinearIndex].y; + const ivec3 reactorPos = ivec3(controlRodPos.x, gl_GlobalInvocationID.y * 2, controlRodPos.y); + + for (uint i = 0; i < RaysPerBatch; i++) { + const uint currentRayIndex = batchBaseRay + i; + if (isProvokingInvokation) { + currentRay = rays[currentRayIndex]; + } + BARRIER; + + RayBurnInfo rayBurnInfo = raySim(reactorPos, controlRodPos, initialIntensity); + + accumBurnInfo.fuelRFAdded += rayBurnInfo.fuelRFAdded; + accumBurnInfo.fuelRadAdded += rayBurnInfo.fuelRadAdded; + accumBurnInfo.caseRFAdded += rayBurnInfo.caseRFAdded; + } + + const uvec3 globalPos = gl_GlobalInvocationID; + const uvec3 globalSize = gl_WorkGroupSize * gl_NumWorkGroups; + const uint fuelRodLinearIndex = ((globalPos.x) * globalSize.z + globalPos.z) * globalSize.y + globalPos.y; + // results[fuelRodLinearIndex] = accumBurnInfo; + results[fuelRodLinearIndex].fuelRFAdded = accumBurnInfo.fuelRFAdded; + results[fuelRodLinearIndex].fuelRadAdded = accumBurnInfo.fuelRadAdded; + results[fuelRodLinearIndex].caseRFAdded = accumBurnInfo.caseRFAdded; +} + +void copyLocalResources(const u16vec2 controlRodPos){ + for (uint i = 0; i < MAXIMUM_MODERATOR_COUNT; i++){ + moderators[i].absorption = ReactorInfo.moderators[i].absorption; + moderators[i].heatEfficiency = ReactorInfo.moderators[i].heatEfficiency; + moderators[i].moderation = ReactorInfo.moderators[i].moderation; + } + for (uint i = 0; i < RodAreaSize; i++) { + const uint readX = (controlRodPos.x - RayTTL) + i; + const uint xReadOffset = readX * ReactorConstantInfo.xSize; + for (uint j = 0; j < RodAreaSize; j++) { + const uint readZ = (controlRodPos.y - RayTTL) + j; + if (readX > ReactorConstantInfo.xSize || readZ > ReactorConstantInfo.zSize) { + localInsertions[i][j] = 0; + continue; + } + const uint xzReadOffset = xReadOffset + readZ; + localInsertions[i][j] = controlRodInfo[xzReadOffset].x; + } + } +} + +RayBurnInfo raySim(const ivec3 reactorPos, const u16vec2 controlRodPosition, const float initialIntensity) { + vec2 caseRFAdded = vec2(0); + vec2 fuelRFAdded = vec2(0); + vec2 fuelRadAdded = vec2(0); + vec2 hardness = vec2(ReactorInfo.InitialHardness); + vec2 intensity = vec2(initialIntensity); + + for (int i = 0; i < MAXIMUM_RAY_STEPS; i++) { + if (isProvokingInvokation){ + currentRayStep = currentRay.steps[i]; + } + BARRIER; + if (currentRayStep.stepLength == 0.0) { + break; + } + const int currentX = reactorPos.x + currentRayStep.x; + const int currentZ = reactorPos.z + currentRayStep.z; + if (currentX < 0 || currentX >= ReactorConstantInfo.xSize || currentZ < 0 || currentZ >= ReactorConstantInfo.zSize) { + // all work items in this workgroup will hit this at the same time + break; + } + const float stepLength = currentRayStep.stepLength; + const int currentYScalar = reactorPos.y + currentRayStep.y; + const ivec2 currentY = ivec2(currentYScalar, currentYScalar + 1); + const ivec2 inRangeY = ivec2(greaterThanEqual(currentY, ivec2(0))) & ivec2(lessThan(currentY, ivec2((gl_WorkGroupSize.y * 2) * gl_NumWorkGroups.y))); + const vec2 NoOpMultiplier = vec2(inRangeY); + const int baseModeratorIndexIndex = ((((currentX * ReactorConstantInfo.zSize) + currentZ)) * int((gl_WorkGroupSize.y * 2) * gl_NumWorkGroups.y)); + const ivec2 moderatorIndexIndicies = ivec2(baseModeratorIndexIndex) + (currentY * inRangeY); + const uvec2 moderatorIndices = uvec2(moderatorIndices[moderatorIndexIndicies.x], moderatorIndices[moderatorIndexIndicies.y]); + if(moderatorIndices.x != 0) { + // not a fuel rod + const Moderator moderator0 = moderators[moderatorIndices.x]; + const Moderator moderator1 = moderators[moderatorIndices.y]; + const vec2 absorption = vec2(moderator0.absorption, moderator1.absorption); + const vec2 heatEfficiency = vec2(moderator0.heatEfficiency, moderator1.heatEfficiency); + const vec2 moderation = vec2(moderator0.moderation, moderator1.moderation); + + const vec2 radAbsorbed = (intensity * absorption * (1.0f - hardness) * stepLength); + intensity = max(vec2(0.0f), intensity - radAbsorbed); + // if i could get rid of this div, that would be great + hardness /= (((moderation) * stepLength) + 1.0f); + caseRFAdded = fma(heatEfficiency * radAbsorbed, NoOpMultiplier, caseRFAdded); + } else { + // not not fuel rod + + const uint rodX = currentRayStep.x + RayTTL; + const uint rodZ = currentRayStep.z + RayTTL; + const float controlRodInsertion = localInsertions[rodX][rodZ]; + + const vec2 baseAbsorption = ReactorInfo.FuelAbsorptionTemperatureCoefficient * (1.0f - (hardness * ReactorConstantInfo.FuelHardnessMultiplier)); + + const vec2 scaledAbsorption = baseAbsorption * ReactorConstantInfo.FuelAbsorptionCoefficient * stepLength; + + const float halfRodInsertion = controlRodInsertion * 0.5f; + const vec2 controlRodBonus = (1.0f - scaledAbsorption) * halfRodInsertion; + const vec2 controlRodPenalty = scaledAbsorption * halfRodInsertion; + + const vec2 radiationAbsorbed = (scaledAbsorption + controlRodBonus) * intensity; + const vec2 fertilityAbsorbed = (scaledAbsorption - controlRodPenalty) * intensity; + + const float fuelModerationFactor = ReactorConstantInfo.FuelModerationFactor + fma(ReactorConstantInfo.FuelModerationFactor, controlRodInsertion, controlRodInsertion); + + intensity = max(vec2(0.0f), intensity - (radiationAbsorbed)); + hardness /= vec2(((fuelModerationFactor - 1.0f) * stepLength) + 1.0f); + + fuelRFAdded = fma(radiationAbsorbed, NoOpMultiplier, fuelRFAdded); + fuelRadAdded = fma(fertilityAbsorbed, NoOpMultiplier, fuelRadAdded); + } + } + RayBurnInfo burnInfo; + burnInfo.fuelRFAdded = fuelRFAdded.x + fuelRFAdded.y; + burnInfo.fuelRadAdded = fuelRadAdded.x + fuelRadAdded.y; + burnInfo.caseRFAdded = caseRFAdded.x + caseRFAdded.y; + return burnInfo; +} \ No newline at end of file diff --git a/src/main/resources/biggerreactors/simulation/vk/glsl/reduction.comp b/src/main/resources/biggerreactors/simulation/vk/glsl/reduction.comp new file mode 100644 index 00000000..ac3767c3 --- /dev/null +++ b/src/main/resources/biggerreactors/simulation/vk/glsl/reduction.comp @@ -0,0 +1,40 @@ +#version 460 core + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +struct RayBurnInfo { + float fuelRFAdded; + float fuelRadAdded; + float caseRFAdded; + float padding; +}; + +layout(push_constant, std430) uniform PushConstants { + int reductionCount; +}; + +layout(binding = 5, std430) readonly buffer InSSBO { + RayBurnInfo inputs[]; +}; + +layout(binding = 6, std430) writeonly buffer OutSSBO { + RayBurnInfo outputs[]; +}; + +void main() { + const uint globalID = gl_GlobalInvocationID.x; + const uint globalSize = gl_NumWorkGroups.x; + + RayBurnInfo outputInfo; + outputInfo.caseRFAdded = 0; + outputInfo.fuelRFAdded = 0; + outputInfo.fuelRadAdded = 0; + uint currentIndex = globalID; + for (uint i = 0; i < reductionCount; i++, currentIndex += globalSize) { + const RayBurnInfo inputInfo = inputs[currentIndex]; + outputInfo.caseRFAdded += inputInfo.caseRFAdded; + outputInfo.fuelRFAdded += inputInfo.fuelRFAdded; + outputInfo.fuelRadAdded += inputInfo.fuelRadAdded; + } + outputs[globalID] = outputInfo; +} diff --git a/src/main/resources/biggerreactors/simulation/vk/spv/raysim.comp.spv b/src/main/resources/biggerreactors/simulation/vk/spv/raysim.comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..1b08dccab0187b66d8bc27c710d736dc6959fbff GIT binary patch literal 18596 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 I`|o4_3k+us(EtDd literal 0 HcmV?d00001 diff --git a/src/main/resources/biggerreactors/simulation/vk/spv/raysimvec2.comp.spv b/src/main/resources/biggerreactors/simulation/vk/spv/raysimvec2.comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..f4fea5070affa1c9c36872e8e80474701ca92eca GIT binary patch literal 19808 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

&h5nC1kNAJ0 z%Xy7>&wB~{FT^-)=6t2#%%T0?h@9&?h6`goM2;olx@*gQ#umK4U6PO3RKztewQ*HPCh<6tPl2gP4e+K;tjy^QS$__oZ>#Tt_>0A(-w7YRPa&P<3-OK!&|d< zd-i!Q7jF%zx%Q850;DfX4mQfba|g+{)X%z#NU;b z3Y+uqjec-pi_gY~6kOy!6y4mh_sl&BT|ROj29Dg?BKKslw#fYku$=4T@8k|goKN1q ze7}=(Zr{J&2$qY!I^d2#mtT#K&-f$3a{72LngaIl9;xjp*f@FT@!eQ1ax4TpPrL^>&k5-A;d3I`c~YN~ z(B)&ElflNxJCE<&a*^ZBVCRYZwey^cE+0Opft@Gyc?-IH%=1>Taq`Y{3ZtBBWWT3_ z?_-@qFQeP@Ma6n70_!6mK0V-jh>1BW=-q`}P{j43%j+At7K6>FEzZ#ru+Oh6inuDe ze)87a#V8kZzYUz$dj`5bF>fDOANdKq<=f*@FjM5eQ@jhHkGajGEpqpRU7x6}22N`m zK-Wh;dS3>P-d7eq)Zz5i7P$w(uGyu9&k(wtzSg2mF8qhV?upQsgY7fc^6g-K#vXV>!;m!kSUDb2fQD+*L;6?C)oFg*wfzM&ViGU z?{&@v%XvTUz89b^6)wJ>a>-l)&MCIh?$@YkLLQb7;(! z;P)avr=Lk;-dFIk*WZtBoP6x3tH80JVozTUC!hP1-}$aVm$wdUzKl^W>iGazF6y}s zY(25o_WVIO`Kaf5uyOLy=ZC=QHSl3{{p6kZT1L6>{|MOibDuiLO<=hj5&dsql#4n) z3N}ade>1qb|Bu1R>l^cY9Bi(r{T8r(^3Jo0Q7-1W4eUG-e>*shzXM$#dE;+ol#BQ~ z!4dEJ--YfRD~t272CR>K#M}+`9uwE>J?Q$$JI889x$yr4IGy8@=++VY;6AWE@)7eX za5~5R>WI8^+{-8z``|&a`@p~Nn8S1QX*l`td1xIz55vhv%xA!!=g>b}=-zA0`3O3# z=l2?8_1DMs(*8NH^Xg}v4=~C_Uyp**`~2t8U9VV+FM#!tkNf;%VCUQe@jkDQxy_?3 zYW*VE`OIZ4Ujoay@51NHVE29O~0H^o$Z=(BMRovH~L`Tin+F1SdF}Hr&BiFaU?upR94Nh}Eg?@LE`#b27 z+gSbeF}Hr&(`Uw%LVp;W&k#rF^4|VkY!9HvXOQoq%lS+(pEf!3Jy^s)#OS{4#OM3i z>?huHJ$FBVlMkOC7C!NAsn0WT@^RjN1U61S;(iQ%8Y$s#E$aG({U>1iP3Qh8oP7BF ztnf+aeilwX=6()roP5On9PHe&4(j@a{TE=L&*|L1gp&`S=L?^7?q9*l$K1aL8z&!e dzX3b9?~wMbuAk@3@7{k~*k9wEi2d98{{yFR(b@n2 literal 0 HcmV?d00001 diff --git a/src/main/resources/biggerreactors/simulation/vk/spv/reduction.comp.spv b/src/main/resources/biggerreactors/simulation/vk/spv/reduction.comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..e8f53e1f64a8f969aa3a66b5311c323253e1e4c6 GIT binary patch literal 3292 zcmZ{ldvgbD)9awsZY_2b+^H%@RIm7I`FD<2-4Sd+T)$Ao_qG477Ipw$Vswu07; zPH!;ijIu}lsMC*=s1wG+sF%eLBjP42adFb?=V3LVp@`}X4NWzv9((=tUbnw_U8ZN4 zZLi-63Oae1_PSY|CO&|i>4Thh{G<9dbUx-+&aHg^ZaRDr4AXot5+z^5%}Q@~AFbuX zWHZ@Kb>gPy@bBhPfBWWY7)GJk3D0u}p6`Z*L)db-lU{ce{hL$N=e7skFpQHu-}AI^ znrDMN^DV_S-2%D!a2O>b!{`S=@pZQ-9eca!UX#9^kM6Ih$tde48HZplc%ESt=DO}Q zSx@sMEAr15F5mZU*>Q5v)^p3^4xb;6=kWRA|L^?x{_FhkkDq_sT^6^QwA*W2%-`@> zR56~Ve7{{aMU56yErT1G0eX3 z-GaZBuGY8vc}6@l8Lrlcv-&%-tM$RurzZ9JQQ-clcT%^+nHQ8zKK86)h@F@4%nR#B z$qW2x;U}cA$-#d_x+a0YQet|*y)H~F_s2v0lr%ngi?`pUQ>r@SbDD{rDte5|Uz`<=`N4df zoS)hkN}Ko@P4K2PXIb|6@w1#!ZFUMDeb^N+b>5L?emMGoS4s~5d!4nBfmG>@_{O zYrZSAVZI^5yia~h4Wkzh;l&Cjp5H*?R@G%n`j~{hW7n>hb007HYnq7uV2giBHhWi% zKPe1PJoABxXJ7aYVn+4~KbV~||D0_6>=Ax&)juzcpS{8l#&5HpmCcO!I6D}db2HI^#L%mnA&-Uy;U-wz{v%rUr9fkY19ougpmdd-{e1{-^TZE|%P{%3*)s zl28Z!FU5dglF*-i*w*h|+04JHU13MBNZ4EY;UkW{d|!g^j(V_bS4&Rn;7+f}<~`e; zf{C-74`frPCb9SMp=@&Op25Uf&Z=y3*jLM0lTD7jTQG5!vo4#Qy6201xFMSyzB%3# zm^iC>Q?}LQ%$zZhz+23QY}+Y|*%Sx=OL;FJ$%Z4>@;;VrdGrPoXa1IKdUJ19_Y>Lh z7IRCs?W@J;Z`{FK@7uEB$hEvXvMrC^VB*ZbEt}rlztwHahPRkcWmBUX^O-Qb_5NHo z9J!WvSGMKR8%!L#&v(EsqUqa|{zAg;|E#+Ne_3+28~ETX{wvwj75ueqcG>d3kqt*2 z{qez7zs+;PR Date: Thu, 19 Oct 2023 12:20:06 -0700 Subject: [PATCH 11/27] fix SimulationConfiguration json deserialization --- .../simulation/SimulationConfiguration.java | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java index f8584b3a..15c4eb44 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationConfiguration.java @@ -91,41 +91,41 @@ public SimulationConfiguration(Config.Reactor reactorConfig, double ambientTempe public SimulationConfiguration(Map jsonMap) { this( - (double) jsonMap.get("ambientTemperature"), + ((Number)jsonMap.get("ambientTemperature")).doubleValue(), (boolean) jsonMap.get("passivelyCooled"), - (double) jsonMap.get("fuelUsageMultiplier"), - (double) jsonMap.get("outputMultiplier"), - (double) jsonMap.get("passiveOutputMultiplier"), - (double) jsonMap.get("activeOutputMultiplier"), - (long) jsonMap.get("fuelRodFuelCapacity"), - (double) jsonMap.get("fuelFertilityMinimumDecay"), - (double) jsonMap.get("fuelFertilityDecayDenominator"), - (double) jsonMap.get("fuelFertilityDecayDenominatorInactiveMultiplier"), - (double) jsonMap.get("casingHeatTransferRFMKT"), - (double) jsonMap.get("fuelToStackRFKTMultiplier"), - (double) jsonMap.get("stackToCoolantRFMKT"), - (double) jsonMap.get("stackToAmbientRFMKT"), - (long) jsonMap.get("passiveBatteryPerExternalBlock"), - (double) jsonMap.get("passiveCoolingTransferEfficiency"), - (long) jsonMap.get("coolantTankCapacityPerFuelRod"), - (double) jsonMap.get("stackRFM3K"), - (double) jsonMap.get("rodRFM3K"), - (double) jsonMap.get("fuelReactivity"), - (double) jsonMap.get("fissionEventsPerFuelUnit"), - (double) jsonMap.get("RFPerRadiationUnit"), - (double) jsonMap.get("fuelPerRadiationUnit"), - (double) jsonMap.get("fuelHardnessDivisor"), - (double) jsonMap.get("fuelAbsorptionCoefficient"), - (double) jsonMap.get("fuelModerationFactor"), - (double) jsonMap.get("radIntensityScalingMultiplier"), - (double) jsonMap.get("radIntensityScalingRateExponentMultiplier"), - (double) jsonMap.get("radIntensityScalingShiftMultiplier"), - (double) jsonMap.get("radPenaltyShiftMultiplier"), - (double) jsonMap.get("radPenaltyRateMultiplier"), - (double) jsonMap.get("fuelAbsorptionScalingMultiplier"), - (double) jsonMap.get("fuelAbsorptionScalingShiftMultiplier"), - (double) jsonMap.get("fuelAbsorptionScalingRateExponentMultiplier"), - (double) jsonMap.get("fuelRadScalingMultiplier") + ((Number)jsonMap.get("fuelUsageMultiplier")).doubleValue(), + ((Number)jsonMap.get("outputMultiplier")).doubleValue(), + ((Number)jsonMap.get("passiveOutputMultiplier")).doubleValue(), + ((Number)jsonMap.get("activeOutputMultiplier")).doubleValue(), + ((Number)jsonMap.get("fuelRodFuelCapacity")).longValue(), + ((Number)jsonMap.get("fuelFertilityMinimumDecay")).doubleValue(), + ((Number)jsonMap.get("fuelFertilityDecayDenominator")).doubleValue(), + ((Number)jsonMap.get("fuelFertilityDecayDenominatorInactiveMultiplier")).doubleValue(), + ((Number)jsonMap.get("casingHeatTransferRFMKT")).doubleValue(), + ((Number)jsonMap.get("fuelToStackRFKTMultiplier")).doubleValue(), + ((Number)jsonMap.get("stackToCoolantRFMKT")).doubleValue(), + ((Number)jsonMap.get("stackToAmbientRFMKT")).doubleValue(), + ((Number)jsonMap.get("passiveBatteryPerExternalBlock")).longValue(), + ((Number)jsonMap.get("passiveCoolingTransferEfficiency")).doubleValue(), + ((Number)jsonMap.get("coolantTankCapacityPerFuelRod")).longValue(), + ((Number)jsonMap.get("stackRFM3K")).doubleValue(), + ((Number)jsonMap.get("rodRFM3K")).doubleValue(), + ((Number)jsonMap.get("fuelReactivity")).doubleValue(), + ((Number)jsonMap.get("fissionEventsPerFuelUnit")).doubleValue(), + ((Number)jsonMap.get("RFPerRadiationUnit")).doubleValue(), + ((Number)jsonMap.get("fuelPerRadiationUnit")).doubleValue(), + ((Number)jsonMap.get("fuelHardnessDivisor")).doubleValue(), + ((Number)jsonMap.get("fuelAbsorptionCoefficient")).doubleValue(), + ((Number)jsonMap.get("fuelModerationFactor")).doubleValue(), + ((Number)jsonMap.get("radIntensityScalingMultiplier")).doubleValue(), + ((Number)jsonMap.get("radIntensityScalingRateExponentMultiplier")).doubleValue(), + ((Number)jsonMap.get("radIntensityScalingShiftMultiplier")).doubleValue(), + ((Number)jsonMap.get("radPenaltyShiftMultiplier")).doubleValue(), + ((Number)jsonMap.get("radPenaltyRateMultiplier")).doubleValue(), + ((Number)jsonMap.get("fuelAbsorptionScalingMultiplier")).doubleValue(), + ((Number)jsonMap.get("fuelAbsorptionScalingShiftMultiplier")).doubleValue(), + ((Number)jsonMap.get("fuelAbsorptionScalingRateExponentMultiplier")).doubleValue(), + ((Number)jsonMap.get("fuelRadScalingMultiplier")).doubleValue() ); } } From ce6eadea082380ec7d4bd72d98e56bf48c417325 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Thu, 19 Oct 2023 13:09:36 -0700 Subject: [PATCH 12/27] update changelog and bump version --- Phosphophyllite | 2 +- Quartz | 2 +- changelog.md | 10 ++++++++++ gradle.properties | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Phosphophyllite b/Phosphophyllite index 7371a6ba..e4685db6 160000 --- a/Phosphophyllite +++ b/Phosphophyllite @@ -1 +1 @@ -Subproject commit 7371a6bab84271d10d80564bc757876c8b08235c +Subproject commit e4685db6443344fc3ac1b9b844a7fc5f4ee9863c diff --git a/Quartz b/Quartz index 965eb12a..4c98c0d1 160000 --- a/Quartz +++ b/Quartz @@ -1 +1 @@ -Subproject commit 965eb12a6110ec0d6610f83522996617033e0588 +Subproject commit 4c98c0d185b589899b9896a935a944315ead475d diff --git a/changelog.md b/changelog.md index c1e92b9f..0078631e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,13 @@ +# 1.20.1-0.6.0-beta.10.2 + +## Reactor + - fix coolant port not accepting coolant + - add Vulkan backed experimental simulation + - simulation fully able to be loaded without Neo, backing web accessible simulator + +# Misc + - migrate to Neo + # 1.20.1-0.6.0-beta.10.1 ## Reactor diff --git a/gradle.properties b/gradle.properties index 5dd26a35..23cf7483 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,6 +15,6 @@ jei_version=15.2.0.22 majorVersion=0 minorVersion=6 patchVersion=0 -postfixVersion=beta.10.1 +postfixVersion=beta.10.2 mod_id=biggerreactors \ No newline at end of file From 15dbaddb013074c8fb2c8dc2a4f4b039ab732065 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Thu, 19 Oct 2023 17:15:30 -0700 Subject: [PATCH 13/27] add z size for height zero arrays are zero indexed ya know --- .../reactor/simulation/accellerated/vk/VkPipelines.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPipelines.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPipelines.java index 32f25d85..31fb596a 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPipelines.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkPipelines.java @@ -28,6 +28,7 @@ public class VkPipelines { // best sizes benchmarked on a 5800u iGPU private static final int[] zSizes = new int[]{ + 0, // height 0 is invalid 16, 16, 16, 16, 16, 8, 8, 16, 16, 8, 8, 8, From 3abc3803631d131b94697572876f6d2311000f06 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Sat, 21 Oct 2023 20:25:32 -0700 Subject: [PATCH 14/27] dont use mojang's pair and a couple other things --- .../simulation/accellerated/vk/Vk13Simulation.java | 10 ++++------ .../simulation/accellerated/vk/VkMemUtil.java | 14 +++++++------- .../reactor/simulation/accellerated/vk/VkUtil.java | 6 +++++- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/Vk13Simulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/Vk13Simulation.java index ba0eb167..063c33d8 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/Vk13Simulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/Vk13Simulation.java @@ -13,13 +13,11 @@ import java.nio.LongBuffer; -import static com.sun.jna.Native.LONG_SIZE; -import static com.sun.jna.Native.POINTER_SIZE; import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkPools.allocCommandBuffer; import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkPools.freeCommandBufferNow; import static net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkUtil.*; import static org.lwjgl.system.MemoryUtil.memGetAddress; -import static org.lwjgl.system.MemoryUtil.memPutAddress; +import static org.lwjgl.system.MemoryUtil.memPutLong; import static org.lwjgl.vulkan.VK13.*; @NonnullDefault @@ -505,7 +503,7 @@ private void waitSemaphore() { } @Override - protected void finalize() throws Throwable { + protected void finalize() { waitSemaphore(); } @@ -513,8 +511,8 @@ public void addSemaphoreToWaitInto(VkSemaphoreWaitInfo waitInfo, int index) { var structAddress = waitInfo.address(); var semaphoresPointer = memGetAddress(structAddress + VkSemaphoreWaitInfo.PSEMAPHORES); var valuesPointer = memGetAddress(structAddress + VkSemaphoreWaitInfo.PVALUES); - memPutAddress(semaphoresPointer + ((long) index * POINTER_SIZE), semaphorePointer.get(0)); - memPutAddress(valuesPointer + ((long) index * LONG_SIZE), semaphoreWaitValuePointer.get(0)); + memPutLong(semaphoresPointer + ((long) index * 8), semaphorePointer.get(0)); + memPutLong(valuesPointer + ((long) index * 8), semaphoreWaitValuePointer.get(0)); } @Override diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java index c31c9f65..f6a291e6 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java @@ -1,9 +1,9 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk; -import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import net.roguelogix.phosphophyllite.util.NonnullDefault; +import net.roguelogix.phosphophyllite.util.Pair; import net.roguelogix.quartz.internal.util.PointerWrapper; import org.jetbrains.annotations.Nullable; import org.lwjgl.system.MemoryStack; @@ -134,19 +134,19 @@ private Info attemptAllocInSpace(Info freeAlloc, long size, long alignment) { if (alignmentWaste > 0) { final var newAllocs = freeAlloc.split(alignmentWaste); // not concurrent modification because this will always return - freeAllocations.add(newAllocs.getFirst()); - freeAlloc = newAllocs.getSecond(); + freeAllocations.add(newAllocs.first); + freeAlloc = newAllocs.second; - int index = freeAllocations.indexOf(newAllocs.getFirst()); + int index = freeAllocations.indexOf(newAllocs.first); collapseFreeAllocationWithNext(index - 1); collapseFreeAllocationWithNext(index); } if (freeAlloc.size > size) { final var newAllocs = freeAlloc.split(size); // not concurrent modification because this will always return - freeAlloc = newAllocs.getFirst(); - freeAllocations.add(newAllocs.getSecond()); - int index = freeAllocations.indexOf(newAllocs.getSecond()); + freeAlloc = newAllocs.first; + freeAllocations.add(newAllocs.second); + int index = freeAllocations.indexOf(newAllocs.second); collapseFreeAllocationWithNext(index - 1); collapseFreeAllocationWithNext(index); } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkUtil.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkUtil.java index 5220c42e..5c65281f 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkUtil.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkUtil.java @@ -446,6 +446,10 @@ public static int checkVkResult(int returnCode) { return returnCode; } + public static boolean canThreadSubmit(){ + return roundRobinQueues || threadQueueIndex.get() != -1; + } + public static void queueSubmit(VkSubmitInfo2.Buffer submitInfos) { final int queueIndex; if (roundRobinQueues) { @@ -454,7 +458,7 @@ public static void queueSubmit(VkSubmitInfo2.Buffer submitInfos) { } else { queueIndex = threadQueueIndex.get(); if (queueIndex == -1) { - throw new VulkanException("No queue aquired for thread"); + throw new VulkanException("No queue acquired for thread"); } } vkQueueSubmit2(queues.get(queueIndex), submitInfos, VK_NULL_HANDLE); From 5d0a739fb3ef91fc3ac56688c298f7ea1dd138a3 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Sat, 21 Oct 2023 20:27:29 -0700 Subject: [PATCH 15/27] update quartz --- Quartz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Quartz b/Quartz index 4c98c0d1..077a68fa 160000 --- a/Quartz +++ b/Quartz @@ -1 +1 @@ -Subproject commit 4c98c0d185b589899b9896a935a944315ead475d +Subproject commit 077a68fa5a191044ae67ce493163eaf8b4027d7b From 8302634863a34e302a2a9951e9288f5bbf051a4d Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Sat, 21 Oct 2023 20:29:18 -0700 Subject: [PATCH 16/27] add glslc to git ignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ed2ac11b..d0b65f00 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,6 @@ logs # Files from Forge MDK forge*changelog.txt -publishlocal \ No newline at end of file +publishlocal + +glslc \ No newline at end of file From 046b0d433e3493382292140f5bf9405a15df27c4 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Fri, 27 Oct 2023 19:46:40 -0700 Subject: [PATCH 17/27] add setAllControlRodInsertions to simulation --- .../multiblocks/reactor/simulation/IReactorSimulation.java | 2 ++ .../reactor/simulation/base/BaseReactorSimulation.java | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java index 122706c9..d71b2e4e 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/IReactorSimulation.java @@ -32,6 +32,8 @@ public interface IReactorSimulation extends IPhosphophylliteSerializable, IDebug @Nullable ControlRod controlRodAt(int x, int z); + void setAllControlRodInsertions(double insertion); + double fertility(); double fuelHeat(); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java index 43f2ab29..d496794d 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/base/BaseReactorSimulation.java @@ -244,6 +244,13 @@ public ControlRod controlRodAt(int x, int z) { return controlRodsXZ[x][z]; } + @Override + public void setAllControlRodInsertions(double insertion) { + for (int i = 0; i < controlRods.length; i++) { + controlRods[i].setInsertion(insertion); + } + } + @Override public double fertility() { if (fuelFertility <= 1f) { From 563fb53d8a2914b2c85b9006015f96ab39d9489b Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Fri, 27 Oct 2023 19:47:02 -0700 Subject: [PATCH 18/27] fix synchronization issues with VkMemUtil --- .../reactor/simulation/accellerated/vk/VkMemUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java index f6a291e6..04611d33 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java @@ -239,7 +239,7 @@ public record VkAllocation(AllocationBlock block, long vkMemoryHandle, long offs } - public static VkAllocation allocHost(VkMemoryRequirements memoryRequirements) { + public static synchronized VkAllocation allocHost(VkMemoryRequirements memoryRequirements) { if ((memoryRequirements.memoryTypeBits() & (1 << hostMemoryType)) == 0) { throw new IllegalStateException("Cannot allocate on host"); } @@ -251,7 +251,7 @@ public static VkAllocation allocHost(long size, long alignment) { return block.alloc(size, alignment); } - public static void freeHost(@Nullable VkAllocation allocation) { + public static synchronized void freeHost(@Nullable VkAllocation allocation) { if (allocation == null) { return; } @@ -263,7 +263,7 @@ public static void freeHost(@Nullable VkAllocation allocation) { } } - public static VkAllocation allocGPU(VkMemoryRequirements memoryRequirements) { + public static synchronized VkAllocation allocGPU(VkMemoryRequirements memoryRequirements) { if ((memoryRequirements.memoryTypeBits() & (1 << gpuMemoryType)) == 0) { throw new IllegalStateException("Cannot allocate on gpu"); } @@ -275,7 +275,7 @@ public static VkAllocation allocGPU(long size, long alignment) { return block.alloc(size, alignment); } - public static void freeGPU(@Nullable VkAllocation allocation) { + public static synchronized void freeGPU(@Nullable VkAllocation allocation) { if (allocation == null) { return; } From 5e2e1c3655a7538fcee7693b5a36b2bbcfc7ff8d Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Fri, 27 Oct 2023 19:48:24 -0700 Subject: [PATCH 19/27] update serialized description format to reduce file size --- .../simulation/SimulationDescription.java | 61 ++++++------------- 1 file changed, 19 insertions(+), 42 deletions(-) diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java index 27f5d5ac..8819a005 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/SimulationDescription.java @@ -1,8 +1,8 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.simulation; import net.roguelogix.biggerreactors.Config; -import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.ocl.SingleQueueOpenCL12Simulation; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.ocl.CLUtil; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.ocl.SingleQueueOpenCL12Simulation; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.Vk13Simulation; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.accellerated.vk.VkUtil; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.cpu.FullPassReactorSimulation; @@ -209,38 +209,36 @@ public PhosphophylliteCompound save() { } ArrayList moderatorProperties = new ArrayList<>(); ArrayList>> moderatorIndexes = new ArrayList<>(); - ArrayList>> manifoldLocations = new ArrayList<>(); - ArrayList> controlRodLocations = new ArrayList<>(); for (int i = 0; i < x; i++) { ArrayList> moderatorIndexesX = new ArrayList<>(); - ArrayList> manifoldLocationsX = new ArrayList<>(); - ArrayList controlRodLocationsX = new ArrayList<>(); for (int j = 0; j < y; j++) { ArrayList moderatorIndexesXY = new ArrayList<>(); - ArrayList manifoldLocationsXY = new ArrayList<>(); for (int k = 0; k < z; k++) { + moderatorIndexesXY.add(-1); + ReactorModeratorRegistry.IModeratorProperties properties = this.moderatorProperties[i][j][k]; - if (properties == null) { - moderatorIndexesXY.add(-1); - } else { + if (properties != null) { int index = moderatorProperties.indexOf(properties); if (index == -1) { index = moderatorProperties.size(); moderatorProperties.add(properties); } - moderatorIndexesXY.add(index); + moderatorIndexesXY.set(moderatorIndexesXY.size() - 1, index); + } + if (this.manifoldLocations[i][j][k]) { + moderatorIndexesXY.set(moderatorIndexesXY.size() - 1, -2); } - manifoldLocationsXY.add(this.manifoldLocations[i][j][k]); } moderatorIndexesX.add(moderatorIndexesXY); - manifoldLocationsX.add(manifoldLocationsXY); } for (int j = 0; j < z; j++) { - controlRodLocationsX.add(this.controlRodLocations[i][j]); + if(this.controlRodLocations[i][j]){ + for (int k = 0; k < y; k++) { + moderatorIndexesX.get(k).set(j, -3); + } + } } moderatorIndexes.add(moderatorIndexesX); - manifoldLocations.add(manifoldLocationsX); - controlRodLocations.add(controlRodLocationsX); } @@ -249,8 +247,6 @@ public PhosphophylliteCompound save() { compound.put("z", z); compound.put("moderatorProperties", moderatorProperties); compound.put("moderatorIndices", moderatorIndexes); - compound.put("manifoldLocations", manifoldLocations); - compound.put("controlRodLocations", controlRodLocations); compound.put("defaultModeratorProperties", defaultModeratorProperties.toROBNMap()); return compound; @@ -286,51 +282,32 @@ public void load(@Nonnull PhosphophylliteCompound compound) { } } List moderatorIndices = compound.getList("moderatorIndices"); - List manifoldLocations = compound.getList("manifoldLocations"); - List controlRodLocations = compound.getList("controlRodLocations"); - if (moderatorIndices.size() != x || manifoldLocations.size() != x || controlRodLocations.size() != x) { + if (moderatorIndices.size() != x) { throw new IllegalArgumentException("Malformed Binary"); } for (int i = 0; i < x; i++) { if (!(moderatorIndices.get(i) instanceof List moderatorIndicesX)) { throw new IllegalArgumentException("Malformed Binary"); } - if (!(manifoldLocations.get(i) instanceof List manifoldLocationsX)) { - throw new IllegalArgumentException("Malformed Binary"); - } - if (!(controlRodLocations.get(i) instanceof List controlRodLocationsX)) { - throw new IllegalArgumentException("Malformed Binary"); - } - if (moderatorIndicesX.size() != y || manifoldLocationsX.size() != y || controlRodLocations.size() != z) { + if (moderatorIndicesX.size() != y) { throw new IllegalArgumentException("Malformed Binary"); } for (int j = 0; j < y; j++) { if (!(moderatorIndicesX.get(j) instanceof List moderatorIndicesXY)) { throw new IllegalArgumentException("Malformed Binary"); } - if (!(manifoldLocationsX.get(j) instanceof List manifoldLocationsXY)) { - throw new IllegalArgumentException("Malformed Binary"); - } - if (moderatorIndicesXY.size() != z || manifoldLocationsXY.size() != z) { + if (moderatorIndicesXY.size() != z) { throw new IllegalArgumentException("Malformed Binary"); } for (int k = 0; k < z; k++) { if (!(moderatorIndicesXY.get(k) instanceof Number moderatorIndex)) { throw new IllegalArgumentException("Malformed Binary"); } - if (!(manifoldLocationsXY.get(k) instanceof Boolean isManifold)) { - throw new IllegalArgumentException("Malformed Binary"); - } int index = moderatorIndex.intValue(); - setModeratorProperties(i, j, k, index != -1 ? moderatorProperties.get(index) : null); - setManifold(i, j, k, isManifold); - } - } - for (int j = 0; j < z; j++) { - if (!(controlRodLocationsX.get(j) instanceof Boolean isControlRod)) { - throw new IllegalArgumentException("Malformed Binary"); + setModeratorProperties(i, j, k, index >= 0 ? moderatorProperties.get(index) : null); + setManifold(i, j, k, index == -2); + setControlRod(i, k, index == -3); } - setControlRod(i, j, isControlRod); } } From 9fdaf03771c40754c16b37ea180161d0e40b32cc Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Fri, 27 Oct 2023 19:49:21 -0700 Subject: [PATCH 20/27] add constant transition properties record used by simulator --- .../registries/FluidTransitionRegistry.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java b/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java index cd997c13..7b3fb4d6 100644 --- a/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java +++ b/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java @@ -48,6 +48,19 @@ default void fromROBNMap(Map map) { } + public record TransitionProperties(double latentHeat, double boilingPoint, double liquidRFMKT, double gasRFMKT, double turbineMultiplier) implements ITransitionProperties { + + public TransitionProperties(Map map) { + this( + ((Number) map.get("latentHeat")).doubleValue(), + ((Number) map.get("boilingPoint")).doubleValue(), + ((Number) map.get("liquidRFMKT")).doubleValue(), + ((Number) map.get("gasRFMKT")).doubleValue(), + ((Number) map.get("turbineMultiplier")).doubleValue() + ); + } + } + public static class FluidTransition implements ITransitionProperties { public final List liquids; public final List gases; From 3dc233621baa9ea650cfbc8eb2e65a93a0010e01 Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 19 Nov 2023 15:58:52 -0600 Subject: [PATCH 21/27] Fix mod compat recipes (including AllTheMods/ATM-8#1766) (cherry picked from commit e12ce41f6b4297ae706b7c885629caba00f0b0cd) --- .../crusher_deepslate_uranium_ingot.json | 18 --------------- .../crushing/crusher_uranium_chunk.json | 18 --------------- .../{uranium_ingot.json => uranium_dust.json} | 0 .../pulverizer_mod_deepslate_uranium_ore.json | 23 +++++++++++++++++++ .../pulverizer_mod_uranium_chunk.json | 19 +++++++++++++++ 5 files changed, 42 insertions(+), 36 deletions(-) delete mode 100644 src/main/resources/data/biggerreactors/recipes/compat/mekanism/crushing/crusher_deepslate_uranium_ingot.json delete mode 100644 src/main/resources/data/biggerreactors/recipes/compat/mekanism/crushing/crusher_uranium_chunk.json rename src/main/resources/data/biggerreactors/recipes/smelting/{uranium_ingot.json => uranium_dust.json} (100%) create mode 100644 src/main/resources/data/thermal/recipes/machine/biggerreactors/pulverizer_mod_deepslate_uranium_ore.json create mode 100644 src/main/resources/data/thermal/recipes/machine/biggerreactors/pulverizer_mod_uranium_chunk.json diff --git a/src/main/resources/data/biggerreactors/recipes/compat/mekanism/crushing/crusher_deepslate_uranium_ingot.json b/src/main/resources/data/biggerreactors/recipes/compat/mekanism/crushing/crusher_deepslate_uranium_ingot.json deleted file mode 100644 index cdcfc7c5..00000000 --- a/src/main/resources/data/biggerreactors/recipes/compat/mekanism/crushing/crusher_deepslate_uranium_ingot.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "mekanism:crushing", - "conditions": [ - { - "modid": "mekanism", - "type": "forge:mod_loaded" - } - ], - "input": { - "ingredient": { - "item": "biggerreactors:deepslate_uranium_ingot" - } - }, - "output": { - "item": "biggerreactors:uranium_dust", - "count": 1 - } -} \ No newline at end of file diff --git a/src/main/resources/data/biggerreactors/recipes/compat/mekanism/crushing/crusher_uranium_chunk.json b/src/main/resources/data/biggerreactors/recipes/compat/mekanism/crushing/crusher_uranium_chunk.json deleted file mode 100644 index 500bda23..00000000 --- a/src/main/resources/data/biggerreactors/recipes/compat/mekanism/crushing/crusher_uranium_chunk.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "mekanism:crushing", - "conditions": [ - { - "modid": "mekanism", - "type": "forge:mod_loaded" - } - ], - "input": { - "ingredient": { - "item": "biggerreactors:uranium_chunk" - } - }, - "output": { - "item": "biggerreactors:uranium_dust", - "count": 1 - } -} \ No newline at end of file diff --git a/src/main/resources/data/biggerreactors/recipes/smelting/uranium_ingot.json b/src/main/resources/data/biggerreactors/recipes/smelting/uranium_dust.json similarity index 100% rename from src/main/resources/data/biggerreactors/recipes/smelting/uranium_ingot.json rename to src/main/resources/data/biggerreactors/recipes/smelting/uranium_dust.json diff --git a/src/main/resources/data/thermal/recipes/machine/biggerreactors/pulverizer_mod_deepslate_uranium_ore.json b/src/main/resources/data/thermal/recipes/machine/biggerreactors/pulverizer_mod_deepslate_uranium_ore.json new file mode 100644 index 00000000..e4b498a1 --- /dev/null +++ b/src/main/resources/data/thermal/recipes/machine/biggerreactors/pulverizer_mod_deepslate_uranium_ore.json @@ -0,0 +1,23 @@ +{ + "type": "thermal:pulverizer", + "conditions": [ + { + "modid": "thermal_expansion", + "type": "forge:mod_loaded" + } + ], + "ingredient": { + "item": "biggerreactors:deepslate_uranium_ore" + }, + "result": [ + { + "item": "biggerreactors:uranium_dust", + "chance": 2.0 + }, + { + "item": "minecraft:gravel", + "chance": 0.2 + } + ], + "experience": 0.35 +} \ No newline at end of file diff --git a/src/main/resources/data/thermal/recipes/machine/biggerreactors/pulverizer_mod_uranium_chunk.json b/src/main/resources/data/thermal/recipes/machine/biggerreactors/pulverizer_mod_uranium_chunk.json new file mode 100644 index 00000000..3547bca6 --- /dev/null +++ b/src/main/resources/data/thermal/recipes/machine/biggerreactors/pulverizer_mod_uranium_chunk.json @@ -0,0 +1,19 @@ +{ + "type": "thermal:pulverizer", + "conditions": [ + { + "modid": "thermal_expansion", + "type": "forge:mod_loaded" + } + ], + "ingredient": { + "item": "biggerreactors:uranium_chunk" + }, + "result": [ + { + "item": "biggerreactors:uranium_dust", + "chance": 1.25 + } + ], + "experience": 0.35 +} \ No newline at end of file From 02ff3a31b50f35917101638bd1c04d555b2c176c Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 19 Nov 2023 15:59:22 -0600 Subject: [PATCH 22/27] Remove defunct superheated sodium fluid (cherry picked from commit 852d69827ab902c9eaec34e97f3a3479901b8ed5) # Conflicts: # src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png # src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png.mcmeta # src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png # src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png.mcmeta --- .../fluids/SuperheatedSodium.java | 17 ------------ .../item/superheated_sodium_bucket.json | 6 ----- .../fluid/superheated_sodium_flowing.png | Bin 8234 -> 0 bytes .../superheated_sodium_flowing.png.mcmeta | 3 --- .../block/fluid/superheated_sodium_still.png | Bin 5947 -> 0 bytes .../fluid/superheated_sodium_still.png.mcmeta | 5 ---- .../item/superheated_sodium_bucket.png | Bin 3480 -> 0 bytes .../mekanism/rotary/superheated_sodium.json | 25 ------------------ 8 files changed, 56 deletions(-) delete mode 100644 src/main/java/net/roguelogix/biggerreactors/fluids/SuperheatedSodium.java delete mode 100644 src/main/resources/assets/biggerreactors/models/item/superheated_sodium_bucket.json delete mode 100644 src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png delete mode 100644 src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png.mcmeta delete mode 100644 src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png delete mode 100644 src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png.mcmeta delete mode 100644 src/main/resources/assets/biggerreactors/textures/item/superheated_sodium_bucket.png delete mode 100644 src/main/resources/data/biggerreactors/recipes/compat/mekanism/rotary/superheated_sodium.json diff --git a/src/main/java/net/roguelogix/biggerreactors/fluids/SuperheatedSodium.java b/src/main/java/net/roguelogix/biggerreactors/fluids/SuperheatedSodium.java deleted file mode 100644 index 91204104..00000000 --- a/src/main/java/net/roguelogix/biggerreactors/fluids/SuperheatedSodium.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.roguelogix.biggerreactors.fluids; - -import net.roguelogix.phosphophyllite.registry.PhosphophylliteFluid; -import net.roguelogix.phosphophyllite.registry.RegisterFluid; - -import javax.annotation.Nonnull; - -//@RegisterFluid(name = "superheated_sodium", registerBucket = true) -public class SuperheatedSodium extends PhosphophylliteFluid { - - @RegisterFluid.Instance - public static SuperheatedSodium INSTANCE; - - public SuperheatedSodium(@Nonnull Properties properties) { - super(properties); - } -} diff --git a/src/main/resources/assets/biggerreactors/models/item/superheated_sodium_bucket.json b/src/main/resources/assets/biggerreactors/models/item/superheated_sodium_bucket.json deleted file mode 100644 index fd91824c..00000000 --- a/src/main/resources/assets/biggerreactors/models/item/superheated_sodium_bucket.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/handheld", - "textures": { - "layer0": "biggerreactors:item/superheated_sodium_bucket" - } -} \ No newline at end of file diff --git a/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png b/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png deleted file mode 100644 index 68f17cba3bb217b5225f477abbdfc8b28e5d6196..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8234 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 diff --git a/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png.mcmeta b/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png.mcmeta deleted file mode 100644 index 4f0718ac..00000000 --- a/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_flowing.png.mcmeta +++ /dev/null @@ -1,3 +0,0 @@ -{ - "animation": {} -} \ No newline at end of file diff --git a/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png b/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png deleted file mode 100644 index 0610405cbb60efa8a363b8a473eca87631896186..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5947 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 BdAR@p diff --git a/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png.mcmeta b/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png.mcmeta deleted file mode 100644 index 0645f48c..00000000 --- a/src/main/resources/assets/biggerreactors/textures/block/fluid/superheated_sodium_still.png.mcmeta +++ /dev/null @@ -1,5 +0,0 @@ -{ - "animation": { - "frametime": 2 - } -} diff --git a/src/main/resources/assets/biggerreactors/textures/item/superheated_sodium_bucket.png b/src/main/resources/assets/biggerreactors/textures/item/superheated_sodium_bucket.png deleted file mode 100644 index 2a3900fa4f6c4e27ef286dc24411b9004bf8dda6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3480 zcmcIn4U8OB9iJA$M?VZkAx$x1m>O*%i3Sh|+JID)sI9))-P_xm zyWR$Mllgk@_x>Nh_y2f%_x6EpE0?WarYOqF{=V`K`MfN@F1bkFuR8rNDj%1|eY;Xc zS^lB?TA~~|x=OyB4hDy_;mVCJi)sbRBTp3SwOFDRWy5v#n6f=0Q#~;fgeC2*nI|+g z;3aLys=!LzD@KF9y@}YlcVLk1-NOjiuG^??sJl`?O=MK9*Q#Oa)=OGLt}Ea3VO>)j zkZey$>&X?W!TE#?JOx+fDxkU=)Pz8tZ!JgD;Z&HUmKlQP=7;bKfJUlcL0e8hl_OcM}MGyrGZG?`<< zqVLQ~yD14|iqmSR)Z8jACE6St#GnR1P#T0ClL1F~3=n3CB64is!(3D6^!7&8D5*qT za&Bm9zT2)8FHNO+ew8%T8XV3;wK~=uEMh2sI?C^@`CW_5&rRPF29jc|sd>D(4gEW1 z>5>N6mStG2@$ErfRENufWG!tPVt3B$I(H_oWO;_VeL*T?Zn9Ntc8X86-l~DxNJ^Ko zrVA{OP9dpi4hQpWaCcNT*H4TJN!EFywh2okKbxS5=oyg=FPatlLdK_b{QRav&$oDy z5MUQg4zMpn!6TdiZbDypCM1}8v#!r)I8B30QF5DP-H>iV`vhNed_pThg}VCo7Cy&=eU9FIJruK8bk6poWHiu;qs$> zk{6+@oQXWAe`o2R0!3MJLw~tv&^dJcz7y9kz4^m;J@KVGSK-5Jrk1a~`oyVgk5*>x z->qN0v2Pl_0DrcjZ~2LX-+OBJ$6mVr&PzUW?>)%)+QCDAIC)ro;mvnW|L(1S{wsnn&ZDc^7*Hqj(U?{j_p=fAKH54gJ18tZT~CIqksJ2i?1z9 z&usd}@a@*V3x9v=%mw=gW=_8P;=m^DzAxKDM~9wYd&N6f(jRz_ojrEzM*8^F+RK-} z{nfu1%J+Z#z|x)WDSXS%KN`LI?3Kj-?9}UTAAU&eyW_9Q0d>>5gRf6MIsNC?{(j&g z@vG@Kvzejye)6r0m6sl`Ty~+d_OZJ^acS>0H%$cVm2K{$zy757?!Li`pZxYW&+I?; z;3I|UXFmP$RVyyKV@dx3xZ+)9-SIcx-K(tlOfNY0o9fH|IQ#sz=T53;?#Z6XPASK} x@YB;jTEWfL!OR6yeBIfZ8(;p#*x9AwgLi%9s`n0^%>O&}Zy6{*vibG{{|0dWj0XS! diff --git a/src/main/resources/data/biggerreactors/recipes/compat/mekanism/rotary/superheated_sodium.json b/src/main/resources/data/biggerreactors/recipes/compat/mekanism/rotary/superheated_sodium.json deleted file mode 100644 index ea738968..00000000 --- a/src/main/resources/data/biggerreactors/recipes/compat/mekanism/rotary/superheated_sodium.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "type": "mekanism:rotary", - "conditions": [ - { - "modid": "mekanism", - "type": "forge:mod_loaded" - } - ], - "fluidInput": { - "amount": 1, - "tag": "forge:superheated_sodium" - }, - "gasOutput": { - "gas": "mekanism:superheated_sodium", - "amount": 1 - }, - "gasInput": { - "amount": 1, - "gas": "mekanism:superheated_sodium" - }, - "fluidOutput": { - "amount": 1, - "fluid": "biggerreactors:superheated_sodium" - } -} \ No newline at end of file From 9fe97f8ac1b7d9f7d2092f0c38b7b6fb7da288c3 Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Mon, 18 Dec 2023 11:30:06 -0800 Subject: [PATCH 23/27] async reactor simulation fake ticks are wonderful things --- .../cpu/AsyncReactorSimulation.java | 85 +++++++++++++++++++ .../cpu/FullPassReactorSimulation.java | 54 ++++++++++-- 2 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/AsyncReactorSimulation.java diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/AsyncReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/AsyncReactorSimulation.java new file mode 100644 index 00000000..f7356748 --- /dev/null +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/AsyncReactorSimulation.java @@ -0,0 +1,85 @@ +package net.roguelogix.biggerreactors.multiblocks.reactor.simulation.cpu; + +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationConfiguration; +import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.SimulationDescription; + +public class AsyncReactorSimulation extends FullPassReactorSimulation { + + private final Thread asyncThread = new Thread(this::asyncThreadFunc); + + private boolean requestRunning; + private double runningResultAverageIntensity = 0; + private double currentResultAverageIntensity = 0; + private final ReactorStateData asyncReactorStateData = new ReactorStateData(); + private final IrradiationResult currentResult = new IrradiationResult(); + private final IrradiationResult scaledResult = new IrradiationResult(); + public int tickNumber = 0; + public int realTicks = 0; + + public AsyncReactorSimulation(SimulationDescription simulationDescription, SimulationConfiguration configuration) { + super(simulationDescription, configuration); + asyncThread.setDaemon(true); + asyncThread.setName(this.getClass().getSimpleName()); + asyncThread.start(); + } + + private void asyncThreadFunc() { + while (true) { + if (!requestRunning) { + try { + Thread.sleep(100); + } catch (InterruptedException ignored) { + } + continue; + } + runIrradiationRequest(fullPassIrradiationRequest, asyncReactorStateData); + requestRunning = false; + } + } + + @Override + protected double radiate() { + setupIrradiationTick(); + if (!requestRunning) { + realTicks++; + currentResult.fuelRFAdded = fullPassIrradiationRequest.result.fuelRFAdded; + currentResult.fuelRadAdded = fullPassIrradiationRequest.result.fuelRadAdded; + currentResult.caseRFAdded = fullPassIrradiationRequest.result.caseRFAdded; + + fullPassIrradiationRequest.updateCache(); + asyncReactorStateData.update(this); + currentResultAverageIntensity = runningResultAverageIntensity; + runningResultAverageIntensity = 0; + for (int i = 0; i < initialIntensties.length; i++) { + runningResultAverageIntensity += initialIntensties[i]; + } + runningResultAverageIntensity /= initialIntensties.length; + if (realTicks < 2) { + runIrradiationRequest(fullPassIrradiationRequest, asyncReactorStateData); + } else { + requestRunning = true; + asyncThread.interrupt(); + } + } + + scaledResult.fuelRFAdded = currentResult.fuelRFAdded; + scaledResult.fuelRadAdded = currentResult.fuelRadAdded; + scaledResult.caseRFAdded = currentResult.caseRFAdded; + + double averageIntensity = 0; + for (int i = 0; i < initialIntensties.length; i++) { + averageIntensity += initialIntensties[i]; + } + averageIntensity /= initialIntensties.length; + + double scalingFactor = averageIntensity / currentResultAverageIntensity; + + scaledResult.fuelRFAdded *= scalingFactor; + scaledResult.fuelRadAdded *= scalingFactor; + scaledResult.caseRFAdded *= scalingFactor; + + collectIrradiationResult(scaledResult); + tickNumber++; + return realizeIrradiationTick(); + } +} diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java index da483555..2eedf3ab 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/cpu/FullPassReactorSimulation.java @@ -110,6 +110,7 @@ protected static class IrradiationResult { protected double initialHardness; protected IrradiationRequest fullPassIrradiationRequest; + protected final ReactorStateData reactorStateData = new ReactorStateData(); protected double rawFuelUsage = 0; protected double fuelRFAdded = 0; @@ -124,7 +125,7 @@ protected double radiate() { setupIrradiationTick(); fullPassIrradiationRequest.updateCache(); - runIrradiationRequest(fullPassIrradiationRequest); + runIrradiationRequest(fullPassIrradiationRequest, reactorStateData); collectIrradiationResult(fullPassIrradiationRequest.result); return realizeIrradiationTick(); } @@ -182,6 +183,8 @@ protected void setupIrradiationTick() { this.rawFuelUsage = rawFuelUsage / controlRods.length; this.fuelRFAdded = fuelRFAdded; + + reactorStateData.update(this); } protected void collectIrradiationResult(IrradiationResult result) { @@ -222,7 +225,40 @@ protected double realizeIrradiationTick() { return rawFuelUsage; } - protected void runIrradiationRequest(IrradiationRequest request) { + protected static class ReactorStateData { + + int x, z; + SimUtil.ControlRod[][] controlRodsXZ; + SimUtil.ControlRod[] controlRods; + double[] initialIntensities; + double initialHardness; + double fuelAbsorptionTemperatureCoefficient; + + public void update(FullPassReactorSimulation reactor) { + if(x != reactor.x || z != reactor.z || controlRods.length != reactor.controlRods.length){ + x = reactor.x; + z = reactor.z; + controlRodsXZ = new SimUtil.ControlRod[x][z]; + controlRods = new SimUtil.ControlRod[reactor.controlRods.length]; + for (int i = 0; i < controlRods.length; i++) { + var reactorRod = reactor.controlRods[i]; + var copyRod = new SimUtil.ControlRod(reactorRod.x, reactorRod.z); + controlRods[i] = copyRod; + controlRodsXZ[copyRod.x][copyRod.z] = copyRod; + } + initialIntensities = new double[reactor.initialIntensties.length]; + } + + for (int i = 0; i < initialIntensities.length; i++) { + controlRods[i].insertion = reactor.controlRods[i].insertion; + initialIntensities[i] = reactor.initialIntensties[i]; + } + initialHardness = reactor.initialHardness; + fuelAbsorptionTemperatureCoefficient = reactor.fuelAbsorptionTemperatureCoefficient; + } + } + + protected void runIrradiationRequest(IrradiationRequest request, ReactorStateData reactorState) { final double FuelAbsorptionCoefficient = this.FuelAbsorptionCoefficient; final double FuelModerationFactor = this.FuelModerationFactor; final double fuelHardnessMultiplier = this.fuelHardnessMultiplier; @@ -236,12 +272,12 @@ protected void runIrradiationRequest(IrradiationRequest request) { int rods = 0; for (int cro = 0; cro < request.controlRodCount; cro++) { final int cri = cro + request.baseControlRod; - final var controlRod = controlRods[cri]; - final var initialIntensity = initialIntensties[cri] * rayMultiplier; + final var controlRod = reactorState.controlRods[cri]; + final var initialIntensity = reactorState.initialIntensities[cri] * rayMultiplier; for (int i = 0; i < SimUtil.rays.size(); i++) { for (int j = 0; j < intensities.length; j++) { intensities[j] = initialIntensity; - hardnesses[j] = initialHardness; + hardnesses[j] = reactorState.initialHardness; } final var raySteps = SimUtil.rays.get(i); //noinspection ForLoopReplaceableByForEach @@ -281,7 +317,7 @@ protected void runIrradiationRequest(IrradiationRequest request) { } else { // Scale control rod insertion 0..1 // TODO: race condition with computer craft is possible here - final double controlRodInsertion = controlRodsXZ[currentX][currentZ].insertion * .001; + final double controlRodInsertion = reactorState.controlRodsXZ[currentX][currentZ].insertion * .001; final double halfRodInsertion = controlRodInsertion * 0.5; // Full insertion doubles the moderation factor of the fuel as well as adding its own level final double fuelModerationFactor = FuelModerationFactor + (FuelModerationFactor * controlRodInsertion + controlRodInsertion); @@ -306,7 +342,7 @@ protected void runIrradiationRequest(IrradiationRequest request) { // Fuel absorptiveness is determined by control rod + a heat modifier. // Starts at 1 and decays towards 0.05, reaching 0.6 at 1000 and just under 0.2 at 2000. Inflection point at about 500-600. // Harder radiation makes absorption more difficult. - final double baseAbsorption = fuelAbsorptionTemperatureCoefficient * (1.0 - (neutronHardness * fuelHardnessMultiplier)); + final double baseAbsorption = reactorState.fuelAbsorptionTemperatureCoefficient * (1.0 - (neutronHardness * fuelHardnessMultiplier)); // Some fuels are better at absorbing radiation than others final double scaledAbsorption = baseAbsorption * stepFuelAbsorptionCoefficient; @@ -348,7 +384,7 @@ public static class MultiThreaded extends FullPassReactorSimulation { protected final Event[] irradiationRequestEvents; @Nullable private Event doneEvent; - private final Runnable mainRunnable = () -> runIrradiationRequest(fullPassIrradiationRequest); + private final Runnable mainRunnable = () -> runIrradiationRequest(fullPassIrradiationRequest, reactorStateData); public MultiThreaded(SimulationDescription simulationDescription, SimulationConfiguration configuration) { this(simulationDescription, configuration, false); @@ -368,7 +404,7 @@ public MultiThreaded(SimulationDescription simulationDescription, SimulationConf int baseRod = i * batchSize; int rodCount = Math.min(batchSize, controlRods.length - baseRod); final var request = new IrradiationRequest(baseRod, rodCount, cacheArray, y); - irradiationRequestRunnables[i] = () -> runIrradiationRequest(request); + irradiationRequestRunnables[i] = () -> runIrradiationRequest(request, reactorStateData); irradiationRequests[i] = request; } } else { From b08980a0546a67974b5b649dffe367b508fb7c2e Mon Sep 17 00:00:00 2001 From: RogueLogix Date: Sun, 18 Feb 2024 13:12:21 -0800 Subject: [PATCH 24/27] 1.20.4 --- .gitignore | 1 - .idea/.gitignore | 11 + .idea/codeStyles/Project.xml | 20 + .idea/codeStyles/codeStyleConfig.xml | 6 + .idea/compiler.xml | 6 + .idea/gradle.xml | 20 + .idea/inspectionProfiles/PhosCodeStyle.xml | 28 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 64 ++ .idea/modules.xml | 8 + .idea/remote-targets.xml | 72 ++ .idea/vcs.xml | 6 + Phosphophyllite | 2 +- Quartz | 2 +- build.gradle | 164 ++- gradle.properties | 10 +- .../biggerreactors/BiggerReactors.java | 20 +- .../blocks/materials/DeepslateUraniumOre.java | 3 +- .../blocks/materials/UraniumOre.java | 3 +- .../biggerreactors/client/Biselector.java | 4 +- .../biggerreactors/client/CommonButton.java | 4 +- .../biggerreactors/client/CommonRender.java | 6 +- .../biggerreactors/client/TextBox.java | 4 +- .../biggerreactors/client/Triselector.java | 7 +- .../deps/jei/BiggerReactorsJEIPlugin.java | 2 +- .../reactor/FluidModeratorCategory.java | 3 +- .../machine/blocks/CyaniteReprocessor.java | 215 ++-- .../client/CyaniteReprocessorScreen.java | 234 ++--- .../CyaniteReprocessorContainer.java | 232 ++--- .../state/CyaniteReprocessorState.java | 144 +-- .../machine/tiles/CyaniteReprocessorTile.java | 953 +++++++++--------- .../impl/CyaniteReprocessorItemHandler.java | 4 +- .../blocks/HeatExchangerBaseBlock.java | 3 +- .../client/HeatExchangerFluidPortScreen.java | 4 +- .../client/HeatExchangerTerminalScreen.java | 13 +- .../deps/HeatExchangerPeripheral.java | 9 +- .../tiles/HeatExchangerComputerPortTile.java | 23 +- .../tiles/HeatExchangerFluidPortTile.java | 74 +- .../tiles/HeatExchangerTerminalTile.java | 10 +- .../reactor/ReactorMultiblockController.java | 10 +- .../reactor/blocks/ReactorBaseBlock.java | 3 +- .../reactor/blocks/ReactorFuelRod.java | 4 +- .../reactor/blocks/ReactorManifold.java | 4 +- .../client/ActiveReactorTerminalScreen.java | 13 +- .../client/CommonReactorTerminalScreen.java | 4 +- .../client/PassiveReactorTerminalScreen.java | 4 +- .../client/ReactorAccessPortScreen.java | 4 +- .../client/ReactorControlRodScreen.java | 4 +- .../client/ReactorCoolantPortScreen.java | 5 +- .../client/ReactorRedstonePortScreen.java | 7 +- .../reactor/deps/ReactorPeripheral.java | 5 +- .../simulation/accellerated/vk/VkMemUtil.java | 12 +- .../reactor/tiles/ReactorAccessPortTile.java | 58 +- .../tiles/ReactorComputerPortTile.java | 47 +- .../reactor/tiles/ReactorCoolantPortTile.java | 84 +- .../reactor/tiles/ReactorPowerTapTile.java | 52 +- .../turbine/TurbineMultiblockController.java | 6 +- .../turbine/blocks/TurbineBaseBlock.java | 3 +- .../client/TurbineFluidPortScreen.java | 4 +- .../turbine/client/TurbineTerminalScreen.java | 5 +- .../turbine/deps/TurbinePeripheral.java | 9 +- .../turbine/simulation/ITurbineBattery.java | 2 +- .../turbine/simulation/ITurbineFluidTank.java | 2 +- .../simulation/ITurbineSimulation.java | 2 +- .../tiles/TurbineComputerPortTile.java | 25 +- .../turbine/tiles/TurbineFluidPortTile.java | 72 +- .../turbine/tiles/TurbinePowerTapTile.java | 35 +- .../tiles/TurbineRotorBearingTile.java | 11 - .../registries/FluidTransitionRegistry.java | 13 +- .../registries/ReactorModeratorRegistry.java | 34 +- .../registries/TurbineCoilRegistry.java | 28 +- .../util/FluidTransitionTank.java | 16 +- src/main/resources/META-INF/mods.toml | 12 +- ...{BiggerReactors.png => biggerreactors.png} | Bin 74 files changed, 1567 insertions(+), 1432 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/inspectionProfiles/PhosCodeStyle.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/remote-targets.xml create mode 100644 .idea/vcs.xml rename src/main/resources/{BiggerReactors.png => biggerreactors.png} (100%) diff --git a/.gitignore b/.gitignore index d0b65f00..eb49f0ce 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ out *.ipr *.iws *.iml -.idea # gradle build diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..33e97fdd --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,11 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml + +jarRepositories.xml +uiDesigner.xml \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..41c8fbb4 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..6e6eec11 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..b589d56e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000..c26b135d --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/PhosCodeStyle.xml b/.idea/inspectionProfiles/PhosCodeStyle.xml new file mode 100644 index 00000000..4b5bd5b1 --- /dev/null +++ b/.idea/inspectionProfiles/PhosCodeStyle.xml @@ -0,0 +1,28 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..d77aa703 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..2bfae1f8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..e4f6507d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/remote-targets.xml b/.idea/remote-targets.xml new file mode 100644 index 00000000..7a8ddc42 --- /dev/null +++ b/.idea/remote-targets.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Phosphophyllite b/Phosphophyllite index e4685db6..d1b37c8d 160000 --- a/Phosphophyllite +++ b/Phosphophyllite @@ -1 +1 @@ -Subproject commit e4685db6443344fc3ac1b9b844a7fc5f4ee9863c +Subproject commit d1b37c8d53a79a897de0c219bc12411ea57d809a diff --git a/Quartz b/Quartz index 077a68fa..310fc60a 160000 --- a/Quartz +++ b/Quartz @@ -1 +1 @@ -Subproject commit 077a68fa5a191044ae67ce493163eaf8b4027d7b +Subproject commit 310fc60af9a3710ecb3d99d67b3cf0928c765e06 diff --git a/build.gradle b/build.gradle index ff91782e..f527a318 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,14 @@ plugins { + id 'java-library' id 'eclipse' id 'idea' id 'maven-publish' - id 'net.neoforged.gradle' version '[6.0.18,6.2)' - id 'org.spongepowered.mixin' version '0.7.+' - id 'org.parchmentmc.librarian.forgegradle' version '1.+' + id 'net.neoforged.gradle.userdev' version '7.0.+' + id 'net.neoforged.gradle.mixin' version '7.0.+' } -evaluationDependsOnChildren() +evaluationDependsOn(':Phosphophyllite') +evaluationDependsOn(':Quartz') version = "${majorVersion}.${minorVersion}.${patchVersion}" if (!"${postfixVersion}".isEmpty()) { @@ -20,63 +21,53 @@ base { } java.toolchain.languageVersion = JavaLanguageVersion.of(17) -println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" - -minecraft { - mappings channel: mapping_channel, version: mapping_version - - copyIdeResources = true - accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - - runs { - // applies to all the run configs below - configureEach { - workingDirectory project.file("run/${it.name}") - - property 'forge.logging.markers', 'SCAN,REGISTRIES' - property 'forge.logging.console.level', 'debug' - - mods { - "${mod_id}" { - source sourceSets.main - } - Quartz { - source project(':Quartz').sourceSets.main - } - Phosphophyllite { - source project(':Phosphophyllite').sourceSets.main - } + +//accessTransformers { +// file 'src/main/resources/META-INF/accesstransformer.cfg' +//} + +runs { + configureEach { + workingDirectory project.file("run/${it.name}") + + systemProperty 'forge.logging.markers', 'SCAN,REGISTRIES' + systemProperty 'forge.logging.console.level', 'debug' + + modSource project.sourceSets.main + modSource project(':Quartz').sourceSets.main + modSource project(':Phosphophyllite').sourceSets.main + + dependencies { + runtime("org.lwjgl:lwjgl-opencl:3.3.1") { + transitive(false) + } + runtime("org.lwjgl:lwjgl-vulkan:3.3.1"){ + transitive(false) } } + } - client { - // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. - property 'forge.enabledGameTestNamespaces', mod_id - } + client { + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + } - server { - property 'forge.enabledGameTestNamespaces', mod_id - args '--nogui' - } + server { + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + programArgument '--nogui' + } - gameTestServer { - property 'forge.enabledGameTestNamespaces', mod_id - } + gameTestServer { + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + } - data { - args '--mod', mod_id, '--all', '--existing-mod', 'biggerreactors', '--existing-mod', 'phosphophyllite', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') - } + data { + programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() } } // Include resources generated by data generators. sourceSets.main.resources { srcDir 'src/generated/resources' } -mixin { - config 'quartz.mixins.json' - config 'phosphophyllite.mixins.json' -} - repositories { maven { url = "https://www.cursemaven.com" @@ -101,39 +92,39 @@ repositories { } dependencies { - minecraft "net.neoforged:forge:${mc_version}-${neo_version}" + implementation "net.neoforged:neoforge:${neo_version}" compileOnly project(':Phosphophyllite') compileOnly project(':Quartz') compileOnly("cc.tweaked:cc-tweaked-${cc_mc_version}-core-api:${cc_version}") - compileOnly(fg.deobf("cc.tweaked:cc-tweaked-${cc_mc_version}-forge-api:${cc_version}")) - runtimeOnly(fg.deobf("cc.tweaked:cc-tweaked-${cc_mc_version}-forge:${cc_version}")) + compileOnly("cc.tweaked:cc-tweaked-${cc_mc_version}-forge-api:${cc_version}") +// runtimeOnly("cc.tweaked:cc-tweaked-${cc_mc_version}-forge:${cc_version}") - compileOnly(fg.deobf("mezz.jei:jei-${jei_mc_version}-common-api:${jei_version}")) - compileOnly(fg.deobf("mezz.jei:jei-${jei_mc_version}-forge-api:${jei_version}")) + compileOnly("mezz.jei:jei-${jei_mc_version}-common-api:${jei_version}") + compileOnly("mezz.jei:jei-${jei_mc_version}-forge-api:${jei_version}") // at runtime, use the full JEI jar for Forge - runtimeOnly(fg.deobf("mezz.jei:jei-${jei_mc_version}-forge:${jei_version}")) +// runtimeOnly("mezz.jei:jei-${jei_mc_version}-forge:${jei_version}") compileOnly "mekanism:Mekanism:1.19.2-10.3.5.474:api" -// runtimeOnly fg.deobf('curse.maven:MEK-268560:4041164') -// runtimeOnly fg.deobf('curse.maven:MEKG-268566:4041168') -// runtimeOnly fg.deobf('curse.maven:COFHCore-69162:4385216') -// runtimeOnly fg.deobf('curse.maven:ThermalFoundation-222880:4382373') -// runtimeOnly fg.deobf('curse.maven:ThermalExpansion-69163:4382371') -// runtimeOnly fg.deobf('curse.maven:ThermalDynamics-227443:4391160') +// runtimeOnly 'curse.maven:MEK-268560:4041164' +// runtimeOnly 'curse.maven:MEKG-268566:4041168' +// runtimeOnly 'curse.maven:COFHCore-69162:4385216' +// runtimeOnly 'curse.maven:ThermalFoundation-222880:4382373' +// runtimeOnly 'curse.maven:ThermalExpansion-69163:4382371' +// runtimeOnly 'curse.maven:ThermalDynamics-227443:4391160' -// runtimeOnly fg.deobf('curse.maven:Rubidium-574856:4448157') - runtimeOnly fg.deobf('curse.maven:Oculus-581495:4578741') +// runtimeOnly 'curse.maven:Rubidium-574856:4448157' +// runtimeOnly 'curse.maven:Oculus-581495:4578741' -// runtimeOnly fg.deobf('curse.maven:WorldStripper-250603:3545856') -// runtimeOnly fg.deobf('curse.maven:CW-399558:3926815') +// runtimeOnly 'curse.maven:WorldStripper-250603:3545856') +// runtimeOnly 'curse.maven:CW-399558:3926815') - minecraftLibrary("org.lwjgl:lwjgl-opencl:3.3.1") { + compileOnly("org.lwjgl:lwjgl-opencl:3.3.1") { transitive(false) } - minecraftLibrary ("org.lwjgl:lwjgl-vulkan:3.3.1"){ + compileOnly("org.lwjgl:lwjgl-vulkan:3.3.1"){ transitive(false) } } @@ -159,7 +150,7 @@ gradle.projectsEvaluated { var replaceProperties = [ minecraft_version : mc_version, neo_version : neo_version, - loader_version : neo_version.substring(0, neo_version.indexOf('.')), + loader_version : loader_version, version : version, phos_version_range : project.project(":Phosphophyllite").property("compatibility").toString(), quartz_version_range: project.project(":Quartz").property("compatibility").toString(), @@ -215,27 +206,22 @@ publishing { } } -// NeoGradle is dumb, and generates the run configs incorrectly, this fixes them -tasks.register('zzz_copyRunConfigsToTmpDir', Copy) { - from '.idea/runConfigurations' - into '.idea/runConfigurations1' -} - -tasks.register('zzz_depeteTmpDir', Delete) { - delete '.idea/runConfigurations1' -} - -tasks.register('_createIntellijRunsThatWork', Copy) { - dependsOn 'genIntellijRuns' - mustRunAfter 'genIntellijRuns' - dependsOn 'zzz_copyRunConfigsToTmpDir' - mustRunAfter 'zzz_copyRunConfigsToTmpDir' +// NeoGradle bug, this works around it +gradle.projectsEvaluated { + var subProjects = List.of(project.project(':Quartz'), project.project(':Phosphophyllite')) - from '.idea/runConfigurations1' - into '.idea/runConfigurations' - filter { String line -> line.replace("out/production/classes", "build/classes/java/main") } - filter { String line -> line.replace("out/production/resources", "build/resources/main") } - filter { String line -> line.replace("copyIntellijResources", "prepareRunClientCompile") } + var neoFormJoinDownloadAssetsTaskName = null + for (final def taskName in project.tasks.getNames()) { + if (taskName.contains("neoFormJoined") && taskName.contains("DownloadAssets")) { + neoFormJoinDownloadAssetsTaskName = taskName + break + } + } - finalizedBy 'zzz_depeteTmpDir' + var lastTask = project.tasks.getByPath(neoFormJoinDownloadAssetsTaskName) + for (final def subProject in subProjects) { + var nextTask = subProject.tasks.getByPath(neoFormJoinDownloadAssetsTaskName); + lastTask.mustRunAfter(nextTask) + lastTask = nextTask + } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 23cf7483..5cbdcf29 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,12 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -mc_version=1.20.1 -mapping_channel=parchment -mapping_version=2023.07.09-1.20.1 -neo_version=47.1.76 +mc_version=1.20.4 +mapping_channel=official +mapping_version=1.20.4 +neo_version=20.4.156-beta +loader_version=1 + cc_mc_version=1.20.1 cc_version=1.106.1 diff --git a/src/main/java/net/roguelogix/biggerreactors/BiggerReactors.java b/src/main/java/net/roguelogix/biggerreactors/BiggerReactors.java index 02eb950f..2c6998ad 100644 --- a/src/main/java/net/roguelogix/biggerreactors/BiggerReactors.java +++ b/src/main/java/net/roguelogix/biggerreactors/BiggerReactors.java @@ -3,13 +3,11 @@ import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.fml.loading.FMLLoader; -import net.roguelogix.biggerreactors.machine.client.CyaniteReprocessorScreen; -import net.roguelogix.biggerreactors.machine.containers.CyaniteReprocessorContainer; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.common.NeoForge; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.client.HeatExchangerFluidPortScreen; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.client.HeatExchangerTerminalScreen; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.containers.HeatExchangerFluidPortContainer; @@ -41,8 +39,8 @@ public class BiggerReactors { public BiggerReactors() { new Registry(new ReferenceArrayList<>(), ReferenceArrayList.of(new ResourceLocation(Phosphophyllite.modid, "creative_tab"), new ResourceLocation(Quartz.modid, "creative_tab"))); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetup); - MinecraftForge.EVENT_BUS.addListener(this::onReloadData); + ModLoadingContext.get().getActiveContainer().getEventBus().addListener(this::onClientSetup); + NeoForge.EVENT_BUS.addListener(this::onReloadData); version = FMLLoader.getLoadingModList().getModFileById(modid).versionString(); } @@ -55,8 +53,8 @@ public void onReloadData(final ReloadDataEvent reloadDataEvent) { public void onClientSetup(final FMLClientSetupEvent e) { // TODO: 6/28/20 Registry. // Since I already have the comment here, also need to do a capability registry. I have a somewhat dumb capability to register. - MenuScreens.register(CyaniteReprocessorContainer.INSTANCE, - CyaniteReprocessorScreen::new); +// MenuScreens.register(CyaniteReprocessorContainer.INSTANCE, +// CyaniteReprocessorScreen::new); MenuScreens.register(ReactorTerminalContainer.INSTANCE, CommonReactorTerminalScreen::new); MenuScreens.register(ReactorCoolantPortContainer.INSTANCE, diff --git a/src/main/java/net/roguelogix/biggerreactors/blocks/materials/DeepslateUraniumOre.java b/src/main/java/net/roguelogix/biggerreactors/blocks/materials/DeepslateUraniumOre.java index be5fd761..21551e33 100644 --- a/src/main/java/net/roguelogix/biggerreactors/blocks/materials/DeepslateUraniumOre.java +++ b/src/main/java/net/roguelogix/biggerreactors/blocks/materials/DeepslateUraniumOre.java @@ -1,5 +1,6 @@ package net.roguelogix.biggerreactors.blocks.materials; +import net.minecraft.util.valueproviders.ConstantInt; import net.minecraft.world.level.block.DropExperienceBlock; import net.minecraft.world.level.block.SoundType; import net.roguelogix.phosphophyllite.registry.RegisterBlock; @@ -11,7 +12,7 @@ public class DeepslateUraniumOre extends DropExperienceBlock { public static final DeepslateUraniumOre INSTANCE = new DeepslateUraniumOre(); public DeepslateUraniumOre() { - super( + super(ConstantInt.of(0), Properties.of() .sound(SoundType.DEEPSLATE) .explosionResistance(3.0F) diff --git a/src/main/java/net/roguelogix/biggerreactors/blocks/materials/UraniumOre.java b/src/main/java/net/roguelogix/biggerreactors/blocks/materials/UraniumOre.java index bca46dcd..f1716e01 100644 --- a/src/main/java/net/roguelogix/biggerreactors/blocks/materials/UraniumOre.java +++ b/src/main/java/net/roguelogix/biggerreactors/blocks/materials/UraniumOre.java @@ -1,5 +1,6 @@ package net.roguelogix.biggerreactors.blocks.materials; +import net.minecraft.util.valueproviders.ConstantInt; import net.minecraft.world.level.block.DropExperienceBlock; import net.minecraft.world.level.block.SoundType; import net.roguelogix.phosphophyllite.registry.RegisterBlock; @@ -10,7 +11,7 @@ public class UraniumOre extends DropExperienceBlock { public static final UraniumOre INSTANCE = new UraniumOre(); public UraniumOre() { - super( + super(ConstantInt.of(0), Properties.of() .sound(SoundType.STONE) .explosionResistance(3.0F) diff --git a/src/main/java/net/roguelogix/biggerreactors/client/Biselector.java b/src/main/java/net/roguelogix/biggerreactors/client/Biselector.java index 6eeb74cd..5e91958b 100644 --- a/src/main/java/net/roguelogix/biggerreactors/client/Biselector.java +++ b/src/main/java/net/roguelogix/biggerreactors/client/Biselector.java @@ -6,8 +6,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; import net.roguelogix.phosphophyllite.client.gui.RenderHelper; import net.roguelogix.phosphophyllite.client.gui.elements.InteractiveElement; diff --git a/src/main/java/net/roguelogix/biggerreactors/client/CommonButton.java b/src/main/java/net/roguelogix/biggerreactors/client/CommonButton.java index 1cd83a89..4d553479 100644 --- a/src/main/java/net/roguelogix/biggerreactors/client/CommonButton.java +++ b/src/main/java/net/roguelogix/biggerreactors/client/CommonButton.java @@ -6,8 +6,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.phosphophyllite.client.gui.RenderHelper; import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; import net.roguelogix.phosphophyllite.client.gui.elements.InteractiveElement; diff --git a/src/main/java/net/roguelogix/biggerreactors/client/CommonRender.java b/src/main/java/net/roguelogix/biggerreactors/client/CommonRender.java index c810e688..ede26eda 100644 --- a/src/main/java/net/roguelogix/biggerreactors/client/CommonRender.java +++ b/src/main/java/net/roguelogix/biggerreactors/client/CommonRender.java @@ -6,9 +6,9 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.fluids.FluidStack; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.phosphophyllite.client.gui.RenderHelper; import net.roguelogix.phosphophyllite.client.gui.elements.RenderedElement; diff --git a/src/main/java/net/roguelogix/biggerreactors/client/TextBox.java b/src/main/java/net/roguelogix/biggerreactors/client/TextBox.java index d51626f2..ec2396d1 100644 --- a/src/main/java/net/roguelogix/biggerreactors/client/TextBox.java +++ b/src/main/java/net/roguelogix/biggerreactors/client/TextBox.java @@ -11,8 +11,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; import net.roguelogix.phosphophyllite.client.gui.RenderHelper; diff --git a/src/main/java/net/roguelogix/biggerreactors/client/Triselector.java b/src/main/java/net/roguelogix/biggerreactors/client/Triselector.java index a8e388d6..d4feb169 100644 --- a/src/main/java/net/roguelogix/biggerreactors/client/Triselector.java +++ b/src/main/java/net/roguelogix/biggerreactors/client/Triselector.java @@ -1,16 +1,15 @@ package net.roguelogix.biggerreactors.client; -import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.phosphophyllite.client.gui.RenderHelper; -import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; import net.roguelogix.phosphophyllite.client.gui.elements.InteractiveElement; +import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/net/roguelogix/biggerreactors/client/deps/jei/BiggerReactorsJEIPlugin.java b/src/main/java/net/roguelogix/biggerreactors/client/deps/jei/BiggerReactorsJEIPlugin.java index 8f395064..9ee76e67 100644 --- a/src/main/java/net/roguelogix/biggerreactors/client/deps/jei/BiggerReactorsJEIPlugin.java +++ b/src/main/java/net/roguelogix/biggerreactors/client/deps/jei/BiggerReactorsJEIPlugin.java @@ -10,7 +10,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.AirBlock; import net.minecraft.world.level.block.LiquidBlock; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidStack; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.client.deps.jei.classic.reactor.BlockModeratorCategory; diff --git a/src/main/java/net/roguelogix/biggerreactors/client/deps/jei/classic/reactor/FluidModeratorCategory.java b/src/main/java/net/roguelogix/biggerreactors/client/deps/jei/classic/reactor/FluidModeratorCategory.java index 51ff7c1c..5f25b7e7 100644 --- a/src/main/java/net/roguelogix/biggerreactors/client/deps/jei/classic/reactor/FluidModeratorCategory.java +++ b/src/main/java/net/roguelogix/biggerreactors/client/deps/jei/classic/reactor/FluidModeratorCategory.java @@ -1,6 +1,5 @@ package net.roguelogix.biggerreactors.client.deps.jei.classic.reactor; -import com.mojang.blaze3d.vertex.PoseStack; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IRecipeSlotsView; @@ -14,7 +13,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidStack; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorTerminal; import net.roguelogix.biggerreactors.registries.ReactorModeratorRegistry; diff --git a/src/main/java/net/roguelogix/biggerreactors/machine/blocks/CyaniteReprocessor.java b/src/main/java/net/roguelogix/biggerreactors/machine/blocks/CyaniteReprocessor.java index 01d58056..a48b1fb4 100644 --- a/src/main/java/net/roguelogix/biggerreactors/machine/blocks/CyaniteReprocessor.java +++ b/src/main/java/net/roguelogix/biggerreactors/machine/blocks/CyaniteReprocessor.java @@ -1,108 +1,107 @@ -package net.roguelogix.biggerreactors.machine.blocks; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.*; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityTicker; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.common.ToolAction; -import net.roguelogix.biggerreactors.machine.tiles.CyaniteReprocessorTile; -import net.roguelogix.phosphophyllite.registry.RegisterBlock; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class CyaniteReprocessor extends BaseEntityBlock implements EntityBlock{ - - public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - public static final BooleanProperty ENABLED = BlockStateProperties.ENABLED; - - @RegisterBlock(name = "cyanite_reprocessor", tileEntityClass = CyaniteReprocessorTile.class) - public static final CyaniteReprocessor INSTANCE = new CyaniteReprocessor(); - - public CyaniteReprocessor() { - super(Properties.of() - .sound(SoundType.STONE) - .destroyTime(1.0F) - .explosionResistance(1.0F) - .requiresCorrectToolForDrops()); - this.registerDefaultState(this.getStateDefinition().any() - .setValue(FACING, Direction.NORTH) - .setValue(ENABLED, Boolean.FALSE)); - } - - public static Direction getFacingFromEntity(BlockPos clickedBlockPos, LivingEntity entity) { - return Direction.getNearest((float) (entity.getX() - clickedBlockPos.getX()), 0.0F, (float) (entity.getZ() - clickedBlockPos.getZ())); - } - - @Nonnull - @Override - public RenderShape getRenderShape(@Nonnull BlockState blockState) { - return RenderShape.MODEL; - } - - @Nullable - @Override - public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { - return CyaniteReprocessorTile.SUPPLIER.create(pos, state); - } - - @Nullable - @Override - public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { - return (a, b, c, tile) -> { - assert tile instanceof CyaniteReprocessorTile; - ((CyaniteReprocessorTile) tile).tick(); - }; - } - - @Override - public void createBlockStateDefinition(StateDefinition.Builder builder) { - builder.add(FACING).add(ENABLED); - } - - @Nonnull - @Override - public InteractionResult use(@Nonnull BlockState blockState, Level world, @Nonnull BlockPos blockPos, @Nonnull Player player, @Nonnull InteractionHand hand, @Nonnull BlockHitResult trace) { - BlockEntity tile = world.getBlockEntity(blockPos); - if (tile instanceof CyaniteReprocessorTile) { - return ((CyaniteReprocessorTile) tile).onBlockActivated(blockState, world, blockPos, player, hand, trace); - } - return InteractionResult.FAIL; - } - - - - @Override - public void onRemove(BlockState blockState, Level world, BlockPos blockPos, BlockState newBlockState, boolean isMoving) { - if (blockState.getBlock() != newBlockState.getBlock()) { - BlockEntity tile = world.getBlockEntity(blockPos); - if (tile instanceof CyaniteReprocessorTile) { - ((CyaniteReprocessorTile) tile).onReplaced(blockState, world, blockPos, newBlockState, isMoving); - } - super.onRemove(blockState, world, blockPos, newBlockState, isMoving); - } - } - - @Override - public void setPlacedBy(@Nonnull Level world, @Nonnull BlockPos blockPos, @Nonnull BlockState blockState, @Nullable LivingEntity entity, @Nonnull ItemStack stack) { - if (entity != null) { - world.setBlock(blockPos, blockState - .setValue(FACING, getFacingFromEntity(blockPos, entity)) - .setValue(ENABLED, false), 2); - } - } -} +//package net.roguelogix.biggerreactors.machine.blocks; +// +//import net.minecraft.core.BlockPos; +//import net.minecraft.core.Direction; +//import net.minecraft.world.InteractionHand; +//import net.minecraft.world.InteractionResult; +//import net.minecraft.world.entity.LivingEntity; +//import net.minecraft.world.entity.player.Player; +//import net.minecraft.world.item.ItemStack; +//import net.minecraft.world.level.Level; +//import net.minecraft.world.level.block.*; +//import net.minecraft.world.level.block.entity.BlockEntity; +//import net.minecraft.world.level.block.entity.BlockEntityTicker; +//import net.minecraft.world.level.block.entity.BlockEntityType; +//import net.minecraft.world.level.block.state.BlockState; +//import net.minecraft.world.level.block.state.StateDefinition; +//import net.minecraft.world.level.block.state.properties.BlockStateProperties; +//import net.minecraft.world.level.block.state.properties.BooleanProperty; +//import net.minecraft.world.level.block.state.properties.DirectionProperty; +//import net.minecraft.world.phys.BlockHitResult; +//import net.roguelogix.biggerreactors.machine.tiles.CyaniteReprocessorTile; +//import net.roguelogix.phosphophyllite.registry.RegisterBlock; +// +//import javax.annotation.Nonnull; +//import javax.annotation.Nullable; +// +//public class CyaniteReprocessor extends Block implements EntityBlock{ +// +// public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; +// public static final BooleanProperty ENABLED = BlockStateProperties.ENABLED; +// +// @RegisterBlock(name = "cyanite_reprocessor", tileEntityClass = CyaniteReprocessorTile.class) +// public static final CyaniteReprocessor INSTANCE = new CyaniteReprocessor(); +// +// public CyaniteReprocessor() { +// super(Properties.of() +// .sound(SoundType.STONE) +// .destroyTime(1.0F) +// .explosionResistance(1.0F) +// .requiresCorrectToolForDrops()); +// this.registerDefaultState(this.getStateDefinition().any() +// .setValue(FACING, Direction.NORTH) +// .setValue(ENABLED, Boolean.FALSE)); +// } +// +// public static Direction getFacingFromEntity(BlockPos clickedBlockPos, LivingEntity entity) { +// return Direction.getNearest((float) (entity.getX() - clickedBlockPos.getX()), 0.0F, (float) (entity.getZ() - clickedBlockPos.getZ())); +// } +// +// @Nonnull +// @Override +// public RenderShape getRenderShape(@Nonnull BlockState blockState) { +// return RenderShape.MODEL; +// } +// +// @Nullable +// @Override +// public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { +// return CyaniteReprocessorTile.SUPPLIER.create(pos, state); +// } +// +// @Nullable +// @Override +// public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { +// return (a, b, c, tile) -> { +// assert tile instanceof CyaniteReprocessorTile; +// ((CyaniteReprocessorTile) tile).tick(); +// }; +// } +// +// @Override +// public void createBlockStateDefinition(StateDefinition.Builder builder) { +// builder.add(FACING).add(ENABLED); +// } +// +// @Nonnull +// @Override +// public InteractionResult use(@Nonnull BlockState blockState, Level world, @Nonnull BlockPos blockPos, @Nonnull Player player, @Nonnull InteractionHand hand, @Nonnull BlockHitResult trace) { +// BlockEntity tile = world.getBlockEntity(blockPos); +// if (tile instanceof CyaniteReprocessorTile) { +// return ((CyaniteReprocessorTile) tile).onBlockActivated(blockState, world, blockPos, player, hand, trace); +// } +// return InteractionResult.FAIL; +// } +// +// +// +// @Override +// public void onRemove(BlockState blockState, Level world, BlockPos blockPos, BlockState newBlockState, boolean isMoving) { +// if (blockState.getBlock() != newBlockState.getBlock()) { +// BlockEntity tile = world.getBlockEntity(blockPos); +// if (tile instanceof CyaniteReprocessorTile) { +// ((CyaniteReprocessorTile) tile).onReplaced(blockState, world, blockPos, newBlockState, isMoving); +// } +// super.onRemove(blockState, world, blockPos, newBlockState, isMoving); +// } +// } +// +// @Override +// public void setPlacedBy(@Nonnull Level world, @Nonnull BlockPos blockPos, @Nonnull BlockState blockState, @Nullable LivingEntity entity, @Nonnull ItemStack stack) { +// if (entity != null) { +// world.setBlock(blockPos, blockState +// .setValue(FACING, getFacingFromEntity(blockPos, entity)) +// .setValue(ENABLED, false), 2); +// } +// } +//} diff --git a/src/main/java/net/roguelogix/biggerreactors/machine/client/CyaniteReprocessorScreen.java b/src/main/java/net/roguelogix/biggerreactors/machine/client/CyaniteReprocessorScreen.java index 35f2a0fa..466310a5 100644 --- a/src/main/java/net/roguelogix/biggerreactors/machine/client/CyaniteReprocessorScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/machine/client/CyaniteReprocessorScreen.java @@ -1,117 +1,117 @@ -package net.roguelogix.biggerreactors.machine.client; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.level.material.Fluids; -import net.roguelogix.biggerreactors.BiggerReactors; -import net.roguelogix.biggerreactors.client.CommonRender; -import net.roguelogix.biggerreactors.machine.containers.CyaniteReprocessorContainer; -import net.roguelogix.biggerreactors.machine.state.CyaniteReprocessorState; -import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; -import net.roguelogix.phosphophyllite.client.gui.RenderHelper; -import net.roguelogix.phosphophyllite.client.gui.elements.RenderedElement; -import net.roguelogix.phosphophyllite.client.gui.elements.TooltipElement; - -import javax.annotation.Nonnull; - -public class CyaniteReprocessorScreen extends PhosphophylliteScreen { - - private static final ResourceLocation DEFAULT_TEXTURE = new ResourceLocation(BiggerReactors.modid, "textures/screen/cyanite_reprocessor.png"); - - private CyaniteReprocessorState cyaniteReprocessorState; - - public CyaniteReprocessorScreen(CyaniteReprocessorContainer container, Inventory playerInventory, Component title) { - super(container, playerInventory, title, DEFAULT_TEXTURE, 176, 175); - - // Initialize reprocessor state. - cyaniteReprocessorState = (CyaniteReprocessorState) this.getMenu().getGuiPacket(); - } - - /** - * Initialize the screen. - */ - @Override - public void init() { - super.init(); - - // Set title to be drawn in the center. - this.titleLabelX = (this.getXSize() / 2) - (this.getFont().width(this.getTitle()) / 2); - - // Initialize tooltips: - this.initTooltips(); - - // Initialize controls: - - // Initialize gauges: - this.initGauges(); - - // Initialize symbols: - this.initSymbols(); - } - - /** - * Initialize tooltips. - */ - public void initTooltips() { - // (Left) Internal battery: - this.addScreenElement(new TooltipElement<>(this, 8, 6, 16, 16, Component.translatable("screen.biggerreactors.cyanite_reprocessor.internal_battery.tooltip"))); - } - - /** - * Initialize gauges. - */ - public void initGauges() { - // (Top) Internal battery: - RenderedElement internalBattery = new RenderedElement<>(this, 7, 25, 18, 64, 0, 152, Component.empty()); - internalBattery.onRender = (@Nonnull GuiGraphics graphics, int mX, int mY) -> CommonRender.renderEnergyGauge(graphics, - internalBattery, cyaniteReprocessorState.energyStored, cyaniteReprocessorState.energyCapacity); - this.addScreenElement(internalBattery); - - // (Top) Water tank: - RenderedElement waterTank = new RenderedElement<>(this, 151, 25, 18, 64, 0, 152, Component.empty()); - waterTank.onRender = (@Nonnull GuiGraphics graphics, int mX, int mY) -> CommonRender.renderFluidGauge(graphics, - waterTank, cyaniteReprocessorState.waterStored, cyaniteReprocessorState.waterCapacity, - Fluids.WATER.getSource()); - this.addScreenElement(waterTank); - - // (Center) Progress bar: - RenderedElement progressBar = new RenderedElement<>(this, 75, 40, 24, 18, 0, 175, null); - progressBar.onRender = (@Nonnull GuiGraphics graphics, int mX, int mY) -> CyaniteReprocessorScreen.renderProgressBar(graphics, - progressBar, cyaniteReprocessorState.workTime, cyaniteReprocessorState.workTimeTotal); - this.addScreenElement(progressBar); - } - - /** - * Initialize symbols. - */ - public void initSymbols() { - // (Right) Water tank symbol: - RenderedElement waterTankSymbol = new RenderedElement<>(this, 152, 6, 16, 16, 48, 175, Component.translatable("screen.biggerreactors.cyanite_reprocessor.water_tank.tooltip")); - waterTankSymbol.onRender = (@Nonnull GuiGraphics graphics, int mX, int mY) -> RenderHelper.drawMaskedFluid(graphics, - waterTankSymbol.x, waterTankSymbol.y, 0, - waterTankSymbol.width, waterTankSymbol.height, - waterTankSymbol.u, waterTankSymbol.v, Fluids.WATER.getSource()); - this.addScreenElement(waterTankSymbol); - } - - /** - * Render the progress bar. - * - * @param poseStack The current pose stack. - * @param symbol The symbol to draw as. - * @param workTime The time the machine has been working. - * @param workTimeTotal The total time needed for completion. - */ - private static void renderProgressBar(@Nonnull GuiGraphics graphics, @Nonnull RenderedElement symbol, int workTime, int workTimeTotal) { - // If there's no progress, there's no need to draw. - if ((workTime > 0) && (workTimeTotal > 0)) { - // Calculate how much needs to be rendered. - int renderSize = (int) ((symbol.width * workTime) / workTimeTotal); - // Render progress. - symbol.blit(graphics, renderSize, symbol.height, symbol.u + 24, symbol.v); - } - } -} +//package net.roguelogix.biggerreactors.machine.client; +// +//import com.mojang.blaze3d.vertex.PoseStack; +//import net.minecraft.client.gui.GuiGraphics; +//import net.minecraft.network.chat.Component; +//import net.minecraft.resources.ResourceLocation; +//import net.minecraft.world.entity.player.Inventory; +//import net.minecraft.world.level.material.Fluids; +//import net.roguelogix.biggerreactors.BiggerReactors; +//import net.roguelogix.biggerreactors.client.CommonRender; +//import net.roguelogix.biggerreactors.machine.containers.CyaniteReprocessorContainer; +//import net.roguelogix.biggerreactors.machine.state.CyaniteReprocessorState; +//import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; +//import net.roguelogix.phosphophyllite.client.gui.RenderHelper; +//import net.roguelogix.phosphophyllite.client.gui.elements.RenderedElement; +//import net.roguelogix.phosphophyllite.client.gui.elements.TooltipElement; +// +//import javax.annotation.Nonnull; +// +//public class CyaniteReprocessorScreen extends PhosphophylliteScreen { +// +// private static final ResourceLocation DEFAULT_TEXTURE = new ResourceLocation(BiggerReactors.modid, "textures/screen/cyanite_reprocessor.png"); +// +// private CyaniteReprocessorState cyaniteReprocessorState; +// +// public CyaniteReprocessorScreen(CyaniteReprocessorContainer container, Inventory playerInventory, Component title) { +// super(container, playerInventory, title, DEFAULT_TEXTURE, 176, 175); +// +// // Initialize reprocessor state. +// cyaniteReprocessorState = (CyaniteReprocessorState) this.getMenu().getGuiPacket(); +// } +// +// /** +// * Initialize the screen. +// */ +// @Override +// public void init() { +// super.init(); +// +// // Set title to be drawn in the center. +// this.titleLabelX = (this.getXSize() / 2) - (this.getFont().width(this.getTitle()) / 2); +// +// // Initialize tooltips: +// this.initTooltips(); +// +// // Initialize controls: +// +// // Initialize gauges: +// this.initGauges(); +// +// // Initialize symbols: +// this.initSymbols(); +// } +// +// /** +// * Initialize tooltips. +// */ +// public void initTooltips() { +// // (Left) Internal battery: +// this.addScreenElement(new TooltipElement<>(this, 8, 6, 16, 16, Component.translatable("screen.biggerreactors.cyanite_reprocessor.internal_battery.tooltip"))); +// } +// +// /** +// * Initialize gauges. +// */ +// public void initGauges() { +// // (Top) Internal battery: +// RenderedElement internalBattery = new RenderedElement<>(this, 7, 25, 18, 64, 0, 152, Component.empty()); +// internalBattery.onRender = (@Nonnull GuiGraphics graphics, int mX, int mY) -> CommonRender.renderEnergyGauge(graphics, +// internalBattery, cyaniteReprocessorState.energyStored, cyaniteReprocessorState.energyCapacity); +// this.addScreenElement(internalBattery); +// +// // (Top) Water tank: +// RenderedElement waterTank = new RenderedElement<>(this, 151, 25, 18, 64, 0, 152, Component.empty()); +// waterTank.onRender = (@Nonnull GuiGraphics graphics, int mX, int mY) -> CommonRender.renderFluidGauge(graphics, +// waterTank, cyaniteReprocessorState.waterStored, cyaniteReprocessorState.waterCapacity, +// Fluids.WATER.getSource()); +// this.addScreenElement(waterTank); +// +// // (Center) Progress bar: +// RenderedElement progressBar = new RenderedElement<>(this, 75, 40, 24, 18, 0, 175, null); +// progressBar.onRender = (@Nonnull GuiGraphics graphics, int mX, int mY) -> CyaniteReprocessorScreen.renderProgressBar(graphics, +// progressBar, cyaniteReprocessorState.workTime, cyaniteReprocessorState.workTimeTotal); +// this.addScreenElement(progressBar); +// } +// +// /** +// * Initialize symbols. +// */ +// public void initSymbols() { +// // (Right) Water tank symbol: +// RenderedElement waterTankSymbol = new RenderedElement<>(this, 152, 6, 16, 16, 48, 175, Component.translatable("screen.biggerreactors.cyanite_reprocessor.water_tank.tooltip")); +// waterTankSymbol.onRender = (@Nonnull GuiGraphics graphics, int mX, int mY) -> RenderHelper.drawMaskedFluid(graphics, +// waterTankSymbol.x, waterTankSymbol.y, 0, +// waterTankSymbol.width, waterTankSymbol.height, +// waterTankSymbol.u, waterTankSymbol.v, Fluids.WATER.getSource()); +// this.addScreenElement(waterTankSymbol); +// } +// +// /** +// * Render the progress bar. +// * +// * @param poseStack The current pose stack. +// * @param symbol The symbol to draw as. +// * @param workTime The time the machine has been working. +// * @param workTimeTotal The total time needed for completion. +// */ +// private static void renderProgressBar(@Nonnull GuiGraphics graphics, @Nonnull RenderedElement symbol, int workTime, int workTimeTotal) { +// // If there's no progress, there's no need to draw. +// if ((workTime > 0) && (workTimeTotal > 0)) { +// // Calculate how much needs to be rendered. +// int renderSize = (int) ((symbol.width * workTime) / workTimeTotal); +// // Render progress. +// symbol.blit(graphics, renderSize, symbol.height, symbol.u + 24, symbol.v); +// } +// } +//} diff --git a/src/main/java/net/roguelogix/biggerreactors/machine/containers/CyaniteReprocessorContainer.java b/src/main/java/net/roguelogix/biggerreactors/machine/containers/CyaniteReprocessorContainer.java index 5831c58a..385bab9f 100644 --- a/src/main/java/net/roguelogix/biggerreactors/machine/containers/CyaniteReprocessorContainer.java +++ b/src/main/java/net/roguelogix/biggerreactors/machine/containers/CyaniteReprocessorContainer.java @@ -1,116 +1,116 @@ -package net.roguelogix.biggerreactors.machine.containers; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.ContainerLevelAccess; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.SlotItemHandler; -import net.roguelogix.biggerreactors.machine.blocks.CyaniteReprocessor; -import net.roguelogix.biggerreactors.machine.tiles.CyaniteReprocessorTile; -import net.roguelogix.biggerreactors.machine.tiles.impl.CyaniteReprocessorItemHandler; -import net.roguelogix.phosphophyllite.client.gui.GuiSync; -import net.roguelogix.phosphophyllite.registry.ContainerSupplier; -import net.roguelogix.phosphophyllite.registry.RegisterContainer; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -@RegisterContainer(name = "cyanite_reprocessor") -public class CyaniteReprocessorContainer extends AbstractContainerMenu implements GuiSync.IGUIPacketProvider { - - @RegisterContainer.Type - public static MenuType INSTANCE; - @RegisterContainer.Supplier - public static final ContainerSupplier SUPPLIER = CyaniteReprocessorContainer::new; - - private Player player; - private CyaniteReprocessorTile tileEntity; - - public CyaniteReprocessorContainer(int windowId, BlockPos blockPos, Player player) { - super(CyaniteReprocessorContainer.INSTANCE, windowId); - this.player = player; - this.tileEntity = (CyaniteReprocessorTile) player.level().getBlockEntity(blockPos); - this.getGuiPacket(); - - // Populate machine slots. - if (this.tileEntity != null) { - IItemHandler handler = tileEntity.getItemHandler(); - // Add input slot. - this.addSlot(new SlotItemHandler(handler, CyaniteReprocessorItemHandler.INPUT_SLOT_INDEX, 44, 41)); - // Add output slot. - this.addSlot(new SlotItemHandler(handler, CyaniteReprocessorItemHandler.OUTPUT_SLOT_INDEX, 116, 41)); - } - - // Populate player inventory. - this.populatePlayerInventory(); - } - - /** - * @return The current state of the machine. - */ - @Nullable - @Override - public GuiSync.IGUIPacket getGuiPacket() { - return this.tileEntity.cyaniteReprocessorState; - } - - @Override - public boolean stillValid(@Nonnull Player player) { - assert this.tileEntity.getLevel() != null; - return stillValid(ContainerLevelAccess.create(tileEntity.getLevel(), tileEntity.getBlockPos()), - player, CyaniteReprocessor.INSTANCE); - } - - @Nonnull - @Override - public ItemStack quickMoveStack(@Nonnull Player player, int index) { - ItemStack itemStackA = ItemStack.EMPTY; - Slot slot = this.slots.get(index); - int inventorySize = this.tileEntity.getContainerSize(); - - if (slot.hasItem()) { - ItemStack itemStackB = slot.getItem(); - itemStackA = itemStackB.copy(); - - if (index < inventorySize) { - if (!this.moveItemStackTo(itemStackB, inventorySize, this.slots.size(), true)) { - return ItemStack.EMPTY; - } - } else if (!this.moveItemStackTo(itemStackB, 0, inventorySize, false)) { - return ItemStack.EMPTY; - } - - if (itemStackB.getCount() == 0) { - slot.set(ItemStack.EMPTY); - } else { - slot.setChanged(); - } - } - - return itemStackA; - } - - /** - * Draw and initialize the player's inventory. - */ - private void populatePlayerInventory() { - int guiOffset = 93; - - // Add player inventory; - for (int rowIndex = 0; rowIndex < 3; rowIndex++) { - for (int columnIndex = 0; columnIndex < 9; columnIndex++) { - this.addSlot(new Slot(player.getInventory(), (columnIndex + rowIndex * 9 + 9), - (8 + columnIndex * 18), (guiOffset + rowIndex * 18))); - } - } - // Add player hotbar. - for (int columnIndex = 0; columnIndex < 9; columnIndex++) { - this.addSlot( - new Slot(player.getInventory(), columnIndex, (8 + columnIndex * 18), (guiOffset + 58))); - } - } -} +//package net.roguelogix.biggerreactors.machine.containers; +// +//import net.minecraft.core.BlockPos; +//import net.minecraft.world.entity.player.Player; +//import net.minecraft.world.inventory.AbstractContainerMenu; +//import net.minecraft.world.inventory.ContainerLevelAccess; +//import net.minecraft.world.inventory.MenuType; +//import net.minecraft.world.inventory.Slot; +//import net.minecraft.world.item.ItemStack; +//import net.minecraftforge.items.IItemHandler; +//import net.minecraftforge.items.SlotItemHandler; +//import net.roguelogix.biggerreactors.machine.blocks.CyaniteReprocessor; +//import net.roguelogix.biggerreactors.machine.tiles.CyaniteReprocessorTile; +//import net.roguelogix.biggerreactors.machine.tiles.impl.CyaniteReprocessorItemHandler; +//import net.roguelogix.phosphophyllite.client.gui.GuiSync; +//import net.roguelogix.phosphophyllite.registry.ContainerSupplier; +//import net.roguelogix.phosphophyllite.registry.RegisterContainer; +// +//import javax.annotation.Nonnull; +//import javax.annotation.Nullable; +// +//@RegisterContainer(name = "cyanite_reprocessor") +//public class CyaniteReprocessorContainer extends AbstractContainerMenu implements GuiSync.IGUIPacketProvider { +// +// @RegisterContainer.Type +// public static MenuType INSTANCE; +// @RegisterContainer.Supplier +// public static final ContainerSupplier SUPPLIER = CyaniteReprocessorContainer::new; +// +// private Player player; +// private CyaniteReprocessorTile tileEntity; +// +// public CyaniteReprocessorContainer(int windowId, BlockPos blockPos, Player player) { +// super(CyaniteReprocessorContainer.INSTANCE, windowId); +// this.player = player; +// this.tileEntity = (CyaniteReprocessorTile) player.level().getBlockEntity(blockPos); +// this.getGuiPacket(); +// +// // Populate machine slots. +// if (this.tileEntity != null) { +// IItemHandler handler = tileEntity.getItemHandler(); +// // Add input slot. +// this.addSlot(new SlotItemHandler(handler, CyaniteReprocessorItemHandler.INPUT_SLOT_INDEX, 44, 41)); +// // Add output slot. +// this.addSlot(new SlotItemHandler(handler, CyaniteReprocessorItemHandler.OUTPUT_SLOT_INDEX, 116, 41)); +// } +// +// // Populate player inventory. +// this.populatePlayerInventory(); +// } +// +// /** +// * @return The current state of the machine. +// */ +// @Nullable +// @Override +// public GuiSync.IGUIPacket getGuiPacket() { +// return this.tileEntity.cyaniteReprocessorState; +// } +// +// @Override +// public boolean stillValid(@Nonnull Player player) { +// assert this.tileEntity.getLevel() != null; +// return stillValid(ContainerLevelAccess.create(tileEntity.getLevel(), tileEntity.getBlockPos()), +// player, CyaniteReprocessor.INSTANCE); +// } +// +// @Nonnull +// @Override +// public ItemStack quickMoveStack(@Nonnull Player player, int index) { +// ItemStack itemStackA = ItemStack.EMPTY; +// Slot slot = this.slots.get(index); +// int inventorySize = this.tileEntity.getContainerSize(); +// +// if (slot.hasItem()) { +// ItemStack itemStackB = slot.getItem(); +// itemStackA = itemStackB.copy(); +// +// if (index < inventorySize) { +// if (!this.moveItemStackTo(itemStackB, inventorySize, this.slots.size(), true)) { +// return ItemStack.EMPTY; +// } +// } else if (!this.moveItemStackTo(itemStackB, 0, inventorySize, false)) { +// return ItemStack.EMPTY; +// } +// +// if (itemStackB.getCount() == 0) { +// slot.set(ItemStack.EMPTY); +// } else { +// slot.setChanged(); +// } +// } +// +// return itemStackA; +// } +// +// /** +// * Draw and initialize the player's inventory. +// */ +// private void populatePlayerInventory() { +// int guiOffset = 93; +// +// // Add player inventory; +// for (int rowIndex = 0; rowIndex < 3; rowIndex++) { +// for (int columnIndex = 0; columnIndex < 9; columnIndex++) { +// this.addSlot(new Slot(player.getInventory(), (columnIndex + rowIndex * 9 + 9), +// (8 + columnIndex * 18), (guiOffset + rowIndex * 18))); +// } +// } +// // Add player hotbar. +// for (int columnIndex = 0; columnIndex < 9; columnIndex++) { +// this.addSlot( +// new Slot(player.getInventory(), columnIndex, (8 + columnIndex * 18), (guiOffset + 58))); +// } +// } +//} diff --git a/src/main/java/net/roguelogix/biggerreactors/machine/state/CyaniteReprocessorState.java b/src/main/java/net/roguelogix/biggerreactors/machine/state/CyaniteReprocessorState.java index af0971fe..e94faf91 100644 --- a/src/main/java/net/roguelogix/biggerreactors/machine/state/CyaniteReprocessorState.java +++ b/src/main/java/net/roguelogix/biggerreactors/machine/state/CyaniteReprocessorState.java @@ -1,72 +1,72 @@ -package net.roguelogix.biggerreactors.machine.state; - -import net.roguelogix.biggerreactors.machine.tiles.CyaniteReprocessorTile; -import net.roguelogix.phosphophyllite.client.gui.GuiSync; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; - -public class CyaniteReprocessorState implements GuiSync.IGUIPacket { - - /** - * The number of ticks the current item has processed for. - */ - public int workTime = 0; - /** - * The total amount of time required to process the item. - */ - public int workTimeTotal = 0; - - /** - * The amount of energy stored in the machine. - */ - public int energyStored = 0; - /** - * The max energy capacity of the machine. - */ - public int energyCapacity = 0; - - /** - * The amount of water stored in the machine. - */ - public int waterStored = 0; - /** - * The max water capacity of the machine. - */ - public int waterCapacity = 0; - - /** - * The tile whose information this belongs to. - */ - CyaniteReprocessorTile cyaniteReprocessorTile; - - public CyaniteReprocessorState(CyaniteReprocessorTile cyaniteReprocessorTile) { - this.cyaniteReprocessorTile = cyaniteReprocessorTile; - } - - @Override - public void read(@Nonnull Map data) { - this.workTime = (Integer) data.get("workTime"); - this.workTimeTotal = (Integer) data.get("workTimeTotal"); - this.energyStored = (Integer) data.get("energyStored"); - this.energyCapacity = (Integer) data.get("energyCapacity"); - this.waterStored = (Integer) data.get("waterStored"); - this.waterCapacity = (Integer) data.get("waterCapacity"); - } - - @Nullable - @Override - public Map write() { - this.cyaniteReprocessorTile.updateState(); - HashMap data = new HashMap<>(); - data.put("workTime", this.workTime); - data.put("workTimeTotal", this.workTimeTotal); - data.put("energyStored", this.energyStored); - data.put("energyCapacity", this.energyCapacity); - data.put("waterStored", this.waterStored); - data.put("waterCapacity", this.waterCapacity); - return data; - } -} +//package net.roguelogix.biggerreactors.machine.state; +// +//import net.roguelogix.biggerreactors.machine.tiles.CyaniteReprocessorTile; +//import net.roguelogix.phosphophyllite.client.gui.GuiSync; +// +//import javax.annotation.Nonnull; +//import javax.annotation.Nullable; +//import java.util.HashMap; +//import java.util.Map; +// +//public class CyaniteReprocessorState implements GuiSync.IGUIPacket { +// +// /** +// * The number of ticks the current item has processed for. +// */ +// public int workTime = 0; +// /** +// * The total amount of time required to process the item. +// */ +// public int workTimeTotal = 0; +// +// /** +// * The amount of energy stored in the machine. +// */ +// public int energyStored = 0; +// /** +// * The max energy capacity of the machine. +// */ +// public int energyCapacity = 0; +// +// /** +// * The amount of water stored in the machine. +// */ +// public int waterStored = 0; +// /** +// * The max water capacity of the machine. +// */ +// public int waterCapacity = 0; +// +// /** +// * The tile whose information this belongs to. +// */ +// CyaniteReprocessorTile cyaniteReprocessorTile; +// +// public CyaniteReprocessorState(CyaniteReprocessorTile cyaniteReprocessorTile) { +// this.cyaniteReprocessorTile = cyaniteReprocessorTile; +// } +// +// @Override +// public void read(@Nonnull Map data) { +// this.workTime = (Integer) data.get("workTime"); +// this.workTimeTotal = (Integer) data.get("workTimeTotal"); +// this.energyStored = (Integer) data.get("energyStored"); +// this.energyCapacity = (Integer) data.get("energyCapacity"); +// this.waterStored = (Integer) data.get("waterStored"); +// this.waterCapacity = (Integer) data.get("waterCapacity"); +// } +// +// @Nullable +// @Override +// public Map write() { +// this.cyaniteReprocessorTile.updateState(); +// HashMap data = new HashMap<>(); +// data.put("workTime", this.workTime); +// data.put("workTimeTotal", this.workTimeTotal); +// data.put("energyStored", this.energyStored); +// data.put("energyCapacity", this.energyCapacity); +// data.put("waterStored", this.waterStored); +// data.put("waterCapacity", this.waterCapacity); +// return data; +// } +//} diff --git a/src/main/java/net/roguelogix/biggerreactors/machine/tiles/CyaniteReprocessorTile.java b/src/main/java/net/roguelogix/biggerreactors/machine/tiles/CyaniteReprocessorTile.java index 57ea9ebb..d2a79442 100644 --- a/src/main/java/net/roguelogix/biggerreactors/machine/tiles/CyaniteReprocessorTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/machine/tiles/CyaniteReprocessorTile.java @@ -1,482 +1,471 @@ -package net.roguelogix.biggerreactors.machine.tiles; - - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.*; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.energy.EnergyStorage; -import net.minecraftforge.energy.IEnergyStorage; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidTank; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.templates.FluidTank; -import net.minecraftforge.network.NetworkHooks; -import net.minecraftforge.items.IItemHandler; -import net.roguelogix.biggerreactors.BiggerReactors; -import net.roguelogix.biggerreactors.Config; -import net.roguelogix.biggerreactors.api.IWorkHandler; -import net.roguelogix.biggerreactors.api.WorkHandler; -import net.roguelogix.biggerreactors.machine.blocks.CyaniteReprocessor; -import net.roguelogix.biggerreactors.machine.containers.CyaniteReprocessorContainer; -import net.roguelogix.biggerreactors.machine.state.CyaniteReprocessorState; -import net.roguelogix.biggerreactors.machine.tiles.impl.CyaniteReprocessorItemHandler; -import net.roguelogix.biggerreactors.items.ingots.BlutoniumIngot; -import net.roguelogix.phosphophyllite.client.gui.api.IHasUpdatableState; -import net.roguelogix.phosphophyllite.debug.DebugTool; -import net.roguelogix.phosphophyllite.registry.RegisterTile; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Objects; - -public class CyaniteReprocessorTile extends BaseContainerBlockEntity implements MenuProvider, IHasUpdatableState { - - @RegisterTile("cyanite_reprocessor") - public static final BlockEntityType.BlockEntitySupplier SUPPLIER = new RegisterTile.Producer<>(CyaniteReprocessorTile::new); - - /** - * The (mostly) current state of the machine. - */ - public final CyaniteReprocessorState cyaniteReprocessorState = new CyaniteReprocessorState(this); - /** - * The work handler. - */ - private WorkHandler workHandler; - /** - * Capability access to the work handler. - */ - private final LazyOptional WORK_HANDLER_CAPABILITY = LazyOptional.of(() -> this.workHandler); - /** - * The item handler. - */ - private CyaniteReprocessorItemHandler itemHandler; - /** - * Capability access to the item handler. - */ - private final LazyOptional ITEM_HANDLER_CAPABILITY = LazyOptional.of(() -> this.itemHandler.pipeHandler()); - /** - * The energy storage. - */ - private EnergyStorage energyStorage; - /** - * Capability access to the energy storage. - */ - private final LazyOptional ENERGY_STORAGE_CAPABILITY = LazyOptional.of(() -> this.energyStorage); - /** - * The fluid tank. - */ - private FluidTank fluidTank; - /** - * Capability access to the fluid tank. - */ - private final LazyOptional FLUID_TANK_CAPABILITY = LazyOptional.of(() -> this.fluidTank); - /** - * "Anti-cheat" item stack, to ensure players don't swap items mid-process. - * - * @see CyaniteReprocessorTile#tick() - */ - private ItemStack itemPresentLastTick = ItemStack.EMPTY; - - public CyaniteReprocessorTile(BlockEntityType TYPE, BlockPos pos, BlockState state) { - super(TYPE, pos, state); - this.clearContent(); - this.updateState(); - } - - /** - * Do right-click stuff. - */ - @Nonnull - public InteractionResult onBlockActivated(@Nonnull BlockState blockState, Level world, @Nonnull BlockPos blockPos, @Nonnull Player player, @Nonnull InteractionHand hand, @Nonnull BlockHitResult trace) { - // Check for client-side. - if (world.isClientSide) { - return InteractionResult.SUCCESS; - } - - // Print tile data. - if (ItemStack.isSameItem(player.getMainHandItem(), new ItemStack(DebugTool.INSTANCE))) { - player.sendSystemMessage(Component.literal(String.format("[%s] Progress: %s/%s", BiggerReactors.modid, this.cyaniteReprocessorState.workTime, this.cyaniteReprocessorState.workTimeTotal))); - player.sendSystemMessage(Component.literal(String.format("[%s] Energy: %s/%s RF", BiggerReactors.modid, this.cyaniteReprocessorState.energyStored, this.cyaniteReprocessorState.energyCapacity))); - player.sendSystemMessage(Component.literal(String.format("[%s] Fluid Tank: %s/%s mB", BiggerReactors.modid, this.cyaniteReprocessorState.waterStored, this.cyaniteReprocessorState.waterCapacity))); - return InteractionResult.SUCCESS; - } - - // Do water bucket check. - if (ItemStack.isSameItem(player.getMainHandItem(), new ItemStack(Items.WATER_BUCKET))) { - if (this.fluidTank.getFluidAmount() <= (Config.CONFIG.CyaniteReprocessor.WaterTankCapacity - 1000)) { - this.fluidTank.fill(new FluidStack(Fluids.WATER, 1000), IFluidHandler.FluidAction.EXECUTE); - player.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.BUCKET)); - } - return InteractionResult.SUCCESS; - } - - // Get container and open GUI. - NetworkHooks.openScreen((ServerPlayer) player, this, blockPos); - return InteractionResult.SUCCESS; - } - - /** - * Drop items on destruction. - */ - public void onReplaced(BlockState blockState, Level world, BlockPos blockPos, BlockState newBlockState, boolean isMoving) { - ItemStack inputStack = this.itemHandler.getStackInSlot(CyaniteReprocessorItemHandler.INPUT_SLOT_INDEX); - if (!inputStack.isEmpty()) { - Containers.dropContents(world, blockPos, new SimpleContainer(inputStack)); - } - - ItemStack outputStack = this.itemHandler.getStackInSlot(CyaniteReprocessorItemHandler.OUTPUT_SLOT_INDEX); - if (!outputStack.isEmpty()) { - Containers.dropContents(world, blockPos, new SimpleContainer(outputStack)); - } - } - - /** - * @see CyaniteReprocessorTile#getDefaultName() - */ - @Override - public Component getDisplayName() { - return this.getDefaultName(); - } - - /** - * @return The localized default name for the tile. - */ - @Override - protected Component getDefaultName() { - return Component.translatable("block.biggerreactors.cyanite_reprocessor"); - } - - /** - * Create a GUI container for the tile. - * - * @param windowId The window ID to use. - * @param playerInventory The player's inventory. - * @return A GUI container to render. - */ - @Override - protected AbstractContainerMenu createMenu(int windowId, Inventory playerInventory) { - return new CyaniteReprocessorContainer(windowId, this.getBlockPos(), playerInventory.player); - } - - /** - * @return The current state of the tile. - */ - @Override - @Nonnull - public CyaniteReprocessorState getState() { - this.updateState(); - return this.cyaniteReprocessorState; - } - - /** - * Call for an update to the current state information. - */ - @Override - public void updateState() { - this.cyaniteReprocessorState.workTime = this.workHandler.getProgress(); - this.cyaniteReprocessorState.workTimeTotal = this.workHandler.getGoal(); - this.cyaniteReprocessorState.energyStored = this.energyStorage.getEnergyStored(); - this.cyaniteReprocessorState.energyCapacity = this.energyStorage.getMaxEnergyStored(); - this.cyaniteReprocessorState.waterStored = this.fluidTank.getFluidAmount(); - this.cyaniteReprocessorState.waterCapacity = this.fluidTank.getCapacity(); - } - - /** - * @return How large this tile's inventory is. - */ - @Override - public int getContainerSize() { - return this.itemHandler.getSlots(); - } - - /** - * @return Whether or not the inventory is empty. - */ - @Override - public boolean isEmpty() { - for (int index = 0; index < this.itemHandler.getSlots(); ++index) { - if (!this.itemHandler.getStackInSlot(index).isEmpty()) { - return false; - } - } - return true; - } - - /** - * Gets the item held in the specified slot. - * - * @param index The slot index to fetch from. - * @return Any items held in that slot. - */ - @Override - public ItemStack getItem(int index) { - return this.itemHandler.getStackInSlot(index); - } - - /** - * Removes the specified number of items from the specified slot. - * - * @param index The slot index to remove from. - * @param count The number of items to remove. - * @return The items that were removed. - */ - @Override - public ItemStack removeItem(int index, int count) { - return this.itemHandler.getStackInSlot(index).split(count); - } - - /** - * Removes an entire stack fromm the specified slot. - * - * @param index The slot index to remove from. - * @return The items that were removed. - */ - @Override - public ItemStack removeItemNoUpdate(int index) { - ItemStack itemStack = this.itemHandler.getStackInSlot(index).copy(); - this.itemHandler.setStackInSlot(index, ItemStack.EMPTY); - return itemStack; - } - - /** - * Updates the stored items in the specified slot. - * - * @param index The slot index to update. - * @param stack The items to update with. - */ - @Override - public void setItem(int index, ItemStack stack) { - ItemStack oldStack = this.itemHandler.getStackInSlot(index); - boolean flag = !stack.isEmpty() && ItemStack - .isSameItem(stack, oldStack); - this.itemHandler.setStackInSlot(index, stack); - if (stack.getCount() > this.getMaxStackSize()) { - stack.setCount(this.getMaxStackSize()); - } - - if (index == 0 && !flag) { - this.workHandler.clear(); - this.setChanged(); - } - } - - /** - * Clears all data and inventory for this tile. - */ - @Override - public void clearContent() { - // Reset work. - this.workHandler = new WorkHandler(Config.CONFIG.CyaniteReprocessor.TotalWorkTime); - - // Reset items. - this.itemHandler = new CyaniteReprocessorItemHandler(); - this.itemHandler.setSize(2); - - // Reset energy. - this.energyStorage = new EnergyStorage(Config.CONFIG.CyaniteReprocessor.EnergyTankCapacity); - - // Reset fluids. - this.fluidTank = new FluidTank(Config.CONFIG.CyaniteReprocessor.WaterTankCapacity, fluid -> fluid.getFluid() == Fluids.WATER); - } - - /** - * Checks if the player can currently use this tile. - * - * @param player The player to check. - * @return True if usable, false otherwise. - */ - @Override - public boolean stillValid(Player player) { - assert this.level != null; - if (this.level.getBlockEntity(this.getBlockPos()) != this) { - return false; - } else { - return player.distanceToSqr( - (double) this.getBlockPos().getX() + 0.5D, - (double) this.getBlockPos().getY() + 0.5D, - (double) this.getBlockPos().getZ() + 0.5D) <= 64.0D; - } - } - - /** - * Read NBT data from the world. - * - * @param parentCompound The parent compound to read from. - */ - @Override - public void load(@Nonnull CompoundTag parentCompound) { - super.load(parentCompound); - CompoundTag childCompound = parentCompound.getCompound("cyaniteReprocessorState"); - - // Read work. - this.workHandler = new WorkHandler(childCompound.getInt("workTimeTotal"), childCompound.getInt("workTime")); - // Read items. - this.itemHandler.deserializeNBT(childCompound.getCompound("inventory")); - // Read energy. - this.energyStorage = new EnergyStorage(childCompound.getInt("energyCapacity"), - Config.CONFIG.CyaniteReprocessor.TransferRate, - Config.CONFIG.CyaniteReprocessor.TransferRate, - childCompound.getInt("energyStored")); - // Read fluids. - this.fluidTank = this.fluidTank.readFromNBT(childCompound.getCompound("fluidStorage")); - } - - /** - * Save NBT data to the world. - * - * @param parentCompound The parent compound to append onto. - * @return The updated compound. - */ - @Override - public final void saveAdditional(@Nonnull CompoundTag parentCompound) { - super.saveAdditional(parentCompound); - CompoundTag childCompound = new CompoundTag(); - - // Write work. - childCompound.putInt("workTime", this.workHandler.getProgress()); - childCompound.putInt("workTimeTotal", this.workHandler.getGoal()); - // Write items. - childCompound.put("inventory", this.itemHandler.serializeNBT()); - // Write energy. - childCompound.putInt("energyStored", this.energyStorage.getEnergyStored()); - childCompound.putInt("energyCapacity", this.energyStorage.getMaxEnergyStored()); - // Write fluids. - childCompound.put("fluidTank", fluidTank.writeToNBT(new CompoundTag())); - - parentCompound.put("cyaniteReprocessorState", childCompound); - } - - /** - * @return Whether or not the machine can perform work. - * @see CyaniteReprocessorTile#tick() - */ - private boolean canWork() { - // If the output slot is full, we cannot work. - if (this.getItem(CyaniteReprocessorItemHandler.OUTPUT_SLOT_INDEX).getCount() >= 64) { - return false; - } - return (this.energyStorage.getEnergyStored() >= Config.CONFIG.CyaniteReprocessor.EnergyConsumptionPerTick - && this.fluidTank.getFluidAmount() >= Config.CONFIG.CyaniteReprocessor.WaterConsumptionPerTick); - } - - /** - * Do work (if possible). - */ - public void tick() { - // Check for client-side. - assert level != null; - if (level.isClientSide()) { - return; - } - - boolean doUpdate = false; - boolean isActive = false; - ItemStack inputStack = this.itemHandler.getStackInSlot(CyaniteReprocessorItemHandler.INPUT_SLOT_INDEX); - - // Check to make sure the player doesn't try to pull a fast one. - if (!ItemStack.isSameItem(this.itemPresentLastTick, inputStack)) { - this.workHandler.clear(); - } - this.itemPresentLastTick = inputStack.copy(); - - if (inputStack.getCount() >= 2) { - // Can we continue? - if (canWork()) { - isActive = true; - doUpdate = true; - this.workHandler.increment(1); - this.energyStorage.extractEnergy(Config.CONFIG.CyaniteReprocessor.EnergyConsumptionPerTick, false); - this.fluidTank.drain(Config.CONFIG.CyaniteReprocessor.WaterConsumptionPerTick, IFluidHandler.FluidAction.EXECUTE); - // We've run out of resources, halt. - } else if (this.workHandler.getProgress() > 0) { - this.workHandler.decrement(2); - } - - // Item is done. - if (this.workHandler.isFinished()) { - this.itemHandler.extractItem(CyaniteReprocessorItemHandler.INPUT_SLOT_INDEX, 2, false); - this.itemHandler.insertItem(CyaniteReprocessorItemHandler.OUTPUT_SLOT_INDEX, new ItemStack(BlutoniumIngot.INSTANCE, 1), false); - this.workHandler.clear(); - } - } - - BlockState currentBlockState = level.getBlockState(this.getBlockPos()); - BlockState newBlockState = currentBlockState.setValue(CyaniteReprocessor.ENABLED, isActive); - if (!newBlockState.equals(currentBlockState)) { - this.level.setBlock(this.getBlockPos(), newBlockState, 3); - doUpdate = true; - } - - if (doUpdate) { - setChanged(); - } - - // Update the current machine state. - this.updateState(); - } - - /** - * Check if the tile holds a certain capability. - * - * @param capability The capability to check for. - * @param side Which side this capability should belong to. - * @param The type class of the capability. - * @return The handler for the capability, if present. - */ - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability capability, - @Nullable Direction side) { - // Check for work. - // TODO: While this capability is exclusive to the Reprocessor for now, it may not always be. - // The capability is technically implemented, but no registration is done. - // That oughta be fixed, so it can be checked for here. - // But I'm lazy, so I'll do that some other time. - //if (capability.equals(CapabilityWorkHandler.WORK_HANDLER_CAPABILITY)) { - // return this.WORK_HANDLER_CAPABILITY.cast(); - //} - - // Check for items. - if (capability.equals(ForgeCapabilities.ITEM_HANDLER)) { - return this.ITEM_HANDLER_CAPABILITY.cast(); - } - - // Check for energy. - if (capability.equals(ForgeCapabilities.ENERGY)) { - return this.ENERGY_STORAGE_CAPABILITY.cast(); - } - - // Check for water. - if (capability.equals(ForgeCapabilities.FLUID_HANDLER)) { - return this.FLUID_TANK_CAPABILITY.cast(); - } - - return Objects.requireNonNull(super.getCapability(capability, side)); - } - - @Override - public boolean canPlaceItem(int index, ItemStack stack) { - return this.itemHandler.isItemValid(index, stack); - } - - public CyaniteReprocessorItemHandler getItemHandler() { - return itemHandler; - } -} +//package net.roguelogix.biggerreactors.machine.tiles; +// +// +//import net.minecraft.core.BlockPos; +//import net.minecraft.core.Direction; +//import net.minecraft.nbt.CompoundTag; +//import net.minecraft.network.chat.Component; +//import net.minecraft.server.level.ServerPlayer; +//import net.minecraft.world.*; +//import net.minecraft.world.entity.player.Inventory; +//import net.minecraft.world.entity.player.Player; +//import net.minecraft.world.inventory.AbstractContainerMenu; +//import net.minecraft.world.item.ItemStack; +//import net.minecraft.world.item.Items; +//import net.minecraft.world.level.Level; +//import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; +//import net.minecraft.world.level.block.entity.BlockEntityType; +//import net.minecraft.world.level.block.state.BlockState; +//import net.minecraft.world.level.material.Fluids; +//import net.minecraft.world.phys.BlockHitResult; +//import net.roguelogix.biggerreactors.BiggerReactors; +//import net.roguelogix.biggerreactors.Config; +//import net.roguelogix.biggerreactors.api.IWorkHandler; +//import net.roguelogix.biggerreactors.api.WorkHandler; +//import net.roguelogix.biggerreactors.machine.blocks.CyaniteReprocessor; +//import net.roguelogix.biggerreactors.machine.containers.CyaniteReprocessorContainer; +//import net.roguelogix.biggerreactors.machine.state.CyaniteReprocessorState; +//import net.roguelogix.biggerreactors.machine.tiles.impl.CyaniteReprocessorItemHandler; +//import net.roguelogix.biggerreactors.items.ingots.BlutoniumIngot; +//import net.roguelogix.phosphophyllite.client.gui.api.IHasUpdatableState; +//import net.roguelogix.phosphophyllite.debug.DebugTool; +//import net.roguelogix.phosphophyllite.registry.RegisterTile; +// +//import javax.annotation.Nonnull; +//import javax.annotation.Nullable; +//import java.util.Objects; +// +//public class CyaniteReprocessorTile extends BaseContainerBlockEntity implements MenuProvider, IHasUpdatableState { +// +// @RegisterTile("cyanite_reprocessor") +// public static final BlockEntityType.BlockEntitySupplier SUPPLIER = new RegisterTile.Producer<>(CyaniteReprocessorTile::new); +// +// /** +// * The (mostly) current state of the machine. +// */ +// public final CyaniteReprocessorState cyaniteReprocessorState = new CyaniteReprocessorState(this); +// /** +// * The work handler. +// */ +// private WorkHandler workHandler; +// /** +// * Capability access to the work handler. +// */ +// private final LazyOptional WORK_HANDLER_CAPABILITY = LazyOptional.of(() -> this.workHandler); +// /** +// * The item handler. +// */ +// private CyaniteReprocessorItemHandler itemHandler; +// /** +// * Capability access to the item handler. +// */ +// private final LazyOptional ITEM_HANDLER_CAPABILITY = LazyOptional.of(() -> this.itemHandler.pipeHandler()); +// /** +// * The energy storage. +// */ +// private EnergyStorage energyStorage; +// /** +// * Capability access to the energy storage. +// */ +// private final LazyOptional ENERGY_STORAGE_CAPABILITY = LazyOptional.of(() -> this.energyStorage); +// /** +// * The fluid tank. +// */ +// private FluidTank fluidTank; +// /** +// * Capability access to the fluid tank. +// */ +// private final LazyOptional FLUID_TANK_CAPABILITY = LazyOptional.of(() -> this.fluidTank); +// /** +// * "Anti-cheat" item stack, to ensure players don't swap items mid-process. +// * +// * @see CyaniteReprocessorTile#tick() +// */ +// private ItemStack itemPresentLastTick = ItemStack.EMPTY; +// +// public CyaniteReprocessorTile(BlockEntityType TYPE, BlockPos pos, BlockState state) { +// super(TYPE, pos, state); +// this.clearContent(); +// this.updateState(); +// } +// +// /** +// * Do right-click stuff. +// */ +// @Nonnull +// public InteractionResult onBlockActivated(@Nonnull BlockState blockState, Level world, @Nonnull BlockPos blockPos, @Nonnull Player player, @Nonnull InteractionHand hand, @Nonnull BlockHitResult trace) { +// // Check for client-side. +// if (world.isClientSide) { +// return InteractionResult.SUCCESS; +// } +// +// // Print tile data. +// if (ItemStack.isSameItem(player.getMainHandItem(), new ItemStack(DebugTool.INSTANCE))) { +// player.sendSystemMessage(Component.literal(String.format("[%s] Progress: %s/%s", BiggerReactors.modid, this.cyaniteReprocessorState.workTime, this.cyaniteReprocessorState.workTimeTotal))); +// player.sendSystemMessage(Component.literal(String.format("[%s] Energy: %s/%s RF", BiggerReactors.modid, this.cyaniteReprocessorState.energyStored, this.cyaniteReprocessorState.energyCapacity))); +// player.sendSystemMessage(Component.literal(String.format("[%s] Fluid Tank: %s/%s mB", BiggerReactors.modid, this.cyaniteReprocessorState.waterStored, this.cyaniteReprocessorState.waterCapacity))); +// return InteractionResult.SUCCESS; +// } +// +// // Do water bucket check. +// if (ItemStack.isSameItem(player.getMainHandItem(), new ItemStack(Items.WATER_BUCKET))) { +// if (this.fluidTank.getFluidAmount() <= (Config.CONFIG.CyaniteReprocessor.WaterTankCapacity - 1000)) { +// this.fluidTank.fill(new FluidStack(Fluids.WATER, 1000), IFluidHandler.FluidAction.EXECUTE); +// player.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.BUCKET)); +// } +// return InteractionResult.SUCCESS; +// } +// +// // Get container and open GUI. +// NetworkHooks.openScreen((ServerPlayer) player, this, blockPos); +// return InteractionResult.SUCCESS; +// } +// +// /** +// * Drop items on destruction. +// */ +// public void onReplaced(BlockState blockState, Level world, BlockPos blockPos, BlockState newBlockState, boolean isMoving) { +// ItemStack inputStack = this.itemHandler.getStackInSlot(CyaniteReprocessorItemHandler.INPUT_SLOT_INDEX); +// if (!inputStack.isEmpty()) { +// Containers.dropContents(world, blockPos, new SimpleContainer(inputStack)); +// } +// +// ItemStack outputStack = this.itemHandler.getStackInSlot(CyaniteReprocessorItemHandler.OUTPUT_SLOT_INDEX); +// if (!outputStack.isEmpty()) { +// Containers.dropContents(world, blockPos, new SimpleContainer(outputStack)); +// } +// } +// +// /** +// * @see CyaniteReprocessorTile#getDefaultName() +// */ +// @Override +// public Component getDisplayName() { +// return this.getDefaultName(); +// } +// +// /** +// * @return The localized default name for the tile. +// */ +// @Override +// protected Component getDefaultName() { +// return Component.translatable("block.biggerreactors.cyanite_reprocessor"); +// } +// +// /** +// * Create a GUI container for the tile. +// * +// * @param windowId The window ID to use. +// * @param playerInventory The player's inventory. +// * @return A GUI container to render. +// */ +// @Override +// protected AbstractContainerMenu createMenu(int windowId, Inventory playerInventory) { +// return new CyaniteReprocessorContainer(windowId, this.getBlockPos(), playerInventory.player); +// } +// +// /** +// * @return The current state of the tile. +// */ +// @Override +// @Nonnull +// public CyaniteReprocessorState getState() { +// this.updateState(); +// return this.cyaniteReprocessorState; +// } +// +// /** +// * Call for an update to the current state information. +// */ +// @Override +// public void updateState() { +// this.cyaniteReprocessorState.workTime = this.workHandler.getProgress(); +// this.cyaniteReprocessorState.workTimeTotal = this.workHandler.getGoal(); +// this.cyaniteReprocessorState.energyStored = this.energyStorage.getEnergyStored(); +// this.cyaniteReprocessorState.energyCapacity = this.energyStorage.getMaxEnergyStored(); +// this.cyaniteReprocessorState.waterStored = this.fluidTank.getFluidAmount(); +// this.cyaniteReprocessorState.waterCapacity = this.fluidTank.getCapacity(); +// } +// +// /** +// * @return How large this tile's inventory is. +// */ +// @Override +// public int getContainerSize() { +// return this.itemHandler.getSlots(); +// } +// +// /** +// * @return Whether or not the inventory is empty. +// */ +// @Override +// public boolean isEmpty() { +// for (int index = 0; index < this.itemHandler.getSlots(); ++index) { +// if (!this.itemHandler.getStackInSlot(index).isEmpty()) { +// return false; +// } +// } +// return true; +// } +// +// /** +// * Gets the item held in the specified slot. +// * +// * @param index The slot index to fetch from. +// * @return Any items held in that slot. +// */ +// @Override +// public ItemStack getItem(int index) { +// return this.itemHandler.getStackInSlot(index); +// } +// +// /** +// * Removes the specified number of items from the specified slot. +// * +// * @param index The slot index to remove from. +// * @param count The number of items to remove. +// * @return The items that were removed. +// */ +// @Override +// public ItemStack removeItem(int index, int count) { +// return this.itemHandler.getStackInSlot(index).split(count); +// } +// +// /** +// * Removes an entire stack fromm the specified slot. +// * +// * @param index The slot index to remove from. +// * @return The items that were removed. +// */ +// @Override +// public ItemStack removeItemNoUpdate(int index) { +// ItemStack itemStack = this.itemHandler.getStackInSlot(index).copy(); +// this.itemHandler.setStackInSlot(index, ItemStack.EMPTY); +// return itemStack; +// } +// +// /** +// * Updates the stored items in the specified slot. +// * +// * @param index The slot index to update. +// * @param stack The items to update with. +// */ +// @Override +// public void setItem(int index, ItemStack stack) { +// ItemStack oldStack = this.itemHandler.getStackInSlot(index); +// boolean flag = !stack.isEmpty() && ItemStack +// .isSameItem(stack, oldStack); +// this.itemHandler.setStackInSlot(index, stack); +// if (stack.getCount() > this.getMaxStackSize()) { +// stack.setCount(this.getMaxStackSize()); +// } +// +// if (index == 0 && !flag) { +// this.workHandler.clear(); +// this.setChanged(); +// } +// } +// +// /** +// * Clears all data and inventory for this tile. +// */ +// @Override +// public void clearContent() { +// // Reset work. +// this.workHandler = new WorkHandler(Config.CONFIG.CyaniteReprocessor.TotalWorkTime); +// +// // Reset items. +// this.itemHandler = new CyaniteReprocessorItemHandler(); +// this.itemHandler.setSize(2); +// +// // Reset energy. +// this.energyStorage = new EnergyStorage(Config.CONFIG.CyaniteReprocessor.EnergyTankCapacity); +// +// // Reset fluids. +// this.fluidTank = new FluidTank(Config.CONFIG.CyaniteReprocessor.WaterTankCapacity, fluid -> fluid.getFluid() == Fluids.WATER); +// } +// +// /** +// * Checks if the player can currently use this tile. +// * +// * @param player The player to check. +// * @return True if usable, false otherwise. +// */ +// @Override +// public boolean stillValid(Player player) { +// assert this.level != null; +// if (this.level.getBlockEntity(this.getBlockPos()) != this) { +// return false; +// } else { +// return player.distanceToSqr( +// (double) this.getBlockPos().getX() + 0.5D, +// (double) this.getBlockPos().getY() + 0.5D, +// (double) this.getBlockPos().getZ() + 0.5D) <= 64.0D; +// } +// } +// +// /** +// * Read NBT data from the world. +// * +// * @param parentCompound The parent compound to read from. +// */ +// @Override +// public void load(@Nonnull CompoundTag parentCompound) { +// super.load(parentCompound); +// CompoundTag childCompound = parentCompound.getCompound("cyaniteReprocessorState"); +// +// // Read work. +// this.workHandler = new WorkHandler(childCompound.getInt("workTimeTotal"), childCompound.getInt("workTime")); +// // Read items. +// this.itemHandler.deserializeNBT(childCompound.getCompound("inventory")); +// // Read energy. +// this.energyStorage = new EnergyStorage(childCompound.getInt("energyCapacity"), +// Config.CONFIG.CyaniteReprocessor.TransferRate, +// Config.CONFIG.CyaniteReprocessor.TransferRate, +// childCompound.getInt("energyStored")); +// // Read fluids. +// this.fluidTank = this.fluidTank.readFromNBT(childCompound.getCompound("fluidStorage")); +// } +// +// /** +// * Save NBT data to the world. +// * +// * @param parentCompound The parent compound to append onto. +// * @return The updated compound. +// */ +// @Override +// public final void saveAdditional(@Nonnull CompoundTag parentCompound) { +// super.saveAdditional(parentCompound); +// CompoundTag childCompound = new CompoundTag(); +// +// // Write work. +// childCompound.putInt("workTime", this.workHandler.getProgress()); +// childCompound.putInt("workTimeTotal", this.workHandler.getGoal()); +// // Write items. +// childCompound.put("inventory", this.itemHandler.serializeNBT()); +// // Write energy. +// childCompound.putInt("energyStored", this.energyStorage.getEnergyStored()); +// childCompound.putInt("energyCapacity", this.energyStorage.getMaxEnergyStored()); +// // Write fluids. +// childCompound.put("fluidTank", fluidTank.writeToNBT(new CompoundTag())); +// +// parentCompound.put("cyaniteReprocessorState", childCompound); +// } +// +// /** +// * @return Whether or not the machine can perform work. +// * @see CyaniteReprocessorTile#tick() +// */ +// private boolean canWork() { +// // If the output slot is full, we cannot work. +// if (this.getItem(CyaniteReprocessorItemHandler.OUTPUT_SLOT_INDEX).getCount() >= 64) { +// return false; +// } +// return (this.energyStorage.getEnergyStored() >= Config.CONFIG.CyaniteReprocessor.EnergyConsumptionPerTick +// && this.fluidTank.getFluidAmount() >= Config.CONFIG.CyaniteReprocessor.WaterConsumptionPerTick); +// } +// +// /** +// * Do work (if possible). +// */ +// public void tick() { +// // Check for client-side. +// assert level != null; +// if (level.isClientSide()) { +// return; +// } +// +// boolean doUpdate = false; +// boolean isActive = false; +// ItemStack inputStack = this.itemHandler.getStackInSlot(CyaniteReprocessorItemHandler.INPUT_SLOT_INDEX); +// +// // Check to make sure the player doesn't try to pull a fast one. +// if (!ItemStack.isSameItem(this.itemPresentLastTick, inputStack)) { +// this.workHandler.clear(); +// } +// this.itemPresentLastTick = inputStack.copy(); +// +// if (inputStack.getCount() >= 2) { +// // Can we continue? +// if (canWork()) { +// isActive = true; +// doUpdate = true; +// this.workHandler.increment(1); +// this.energyStorage.extractEnergy(Config.CONFIG.CyaniteReprocessor.EnergyConsumptionPerTick, false); +// this.fluidTank.drain(Config.CONFIG.CyaniteReprocessor.WaterConsumptionPerTick, IFluidHandler.FluidAction.EXECUTE); +// // We've run out of resources, halt. +// } else if (this.workHandler.getProgress() > 0) { +// this.workHandler.decrement(2); +// } +// +// // Item is done. +// if (this.workHandler.isFinished()) { +// this.itemHandler.extractItem(CyaniteReprocessorItemHandler.INPUT_SLOT_INDEX, 2, false); +// this.itemHandler.insertItem(CyaniteReprocessorItemHandler.OUTPUT_SLOT_INDEX, new ItemStack(BlutoniumIngot.INSTANCE, 1), false); +// this.workHandler.clear(); +// } +// } +// +// BlockState currentBlockState = level.getBlockState(this.getBlockPos()); +// BlockState newBlockState = currentBlockState.setValue(CyaniteReprocessor.ENABLED, isActive); +// if (!newBlockState.equals(currentBlockState)) { +// this.level.setBlock(this.getBlockPos(), newBlockState, 3); +// doUpdate = true; +// } +// +// if (doUpdate) { +// setChanged(); +// } +// +// // Update the current machine state. +// this.updateState(); +// } +// +// /** +// * Check if the tile holds a certain capability. +// * +// * @param capability The capability to check for. +// * @param side Which side this capability should belong to. +// * @param The type class of the capability. +// * @return The handler for the capability, if present. +// */ +// @Nonnull +// @Override +// public LazyOptional getCapability(@Nonnull Capability capability, +// @Nullable Direction side) { +// // Check for work. +// // TODO: While this capability is exclusive to the Reprocessor for now, it may not always be. +// // The capability is technically implemented, but no registration is done. +// // That oughta be fixed, so it can be checked for here. +// // But I'm lazy, so I'll do that some other time. +// //if (capability.equals(CapabilityWorkHandler.WORK_HANDLER_CAPABILITY)) { +// // return this.WORK_HANDLER_CAPABILITY.cast(); +// //} +// +// // Check for items. +// if (capability.equals(ForgeCapabilities.ITEM_HANDLER)) { +// return this.ITEM_HANDLER_CAPABILITY.cast(); +// } +// +// // Check for energy. +// if (capability.equals(ForgeCapabilities.ENERGY)) { +// return this.ENERGY_STORAGE_CAPABILITY.cast(); +// } +// +// // Check for water. +// if (capability.equals(ForgeCapabilities.FLUID_HANDLER)) { +// return this.FLUID_TANK_CAPABILITY.cast(); +// } +// +// return Objects.requireNonNull(super.getCapability(capability, side)); +// } +// +// @Override +// public boolean canPlaceItem(int index, ItemStack stack) { +// return this.itemHandler.isItemValid(index, stack); +// } +// +// public CyaniteReprocessorItemHandler getItemHandler() { +// return itemHandler; +// } +//} diff --git a/src/main/java/net/roguelogix/biggerreactors/machine/tiles/impl/CyaniteReprocessorItemHandler.java b/src/main/java/net/roguelogix/biggerreactors/machine/tiles/impl/CyaniteReprocessorItemHandler.java index 1f54324b..a9b3c6ee 100644 --- a/src/main/java/net/roguelogix/biggerreactors/machine/tiles/impl/CyaniteReprocessorItemHandler.java +++ b/src/main/java/net/roguelogix/biggerreactors/machine/tiles/impl/CyaniteReprocessorItemHandler.java @@ -1,8 +1,8 @@ package net.roguelogix.biggerreactors.machine.tiles.impl; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemStackHandler; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.ItemStackHandler; import net.roguelogix.biggerreactors.items.ingots.BlutoniumIngot; import net.roguelogix.biggerreactors.items.ingots.CyaniteIngot; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/blocks/HeatExchangerBaseBlock.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/blocks/HeatExchangerBaseBlock.java index ed7ce4de..b37a931b 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/blocks/HeatExchangerBaseBlock.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/blocks/HeatExchangerBaseBlock.java @@ -12,7 +12,6 @@ import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.network.NetworkHooks; import net.roguelogix.phosphophyllite.modular.block.PhosphophylliteBlock; import net.roguelogix.phosphophyllite.multiblock.rectangular.IRectangularMultiblockBlock; @@ -55,7 +54,7 @@ public InteractionResult onUse(BlockState state, Level level, BlockPos pos, Play if (hand == InteractionHand.MAIN_HAND && state.hasProperty(ASSEMBLED) && state.getValue(ASSEMBLED)) { if (level.getBlockEntity(pos) instanceof MenuProvider menuProvider) { if (!level.isClientSide) { - NetworkHooks.openScreen((ServerPlayer) player, menuProvider, pos); + player.openMenu(menuProvider, pos); } return InteractionResult.SUCCESS; } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/client/HeatExchangerFluidPortScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/client/HeatExchangerFluidPortScreen.java index bcac3ee6..91a8605c 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/client/HeatExchangerFluidPortScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/client/HeatExchangerFluidPortScreen.java @@ -6,8 +6,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.client.Biselector; import net.roguelogix.biggerreactors.client.SelectorColors; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/client/HeatExchangerTerminalScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/client/HeatExchangerTerminalScreen.java index 7bbfc30d..24ce8a5c 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/client/HeatExchangerTerminalScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/client/HeatExchangerTerminalScreen.java @@ -9,9 +9,8 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.client.CommonRender; @@ -145,22 +144,22 @@ private void initGauges() { @Override public void containerTick() { // Check if condenser intake fluid changed. - if (!heatExchangerState.condenserIntakeFluid.equals(Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(condenserIntakeFluid)).toString())) { + if (!heatExchangerState.condenserIntakeFluid.equals(Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(condenserIntakeFluid)).toString())) { condenserIntakeFluid = BuiltInRegistries.FLUID.get(new ResourceLocation(heatExchangerState.condenserIntakeFluid)); } // Check if evaporator intake fluid changed. - if (!heatExchangerState.evaporatorIntakeFluid.equals(Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(evaporatorIntakeFluid)).toString())) { + if (!heatExchangerState.evaporatorIntakeFluid.equals(Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(evaporatorIntakeFluid)).toString())) { evaporatorIntakeFluid = BuiltInRegistries.FLUID.get(new ResourceLocation(heatExchangerState.evaporatorIntakeFluid)); } // Check if condenser exhaust fluid changed. - if (!heatExchangerState.condenserExhaustFluid.equals(Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(condenserExhaustFluid)).toString())) { + if (!heatExchangerState.condenserExhaustFluid.equals(Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(condenserExhaustFluid)).toString())) { condenserExhaustFluid = BuiltInRegistries.FLUID.get(new ResourceLocation(heatExchangerState.condenserExhaustFluid)); } // Check if evaporator exhaust fluid changed. - if (!heatExchangerState.evaporatorExhaustFluid.equals(Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(evaporatorExhaustFluid)).toString())) { + if (!heatExchangerState.evaporatorExhaustFluid.equals(Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(evaporatorExhaustFluid)).toString())) { evaporatorExhaustFluid = BuiltInRegistries.FLUID.get(new ResourceLocation(heatExchangerState.evaporatorExhaustFluid)); } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/deps/HeatExchangerPeripheral.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/deps/HeatExchangerPeripheral.java index 55b02a2c..10826d1b 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/deps/HeatExchangerPeripheral.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/deps/HeatExchangerPeripheral.java @@ -4,8 +4,7 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.registries.ForgeRegistries; +import net.minecraft.core.registries.BuiltInRegistries; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.HeatExchangerMultiblockController; import net.roguelogix.biggerreactors.util.FluidTransitionTank; @@ -27,8 +26,8 @@ public class HeatExchangerPeripheral implements IPeripheral { final Channel evaporator; final InternalEnvironment internalEnvironment; - public static LazyOptional create(@Nonnull Supplier controllerSupplier) { - return LazyOptional.of(() -> new HeatExchangerPeripheral(controllerSupplier)); + public static HeatExchangerPeripheral create(@Nonnull Supplier controllerSupplier) { + return new HeatExchangerPeripheral(controllerSupplier); } public HeatExchangerPeripheral(Supplier rawControllerSupplier) { @@ -94,7 +93,7 @@ public ChannelFluid(LamdbaExceptionUtils.Supplier_WithExceptions tileEntityTypeIn, BlockP super(tileEntityTypeIn, pos, state); } - private static final Capability CAPABILITY_PERIPHERAL = CapabilityManager.get(new CapabilityToken<>(){}); - - @Override - public LazyOptional capability(Capability cap, final @Nullable Direction side) { - if (cap == CAPABILITY_PERIPHERAL) { - return HeatExchangerPeripheral.create(this::controller).cast(); - } - return super.capability(cap, side); - } + // TODO: computercraft capability +// private static final Capability CAPABILITY_PERIPHERAL = CapabilityManager.get(new CapabilityToken<>(){}); +// +// @Override +// public LazyOptional capability(Capability cap, final @Nullable Direction side) { +// if (cap == CAPABILITY_PERIPHERAL) { +// return HeatExchangerPeripheral.create(this::controller).cast(); +// } +// return super.capability(cap, side); +// } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/tiles/HeatExchangerFluidPortTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/tiles/HeatExchangerFluidPortTile.java index e6e12a4a..824d7fec 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/tiles/HeatExchangerFluidPortTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/tiles/HeatExchangerFluidPortTile.java @@ -1,6 +1,5 @@ package net.roguelogix.biggerreactors.multiblocks.heatexchanger.tiles; -import mekanism.api.chemical.gas.IGasHandler; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -15,22 +14,18 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.templates.FluidTank; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.fluids.capability.templates.FluidTank; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.blocks.HeatExchangerFluidPortBlock; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.containers.HeatExchangerFluidPortContainer; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.state.HeatExchangerFluidPortState; import net.roguelogix.phosphophyllite.client.gui.api.IHasUpdatableState; import net.roguelogix.phosphophyllite.fluids.FluidHandlerWrapper; import net.roguelogix.phosphophyllite.fluids.IPhosphophylliteFluidHandler; -import net.roguelogix.phosphophyllite.fluids.MekanismGasWrappers; import net.roguelogix.phosphophyllite.multiblock.common.IEventMultiblock; import net.roguelogix.phosphophyllite.multiblock.validated.IValidatedMultiblock; +import net.roguelogix.phosphophyllite.registry.CapabilityRegistration; +import net.roguelogix.phosphophyllite.registry.RegisterCapability; import net.roguelogix.phosphophyllite.registry.RegisterTile; import net.roguelogix.phosphophyllite.util.BlockStates; @@ -50,23 +45,27 @@ public class HeatExchangerFluidPortTile extends HeatExchangerBaseTile implements @RegisterTile("heat_exchanger_fluid_port") public static final BlockEntityType.BlockEntitySupplier SUPPLIER = new RegisterTile.Producer<>(HeatExchangerFluidPortTile::new); + @RegisterCapability + private static final CapabilityRegistration FLUID_HANDLER_CAP_REGISTRATION = CapabilityRegistration.tileCap(Capabilities.FluidHandler.BLOCK, HeatExchangerFluidPortTile.class); + public HeatExchangerFluidPortTile(BlockEntityType tileEntityTypeIn, BlockPos pos, BlockState state) { super(tileEntityTypeIn, pos, state); } - private static final Capability GAS_HANDLER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>(){}); - - @Override - public LazyOptional capability(Capability cap, @Nullable Direction side) { - if (cap == ForgeCapabilities.FLUID_HANDLER) { - return fluidHandlerCapability().cast(); - } - if (cap == GAS_HANDLER_CAPABILITY) { - return LazyOptional.of(() -> MekanismGasWrappers.wrap(this)).cast(); - } - return super.capability(cap, side); - } + // TODO: mek gas +// private static final Capability GAS_HANDLER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>(){}); +// +// @Override +// public LazyOptional capability(Capability cap, @Nullable Direction side) { +// if (cap == ForgeCapabilities.FLUID_HANDLER) { +// return fluidHandlerCapability().cast(); +// } +// if (cap == GAS_HANDLER_CAPABILITY) { +// return LazyOptional.of(() -> MekanismGasWrappers.wrap(this)).cast(); +// } +// return super.capability(cap, side); +// } private IPhosphophylliteFluidHandler HETank; @@ -173,7 +172,7 @@ public long pushFluid() { if (!connected || inlet) { return 0; } - if (handlerOptional.isPresent()) { + if (handler != null) { Fluid fluid = HETank.fluidTypeInTank(1); long amount = HETank.fluidAmountInTank(1); amount = HETank.drain(fluid, null, amount, true); @@ -181,7 +180,6 @@ public long pushFluid() { amount = HETank.drain(fluid, null, amount, false); return amount; } else { - handlerOptional = LazyOptional.empty(); handler = null; connected = false; } @@ -190,38 +188,30 @@ public long pushFluid() { private boolean connected = false; Direction outputDirection = null; - LazyOptional handlerOptional = LazyOptional.empty(); IPhosphophylliteFluidHandler handler = null; FluidTank EMPTY_TANK = new FluidTank(0); @SuppressWarnings("DuplicatedCode") public void neighborChanged() { - handlerOptional = LazyOptional.empty(); handler = null; if (outputDirection == null) { connected = false; return; } assert level != null; - BlockEntity te = level.getBlockEntity(worldPosition.relative(outputDirection)); - if (te == null) { - connected = false; - return; - } + final var outputCap = level.getCapability(Capabilities.FluidHandler.BLOCK, worldPosition.relative(outputDirection), outputDirection.getOpposite()); connected = false; - LazyOptional waterOutput = te.getCapability(ForgeCapabilities.FLUID_HANDLER, outputDirection.getOpposite()); - if (waterOutput.isPresent()) { + if (outputCap != null) { connected = true; - handlerOptional = waterOutput; - handler = FluidHandlerWrapper.wrap(waterOutput.orElse(EMPTY_TANK)); - } else if (GAS_HANDLER_CAPABILITY != null) { - LazyOptional gasOptional = te.getCapability(GAS_HANDLER_CAPABILITY, outputDirection.getOpposite()); - if (gasOptional.isPresent()) { - IGasHandler gasHandler = gasOptional.orElse(MekanismGasWrappers.EMPTY_TANK); - connected = true; - handlerOptional = gasOptional; - handler = MekanismGasWrappers.wrap(gasHandler); - } + handler = FluidHandlerWrapper.wrap(outputCap); +// } else if (GAS_HANDLER_CAPABILITY != null) { +// LazyOptional gasOptional = te.getCapability(GAS_HANDLER_CAPABILITY, outputDirection.getOpposite()); +// if (gasOptional.isPresent()) { +// IGasHandler gasHandler = gasOptional.orElse(MekanismGasWrappers.EMPTY_TANK); +// connected = true; +// handlerOptional = gasOptional; +// handler = MekanismGasWrappers.wrap(gasHandler); +// } } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/tiles/HeatExchangerTerminalTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/tiles/HeatExchangerTerminalTile.java index 8f44f897..ecd0d7e8 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/tiles/HeatExchangerTerminalTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/heatexchanger/tiles/HeatExchangerTerminalTile.java @@ -2,6 +2,7 @@ import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; @@ -9,7 +10,6 @@ import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.registries.ForgeRegistries; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.blocks.HeatExchangerTerminalBlock; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.containers.HeatExchangerTerminalContainer; import net.roguelogix.biggerreactors.multiblocks.heatexchanger.state.HeatExchangerState; @@ -48,19 +48,19 @@ public void updateState() { state.condenserTankSize = controller().condenserTank.perSideCapacity; - state.condenserIntakeFluid = ForgeRegistries.FLUIDS.getKey(controller().condenserTank.fluidTypeInTank(0)).toString(); + state.condenserIntakeFluid = BuiltInRegistries.FLUID.getKey(controller().condenserTank.fluidTypeInTank(0)).toString(); state.condenserIntakeFluidAmount = controller().condenserTank.fluidAmountInTank(0); - state.condenserExhaustFluid = ForgeRegistries.FLUIDS.getKey(controller().condenserTank.fluidTypeInTank(1)).toString(); + state.condenserExhaustFluid = BuiltInRegistries.FLUID.getKey(controller().condenserTank.fluidTypeInTank(1)).toString(); state.condenserExhaustFluidAmount = controller().condenserTank.fluidAmountInTank(1); state.evaporatorTankSize = controller().evaporatorTank.perSideCapacity; - state.evaporatorIntakeFluid = ForgeRegistries.FLUIDS.getKey(controller().evaporatorTank.fluidTypeInTank(0)).toString(); + state.evaporatorIntakeFluid = BuiltInRegistries.FLUID.getKey(controller().evaporatorTank.fluidTypeInTank(0)).toString(); state.evaporatorIntakeFluidAmount = controller().evaporatorTank.fluidAmountInTank(0); - state.evaporatorExhaustFluid = ForgeRegistries.FLUIDS.getKey(controller().evaporatorTank.fluidTypeInTank(1)).toString(); + state.evaporatorExhaustFluid = BuiltInRegistries.FLUID.getKey(controller().evaporatorTank.fluidTypeInTank(1)).toString(); state.evaporatorExhaustFluidAmount = controller().evaporatorTank.fluidAmountInTank(1); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java index ec01572d..e37063f9 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/ReactorMultiblockController.java @@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.world.level.Level; @@ -12,7 +13,6 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.registries.ForgeRegistries; import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorBaseBlock; import net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorFuelRod; @@ -807,20 +807,20 @@ public void updateReactorState(ReactorState reactorState) { reactorState.coolantStored = coolantTank.liquidAmount(); reactorState.coolantCapacity = coolantTank.perSideCapacity(); coolantTankWrapper.liquidType(); - reactorState.coolantResourceLocation = Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(coolantTankWrapper.liquidType())).toString(); + reactorState.coolantResourceLocation = Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(coolantTankWrapper.liquidType())).toString(); reactorState.exhaustStored = coolantTank.vaporAmount(); reactorState.exhaustCapacity = coolantTank.perSideCapacity(); coolantTankWrapper.vaporType(); - reactorState.exhaustResourceLocation = Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(coolantTankWrapper.vaporType())).toString(); + reactorState.exhaustResourceLocation = Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(coolantTankWrapper.vaporType())).toString(); } else { reactorState.coolantStored = 0; reactorState.coolantCapacity = 0; - reactorState.coolantResourceLocation = Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(Fluids.EMPTY)).toString(); + reactorState.coolantResourceLocation = Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(Fluids.EMPTY)).toString(); reactorState.exhaustStored = 0; reactorState.exhaustCapacity = 0; - reactorState.exhaustResourceLocation = Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(Fluids.EMPTY)).toString(); + reactorState.exhaustResourceLocation = Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(Fluids.EMPTY)).toString(); } reactorState.caseHeatStored = simulation.stackHeat(); reactorState.fuelHeatStored = simulation.fuelHeat(); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorBaseBlock.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorBaseBlock.java index d7dd2e00..2ef531ea 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorBaseBlock.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorBaseBlock.java @@ -13,7 +13,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.network.NetworkHooks; import net.roguelogix.biggerreactors.multiblocks.reactor.state.ReactorActivity; import net.roguelogix.phosphophyllite.modular.block.PhosphophylliteBlock; import net.roguelogix.phosphophyllite.multiblock.rectangular.IRectangularMultiblockBlock; @@ -71,7 +70,7 @@ public InteractionResult onUse(BlockState state, Level level, BlockPos pos, Play if (hand == InteractionHand.MAIN_HAND && state.hasProperty(ASSEMBLED) && state.getValue(ASSEMBLED)) { if (level.getBlockEntity(pos) instanceof MenuProvider menuProvider) { if (!level.isClientSide) { - NetworkHooks.openScreen((ServerPlayer) player, menuProvider, pos); + player.openMenu(menuProvider, pos); } return InteractionResult.SUCCESS; } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorFuelRod.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorFuelRod.java index 2e19c8c1..c1854bc2 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorFuelRod.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorFuelRod.java @@ -9,8 +9,8 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.multiblocks.reactor.tiles.ReactorFuelRodTile; import net.roguelogix.phosphophyllite.registry.RegisterBlock; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorManifold.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorManifold.java index 2ad4d966..f822a24c 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorManifold.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/blocks/ReactorManifold.java @@ -7,8 +7,8 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.multiblocks.reactor.tiles.ReactorManifoldTile; import net.roguelogix.phosphophyllite.modular.block.IConnectedTexture; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ActiveReactorTerminalScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ActiveReactorTerminalScreen.java index 1ab4a58e..336c9e68 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ActiveReactorTerminalScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ActiveReactorTerminalScreen.java @@ -9,9 +9,8 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.client.CommonRender; import net.roguelogix.biggerreactors.multiblocks.reactor.containers.ReactorTerminalContainer; @@ -155,11 +154,11 @@ public void containerTick() { this.getMinecraft().setScreen(new PassiveReactorTerminalScreen(this.menu, this.inventory, this.title)); } // Check if coolant type changed. - if (!reactorState.coolantResourceLocation.equals(Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(coolantFluid)).toString())) { + if (!reactorState.coolantResourceLocation.equals(Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(coolantFluid)).toString())) { coolantFluid = BuiltInRegistries.FLUID.get(new ResourceLocation(reactorState.coolantResourceLocation)); } // Check if exhaust type changed. - if (!reactorState.exhaustResourceLocation.equals(Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(exhaustFluid)).toString())) { + if (!reactorState.exhaustResourceLocation.equals(Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(exhaustFluid)).toString())) { exhaustFluid = BuiltInRegistries.FLUID.get(new ResourceLocation(reactorState.exhaustResourceLocation)); } } @@ -167,7 +166,7 @@ public void containerTick() { /** * Draw the status text for this screen. * - * @param poseStack The current pose stack. +// * @param poseStack The current pose stack. * @param mouseX The x position of the mouse. * @param mouseY The y position of the mouse. * @param partialTicks Partial ticks. @@ -187,7 +186,7 @@ public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float /** * Render the progress bar. * - * @param poseStack The current pose stack. +// * @param poseStack The current pose stack. * @param symbol The symbol to draw as. * @param reactorActivity Current status of the reactor. * @param workTime The time the machine has been working. diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/CommonReactorTerminalScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/CommonReactorTerminalScreen.java index 1e47c4a1..c51873d6 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/CommonReactorTerminalScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/CommonReactorTerminalScreen.java @@ -6,8 +6,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.client.Biselector; import net.roguelogix.biggerreactors.client.SelectorColors; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/PassiveReactorTerminalScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/PassiveReactorTerminalScreen.java index e4365190..d5e8d07c 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/PassiveReactorTerminalScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/PassiveReactorTerminalScreen.java @@ -5,8 +5,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.client.CommonRender; import net.roguelogix.biggerreactors.multiblocks.reactor.containers.ReactorTerminalContainer; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorAccessPortScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorAccessPortScreen.java index 8d5beeb2..74eeb70b 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorAccessPortScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorAccessPortScreen.java @@ -6,8 +6,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.client.Biselector; import net.roguelogix.biggerreactors.client.SelectorColors; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorControlRodScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorControlRodScreen.java index edda669f..fe5eb06f 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorControlRodScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorControlRodScreen.java @@ -8,8 +8,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.client.CommonButton; import net.roguelogix.biggerreactors.client.TextBox; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorCoolantPortScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorCoolantPortScreen.java index 7dc08aff..02ce0b45 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorCoolantPortScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorCoolantPortScreen.java @@ -1,13 +1,12 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.client; -import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.client.Biselector; import net.roguelogix.biggerreactors.client.SelectorColors; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorRedstonePortScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorRedstonePortScreen.java index ca5252d1..cf9d48d8 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorRedstonePortScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/client/ReactorRedstonePortScreen.java @@ -1,22 +1,21 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.client; -import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.client.*; import net.roguelogix.biggerreactors.multiblocks.reactor.containers.ReactorRedstonePortContainer; import net.roguelogix.biggerreactors.multiblocks.reactor.state.ReactorRedstonePortSelection; import net.roguelogix.biggerreactors.multiblocks.reactor.state.ReactorRedstonePortState; import net.roguelogix.biggerreactors.multiblocks.reactor.state.ReactorRedstonePortTriggers; -import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; import net.roguelogix.phosphophyllite.client.gui.elements.InteractiveElement; import net.roguelogix.phosphophyllite.client.gui.elements.RenderedElement; +import net.roguelogix.phosphophyllite.client.gui.screens.PhosphophylliteScreen; import javax.annotation.Nonnull; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/deps/ReactorPeripheral.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/deps/ReactorPeripheral.java index 80dcc1ca..60a84c7f 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/deps/ReactorPeripheral.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/deps/ReactorPeripheral.java @@ -4,7 +4,6 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraftforge.common.util.LazyOptional; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.multiblocks.reactor.ReactorMultiblockController; import net.roguelogix.biggerreactors.multiblocks.reactor.simulation.IReactorSimulation; @@ -19,8 +18,8 @@ public class ReactorPeripheral implements IPeripheral { - public static LazyOptional create(@Nonnull Supplier controllerSupplier) { - return LazyOptional.of(() -> new ReactorPeripheral(controllerSupplier)); + public static ReactorPeripheral create(@Nonnull Supplier controllerSupplier) { + return new ReactorPeripheral(controllerSupplier); } @Nonnull diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java index 04611d33..096b5ad0 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/simulation/accellerated/vk/VkMemUtil.java @@ -134,19 +134,19 @@ private Info attemptAllocInSpace(Info freeAlloc, long size, long alignment) { if (alignmentWaste > 0) { final var newAllocs = freeAlloc.split(alignmentWaste); // not concurrent modification because this will always return - freeAllocations.add(newAllocs.first); - freeAlloc = newAllocs.second; + freeAllocations.add(newAllocs.first()); + freeAlloc = newAllocs.second(); - int index = freeAllocations.indexOf(newAllocs.first); + int index = freeAllocations.indexOf(newAllocs.first()); collapseFreeAllocationWithNext(index - 1); collapseFreeAllocationWithNext(index); } if (freeAlloc.size > size) { final var newAllocs = freeAlloc.split(size); // not concurrent modification because this will always return - freeAlloc = newAllocs.first; - freeAllocations.add(newAllocs.second); - int index = freeAllocations.indexOf(newAllocs.second); + freeAlloc = newAllocs.first(); + freeAllocations.add(newAllocs.second()); + int index = freeAllocations.indexOf(newAllocs.second()); collapseFreeAllocationWithNext(index - 1); collapseFreeAllocationWithNext(index); } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorAccessPortTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorAccessPortTile.java index 632d7e10..fe205fa9 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorAccessPortTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorAccessPortTile.java @@ -1,6 +1,5 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.tiles; -import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.registries.BuiltInRegistries; @@ -17,11 +16,8 @@ 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.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.wrapper.EmptyHandler; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.items.IItemHandler; import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.blocks.materials.MaterialBlock; import net.roguelogix.biggerreactors.items.ingots.BlutoniumIngot; @@ -34,22 +30,26 @@ import net.roguelogix.phosphophyllite.debug.DebugInfo; import net.roguelogix.phosphophyllite.multiblock.common.IEventMultiblock; import net.roguelogix.phosphophyllite.multiblock.validated.IValidatedMultiblock; +import net.roguelogix.phosphophyllite.registry.CapabilityRegistration; +import net.roguelogix.phosphophyllite.registry.RegisterCapability; import net.roguelogix.phosphophyllite.registry.RegisterTile; import net.roguelogix.phosphophyllite.util.BlockStates; +import net.roguelogix.phosphophyllite.util.NonnullDefault; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; import static net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorAccessPort.PortDirection.*; -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault +@NonnullDefault public class ReactorAccessPortTile extends ReactorBaseTile implements IItemHandler, MenuProvider, IHasUpdatableState, IEventMultiblock.AssemblyStateTransition { @RegisterTile("reactor_access_port") public static final BlockEntityType.BlockEntitySupplier SUPPLIER = new RegisterTile.Producer<>(ReactorAccessPortTile::new); + @RegisterCapability + private static final CapabilityRegistration ITEM_HANDLER_CAP_REGISTRATION = CapabilityRegistration.tileCap(Capabilities.ItemHandler.BLOCK, ReactorAccessPortTile.class); + private static final TagKey uraniumIngotTag = TagKey.create(BuiltInRegistries.ITEM.key(), new ResourceLocation("forge:ingots/uranium")); private static final TagKey uraniumBlockTag = TagKey.create(BuiltInRegistries.ITEM.key(), new ResourceLocation("forge:storage_blocks/uranium")); @@ -109,16 +109,6 @@ public void onAssemblyStateTransition(IValidatedMultiblock.AssemblyState oldStat neighborChanged(); } - LazyOptional itemStackHandler = LazyOptional.of(() -> this); - - @Override - protected LazyOptional capability(Capability cap, @Nullable Direction side) { - if (cap == ForgeCapabilities.ITEM_HANDLER) { - return itemStackHandler.cast(); - } - return super.capability(cap, side); - } - @Override public int getSlots() { return 3; @@ -130,7 +120,7 @@ public ItemStack getStackInSlot(int slot) { if (nullableController() == null) { return ItemStack.EMPTY; } - var reactorSim = controller().simulation(); + @Nullable var reactorSim = controller().simulation(); if(reactorSim == null){ return ItemStack.EMPTY; } @@ -220,16 +210,15 @@ public boolean isItemValid(int slot, ItemStack stack) { } public int pushWaste(int waste, boolean simulated) { - if (itemOutput.isPresent()) { - IItemHandler output = itemOutput.orElse(EmptyHandler.INSTANCE); + if (itemOutput != null) { waste /= Config.CONFIG.Reactor.FuelMBPerIngot; int wasteHandled = 0; - for (int i = 0; i < output.getSlots(); i++) { + for (int i = 0; i < itemOutput.getSlots(); i++) { if (waste == 0) { break; } ItemStack toInsertStack = new ItemStack(CyaniteIngot.INSTANCE, waste); - ItemStack remainingStack = output.insertItem(i, toInsertStack, simulated); + ItemStack remainingStack = itemOutput.insertItem(i, toInsertStack, simulated); wasteHandled += toInsertStack.getCount() - remainingStack.getCount(); waste -= toInsertStack.getCount() - remainingStack.getCount(); } @@ -243,16 +232,15 @@ public void ejectWaste() { } public int pushFuel(int fuel, boolean simulated) { - if (itemOutput.isPresent()) { - IItemHandler output = itemOutput.orElse(EmptyHandler.INSTANCE); + if (itemOutput != null) { fuel /= Config.CONFIG.Reactor.FuelMBPerIngot; int fuelHandled = 0; - for (int i = 0; i < output.getSlots(); i++) { + for (int i = 0; i < itemOutput.getSlots(); i++) { if (fuel == 0) { break; } ItemStack toInsertStack = new ItemStack(UraniumIngot.INSTANCE, fuel); - ItemStack remainingStack = output.insertItem(i, toInsertStack, simulated); + ItemStack remainingStack = itemOutput.insertItem(i, toInsertStack, simulated); fuelHandled += toInsertStack.getCount() - remainingStack.getCount(); fuel -= toInsertStack.getCount() - remainingStack.getCount(); } @@ -265,26 +253,22 @@ public void ejectFuel() { controller().extractFuel(pushFuel((int) controller().extractFuel(Integer.MAX_VALUE, true), false), false); } + @Nullable Direction itemOutputDirection; boolean connected; - LazyOptional itemOutput = LazyOptional.empty(); + @Nullable + IItemHandler itemOutput = null; public final ReactorAccessPortState reactorAccessPortState = new ReactorAccessPortState(this); @SuppressWarnings("DuplicatedCode") public void neighborChanged() { - itemOutput = LazyOptional.empty(); if (itemOutputDirection == null) { connected = false; return; } assert level != null; - BlockEntity te = level.getBlockEntity(worldPosition.relative(itemOutputDirection)); - if (te == null) { - connected = false; - return; - } - itemOutput = te.getCapability(ForgeCapabilities.ITEM_HANDLER, itemOutputDirection.getOpposite()); - connected = itemOutput.isPresent(); + itemOutput = level.getCapability(Capabilities.ItemHandler.BLOCK, worldPosition.relative(itemOutputDirection), itemOutputDirection.getOpposite()); + connected = itemOutput != null; } @Override diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorComputerPortTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorComputerPortTile.java index c51956ed..fe992b4e 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorComputerPortTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorComputerPortTile.java @@ -6,10 +6,6 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; -import net.minecraftforge.common.util.LazyOptional; import net.roguelogix.biggerreactors.multiblocks.reactor.deps.ReactorPeripheral; import net.roguelogix.phosphophyllite.multiblock.common.IEventMultiblock; import net.roguelogix.phosphophyllite.registry.RegisterTile; @@ -28,30 +24,31 @@ public ReactorComputerPortTile(BlockEntityType TYPE, BlockPos pos, BlockState super(TYPE, pos, state); } - private static final Capability CAPABILITY_PERIPHERAL = CapabilityManager.get(new CapabilityToken<>(){}); - - private LazyOptional peripheralCapability; - - { - // avoids classloading without CC existing - if (CAPABILITY_PERIPHERAL.isRegistered()) { - peripheralCapability = ReactorPeripheral.create(this::controller); - } - } - - @Override - public LazyOptional capability(Capability cap, final @Nullable Direction side) { - if (cap == CAPABILITY_PERIPHERAL) { - return peripheralCapability.cast(); - } - return super.capability(cap, side); - } + // TODO: computercraft capability +// private static final Capability CAPABILITY_PERIPHERAL = CapabilityManager.get(new CapabilityToken<>(){}); +// +// private LazyOptional peripheralCapability; +// +// { +// // avoids classloading without CC existing +// if (CAPABILITY_PERIPHERAL.isRegistered()) { +// peripheralCapability = ReactorPeripheral.create(this::controller); +// } +// } +// +// @Override +// public LazyOptional capability(Capability cap, final @Nullable Direction side) { +// if (cap == CAPABILITY_PERIPHERAL) { +// return peripheralCapability.cast(); +// } +// return super.capability(cap, side); +// } @Override public void onAssembly() { // class loading BS, dont remove this if - if (CAPABILITY_PERIPHERAL.isRegistered()) { - peripheralCapability.ifPresent(ReactorPeripheral::rebuildControlRodList); - } +// if (CAPABILITY_PERIPHERAL.isRegistered()) { +// peripheralCapability.ifPresent(ReactorPeripheral::rebuildControlRodList); +// } } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorCoolantPortTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorCoolantPortTile.java index 1f43ebc9..1517b265 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorCoolantPortTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorCoolantPortTile.java @@ -1,6 +1,5 @@ package net.roguelogix.biggerreactors.multiblocks.reactor.tiles; -import mekanism.api.chemical.gas.IGasHandler; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -10,29 +9,23 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -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.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.templates.FluidTank; -import net.roguelogix.biggerreactors.multiblocks.reactor.util.ReactorTransitionTank; +import net.neoforged.neoforge.capabilities.Capabilities; import net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorAccessPort; import net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorCoolantPort; import net.roguelogix.biggerreactors.multiblocks.reactor.containers.ReactorCoolantPortContainer; import net.roguelogix.biggerreactors.multiblocks.reactor.state.ReactorCoolantPortState; +import net.roguelogix.biggerreactors.multiblocks.reactor.util.ReactorTransitionTank; +import net.roguelogix.phosphophyllite.client.gui.api.IHasUpdatableState; import net.roguelogix.phosphophyllite.fluids.FluidHandlerWrapper; import net.roguelogix.phosphophyllite.fluids.IPhosphophylliteFluidHandler; -import net.roguelogix.phosphophyllite.client.gui.api.IHasUpdatableState; -import net.roguelogix.phosphophyllite.fluids.MekanismGasWrappers; import net.roguelogix.phosphophyllite.multiblock.common.IEventMultiblock; import net.roguelogix.phosphophyllite.multiblock.validated.IValidatedMultiblock; +import net.roguelogix.phosphophyllite.registry.CapabilityRegistration; +import net.roguelogix.phosphophyllite.registry.RegisterCapability; import net.roguelogix.phosphophyllite.registry.RegisterTile; import net.roguelogix.phosphophyllite.util.BlockStates; @@ -48,23 +41,27 @@ public class ReactorCoolantPortTile extends ReactorBaseTile implements IPhosphop @RegisterTile("reactor_coolant_port") public static final BlockEntityType.BlockEntitySupplier SUPPLIER = new RegisterTile.Producer<>(ReactorCoolantPortTile::new); + @RegisterCapability + private static final CapabilityRegistration FLUID_HANDLER_CAP_REGISTRATION = CapabilityRegistration.tileCap(Capabilities.FluidHandler.BLOCK, ReactorCoolantPortTile.class); + public ReactorCoolantPortTile(BlockEntityType TYPE, BlockPos pos, BlockState state) { super(TYPE, pos, state); } - - private static final Capability GAS_HANDLER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>() { - }); - - @Override - public LazyOptional capability(Capability cap, @Nullable Direction side) { - if (cap == ForgeCapabilities.FLUID_HANDLER) { - return LazyOptional.of(() -> this).cast(); - } - if (cap == GAS_HANDLER_CAPABILITY) { - return LazyOptional.of(() -> MekanismGasWrappers.wrap(this)).cast(); - } - return super.capability(cap, side); - } + + // TODO: mek gas cap registration, needs to not be a hard-dep +// private static final Capability GAS_HANDLER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>() { +// }); +// +// @Override +// public LazyOptional capability(Capability cap, @Nullable Direction side) { +// if (cap == ForgeCapabilities.FLUID_HANDLER) { +// return LazyOptional.of(() -> this).cast(); +// } +// if (cap == GAS_HANDLER_CAPABILITY) { +// return LazyOptional.of(() -> MekanismGasWrappers.wrap(this)).cast(); +// } +// return super.capability(cap, side); +// } @Nullable private ReactorTransitionTank transitionTank; @@ -138,7 +135,7 @@ public long pushFluid() { if (!connected || direction == INLET) { return 0; } - if (handlerOptional.isPresent() && transitionTank != null) { + if (handler != null && transitionTank != null) { Fluid fluid = transitionTank.vaporType(); long amount = transitionTank.vaporAmount(); amount = transitionTank.drain(fluid, null, amount, true); @@ -146,7 +143,6 @@ public long pushFluid() { amount = transitionTank.drain(fluid, null, amount, false); return amount; } else { - handlerOptional = LazyOptional.empty(); handler = null; connected = false; } @@ -156,40 +152,32 @@ public long pushFluid() { private boolean connected = false; Direction steamOutputDirection = null; - LazyOptional handlerOptional = LazyOptional.empty(); IPhosphophylliteFluidHandler handler = null; - FluidTank EMPTY_TANK = new FluidTank(0); private ReactorAccessPort.PortDirection direction = INLET; public final ReactorCoolantPortState reactorCoolantPortState = new ReactorCoolantPortState(this); @SuppressWarnings("DuplicatedCode") public void neighborChanged() { - handlerOptional = LazyOptional.empty(); handler = null; if (steamOutputDirection == null) { connected = false; return; } assert level != null; - BlockEntity te = level.getBlockEntity(worldPosition.relative(steamOutputDirection)); - if (te == null) { - connected = false; - return; - } + final var capHandler = level.getCapability(Capabilities.FluidHandler.BLOCK, worldPosition.relative(steamOutputDirection), steamOutputDirection.getOpposite()); connected = false; - LazyOptional fluidOptional = te.getCapability(ForgeCapabilities.FLUID_HANDLER, steamOutputDirection.getOpposite()); - if (fluidOptional.isPresent()) { + if (capHandler != null) { connected = true; - handlerOptional = fluidOptional; - handler = FluidHandlerWrapper.wrap(fluidOptional.orElse(EMPTY_TANK)); - } else if (GAS_HANDLER_CAPABILITY != null) { - LazyOptional gasOptional = te.getCapability(GAS_HANDLER_CAPABILITY, steamOutputDirection.getOpposite()); - if (gasOptional.isPresent()) { - IGasHandler gasHandler = gasOptional.orElse(MekanismGasWrappers.EMPTY_TANK); - connected = true; - handlerOptional = gasOptional; - handler = MekanismGasWrappers.wrap(gasHandler); - } + handler = FluidHandlerWrapper.wrap(capHandler); + // TODO: mek gas +// } else if (GAS_HANDLER_CAPABILITY != null) { +// LazyOptional gasOptional = te.getCapability(GAS_HANDLER_CAPABILITY, steamOutputDirection.getOpposite()); +// if (gasOptional.isPresent()) { +// IGasHandler gasHandler = gasOptional.orElse(MekanismGasWrappers.EMPTY_TANK); +// connected = true; +// handlerOptional = gasOptional; +// handler = MekanismGasWrappers.wrap(gasHandler); +// } } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorPowerTapTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorPowerTapTile.java index 1153d379..91bd9fd1 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorPowerTapTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/reactor/tiles/ReactorPowerTapTile.java @@ -5,23 +5,21 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; +import net.roguelogix.phosphophyllite.capability.CachedWrappedBlockCapability; import net.roguelogix.phosphophyllite.energy.IEnergyTile; import net.roguelogix.phosphophyllite.energy.IPhosphophylliteEnergyHandler; import net.roguelogix.phosphophyllite.multiblock.common.IEventMultiblock; import net.roguelogix.phosphophyllite.multiblock.validated.IValidatedMultiblock; import net.roguelogix.phosphophyllite.registry.RegisterTile; import net.roguelogix.phosphophyllite.util.BlockStates; +import net.roguelogix.phosphophyllite.util.NonnullDefault; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; import static net.roguelogix.biggerreactors.multiblocks.reactor.blocks.ReactorPowerTap.ConnectionState.*; -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault +@NonnullDefault public class ReactorPowerTapTile extends ReactorBaseTile implements IEnergyTile, IPhosphophylliteEnergyHandler, IEventMultiblock.AssemblyStateTransition { @RegisterTile("reactor_power_tap") @@ -32,13 +30,13 @@ public ReactorPowerTapTile(BlockEntityType TYPE, BlockPos pos, BlockState sta } private boolean connected = false; + @Nullable Direction powerOutputDirection = null; - LazyOptional thisCap = LazyOptional.of(() -> this); @Override - public LazyOptional energyHandler() { - return thisCap; + public IPhosphophylliteEnergyHandler energyHandler(Direction direction) { + return this; } private void setConnected(boolean newState) { @@ -49,14 +47,19 @@ private void setConnected(boolean newState) { } } - LazyOptional outputOptional = LazyOptional.empty(); - IPhosphophylliteEnergyHandler output; + @Nullable + CachedWrappedBlockCapability output = null; public long distributePower(long toDistribute, boolean simulate) { - if (outputOptional.isPresent()) { - return Math.max(0, output.insertEnergy(toDistribute, simulate)); + if(output == null) { + return 0; } - return 0; + @Nullable + final var outputCap = output.getCapability(); + if (outputCap == null) { + return 0; + } + return Math.max(0, outputCap.insertEnergy(toDistribute, simulate)); } @Override @@ -69,11 +72,11 @@ public long extractEnergy(long maxExtract, boolean simulate) { if (maxExtract <= 0 || nullableController() == null || controller().assemblyState() != IValidatedMultiblock.AssemblyState.ASSEMBLED) { return 0; } - var reactorSim = controller().simulation(); + @Nullable var reactorSim = controller().simulation(); if (reactorSim == null) { return 0; } - var battery = reactorSim.battery(); + @Nullable var battery = reactorSim.battery(); if (battery == null) { return 0; } @@ -88,11 +91,11 @@ public long extractEnergy(long maxExtract, boolean simulate) { @Override public long energyStored() { if (nullableController() != null) { - var reactorSim = controller().simulation(); + @Nullable var reactorSim = controller().simulation(); if (reactorSim == null) { return 0; } - var battery = reactorSim.battery(); + @Nullable var battery = reactorSim.battery(); if (battery == null) { return 0; } @@ -104,11 +107,11 @@ public long energyStored() { @Override public long maxEnergyStored() { if (nullableController() != null) { - var reactorSim = controller().simulation(); + @Nullable var reactorSim = controller().simulation(); if (reactorSim == null) { return 0; } - var battery = reactorSim.battery(); + @Nullable var battery = reactorSim.battery(); if (battery == null) { return 0; } @@ -119,20 +122,13 @@ public long maxEnergyStored() { @SuppressWarnings("DuplicatedCode") public void neighborChanged() { - outputOptional = LazyOptional.empty(); output = null; if (powerOutputDirection == null) { setConnected(false); return; } - - final var outputCap = this.findEnergyCapability(powerOutputDirection); - setConnected(outputCap.isPresent()); - if (connected) { - outputOptional = outputCap; - //noinspection DataFlowIssue - output = outputOptional.orElse(null); - } + output = findEnergyCapability(powerOutputDirection); + setConnected(output.getCapability() != null); } @Override diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/TurbineMultiblockController.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/TurbineMultiblockController.java index aa10256d..6e64b251 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/TurbineMultiblockController.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/TurbineMultiblockController.java @@ -5,11 +5,11 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.AirBlock; import net.minecraft.world.level.block.Block; -import net.minecraftforge.registries.ForgeRegistries; import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.multiblocks.turbine.blocks.TurbineBaseBlock; import net.roguelogix.biggerreactors.multiblocks.turbine.blocks.TurbineRotorBlade; @@ -538,11 +538,11 @@ public void updateDataPacket(TurbineState turbineState) { turbineState.intakeStored = simulation.fluidTank().vaporAmount(); turbineState.intakeCapacity = simulation.fluidTank().perSideCapacity(); - turbineState.intakeResourceLocation = ForgeRegistries.FLUIDS.getKey(simulation().fluidTank().vaporType()).toString(); + turbineState.intakeResourceLocation = BuiltInRegistries.FLUID.getKey(simulation().fluidTank().vaporType()).toString(); turbineState.exhaustStored = simulation.fluidTank().liquidAmount(); turbineState.exhaustCapacity = simulation.fluidTank().perSideCapacity(); - turbineState.exhaustResourceLocation = ForgeRegistries.FLUIDS.getKey(simulation().fluidTank().liquidType()).toString(); + turbineState.exhaustResourceLocation = BuiltInRegistries.FLUID.getKey(simulation().fluidTank().liquidType()).toString(); turbineState.energyStored = simulation.battery().stored(); turbineState.energyCapacity = simulation.battery().capacity(); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/blocks/TurbineBaseBlock.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/blocks/TurbineBaseBlock.java index 7c003b03..e66190d8 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/blocks/TurbineBaseBlock.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/blocks/TurbineBaseBlock.java @@ -14,7 +14,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.network.NetworkHooks; import net.roguelogix.biggerreactors.multiblocks.turbine.state.TurbineActivity; import net.roguelogix.phosphophyllite.modular.block.PhosphophylliteBlock; import net.roguelogix.phosphophyllite.multiblock.IMultiblockBlock; @@ -72,7 +71,7 @@ public InteractionResult onUse(BlockState state, Level level, BlockPos pos, Play if (hand == InteractionHand.MAIN_HAND && state.hasProperty(ASSEMBLED) && state.getValue(ASSEMBLED)) { if (level.getBlockEntity(pos) instanceof MenuProvider menuProvider) { if (!level.isClientSide) { - NetworkHooks.openScreen((ServerPlayer) player, menuProvider, pos); + player.openMenu(menuProvider, pos); } return InteractionResult.SUCCESS; } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/client/TurbineFluidPortScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/client/TurbineFluidPortScreen.java index c2ae239f..7c50196e 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/client/TurbineFluidPortScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/client/TurbineFluidPortScreen.java @@ -5,8 +5,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.client.Biselector; import net.roguelogix.biggerreactors.client.SelectorColors; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/client/TurbineTerminalScreen.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/client/TurbineTerminalScreen.java index 9722c590..e70c7642 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/client/TurbineTerminalScreen.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/client/TurbineTerminalScreen.java @@ -11,7 +11,6 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.registries.ForgeRegistries; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.Config; import net.roguelogix.biggerreactors.client.Biselector; @@ -280,11 +279,11 @@ public void containerTick() { turbineState = (TurbineState) this.getMenu().getGuiPacket(); super.containerTick(); // Check if intake type changed. - if (!turbineState.intakeResourceLocation.equals(Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(intakeFluid)).toString())) { + if (!turbineState.intakeResourceLocation.equals(Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(intakeFluid)).toString())) { intakeFluid = BuiltInRegistries.FLUID.get(new ResourceLocation(turbineState.intakeResourceLocation)); } // Check if exhaust type changed. - if (!turbineState.exhaustResourceLocation.equals(Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(exhaustFluid)).toString())) { + if (!turbineState.exhaustResourceLocation.equals(Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(exhaustFluid)).toString())) { exhaustFluid = BuiltInRegistries.FLUID.get(new ResourceLocation(turbineState.exhaustResourceLocation)); } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/deps/TurbinePeripheral.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/deps/TurbinePeripheral.java index 4c1459fa..7636c209 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/deps/TurbinePeripheral.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/deps/TurbinePeripheral.java @@ -4,8 +4,7 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.registries.ForgeRegistries; +import net.minecraft.core.registries.BuiltInRegistries; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.multiblocks.turbine.TurbineMultiblockController; import net.roguelogix.biggerreactors.multiblocks.turbine.state.VentState; @@ -22,8 +21,8 @@ public class TurbinePeripheral implements IPeripheral { @Nonnull private final LamdbaExceptionUtils.Supplier_WithExceptions controllerSupplier; - public static LazyOptional create(@Nonnull Supplier controllerSupplier) { - return LazyOptional.of(() -> new TurbinePeripheral(controllerSupplier)); + public static TurbinePeripheral create(@Nonnull Supplier controllerSupplier) { + return new TurbinePeripheral(controllerSupplier); } public TurbinePeripheral(@Nonnull Supplier rawControllerSupplier) { @@ -147,7 +146,7 @@ public TankFluid(LamdbaExceptionUtils.Supplier_WithExceptions { long extract(long toExtract); diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/simulation/ITurbineFluidTank.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/simulation/ITurbineFluidTank.java index f695bc9b..0b28cf22 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/simulation/ITurbineFluidTank.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/simulation/ITurbineFluidTank.java @@ -2,7 +2,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.common.util.INBTSerializable; +import net.neoforged.neoforge.common.util.INBTSerializable; import net.roguelogix.phosphophyllite.fluids.IPhosphophylliteFluidHandler; public interface ITurbineFluidTank extends INBTSerializable, IPhosphophylliteFluidHandler { diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/simulation/ITurbineSimulation.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/simulation/ITurbineSimulation.java index e0399faa..b99c0e4f 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/simulation/ITurbineSimulation.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/simulation/ITurbineSimulation.java @@ -1,7 +1,7 @@ package net.roguelogix.biggerreactors.multiblocks.turbine.simulation; import net.minecraft.nbt.CompoundTag; -import net.minecraftforge.common.util.INBTSerializable; +import net.neoforged.neoforge.common.util.INBTSerializable; import net.roguelogix.biggerreactors.multiblocks.turbine.state.VentState; import net.roguelogix.biggerreactors.registries.TurbineCoilRegistry; import org.joml.Vector4i; diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineComputerPortTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineComputerPortTile.java index 7c6683b5..2549b72f 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineComputerPortTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineComputerPortTile.java @@ -6,10 +6,6 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; -import net.minecraftforge.common.util.LazyOptional; import net.roguelogix.biggerreactors.multiblocks.turbine.deps.TurbinePeripheral; import net.roguelogix.phosphophyllite.registry.RegisterTile; @@ -27,14 +23,15 @@ public TurbineComputerPortTile(BlockEntityType TYPE, BlockPos pos, BlockState super(TYPE, pos, state); } - private static final Capability CAPABILITY_PERIPHERAL = CapabilityManager.get(new CapabilityToken<>(){}); - - @Override - public LazyOptional capability(Capability cap, final @Nullable Direction side) { - if (cap == CAPABILITY_PERIPHERAL) { - return TurbinePeripheral.create(this::controller).cast(); - } - return super.capability(cap, side); - } - + // TODO: computercraft capability +// private static final Capability CAPABILITY_PERIPHERAL = CapabilityManager.get(new CapabilityToken<>(){}); +// +// @Override +// public LazyOptional capability(Capability cap, final @Nullable Direction side) { +// if (cap == CAPABILITY_PERIPHERAL) { +// return TurbinePeripheral.create(this::controller).cast(); +// } +// return super.capability(cap, side); +// } +// } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineFluidPortTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineFluidPortTile.java index 13b564f0..d4209be5 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineFluidPortTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineFluidPortTile.java @@ -15,13 +15,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.templates.FluidTank; +import net.neoforged.neoforge.capabilities.Capabilities; import net.roguelogix.biggerreactors.multiblocks.turbine.blocks.TurbineFluidPort; import net.roguelogix.biggerreactors.multiblocks.turbine.containers.TurbineFluidPortContainer; import net.roguelogix.biggerreactors.multiblocks.turbine.simulation.ITurbineFluidTank; @@ -32,6 +26,8 @@ import net.roguelogix.phosphophyllite.fluids.MekanismGasWrappers; import net.roguelogix.phosphophyllite.multiblock.common.IEventMultiblock; import net.roguelogix.phosphophyllite.multiblock.validated.IValidatedMultiblock; +import net.roguelogix.phosphophyllite.registry.CapabilityRegistration; +import net.roguelogix.phosphophyllite.registry.RegisterCapability; import net.roguelogix.phosphophyllite.registry.RegisterTile; import net.roguelogix.phosphophyllite.util.BlockStates; @@ -47,22 +43,26 @@ public class TurbineFluidPortTile extends TurbineBaseTile implements IPhosphophy @RegisterTile("turbine_fluid_port") public static final BlockEntityType.BlockEntitySupplier SUPPLIER = new RegisterTile.Producer<>(TurbineFluidPortTile::new); + @RegisterCapability + private static final CapabilityRegistration FLUID_HANDLER_CAP_REGISTRATION = CapabilityRegistration.tileCap(Capabilities.FluidHandler.BLOCK, TurbineFluidPortTile.class); + public TurbineFluidPortTile(BlockEntityType TYPE, BlockPos pos, BlockState state) { super(TYPE, pos, state); } - private static final Capability GAS_HANDLER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>(){}); - - @Override - public LazyOptional capability(Capability cap, @Nullable Direction side) { - if (cap == ForgeCapabilities.FLUID_HANDLER) { - return LazyOptional.of(() -> this).cast(); - } - if (cap == GAS_HANDLER_CAPABILITY) { - return LazyOptional.of(() -> MekanismGasWrappers.wrap(this)).cast(); - } - return super.capability(cap, side); - } + // TODO: mek gas +// private static final Capability GAS_HANDLER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>(){}); +// +// @Override +// public LazyOptional capability(Capability cap, @Nullable Direction side) { +// if (cap == ForgeCapabilities.FLUID_HANDLER) { +// return LazyOptional.of(() -> this).cast(); +// } +// if (cap == GAS_HANDLER_CAPABILITY) { +// return LazyOptional.of(() -> MekanismGasWrappers.wrap(this)).cast(); +// } +// return super.capability(cap, side); +// } private ITurbineFluidTank transitionTank; @@ -135,8 +135,7 @@ public long pushFluid() { if (!connected || direction == INLET) { return 0; } - if (handlerOptional.isPresent()) { - + if (handler != null) { Fluid fluid = transitionTank.liquidType(); long amount = transitionTank.liquidAmount(); amount = transitionTank.drain(fluid, null, amount, true); @@ -144,7 +143,6 @@ public long pushFluid() { amount = transitionTank.drain(fluid, null, amount, false); return amount; } else { - handlerOptional = LazyOptional.empty(); handler = null; connected = false; } @@ -154,40 +152,36 @@ public long pushFluid() { private boolean connected = false; Direction waterOutputDirection = null; - LazyOptional handlerOptional = LazyOptional.empty(); IPhosphophylliteFluidHandler handler = null; - FluidTank EMPTY_TANK = new FluidTank(0); private TurbineFluidPort.PortDirection direction = INLET; public final TurbineFluidPortState fluidPortState = new TurbineFluidPortState(this); @SuppressWarnings("DuplicatedCode") public void neighborChanged() { - handlerOptional = LazyOptional.empty(); handler = null; if (waterOutputDirection == null) { connected = false; return; } assert level != null; - BlockEntity te = level.getBlockEntity(worldPosition.relative(waterOutputDirection)); - if (te == null) { + final var outputCap = level.getCapability(Capabilities.FluidHandler.BLOCK, worldPosition.relative(waterOutputDirection), waterOutputDirection.getOpposite()); + if (outputCap == null) { connected = false; return; } connected = false; - LazyOptional waterOutput = te.getCapability(ForgeCapabilities.FLUID_HANDLER, waterOutputDirection.getOpposite()); - if (waterOutput.isPresent()) { + if (outputCap != null) { connected = true; - handlerOptional = waterOutput; - handler = FluidHandlerWrapper.wrap(waterOutput.orElse(EMPTY_TANK)); - } else if (GAS_HANDLER_CAPABILITY != null) { - LazyOptional gasOptional = te.getCapability(GAS_HANDLER_CAPABILITY, waterOutputDirection.getOpposite()); - if (gasOptional.isPresent()) { - IGasHandler gasHandler = gasOptional.orElse(MekanismGasWrappers.EMPTY_TANK); - connected = true; - handlerOptional = gasOptional; - handler = MekanismGasWrappers.wrap(gasHandler); - } + handler = FluidHandlerWrapper.wrap(outputCap); + // todo: mek gas +// } else if (GAS_HANDLER_CAPABILITY != null) { +// LazyOptional gasOptional = te.getCapability(GAS_HANDLER_CAPABILITY, waterOutputDirection.getOpposite()); +// if (gasOptional.isPresent()) { +// IGasHandler gasHandler = gasOptional.orElse(MekanismGasWrappers.EMPTY_TANK); +// connected = true; +// handlerOptional = gasOptional; +// handler = MekanismGasWrappers.wrap(gasHandler); +// } } } diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbinePowerTapTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbinePowerTapTile.java index 0861d8c0..948a636b 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbinePowerTapTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbinePowerTapTile.java @@ -5,9 +5,7 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; +import net.roguelogix.phosphophyllite.capability.CachedWrappedBlockCapability; import net.roguelogix.phosphophyllite.energy.IEnergyTile; import net.roguelogix.phosphophyllite.energy.IPhosphophylliteEnergyHandler; import net.roguelogix.phosphophyllite.multiblock.common.IEventMultiblock; @@ -34,11 +32,9 @@ public TurbinePowerTapTile(BlockEntityType TYPE, BlockPos pos, BlockState sta private boolean connected = false; Direction powerOutputDirection = null; - LazyOptional thisCap = LazyOptional.of(() -> this); - @Override - public LazyOptional energyHandler() { - return thisCap; + public IPhosphophylliteEnergyHandler energyHandler(Direction direction) { + return this; } private void setConnected(boolean newState) { @@ -49,14 +45,19 @@ private void setConnected(boolean newState) { } } - LazyOptional outputOptional = LazyOptional.empty(); - IPhosphophylliteEnergyHandler output; + @Nullable + CachedWrappedBlockCapability output = null;; public long distributePower(long toDistribute, boolean simulate) { - if (outputOptional.isPresent()) { - return Math.max(0, output.insertEnergy(toDistribute, simulate)); + if(output == null) { + return 0; } - return 0; + @Nullable + final var outputCap = output.getCapability(); + if (outputCap == null) { + return 0; + } + return Math.max(0, outputCap.insertEnergy(toDistribute, simulate)); } @Override @@ -96,20 +97,14 @@ public long maxEnergyStored() { @SuppressWarnings("DuplicatedCode") public void neighborChanged() { - outputOptional = LazyOptional.empty(); output = null; if (powerOutputDirection == null) { setConnected(false); return; } - final var outputCap = this.findEnergyCapability(powerOutputDirection); - setConnected(outputCap.isPresent()); - if (connected) { - outputOptional = outputCap; - //noinspection DataFlowIssue - output = outputOptional.orElse(null); - } + output = findEnergyCapability(powerOutputDirection); + setConnected(output.getCapability() != null); } @Override diff --git a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineRotorBearingTile.java b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineRotorBearingTile.java index cc9737fb..1696a38d 100644 --- a/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineRotorBearingTile.java +++ b/src/main/java/net/roguelogix/biggerreactors/multiblocks/turbine/tiles/TurbineRotorBearingTile.java @@ -8,8 +8,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import net.roguelogix.biggerreactors.multiblocks.turbine.blocks.TurbineRotorBlade; import net.roguelogix.biggerreactors.multiblocks.turbine.blocks.TurbineRotorShaft; import net.roguelogix.phosphophyllite.Phosphophyllite; @@ -153,15 +151,6 @@ public void onAssemblyStateTransition(IValidatedMultiblock.AssemblyState oldStat sendFullUpdate = Phosphophyllite.tickNumber() + 10; } - @OnlyIn(Dist.CLIENT) - @Override - public AABB getRenderBoundingBox() { - if (AABB == null) { - return INFINITE_EXTENT_AABB; - } - return AABB; - } - static { Quartz.EVENT_BUS.addListener(TurbineRotorBearingTile::onQuartzStartup); } diff --git a/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java b/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java index 7b3fb4d6..0d17743d 100644 --- a/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java +++ b/src/main/java/net/roguelogix/biggerreactors/registries/FluidTransitionRegistry.java @@ -5,7 +5,6 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.registries.ForgeRegistries; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.phosphophyllite.config.ConfigValue; import net.roguelogix.phosphophyllite.data.DatapackLoader; @@ -174,8 +173,8 @@ public static void loadRegistry() { } })); } else { - if (ForgeRegistries.FLUIDS.containsKey(transitionData.liquid)) { - Fluid fluid = ForgeRegistries.FLUIDS.getValue(transitionData.liquid); + if (BuiltInRegistries.FLUID.containsKey(transitionData.liquid)) { + Fluid fluid = BuiltInRegistries.FLUID.get(transitionData.liquid); liquids.add(fluid); } @@ -196,8 +195,8 @@ public static void loadRegistry() { } })); } else { - if (ForgeRegistries.FLUIDS.containsKey(transitionData.gas)) { - Fluid fluid = ForgeRegistries.FLUIDS.getValue(transitionData.gas); + if (BuiltInRegistries.FLUID.containsKey(transitionData.gas)) { + Fluid fluid = BuiltInRegistries.FLUID.get(transitionData.gas); gases.add(fluid); } @@ -212,13 +211,13 @@ public static void loadRegistry() { for (Fluid liquid : transition.liquids) { if (liquidTransitions.put(liquid, transition) != null) { - BiggerReactors.LOGGER.error("Duplicate transitions given for liquid fluid " + ForgeRegistries.FLUIDS.getKey(liquid).toString()); + BiggerReactors.LOGGER.error("Duplicate transitions given for liquid fluid " + BuiltInRegistries.FLUID.getKey(liquid).toString()); } } for (Fluid gas : transition.gases) { if (gasTransitions.put(gas, transition) != null) { - BiggerReactors.LOGGER.error("Duplicate transitions given for gas fluid " + ForgeRegistries.FLUIDS.getKey(gas).toString()); + BiggerReactors.LOGGER.error("Duplicate transitions given for gas fluid " + BuiltInRegistries.FLUID.getKey(gas).toString()); } } diff --git a/src/main/java/net/roguelogix/biggerreactors/registries/ReactorModeratorRegistry.java b/src/main/java/net/roguelogix/biggerreactors/registries/ReactorModeratorRegistry.java index e4ce915f..86bab906 100644 --- a/src/main/java/net/roguelogix/biggerreactors/registries/ReactorModeratorRegistry.java +++ b/src/main/java/net/roguelogix/biggerreactors/registries/ReactorModeratorRegistry.java @@ -13,11 +13,11 @@ import net.minecraft.world.item.BucketItem; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.OnDatapackSyncEvent; -import net.minecraftforge.event.entity.player.ItemTooltipEvent; -import net.minecraftforge.fml.loading.FMLEnvironment; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.OnDatapackSyncEvent; +import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.Config; import net.roguelogix.phosphophyllite.config.ConfigValue; @@ -161,13 +161,13 @@ public static void loadRegistry() { blockTagOptional.ifPresent(holders -> holders.forEach(blockHolder -> { var element = blockHolder.value(); registry.put(element, properties); - BiggerReactors.LOGGER.debug("Loaded moderator " + ForgeRegistries.BLOCKS.getKey(element)); + BiggerReactors.LOGGER.debug("Loaded moderator " + BuiltInRegistries.BLOCK.getKey(element)); })); } case registry -> { // cant check against air, because air is a valid thing to load - if (ForgeRegistries.BLOCKS.containsKey(moderatorData.location)) { - registry.put(ForgeRegistries.BLOCKS.getValue(moderatorData.location), properties); + if (BuiltInRegistries.BLOCK.containsKey(moderatorData.location)) { + registry.put(BuiltInRegistries.BLOCK.get(moderatorData.location), properties); BiggerReactors.LOGGER.debug("Loaded moderator " + moderatorData.location); } } @@ -177,13 +177,13 @@ public static void loadRegistry() { var element = fluidHolder.value(); Block elementBlock = element.defaultFluidState().createLegacyBlock().getBlock(); registry.put(elementBlock, properties); - BiggerReactors.LOGGER.debug("Loaded moderator " + ForgeRegistries.FLUIDS.getKey(element)); + BiggerReactors.LOGGER.debug("Loaded moderator " + BuiltInRegistries.FLUID.getKey(element)); })); } case fluid -> { // cant check against air, because air is a valid thing to load - if (ForgeRegistries.FLUIDS.containsKey(moderatorData.location)) { - Fluid fluid = ForgeRegistries.FLUIDS.getValue(moderatorData.location); + if (BuiltInRegistries.FLUID.containsKey(moderatorData.location)) { + Fluid fluid = BuiltInRegistries.FLUID.get(moderatorData.location); assert fluid != null; Block block = fluid.defaultFluidState().createLegacyBlock().getBlock(); registry.put(block, properties); @@ -197,15 +197,15 @@ public static void loadRegistry() { public static class Client { - private static final SimplePhosChannel CHANNEL = new SimplePhosChannel(new ResourceLocation(BiggerReactors.modid, "moderator_sync_channel"), "0", Client::readSync); + private static final SimplePhosChannel CHANNEL = new SimplePhosChannel(new ResourceLocation(BiggerReactors.modid, "moderator_sync_channel"), Client::readSync, null); private static final ObjectOpenHashSet moderatorBlocks = new ObjectOpenHashSet<>(); private static final Object2ObjectOpenHashMap moderatorProperties = new Object2ObjectOpenHashMap<>(); @OnModLoad private static void onModLoad() { - MinecraftForge.EVENT_BUS.addListener(Client::datapackEvent); + NeoForge.EVENT_BUS.addListener(Client::datapackEvent); if (FMLEnvironment.dist.isClient()) { - MinecraftForge.EVENT_BUS.addListener(Client::toolTipEvent); + NeoForge.EVENT_BUS.addListener(Client::toolTipEvent); } } @@ -225,7 +225,7 @@ private static PhosphophylliteCompound writeSync() { final var list = new ObjectArrayList(); final var propertiesList = new ObjectArrayList(); for (final var value : registry.entrySet()) { - final var location = ForgeRegistries.BLOCKS.getKey(value.getKey()); + final var location = BuiltInRegistries.BLOCK.getKey(value.getKey()); if (location == null) { continue; } @@ -244,7 +244,7 @@ private static PhosphophylliteCompound writeSync() { return compound; } - private static void readSync(PhosphophylliteCompound compound) { + private static void readSync(PhosphophylliteCompound compound, IPayloadContext context) { moderatorBlocks.clear(); //noinspection unchecked final var list = (List) compound.getList("list"); @@ -256,7 +256,7 @@ private static void readSync(PhosphophylliteCompound compound) { for (int i = 0; i < list.size(); i++) { var blockLocation = list.get(i); var properties = propertiesList.get(i); - final var block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(blockLocation)); + final var block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockLocation)); if (block == null) { return; } diff --git a/src/main/java/net/roguelogix/biggerreactors/registries/TurbineCoilRegistry.java b/src/main/java/net/roguelogix/biggerreactors/registries/TurbineCoilRegistry.java index 9e25bb07..3f653f2d 100644 --- a/src/main/java/net/roguelogix/biggerreactors/registries/TurbineCoilRegistry.java +++ b/src/main/java/net/roguelogix/biggerreactors/registries/TurbineCoilRegistry.java @@ -11,11 +11,11 @@ import net.minecraft.tags.TagKey; import net.minecraft.world.item.BlockItem; import net.minecraft.world.level.block.Block; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.OnDatapackSyncEvent; -import net.minecraftforge.event.entity.player.ItemTooltipEvent; -import net.minecraftforge.fml.loading.FMLEnvironment; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.OnDatapackSyncEvent; +import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; import net.roguelogix.biggerreactors.BiggerReactors; import net.roguelogix.biggerreactors.Config; import net.roguelogix.phosphophyllite.config.ConfigValue; @@ -94,12 +94,12 @@ public static void loadRegistry() { blockTagOptional.ifPresent(holders -> holders.forEach(blockHolder -> { var element = blockHolder.value(); registry.put(element, properties); - BiggerReactors.LOGGER.debug("Loaded coil " + ForgeRegistries.BLOCKS.getKey(element)); + BiggerReactors.LOGGER.debug("Loaded coil " + BuiltInRegistries.BLOCK.getKey(element)); })); } else { // cant check against air, because air is a valid thing to load - if (ForgeRegistries.BLOCKS.containsKey(coilData.location)) { - registry.put(ForgeRegistries.BLOCKS.getValue(coilData.location), properties); + if (BuiltInRegistries.BLOCK.containsKey(coilData.location)) { + registry.put(BuiltInRegistries.BLOCK.get(coilData.location), properties); BiggerReactors.LOGGER.debug("Loaded coil " + coilData.location); } } @@ -109,15 +109,15 @@ public static void loadRegistry() { public static class Client { - private static final SimplePhosChannel CHANNEL = new SimplePhosChannel(new ResourceLocation(BiggerReactors.modid, "coil_sync_channel"), "0", Client::readSync); + private static final SimplePhosChannel CHANNEL = new SimplePhosChannel(new ResourceLocation(BiggerReactors.modid, "coil_sync_channel"), Client::readSync, null); private static final ObjectOpenHashSet coilBlocks = new ObjectOpenHashSet<>(); private static final Object2ObjectOpenHashMap coilProperties = new Object2ObjectOpenHashMap<>(); @OnModLoad private static void onModLoad() { - MinecraftForge.EVENT_BUS.addListener(Client::datapackEvent); + NeoForge.EVENT_BUS.addListener(Client::datapackEvent); if (FMLEnvironment.dist.isClient()) { - MinecraftForge.EVENT_BUS.addListener(Client::toolTipEvent); + NeoForge.EVENT_BUS.addListener(Client::toolTipEvent); } } @@ -137,7 +137,7 @@ private static PhosphophylliteCompound writeSync() { final var list = new ObjectArrayList(); final var propertiesList = new ObjectArrayList(); for (final var value : registry.entrySet()) { - final var location = ForgeRegistries.BLOCKS.getKey(value.getKey()); + final var location = BuiltInRegistries.BLOCK.getKey(value.getKey()); if (location == null) { continue; } @@ -154,7 +154,7 @@ private static PhosphophylliteCompound writeSync() { return compound; } - private static void readSync(PhosphophylliteCompound compound) { + private static void readSync(PhosphophylliteCompound compound, IPayloadContext context) { coilBlocks.clear(); //noinspection unchecked final var list = (List) compound.getList("list"); @@ -166,7 +166,7 @@ private static void readSync(PhosphophylliteCompound compound) { for (int i = 0; i < list.size(); i++) { var value = list.get(i); var properties = propertiesList.get(i); - final var block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(value)); + final var block = BuiltInRegistries.BLOCK.get(new ResourceLocation(value)); if (block == null) { return; } diff --git a/src/main/java/net/roguelogix/biggerreactors/util/FluidTransitionTank.java b/src/main/java/net/roguelogix/biggerreactors/util/FluidTransitionTank.java index 70208aab..8054e4ae 100644 --- a/src/main/java/net/roguelogix/biggerreactors/util/FluidTransitionTank.java +++ b/src/main/java/net/roguelogix/biggerreactors/util/FluidTransitionTank.java @@ -1,12 +1,12 @@ package net.roguelogix.biggerreactors.util; import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.util.INBTSerializable; import net.roguelogix.biggerreactors.registries.FluidTransitionRegistry; import net.roguelogix.phosphophyllite.fluids.IPhosphophylliteFluidHandler; import net.roguelogix.phosphophyllite.util.HeatBody; @@ -231,9 +231,9 @@ public FluidTransitionRegistry.FluidTransition activeTransition() { public CompoundTag serializeNBT() { CompoundTag nbt = new CompoundTag(); if (inFluid != null) { - nbt.putString("inFluid", ForgeRegistries.FLUIDS.getKey(inFluid).toString()); + nbt.putString("inFluid", BuiltInRegistries.FLUID.getKey(inFluid).toString()); nbt.putLong("inAmount", inAmount); - nbt.putString("outFluid", ForgeRegistries.FLUIDS.getKey(outFluid).toString()); + nbt.putString("outFluid", BuiltInRegistries.FLUID.getKey(outFluid).toString()); nbt.putLong("outAmount", outAmount); } return nbt; @@ -245,8 +245,8 @@ public void deserializeNBT(CompoundTag nbt) { return; } ResourceLocation inFluidLocation = new ResourceLocation(nbt.getString("inFluid")); - if (ForgeRegistries.FLUIDS.containsKey(inFluidLocation)) { - Fluid newInFluid = ForgeRegistries.FLUIDS.getValue(inFluidLocation); + if (BuiltInRegistries.FLUID.containsKey(inFluidLocation)) { + Fluid newInFluid = BuiltInRegistries.FLUID.get(inFluidLocation); if (newInFluid == null) { return; } @@ -262,8 +262,8 @@ public void deserializeNBT(CompoundTag nbt) { List outFluidList = (condenser ? newTransition.liquids : newTransition.gases); Fluid newOutFluid = null; ResourceLocation outFluidLocation = new ResourceLocation(nbt.getString("outFluid")); - if (ForgeRegistries.FLUIDS.containsKey(outFluidLocation)) { - Fluid oldOutFluid = ForgeRegistries.FLUIDS.getValue(outFluidLocation); + if (BuiltInRegistries.FLUID.containsKey(outFluidLocation)) { + Fluid oldOutFluid = BuiltInRegistries.FLUID.get(outFluidLocation); if (outFluidList.contains(oldOutFluid)) { newOutFluid = oldOutFluid; } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 5321a912..feaf9f50 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -8,7 +8,7 @@ modId="biggerreactors" version="${version}" displayName="Bigger Reactors" displayURL="https://biggerseries.net/" -logoFile="BiggerReactors.png" +logoFile="biggerreactors.png" credits="ErogeneousBeef for the original Big Reactors mod, that this is spiritually (and semi-literally) derived from" authors="RogueLogix, gizmocodes, Ridanisaurus" description=''' @@ -20,26 +20,26 @@ Official continuation of Big Reactors ''' [[dependencies.biggerreactors]] - modId="forge" - mandatory=true + modId="neoforge" + required=true versionRange="[${neo_version},)" ordering="NONE" side="BOTH" [[dependencies.biggerreactors]] modId="minecraft" - mandatory=true + required=true versionRange="[${minecraft_version}]" ordering="NONE" side="BOTH" [[dependencies.biggerreactors]] modId="phosphophyllite" - mandatory=true + required=true versionRange="${phos_version_range}" ordering="NONE" side="BOTH" [[dependencies.biggerreactors]] modId="quartz" - mandatory=true + required=true versionRange="${quartz_version_range}" ordering="NONE" side="BOTH" diff --git a/src/main/resources/BiggerReactors.png b/src/main/resources/biggerreactors.png similarity index 100% rename from src/main/resources/BiggerReactors.png rename to src/main/resources/biggerreactors.png From 5d3a43d2320f05e6d041013cddf6095294ad70e6 Mon Sep 17 00:00:00 2001 From: SrNadien <76491773+SrNadien@users.noreply.github.com> Date: Sat, 29 Mar 2025 13:51:15 -0300 Subject: [PATCH 25/27] Create es_es.json --- .../assets/biggerreactors/lang/es_es.json | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 src/main/resources/assets/biggerreactors/lang/es_es.json diff --git a/src/main/resources/assets/biggerreactors/lang/es_es.json b/src/main/resources/assets/biggerreactors/lang/es_es.json new file mode 100644 index 00000000..4997e1d5 --- /dev/null +++ b/src/main/resources/assets/biggerreactors/lang/es_es.json @@ -0,0 +1,200 @@ +{ + "item_group.biggerreactors": "Reactores Más Grandes", + +"item.biggerreactors.wrench": "Llave de Reactor", + +"fluid.biggerreactors.liquid_uranium": "Uranio Líquido", +"item.biggerreactors.liquid_uranium_bucket": "Balde de Uranio Líquido", +"fluid.biggerreactors.steam": "Vapor", +"item.biggerreactors.steam_bucket": "Balde de Vapor", +"fluid.biggerreactors.liquid_obsidian": "Obsidiana Líquida", +"item.biggerreactors.liquid_obsidian_bucket": "Balde de Obsidiana Líquida", + +"fluid.biggerreactors.superheated_sodium": "Sodio Sobrecalentado", +"item.biggerreactors.superheated_sodium_bucket": "Balde de Sodio Sobrecalentado", + +"block.biggerreactors.uranium_ore": "Mineral de Uranio", +"block.biggerreactors.deepslate_uranium_ore": "Mineral de Uranio de Pizarra Profunda", +"block.biggerreactors.uranium_block": "Bloque de Uranio", +"block.biggerreactors.raw_uranium_block": "Bloque de Uranio en Bruto", +"item.biggerreactors.uranium_dust": "Polvo de Uranio", +"item.biggerreactors.uranium_ingot": "Lingote de Uranio", +"item.biggerreactors.uranium_chunk": "Trozo de Uranio", + +"block.biggerreactors.blutonium_block": "Bloque de Blutonio", +"item.biggerreactors.blutonium_dust": "Polvo de Blutonio", +"item.biggerreactors.blutonium_ingot": "Lingote de Blutonio", + +"block.biggerreactors.cyanite_block": "Bloque de Cianita", +"item.biggerreactors.cyanite_dust": "Polvo de Cianita", +"item.biggerreactors.cyanite_ingot": "Lingote de Cianita", + +"block.biggerreactors.graphite_block": "Bloque de Grafito", +"item.biggerreactors.graphite_dust": "Polvo de Grafito", +"item.biggerreactors.graphite_ingot": "Lingote de Grafito", + +"block.biggerreactors.ludicrite_block": "Bloque de Ludicrita", +"item.biggerreactors.ludicrite_dust": "Polvo de Ludicrita", +"item.biggerreactors.ludicrite_ingot": "Lingote de Ludicrita", + +"tooltip.biggerreactors.is_a_moderator": "§eEsto se puede usar como moderador en un Reactor Más Grande", +"tooltip.biggerreactors.is_a_coil": "§eEste bloque se puede usar como bobina en una Turbina Más Grande", + +"multiblock.error.biggerreactors.no_terminal": "Los reactores requieren al menos un terminal.", +"multiblock.error.biggerreactors.no_rods": "Los reactores deben tener al menos un elemento de combustible.", +"multiblock.error.biggerreactors.control_rod_not_on_top": "Las barras de control solo pueden colocarse en la parte superior del reactor (%d, %d, %d).", +"multiblock.error.biggerreactors.fuel_rod_gap": "Todos los elementos de combustible deben extenderse desde la parte superior hasta la inferior del reactor (%d, %d, %d).", +"multiblock.error.biggerreactors.no_control_rod_for_fuel_rod": "Todos los elementos de combustible deben estar coronados con una barra de control (%d, %d).", +"multiblock.error.biggerreactors.dangling_internal_part": "Parece haber otro reactor dentro de este, ¿algo está mal? (%d, %d, %d).", +"multiblock.error.biggerreactors.coolant_and_power_ports": "Los reactores solo pueden tener puertos de refrigerante (tipo enfriado activamente) o tomas de energía (tipo enfriado pasivamente), no ambos.", +"multiblock.error.biggerreactors.no_manifold_neighbor": "Los colectores de refrigerante del reactor deben estar junto a otro colector o a una estructura del reactor.", + +"screen.biggerreactors.disabled": "Desactivado", + +"block.biggerreactors.cyanite_reprocessor": "Reprocesador de Cianita", +"screen.biggerreactors.cyanite_reprocessor": "Reprocesador de Cianita", +"screen.biggerreactors.cyanite_reprocessor.internal_battery.tooltip": "Batería Interna", +"screen.biggerreactors.cyanite_reprocessor.water_tank.tooltip": "Depósito de Agua", + +"block.biggerreactors.reactor_casing": "Estructura del Reactor", +"block.biggerreactors.reactor_glass": "Enredaderario de Reactor", +"block.biggerreactors.reactor_fuel_rod": "Barra de Combustible del Reactor", +"block.biggerreactors.reactor_power_tap": "Toma de Energía del Reactor", +"block.biggerreactors.reactor_access_port": "Puerto de Acceso del Reactor", +"block.biggerreactors.reactor_coolant_port": "Puerto de Refrigerante del Reactor", +"block.biggerreactors.reactor_computer_port": "Puerto de Computadora del Reactor", +"block.biggerreactors.reactor_redstone_port": "Puerto de Redstone del Reactor", +"block.biggerreactors.reactor_manifold": "Colector de Refrigerante del Reactor", + +"block.biggerreactors.reactor_terminal": "Terminal del Reactor", +"screen.biggerreactors.reactor_terminal": "Información del Reactor", +"screen.biggerreactors.reactor_terminal.temperature.tooltip": "Temperatura\n§7Qué tan caliente está el reactor.", +"screen.biggerreactors.reactor_terminal.energy_generation_rate.tooltip": "Tasa de Generación de RF\n§7Cuánta RF está generando el reactor.", +"screen.biggerreactors.reactor_terminal.exhaust_generation_rate.tooltip": "Tasa de Generación de Escape\n§7Cuánto escape está generando el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_usage_rate.tooltip": "Tasa de Uso de Combustible\n§7Cuánto combustible está consumiendo el reactor.", +"screen.biggerreactors.reactor_terminal.reactivity_rate.tooltip": "Tasa de ReactiEnredaderaad\n§7Qué tan reactivo es el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_mix.tooltip": "Mezcla de Combustible\n§7Proporción de combustible y desechos dentro del reactor.", +"screen.biggerreactors.reactor_terminal.case_heat.tooltip": "Calor de la Estructura\n§7Qué tan caliente está el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_heat.tooltip": "Calor del Combustible\n§7Qué tan caliente está el combustible.", +"screen.biggerreactors.reactor_terminal.internal_battery.tooltip": "Batería Interna\n§7Cuánta RF se almacena internamente.", +"screen.biggerreactors.reactor_terminal.coolant_intake_tank.tooltip": "Tanque de Entrada de Refrigerante\n§7Cuánto refrigerante se almacena internamente.", +"screen.biggerreactors.reactor_terminal.exhaust_tank.tooltip": "Tanque de Escape\n§7Cuánto escape se almacena internamente.", +"screen.biggerreactors.reactor_terminal.activity_toggle.online": "Estado: §2Encendido", +"screen.biggerreactors.reactor_terminal.activity_toggle.offline": "Estado: §4Apagado", +"screen.biggerreactors.reactor_terminal.activity_toggle.tooltip": "Alternar Estado del Reactor\n§7Encender o apagar el reactor.", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.enabled": "Expulsión de Desechos: §3Activada", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.disabled": "Expulsión de Desechos: §4Desactivada", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.tooltip": "Alternar Expulsión de Desechos\n§7Establecer si los desechos se expulsarán automáticamente.", +"block.biggerreactors.reactor_control_rod": "Varilla de Control del Reactor", +"screen.biggerreactors.reactor_control_rod": "Varilla de Control del Reactor", +"screen.biggerreactors.reactor_control_rod.name": "Nombre:", +"screen.biggerreactors.reactor_control_rod.apply.tooltip": "Aplicar", +"screen.biggerreactors.reactor_control_rod.retract_rod.tooltip": "Retraer Varilla\n§7Menos inserción aumenta la tasa de reacción.\n§8[Shift]: Retraer un 10%.\n§8[Ctrl]: Retraer un 50%.\n§8[Ctrl + Shift]: Retraer al máximo.\n§8[Alt]: Aplicar a todas las varillas.", +"screen.biggerreactors.reactor_control_rod.insert_rod.tooltip": "Insertar Varilla\n§7Más inserción reduce la tasa de reacción.\n§8[Shift]: Insertar un 10%.\n§8[Ctrl]: Insertar un 50%.\n§8[Ctrl + Shift]: Insertar al máximo.\n§8[Alt]: Aplicar a todas las varillas.", + +"screen.biggerreactors.reactor_coolant_port": "Puerto de Refrigerante del Reactor", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.input": "Dirección: §3Entrada", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.output": "Dirección: §cSalida", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.tooltip": "Cambiar Dirección\n§7Modifica la dirección del flujo de este puerto.", +"screen.biggerreactors.reactor_coolant_port.manual_dump": "Vaciado Manual del Tanque", +"screen.biggerreactors.reactor_coolant_port.manual_dump.tooltip": "Vaciar Fluidos del Tanque\n§7Vacia manualmente todos los fluidos del reactor.", + +"screen.biggerreactors.reactor_access_port": "Puerto de Acceso del Reactor", +"screen.biggerreactors.reactor_access_port.direction_toggle.input": "Dirección: §6Entrada", +"screen.biggerreactors.reactor_access_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.reactor_access_port.direction_toggle.tooltip": "Cambiar Dirección\n§7Modifica la dirección del flujo de este puerto.", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.fuel": "Salida: §6Combustible", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.waste": "Salida: §3Desechos", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.nope": "Salida: §7---", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.tooltip": "Cambiar Salida\n§7Modifica lo que este puerto está exportando.", +"screen.biggerreactors.reactor_access_port.manual_eject": "Expulsión Manual de Desechos", +"screen.biggerreactors.reactor_access_port.manual_eject.tooltip": "Expulsar Todos los Desechos\n§7Expulsa manualmente todos los desechos del reactor.", + +"screen.biggerreactors.reactor_redstone_port": "Puerto de Redstone del Reactor", +"screen.biggerreactors.reactor_redstone_port.choose_setting": "Elige una configuración:", +"screen.biggerreactors.reactor_redstone_port.apply.tooltip": "Aplicar", +"screen.biggerreactors.reactor_redstone_port.input_reactor_activity": "Cambiar Estado del Reactor (Entrada)", +"screen.biggerreactors.reactor_redstone_port.input_reactor_activity.tooltip": "Cambiar Estado del Reactor (Entrada)\n§8[Con Pulso] Alterna si el reactor está encendido o apagado.\n§8[Con Señal] Si hay señal de redstone, el reactor estará activo.", + +"block.biggerreactors.turbine_casing": "Carcasa de Turbina", +"block.biggerreactors.turbine_glass": "Enredaderario de Turbina", +"block.biggerreactors.turbine_rotor_shaft": "Eje del Rotor de la Turbina", +"block.biggerreactors.turbine_rotor_blade": "Aspa del Rotor de la Turbina", +"block.biggerreactors.turbine_rotor_bearing": "Cojinete del Rotor de la Turbina", +"block.biggerreactors.turbine_fluid_port": "Puerto de Fluidos de la Turbina", +"block.biggerreactors.turbine_power_tap": "Conexión de Energía de la Turbina", +"block.biggerreactors.turbine_computer_port": "Puerto de Computadora de la Turbina", + +"screen.biggerreactors.turbine_terminal": "Información de la Turbina", +"screen.biggerreactors.turbine_terminal.tachometer.tooltip": "Tacómetro\n§7Indica la velocidad de rotación de la turbina.\n§7El rendimiento óptimo es a 900 o 1800 RPM.", +"screen.biggerreactors.turbine_terminal.energy_generation_rate.tooltip": "Tasa de Generación de RF\n§7Indica la cantidad de RF que genera la turbina.", +"screen.biggerreactors.turbine_terminal.flow_rate_governor.tooltip": "Regulador de Flujo\n§7Controla la velocidad a la que la turbina procesa fluidos.", +"screen.biggerreactors.turbine_terminal.rotor_efficiency.tooltip": "Eficiencia del Rotor\n§7La eficiencia disminuye si la tasa de flujo supera la capacidad del rotor.", +"screen.biggerreactors.turbine_terminal.internal_battery.tooltip": "Batería Interna\n§7Indica la cantidad de RF almacenado internamente.", +"screen.biggerreactors.turbine_terminal.intake_tank.tooltip": "Tanque de Entrada\n§7Cantidad de fluido caliente almacenado internamente.", +"screen.biggerreactors.turbine_terminal.exhaust_tank.tooltip": "Tanque de Escape\n§7Cantidad de fluido frío almacenado internamente.", +"screen.biggerreactors.turbine_terminal.activity_toggle.online": "Estado: §2En Línea", +"screen.biggerreactors.turbine_terminal.activity_toggle.offline": "Estado: §4Fuera de Línea", +"screen.biggerreactors.turbine_terminal.activity_toggle.tooltip": "Alternar estado de la turbina\n§7Encender o apagar la turbina.", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.engaged": "Bobinas: §2Enganchadas", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.disengaged": "Bobinas: §4Desenganchadas", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.tooltip": "Alternar enganche de bobinas\n§7Cuando están enganchadas, la velocidad del rotor se convierte en electricidad.", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.overflow": "Ventilación: §6Solo Exceso", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.all": "Ventilación: §2Todo el Escape", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.closed": "Ventilación: §4Sin Escape", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.tooltip": "Alternar ventilación del escape\n§7Determina cómo o si se ventilará el escape.", +"screen.biggerreactors.turbine_terminal.flow_rate_increase.tooltip": "Aumentar flujo\n§7Un flujo más alto incrementa la velocidad del rotor.\n§8[Shift]: Aumentar en %s mB.\n§8[Ctrl]: Aumentar en %s mB.\n§8[Ctrl + Shift]: Aumentar en %s mB.", +"screen.biggerreactors.turbine_terminal.flow_rate_decrease.tooltip": "Disminuir flujo\n§7Un flujo más bajo reduce la velocidad del rotor.\n§8[Shift]: Disminuir en %s mB.\n§8[Ctrl]: Disminuir en %s mB.\n§8[Ctrl + Shift]: Disminuir en %s mB.", + +"screen.biggerreactors.turbine_fluid_port": "Puerto de Fluido de Turbina", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.input": "Dirección: §cEntrada", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.tooltip": "Alternar dirección\n§7Cambia la dirección del flujo de este puerto.", + +"block.biggerreactors.heat_exchanger_casing": "Carcasa del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_glass": "Cristal del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_condenser_channel": "Canal de Condensador del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_evaporator_channel": "Canal de Evaporador del Intercambiador de Calor", + +"block.biggerreactors.heat_exchanger_terminal": "Terminal del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_terminal": "Información del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_terminal.temperature.condenser.tooltip": "Temperatura del Canal del Condensador\n§7Indica qué tan caliente está el fluido en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.temperature.evaporator.tooltip": "Temperatura del Canal del Evaporador\n§7Indica qué tan caliente está el fluido en los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.flow_rate.condenser.tooltip": "Tasa de Flujo del Condensador\n§7Cantidad de fluido que fluye a través de los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.flow_rate.evaporator.tooltip": "Tasa de Flujo del Evaporador\n§7Cantidad de fluido que fluye a través de los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.intake_gauge.condenser.tooltip": "Tanque de Entrada del Condensador\n§7Cantidad de fluido caliente en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.exhaust_gauge.condenser.tooltip": "Tanque de Escape del Condensador\n§7Cantidad de fluido frío en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.heat_gauge.tooltip": "Temperatura del Intercambiador de Calor\n§7Indica qué tan caliente está el intercambiador.", +"screen.biggerreactors.heat_exchanger_terminal.intake_gauge.evaporator.tooltip": "Tanque de Entrada del Evaporador\n§7Cantidad de fluido frío en los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.exhaust_gauge.evaporator.tooltip": "Tanque de Escape del Evaporador\n§7Cantidad de fluido caliente en los canales del evaporador.", + +"multiblock.error.biggerreactors.heat_exchanger.dangling_internal_part": "Parece haber otro intercambiador de calor dentro de este, ¿algo está mal? (%d, %d, %d).", +"multiblock.error.biggerreactors.heat_exchanger.dangling_channel": "Todos los canales deben estar conectados a un puerto de fluido. (%d, %d, %d)", +"multiblock.error.biggerreactors.heat_exchanger.duplicate_port_types": "El evaporador y el condensador deben estar conectados a dos puertos de fluido cada uno.", +"multiblock.error.biggerreactors.heat_exchanger.fluid_port_unconnected": "Todos los puertos de fluido deben estar conectados a un canal.", +"multiblock.error.biggerreactors.heat_exchanger.invalid_port_count": "Se requieren exactamente 4 puertos de fluido.", +"multiblock.error.biggerreactors.heat_exchanger.missing_channel_type": "Se necesita al menos un canal de evaporador y uno de condensador.", + +"block.biggerreactors.heat_exchanger_computer_port": "Puerto de Computadora del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_fluid_port": "Puerto de Fluido del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_fluid_port": "Puerto de Fluido del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_fluid_port.channel_type.condenser": "Conexión de Canal: §cCondensador", +"screen.biggerreactors.heat_exchanger_fluid_port.channel_type.evaporator": "Conexión de Canal: §9Evaporador", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.input": "Dirección: §cEntrada", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.tooltip": "Alternar Dirección\n§7Cambia la dirección del flujo de este puerto.", +"screen.biggerreactors.heat_exchanger_fluid_port.manual_dump": "Vaciado Manual de Canales de Fluido", +"screen.biggerreactors.heat_exchanger_fluid_port.manual_dump.tooltip": "Vaciar Canales de Fluido\n§7Vaciar manualmente todos los fluidos en el canal conectado.", + +"jei.biggerreactors.classic.turbine_coil_block": "Bloques de Bobina de Turbina", +"jei.biggerreactors.classic.turbine_coil_bonus": "Bono: %s", +"jei.biggerreactors.classic.turbine_coil_efficiency": "Eficiencia: %s", +"jei.biggerreactors.classic.turbine_coil_extraction": "Tasa de Extracción: %s", + +"jei.biggerreactors.classic.reactor_moderator_block": "Bloques Moderadores del Reactor", +"jei.biggerreactors.classic.reactor_moderator_fluid": "Fluidos Moderadores del Reactor", +"jei.biggerreactors.classic.reactor_moderator_moderation": "Moderación: %s", +"jei.biggerreactors.classic.reactor_moderator_absorption": "Absorción: %s", +"jei.biggerreactors.classic.reactor_moderator_conductivity": "Conductividad: %s", +"jei.biggerreactors.classic.reactor_moderator_efficiency": "Eficiencia: %s", +} From 5d9c6e765ffc832aea562028d8b82651f2d84b3c Mon Sep 17 00:00:00 2001 From: SrNadien <76491773+SrNadien@users.noreply.github.com> Date: Sat, 29 Mar 2025 13:51:30 -0300 Subject: [PATCH 26/27] Create es_ar.json --- .../assets/biggerreactors/lang/es_ar.json | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 src/main/resources/assets/biggerreactors/lang/es_ar.json diff --git a/src/main/resources/assets/biggerreactors/lang/es_ar.json b/src/main/resources/assets/biggerreactors/lang/es_ar.json new file mode 100644 index 00000000..4997e1d5 --- /dev/null +++ b/src/main/resources/assets/biggerreactors/lang/es_ar.json @@ -0,0 +1,200 @@ +{ + "item_group.biggerreactors": "Reactores Más Grandes", + +"item.biggerreactors.wrench": "Llave de Reactor", + +"fluid.biggerreactors.liquid_uranium": "Uranio Líquido", +"item.biggerreactors.liquid_uranium_bucket": "Balde de Uranio Líquido", +"fluid.biggerreactors.steam": "Vapor", +"item.biggerreactors.steam_bucket": "Balde de Vapor", +"fluid.biggerreactors.liquid_obsidian": "Obsidiana Líquida", +"item.biggerreactors.liquid_obsidian_bucket": "Balde de Obsidiana Líquida", + +"fluid.biggerreactors.superheated_sodium": "Sodio Sobrecalentado", +"item.biggerreactors.superheated_sodium_bucket": "Balde de Sodio Sobrecalentado", + +"block.biggerreactors.uranium_ore": "Mineral de Uranio", +"block.biggerreactors.deepslate_uranium_ore": "Mineral de Uranio de Pizarra Profunda", +"block.biggerreactors.uranium_block": "Bloque de Uranio", +"block.biggerreactors.raw_uranium_block": "Bloque de Uranio en Bruto", +"item.biggerreactors.uranium_dust": "Polvo de Uranio", +"item.biggerreactors.uranium_ingot": "Lingote de Uranio", +"item.biggerreactors.uranium_chunk": "Trozo de Uranio", + +"block.biggerreactors.blutonium_block": "Bloque de Blutonio", +"item.biggerreactors.blutonium_dust": "Polvo de Blutonio", +"item.biggerreactors.blutonium_ingot": "Lingote de Blutonio", + +"block.biggerreactors.cyanite_block": "Bloque de Cianita", +"item.biggerreactors.cyanite_dust": "Polvo de Cianita", +"item.biggerreactors.cyanite_ingot": "Lingote de Cianita", + +"block.biggerreactors.graphite_block": "Bloque de Grafito", +"item.biggerreactors.graphite_dust": "Polvo de Grafito", +"item.biggerreactors.graphite_ingot": "Lingote de Grafito", + +"block.biggerreactors.ludicrite_block": "Bloque de Ludicrita", +"item.biggerreactors.ludicrite_dust": "Polvo de Ludicrita", +"item.biggerreactors.ludicrite_ingot": "Lingote de Ludicrita", + +"tooltip.biggerreactors.is_a_moderator": "§eEsto se puede usar como moderador en un Reactor Más Grande", +"tooltip.biggerreactors.is_a_coil": "§eEste bloque se puede usar como bobina en una Turbina Más Grande", + +"multiblock.error.biggerreactors.no_terminal": "Los reactores requieren al menos un terminal.", +"multiblock.error.biggerreactors.no_rods": "Los reactores deben tener al menos un elemento de combustible.", +"multiblock.error.biggerreactors.control_rod_not_on_top": "Las barras de control solo pueden colocarse en la parte superior del reactor (%d, %d, %d).", +"multiblock.error.biggerreactors.fuel_rod_gap": "Todos los elementos de combustible deben extenderse desde la parte superior hasta la inferior del reactor (%d, %d, %d).", +"multiblock.error.biggerreactors.no_control_rod_for_fuel_rod": "Todos los elementos de combustible deben estar coronados con una barra de control (%d, %d).", +"multiblock.error.biggerreactors.dangling_internal_part": "Parece haber otro reactor dentro de este, ¿algo está mal? (%d, %d, %d).", +"multiblock.error.biggerreactors.coolant_and_power_ports": "Los reactores solo pueden tener puertos de refrigerante (tipo enfriado activamente) o tomas de energía (tipo enfriado pasivamente), no ambos.", +"multiblock.error.biggerreactors.no_manifold_neighbor": "Los colectores de refrigerante del reactor deben estar junto a otro colector o a una estructura del reactor.", + +"screen.biggerreactors.disabled": "Desactivado", + +"block.biggerreactors.cyanite_reprocessor": "Reprocesador de Cianita", +"screen.biggerreactors.cyanite_reprocessor": "Reprocesador de Cianita", +"screen.biggerreactors.cyanite_reprocessor.internal_battery.tooltip": "Batería Interna", +"screen.biggerreactors.cyanite_reprocessor.water_tank.tooltip": "Depósito de Agua", + +"block.biggerreactors.reactor_casing": "Estructura del Reactor", +"block.biggerreactors.reactor_glass": "Enredaderario de Reactor", +"block.biggerreactors.reactor_fuel_rod": "Barra de Combustible del Reactor", +"block.biggerreactors.reactor_power_tap": "Toma de Energía del Reactor", +"block.biggerreactors.reactor_access_port": "Puerto de Acceso del Reactor", +"block.biggerreactors.reactor_coolant_port": "Puerto de Refrigerante del Reactor", +"block.biggerreactors.reactor_computer_port": "Puerto de Computadora del Reactor", +"block.biggerreactors.reactor_redstone_port": "Puerto de Redstone del Reactor", +"block.biggerreactors.reactor_manifold": "Colector de Refrigerante del Reactor", + +"block.biggerreactors.reactor_terminal": "Terminal del Reactor", +"screen.biggerreactors.reactor_terminal": "Información del Reactor", +"screen.biggerreactors.reactor_terminal.temperature.tooltip": "Temperatura\n§7Qué tan caliente está el reactor.", +"screen.biggerreactors.reactor_terminal.energy_generation_rate.tooltip": "Tasa de Generación de RF\n§7Cuánta RF está generando el reactor.", +"screen.biggerreactors.reactor_terminal.exhaust_generation_rate.tooltip": "Tasa de Generación de Escape\n§7Cuánto escape está generando el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_usage_rate.tooltip": "Tasa de Uso de Combustible\n§7Cuánto combustible está consumiendo el reactor.", +"screen.biggerreactors.reactor_terminal.reactivity_rate.tooltip": "Tasa de ReactiEnredaderaad\n§7Qué tan reactivo es el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_mix.tooltip": "Mezcla de Combustible\n§7Proporción de combustible y desechos dentro del reactor.", +"screen.biggerreactors.reactor_terminal.case_heat.tooltip": "Calor de la Estructura\n§7Qué tan caliente está el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_heat.tooltip": "Calor del Combustible\n§7Qué tan caliente está el combustible.", +"screen.biggerreactors.reactor_terminal.internal_battery.tooltip": "Batería Interna\n§7Cuánta RF se almacena internamente.", +"screen.biggerreactors.reactor_terminal.coolant_intake_tank.tooltip": "Tanque de Entrada de Refrigerante\n§7Cuánto refrigerante se almacena internamente.", +"screen.biggerreactors.reactor_terminal.exhaust_tank.tooltip": "Tanque de Escape\n§7Cuánto escape se almacena internamente.", +"screen.biggerreactors.reactor_terminal.activity_toggle.online": "Estado: §2Encendido", +"screen.biggerreactors.reactor_terminal.activity_toggle.offline": "Estado: §4Apagado", +"screen.biggerreactors.reactor_terminal.activity_toggle.tooltip": "Alternar Estado del Reactor\n§7Encender o apagar el reactor.", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.enabled": "Expulsión de Desechos: §3Activada", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.disabled": "Expulsión de Desechos: §4Desactivada", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.tooltip": "Alternar Expulsión de Desechos\n§7Establecer si los desechos se expulsarán automáticamente.", +"block.biggerreactors.reactor_control_rod": "Varilla de Control del Reactor", +"screen.biggerreactors.reactor_control_rod": "Varilla de Control del Reactor", +"screen.biggerreactors.reactor_control_rod.name": "Nombre:", +"screen.biggerreactors.reactor_control_rod.apply.tooltip": "Aplicar", +"screen.biggerreactors.reactor_control_rod.retract_rod.tooltip": "Retraer Varilla\n§7Menos inserción aumenta la tasa de reacción.\n§8[Shift]: Retraer un 10%.\n§8[Ctrl]: Retraer un 50%.\n§8[Ctrl + Shift]: Retraer al máximo.\n§8[Alt]: Aplicar a todas las varillas.", +"screen.biggerreactors.reactor_control_rod.insert_rod.tooltip": "Insertar Varilla\n§7Más inserción reduce la tasa de reacción.\n§8[Shift]: Insertar un 10%.\n§8[Ctrl]: Insertar un 50%.\n§8[Ctrl + Shift]: Insertar al máximo.\n§8[Alt]: Aplicar a todas las varillas.", + +"screen.biggerreactors.reactor_coolant_port": "Puerto de Refrigerante del Reactor", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.input": "Dirección: §3Entrada", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.output": "Dirección: §cSalida", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.tooltip": "Cambiar Dirección\n§7Modifica la dirección del flujo de este puerto.", +"screen.biggerreactors.reactor_coolant_port.manual_dump": "Vaciado Manual del Tanque", +"screen.biggerreactors.reactor_coolant_port.manual_dump.tooltip": "Vaciar Fluidos del Tanque\n§7Vacia manualmente todos los fluidos del reactor.", + +"screen.biggerreactors.reactor_access_port": "Puerto de Acceso del Reactor", +"screen.biggerreactors.reactor_access_port.direction_toggle.input": "Dirección: §6Entrada", +"screen.biggerreactors.reactor_access_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.reactor_access_port.direction_toggle.tooltip": "Cambiar Dirección\n§7Modifica la dirección del flujo de este puerto.", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.fuel": "Salida: §6Combustible", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.waste": "Salida: §3Desechos", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.nope": "Salida: §7---", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.tooltip": "Cambiar Salida\n§7Modifica lo que este puerto está exportando.", +"screen.biggerreactors.reactor_access_port.manual_eject": "Expulsión Manual de Desechos", +"screen.biggerreactors.reactor_access_port.manual_eject.tooltip": "Expulsar Todos los Desechos\n§7Expulsa manualmente todos los desechos del reactor.", + +"screen.biggerreactors.reactor_redstone_port": "Puerto de Redstone del Reactor", +"screen.biggerreactors.reactor_redstone_port.choose_setting": "Elige una configuración:", +"screen.biggerreactors.reactor_redstone_port.apply.tooltip": "Aplicar", +"screen.biggerreactors.reactor_redstone_port.input_reactor_activity": "Cambiar Estado del Reactor (Entrada)", +"screen.biggerreactors.reactor_redstone_port.input_reactor_activity.tooltip": "Cambiar Estado del Reactor (Entrada)\n§8[Con Pulso] Alterna si el reactor está encendido o apagado.\n§8[Con Señal] Si hay señal de redstone, el reactor estará activo.", + +"block.biggerreactors.turbine_casing": "Carcasa de Turbina", +"block.biggerreactors.turbine_glass": "Enredaderario de Turbina", +"block.biggerreactors.turbine_rotor_shaft": "Eje del Rotor de la Turbina", +"block.biggerreactors.turbine_rotor_blade": "Aspa del Rotor de la Turbina", +"block.biggerreactors.turbine_rotor_bearing": "Cojinete del Rotor de la Turbina", +"block.biggerreactors.turbine_fluid_port": "Puerto de Fluidos de la Turbina", +"block.biggerreactors.turbine_power_tap": "Conexión de Energía de la Turbina", +"block.biggerreactors.turbine_computer_port": "Puerto de Computadora de la Turbina", + +"screen.biggerreactors.turbine_terminal": "Información de la Turbina", +"screen.biggerreactors.turbine_terminal.tachometer.tooltip": "Tacómetro\n§7Indica la velocidad de rotación de la turbina.\n§7El rendimiento óptimo es a 900 o 1800 RPM.", +"screen.biggerreactors.turbine_terminal.energy_generation_rate.tooltip": "Tasa de Generación de RF\n§7Indica la cantidad de RF que genera la turbina.", +"screen.biggerreactors.turbine_terminal.flow_rate_governor.tooltip": "Regulador de Flujo\n§7Controla la velocidad a la que la turbina procesa fluidos.", +"screen.biggerreactors.turbine_terminal.rotor_efficiency.tooltip": "Eficiencia del Rotor\n§7La eficiencia disminuye si la tasa de flujo supera la capacidad del rotor.", +"screen.biggerreactors.turbine_terminal.internal_battery.tooltip": "Batería Interna\n§7Indica la cantidad de RF almacenado internamente.", +"screen.biggerreactors.turbine_terminal.intake_tank.tooltip": "Tanque de Entrada\n§7Cantidad de fluido caliente almacenado internamente.", +"screen.biggerreactors.turbine_terminal.exhaust_tank.tooltip": "Tanque de Escape\n§7Cantidad de fluido frío almacenado internamente.", +"screen.biggerreactors.turbine_terminal.activity_toggle.online": "Estado: §2En Línea", +"screen.biggerreactors.turbine_terminal.activity_toggle.offline": "Estado: §4Fuera de Línea", +"screen.biggerreactors.turbine_terminal.activity_toggle.tooltip": "Alternar estado de la turbina\n§7Encender o apagar la turbina.", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.engaged": "Bobinas: §2Enganchadas", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.disengaged": "Bobinas: §4Desenganchadas", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.tooltip": "Alternar enganche de bobinas\n§7Cuando están enganchadas, la velocidad del rotor se convierte en electricidad.", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.overflow": "Ventilación: §6Solo Exceso", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.all": "Ventilación: §2Todo el Escape", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.closed": "Ventilación: §4Sin Escape", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.tooltip": "Alternar ventilación del escape\n§7Determina cómo o si se ventilará el escape.", +"screen.biggerreactors.turbine_terminal.flow_rate_increase.tooltip": "Aumentar flujo\n§7Un flujo más alto incrementa la velocidad del rotor.\n§8[Shift]: Aumentar en %s mB.\n§8[Ctrl]: Aumentar en %s mB.\n§8[Ctrl + Shift]: Aumentar en %s mB.", +"screen.biggerreactors.turbine_terminal.flow_rate_decrease.tooltip": "Disminuir flujo\n§7Un flujo más bajo reduce la velocidad del rotor.\n§8[Shift]: Disminuir en %s mB.\n§8[Ctrl]: Disminuir en %s mB.\n§8[Ctrl + Shift]: Disminuir en %s mB.", + +"screen.biggerreactors.turbine_fluid_port": "Puerto de Fluido de Turbina", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.input": "Dirección: §cEntrada", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.tooltip": "Alternar dirección\n§7Cambia la dirección del flujo de este puerto.", + +"block.biggerreactors.heat_exchanger_casing": "Carcasa del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_glass": "Cristal del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_condenser_channel": "Canal de Condensador del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_evaporator_channel": "Canal de Evaporador del Intercambiador de Calor", + +"block.biggerreactors.heat_exchanger_terminal": "Terminal del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_terminal": "Información del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_terminal.temperature.condenser.tooltip": "Temperatura del Canal del Condensador\n§7Indica qué tan caliente está el fluido en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.temperature.evaporator.tooltip": "Temperatura del Canal del Evaporador\n§7Indica qué tan caliente está el fluido en los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.flow_rate.condenser.tooltip": "Tasa de Flujo del Condensador\n§7Cantidad de fluido que fluye a través de los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.flow_rate.evaporator.tooltip": "Tasa de Flujo del Evaporador\n§7Cantidad de fluido que fluye a través de los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.intake_gauge.condenser.tooltip": "Tanque de Entrada del Condensador\n§7Cantidad de fluido caliente en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.exhaust_gauge.condenser.tooltip": "Tanque de Escape del Condensador\n§7Cantidad de fluido frío en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.heat_gauge.tooltip": "Temperatura del Intercambiador de Calor\n§7Indica qué tan caliente está el intercambiador.", +"screen.biggerreactors.heat_exchanger_terminal.intake_gauge.evaporator.tooltip": "Tanque de Entrada del Evaporador\n§7Cantidad de fluido frío en los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.exhaust_gauge.evaporator.tooltip": "Tanque de Escape del Evaporador\n§7Cantidad de fluido caliente en los canales del evaporador.", + +"multiblock.error.biggerreactors.heat_exchanger.dangling_internal_part": "Parece haber otro intercambiador de calor dentro de este, ¿algo está mal? (%d, %d, %d).", +"multiblock.error.biggerreactors.heat_exchanger.dangling_channel": "Todos los canales deben estar conectados a un puerto de fluido. (%d, %d, %d)", +"multiblock.error.biggerreactors.heat_exchanger.duplicate_port_types": "El evaporador y el condensador deben estar conectados a dos puertos de fluido cada uno.", +"multiblock.error.biggerreactors.heat_exchanger.fluid_port_unconnected": "Todos los puertos de fluido deben estar conectados a un canal.", +"multiblock.error.biggerreactors.heat_exchanger.invalid_port_count": "Se requieren exactamente 4 puertos de fluido.", +"multiblock.error.biggerreactors.heat_exchanger.missing_channel_type": "Se necesita al menos un canal de evaporador y uno de condensador.", + +"block.biggerreactors.heat_exchanger_computer_port": "Puerto de Computadora del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_fluid_port": "Puerto de Fluido del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_fluid_port": "Puerto de Fluido del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_fluid_port.channel_type.condenser": "Conexión de Canal: §cCondensador", +"screen.biggerreactors.heat_exchanger_fluid_port.channel_type.evaporator": "Conexión de Canal: §9Evaporador", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.input": "Dirección: §cEntrada", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.tooltip": "Alternar Dirección\n§7Cambia la dirección del flujo de este puerto.", +"screen.biggerreactors.heat_exchanger_fluid_port.manual_dump": "Vaciado Manual de Canales de Fluido", +"screen.biggerreactors.heat_exchanger_fluid_port.manual_dump.tooltip": "Vaciar Canales de Fluido\n§7Vaciar manualmente todos los fluidos en el canal conectado.", + +"jei.biggerreactors.classic.turbine_coil_block": "Bloques de Bobina de Turbina", +"jei.biggerreactors.classic.turbine_coil_bonus": "Bono: %s", +"jei.biggerreactors.classic.turbine_coil_efficiency": "Eficiencia: %s", +"jei.biggerreactors.classic.turbine_coil_extraction": "Tasa de Extracción: %s", + +"jei.biggerreactors.classic.reactor_moderator_block": "Bloques Moderadores del Reactor", +"jei.biggerreactors.classic.reactor_moderator_fluid": "Fluidos Moderadores del Reactor", +"jei.biggerreactors.classic.reactor_moderator_moderation": "Moderación: %s", +"jei.biggerreactors.classic.reactor_moderator_absorption": "Absorción: %s", +"jei.biggerreactors.classic.reactor_moderator_conductivity": "Conductividad: %s", +"jei.biggerreactors.classic.reactor_moderator_efficiency": "Eficiencia: %s", +} From 23bbf90ace526f12074800e852cfa6b707ad59b2 Mon Sep 17 00:00:00 2001 From: SrNadien <76491773+SrNadien@users.noreply.github.com> Date: Sat, 29 Mar 2025 13:52:17 -0300 Subject: [PATCH 27/27] Create es_mx.json --- .../assets/biggerreactors/lang/es_mx.json | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 src/main/resources/assets/biggerreactors/lang/es_mx.json diff --git a/src/main/resources/assets/biggerreactors/lang/es_mx.json b/src/main/resources/assets/biggerreactors/lang/es_mx.json new file mode 100644 index 00000000..4997e1d5 --- /dev/null +++ b/src/main/resources/assets/biggerreactors/lang/es_mx.json @@ -0,0 +1,200 @@ +{ + "item_group.biggerreactors": "Reactores Más Grandes", + +"item.biggerreactors.wrench": "Llave de Reactor", + +"fluid.biggerreactors.liquid_uranium": "Uranio Líquido", +"item.biggerreactors.liquid_uranium_bucket": "Balde de Uranio Líquido", +"fluid.biggerreactors.steam": "Vapor", +"item.biggerreactors.steam_bucket": "Balde de Vapor", +"fluid.biggerreactors.liquid_obsidian": "Obsidiana Líquida", +"item.biggerreactors.liquid_obsidian_bucket": "Balde de Obsidiana Líquida", + +"fluid.biggerreactors.superheated_sodium": "Sodio Sobrecalentado", +"item.biggerreactors.superheated_sodium_bucket": "Balde de Sodio Sobrecalentado", + +"block.biggerreactors.uranium_ore": "Mineral de Uranio", +"block.biggerreactors.deepslate_uranium_ore": "Mineral de Uranio de Pizarra Profunda", +"block.biggerreactors.uranium_block": "Bloque de Uranio", +"block.biggerreactors.raw_uranium_block": "Bloque de Uranio en Bruto", +"item.biggerreactors.uranium_dust": "Polvo de Uranio", +"item.biggerreactors.uranium_ingot": "Lingote de Uranio", +"item.biggerreactors.uranium_chunk": "Trozo de Uranio", + +"block.biggerreactors.blutonium_block": "Bloque de Blutonio", +"item.biggerreactors.blutonium_dust": "Polvo de Blutonio", +"item.biggerreactors.blutonium_ingot": "Lingote de Blutonio", + +"block.biggerreactors.cyanite_block": "Bloque de Cianita", +"item.biggerreactors.cyanite_dust": "Polvo de Cianita", +"item.biggerreactors.cyanite_ingot": "Lingote de Cianita", + +"block.biggerreactors.graphite_block": "Bloque de Grafito", +"item.biggerreactors.graphite_dust": "Polvo de Grafito", +"item.biggerreactors.graphite_ingot": "Lingote de Grafito", + +"block.biggerreactors.ludicrite_block": "Bloque de Ludicrita", +"item.biggerreactors.ludicrite_dust": "Polvo de Ludicrita", +"item.biggerreactors.ludicrite_ingot": "Lingote de Ludicrita", + +"tooltip.biggerreactors.is_a_moderator": "§eEsto se puede usar como moderador en un Reactor Más Grande", +"tooltip.biggerreactors.is_a_coil": "§eEste bloque se puede usar como bobina en una Turbina Más Grande", + +"multiblock.error.biggerreactors.no_terminal": "Los reactores requieren al menos un terminal.", +"multiblock.error.biggerreactors.no_rods": "Los reactores deben tener al menos un elemento de combustible.", +"multiblock.error.biggerreactors.control_rod_not_on_top": "Las barras de control solo pueden colocarse en la parte superior del reactor (%d, %d, %d).", +"multiblock.error.biggerreactors.fuel_rod_gap": "Todos los elementos de combustible deben extenderse desde la parte superior hasta la inferior del reactor (%d, %d, %d).", +"multiblock.error.biggerreactors.no_control_rod_for_fuel_rod": "Todos los elementos de combustible deben estar coronados con una barra de control (%d, %d).", +"multiblock.error.biggerreactors.dangling_internal_part": "Parece haber otro reactor dentro de este, ¿algo está mal? (%d, %d, %d).", +"multiblock.error.biggerreactors.coolant_and_power_ports": "Los reactores solo pueden tener puertos de refrigerante (tipo enfriado activamente) o tomas de energía (tipo enfriado pasivamente), no ambos.", +"multiblock.error.biggerreactors.no_manifold_neighbor": "Los colectores de refrigerante del reactor deben estar junto a otro colector o a una estructura del reactor.", + +"screen.biggerreactors.disabled": "Desactivado", + +"block.biggerreactors.cyanite_reprocessor": "Reprocesador de Cianita", +"screen.biggerreactors.cyanite_reprocessor": "Reprocesador de Cianita", +"screen.biggerreactors.cyanite_reprocessor.internal_battery.tooltip": "Batería Interna", +"screen.biggerreactors.cyanite_reprocessor.water_tank.tooltip": "Depósito de Agua", + +"block.biggerreactors.reactor_casing": "Estructura del Reactor", +"block.biggerreactors.reactor_glass": "Enredaderario de Reactor", +"block.biggerreactors.reactor_fuel_rod": "Barra de Combustible del Reactor", +"block.biggerreactors.reactor_power_tap": "Toma de Energía del Reactor", +"block.biggerreactors.reactor_access_port": "Puerto de Acceso del Reactor", +"block.biggerreactors.reactor_coolant_port": "Puerto de Refrigerante del Reactor", +"block.biggerreactors.reactor_computer_port": "Puerto de Computadora del Reactor", +"block.biggerreactors.reactor_redstone_port": "Puerto de Redstone del Reactor", +"block.biggerreactors.reactor_manifold": "Colector de Refrigerante del Reactor", + +"block.biggerreactors.reactor_terminal": "Terminal del Reactor", +"screen.biggerreactors.reactor_terminal": "Información del Reactor", +"screen.biggerreactors.reactor_terminal.temperature.tooltip": "Temperatura\n§7Qué tan caliente está el reactor.", +"screen.biggerreactors.reactor_terminal.energy_generation_rate.tooltip": "Tasa de Generación de RF\n§7Cuánta RF está generando el reactor.", +"screen.biggerreactors.reactor_terminal.exhaust_generation_rate.tooltip": "Tasa de Generación de Escape\n§7Cuánto escape está generando el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_usage_rate.tooltip": "Tasa de Uso de Combustible\n§7Cuánto combustible está consumiendo el reactor.", +"screen.biggerreactors.reactor_terminal.reactivity_rate.tooltip": "Tasa de ReactiEnredaderaad\n§7Qué tan reactivo es el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_mix.tooltip": "Mezcla de Combustible\n§7Proporción de combustible y desechos dentro del reactor.", +"screen.biggerreactors.reactor_terminal.case_heat.tooltip": "Calor de la Estructura\n§7Qué tan caliente está el reactor.", +"screen.biggerreactors.reactor_terminal.fuel_heat.tooltip": "Calor del Combustible\n§7Qué tan caliente está el combustible.", +"screen.biggerreactors.reactor_terminal.internal_battery.tooltip": "Batería Interna\n§7Cuánta RF se almacena internamente.", +"screen.biggerreactors.reactor_terminal.coolant_intake_tank.tooltip": "Tanque de Entrada de Refrigerante\n§7Cuánto refrigerante se almacena internamente.", +"screen.biggerreactors.reactor_terminal.exhaust_tank.tooltip": "Tanque de Escape\n§7Cuánto escape se almacena internamente.", +"screen.biggerreactors.reactor_terminal.activity_toggle.online": "Estado: §2Encendido", +"screen.biggerreactors.reactor_terminal.activity_toggle.offline": "Estado: §4Apagado", +"screen.biggerreactors.reactor_terminal.activity_toggle.tooltip": "Alternar Estado del Reactor\n§7Encender o apagar el reactor.", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.enabled": "Expulsión de Desechos: §3Activada", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.disabled": "Expulsión de Desechos: §4Desactivada", +"screen.biggerreactors.reactor_terminal.auto_eject_toggle.tooltip": "Alternar Expulsión de Desechos\n§7Establecer si los desechos se expulsarán automáticamente.", +"block.biggerreactors.reactor_control_rod": "Varilla de Control del Reactor", +"screen.biggerreactors.reactor_control_rod": "Varilla de Control del Reactor", +"screen.biggerreactors.reactor_control_rod.name": "Nombre:", +"screen.biggerreactors.reactor_control_rod.apply.tooltip": "Aplicar", +"screen.biggerreactors.reactor_control_rod.retract_rod.tooltip": "Retraer Varilla\n§7Menos inserción aumenta la tasa de reacción.\n§8[Shift]: Retraer un 10%.\n§8[Ctrl]: Retraer un 50%.\n§8[Ctrl + Shift]: Retraer al máximo.\n§8[Alt]: Aplicar a todas las varillas.", +"screen.biggerreactors.reactor_control_rod.insert_rod.tooltip": "Insertar Varilla\n§7Más inserción reduce la tasa de reacción.\n§8[Shift]: Insertar un 10%.\n§8[Ctrl]: Insertar un 50%.\n§8[Ctrl + Shift]: Insertar al máximo.\n§8[Alt]: Aplicar a todas las varillas.", + +"screen.biggerreactors.reactor_coolant_port": "Puerto de Refrigerante del Reactor", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.input": "Dirección: §3Entrada", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.output": "Dirección: §cSalida", +"screen.biggerreactors.reactor_coolant_port.direction_toggle.tooltip": "Cambiar Dirección\n§7Modifica la dirección del flujo de este puerto.", +"screen.biggerreactors.reactor_coolant_port.manual_dump": "Vaciado Manual del Tanque", +"screen.biggerreactors.reactor_coolant_port.manual_dump.tooltip": "Vaciar Fluidos del Tanque\n§7Vacia manualmente todos los fluidos del reactor.", + +"screen.biggerreactors.reactor_access_port": "Puerto de Acceso del Reactor", +"screen.biggerreactors.reactor_access_port.direction_toggle.input": "Dirección: §6Entrada", +"screen.biggerreactors.reactor_access_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.reactor_access_port.direction_toggle.tooltip": "Cambiar Dirección\n§7Modifica la dirección del flujo de este puerto.", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.fuel": "Salida: §6Combustible", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.waste": "Salida: §3Desechos", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.nope": "Salida: §7---", +"screen.biggerreactors.reactor_access_port.fuel_mode_toggle.tooltip": "Cambiar Salida\n§7Modifica lo que este puerto está exportando.", +"screen.biggerreactors.reactor_access_port.manual_eject": "Expulsión Manual de Desechos", +"screen.biggerreactors.reactor_access_port.manual_eject.tooltip": "Expulsar Todos los Desechos\n§7Expulsa manualmente todos los desechos del reactor.", + +"screen.biggerreactors.reactor_redstone_port": "Puerto de Redstone del Reactor", +"screen.biggerreactors.reactor_redstone_port.choose_setting": "Elige una configuración:", +"screen.biggerreactors.reactor_redstone_port.apply.tooltip": "Aplicar", +"screen.biggerreactors.reactor_redstone_port.input_reactor_activity": "Cambiar Estado del Reactor (Entrada)", +"screen.biggerreactors.reactor_redstone_port.input_reactor_activity.tooltip": "Cambiar Estado del Reactor (Entrada)\n§8[Con Pulso] Alterna si el reactor está encendido o apagado.\n§8[Con Señal] Si hay señal de redstone, el reactor estará activo.", + +"block.biggerreactors.turbine_casing": "Carcasa de Turbina", +"block.biggerreactors.turbine_glass": "Enredaderario de Turbina", +"block.biggerreactors.turbine_rotor_shaft": "Eje del Rotor de la Turbina", +"block.biggerreactors.turbine_rotor_blade": "Aspa del Rotor de la Turbina", +"block.biggerreactors.turbine_rotor_bearing": "Cojinete del Rotor de la Turbina", +"block.biggerreactors.turbine_fluid_port": "Puerto de Fluidos de la Turbina", +"block.biggerreactors.turbine_power_tap": "Conexión de Energía de la Turbina", +"block.biggerreactors.turbine_computer_port": "Puerto de Computadora de la Turbina", + +"screen.biggerreactors.turbine_terminal": "Información de la Turbina", +"screen.biggerreactors.turbine_terminal.tachometer.tooltip": "Tacómetro\n§7Indica la velocidad de rotación de la turbina.\n§7El rendimiento óptimo es a 900 o 1800 RPM.", +"screen.biggerreactors.turbine_terminal.energy_generation_rate.tooltip": "Tasa de Generación de RF\n§7Indica la cantidad de RF que genera la turbina.", +"screen.biggerreactors.turbine_terminal.flow_rate_governor.tooltip": "Regulador de Flujo\n§7Controla la velocidad a la que la turbina procesa fluidos.", +"screen.biggerreactors.turbine_terminal.rotor_efficiency.tooltip": "Eficiencia del Rotor\n§7La eficiencia disminuye si la tasa de flujo supera la capacidad del rotor.", +"screen.biggerreactors.turbine_terminal.internal_battery.tooltip": "Batería Interna\n§7Indica la cantidad de RF almacenado internamente.", +"screen.biggerreactors.turbine_terminal.intake_tank.tooltip": "Tanque de Entrada\n§7Cantidad de fluido caliente almacenado internamente.", +"screen.biggerreactors.turbine_terminal.exhaust_tank.tooltip": "Tanque de Escape\n§7Cantidad de fluido frío almacenado internamente.", +"screen.biggerreactors.turbine_terminal.activity_toggle.online": "Estado: §2En Línea", +"screen.biggerreactors.turbine_terminal.activity_toggle.offline": "Estado: §4Fuera de Línea", +"screen.biggerreactors.turbine_terminal.activity_toggle.tooltip": "Alternar estado de la turbina\n§7Encender o apagar la turbina.", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.engaged": "Bobinas: §2Enganchadas", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.disengaged": "Bobinas: §4Desenganchadas", +"screen.biggerreactors.turbine_terminal.coil_engage_toggle.tooltip": "Alternar enganche de bobinas\n§7Cuando están enganchadas, la velocidad del rotor se convierte en electricidad.", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.overflow": "Ventilación: §6Solo Exceso", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.all": "Ventilación: §2Todo el Escape", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.closed": "Ventilación: §4Sin Escape", +"screen.biggerreactors.turbine_terminal.vent_state_toggle.tooltip": "Alternar ventilación del escape\n§7Determina cómo o si se ventilará el escape.", +"screen.biggerreactors.turbine_terminal.flow_rate_increase.tooltip": "Aumentar flujo\n§7Un flujo más alto incrementa la velocidad del rotor.\n§8[Shift]: Aumentar en %s mB.\n§8[Ctrl]: Aumentar en %s mB.\n§8[Ctrl + Shift]: Aumentar en %s mB.", +"screen.biggerreactors.turbine_terminal.flow_rate_decrease.tooltip": "Disminuir flujo\n§7Un flujo más bajo reduce la velocidad del rotor.\n§8[Shift]: Disminuir en %s mB.\n§8[Ctrl]: Disminuir en %s mB.\n§8[Ctrl + Shift]: Disminuir en %s mB.", + +"screen.biggerreactors.turbine_fluid_port": "Puerto de Fluido de Turbina", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.input": "Dirección: §cEntrada", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.turbine_fluid_port.direction_toggle.tooltip": "Alternar dirección\n§7Cambia la dirección del flujo de este puerto.", + +"block.biggerreactors.heat_exchanger_casing": "Carcasa del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_glass": "Cristal del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_condenser_channel": "Canal de Condensador del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_evaporator_channel": "Canal de Evaporador del Intercambiador de Calor", + +"block.biggerreactors.heat_exchanger_terminal": "Terminal del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_terminal": "Información del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_terminal.temperature.condenser.tooltip": "Temperatura del Canal del Condensador\n§7Indica qué tan caliente está el fluido en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.temperature.evaporator.tooltip": "Temperatura del Canal del Evaporador\n§7Indica qué tan caliente está el fluido en los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.flow_rate.condenser.tooltip": "Tasa de Flujo del Condensador\n§7Cantidad de fluido que fluye a través de los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.flow_rate.evaporator.tooltip": "Tasa de Flujo del Evaporador\n§7Cantidad de fluido que fluye a través de los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.intake_gauge.condenser.tooltip": "Tanque de Entrada del Condensador\n§7Cantidad de fluido caliente en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.exhaust_gauge.condenser.tooltip": "Tanque de Escape del Condensador\n§7Cantidad de fluido frío en los canales del condensador.", +"screen.biggerreactors.heat_exchanger_terminal.heat_gauge.tooltip": "Temperatura del Intercambiador de Calor\n§7Indica qué tan caliente está el intercambiador.", +"screen.biggerreactors.heat_exchanger_terminal.intake_gauge.evaporator.tooltip": "Tanque de Entrada del Evaporador\n§7Cantidad de fluido frío en los canales del evaporador.", +"screen.biggerreactors.heat_exchanger_terminal.exhaust_gauge.evaporator.tooltip": "Tanque de Escape del Evaporador\n§7Cantidad de fluido caliente en los canales del evaporador.", + +"multiblock.error.biggerreactors.heat_exchanger.dangling_internal_part": "Parece haber otro intercambiador de calor dentro de este, ¿algo está mal? (%d, %d, %d).", +"multiblock.error.biggerreactors.heat_exchanger.dangling_channel": "Todos los canales deben estar conectados a un puerto de fluido. (%d, %d, %d)", +"multiblock.error.biggerreactors.heat_exchanger.duplicate_port_types": "El evaporador y el condensador deben estar conectados a dos puertos de fluido cada uno.", +"multiblock.error.biggerreactors.heat_exchanger.fluid_port_unconnected": "Todos los puertos de fluido deben estar conectados a un canal.", +"multiblock.error.biggerreactors.heat_exchanger.invalid_port_count": "Se requieren exactamente 4 puertos de fluido.", +"multiblock.error.biggerreactors.heat_exchanger.missing_channel_type": "Se necesita al menos un canal de evaporador y uno de condensador.", + +"block.biggerreactors.heat_exchanger_computer_port": "Puerto de Computadora del Intercambiador de Calor", +"block.biggerreactors.heat_exchanger_fluid_port": "Puerto de Fluido del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_fluid_port": "Puerto de Fluido del Intercambiador de Calor", +"screen.biggerreactors.heat_exchanger_fluid_port.channel_type.condenser": "Conexión de Canal: §cCondensador", +"screen.biggerreactors.heat_exchanger_fluid_port.channel_type.evaporator": "Conexión de Canal: §9Evaporador", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.input": "Dirección: §cEntrada", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.output": "Dirección: §9Salida", +"screen.biggerreactors.heat_exchanger_fluid_port.direction_toggle.tooltip": "Alternar Dirección\n§7Cambia la dirección del flujo de este puerto.", +"screen.biggerreactors.heat_exchanger_fluid_port.manual_dump": "Vaciado Manual de Canales de Fluido", +"screen.biggerreactors.heat_exchanger_fluid_port.manual_dump.tooltip": "Vaciar Canales de Fluido\n§7Vaciar manualmente todos los fluidos en el canal conectado.", + +"jei.biggerreactors.classic.turbine_coil_block": "Bloques de Bobina de Turbina", +"jei.biggerreactors.classic.turbine_coil_bonus": "Bono: %s", +"jei.biggerreactors.classic.turbine_coil_efficiency": "Eficiencia: %s", +"jei.biggerreactors.classic.turbine_coil_extraction": "Tasa de Extracción: %s", + +"jei.biggerreactors.classic.reactor_moderator_block": "Bloques Moderadores del Reactor", +"jei.biggerreactors.classic.reactor_moderator_fluid": "Fluidos Moderadores del Reactor", +"jei.biggerreactors.classic.reactor_moderator_moderation": "Moderación: %s", +"jei.biggerreactors.classic.reactor_moderator_absorption": "Absorción: %s", +"jei.biggerreactors.classic.reactor_moderator_conductivity": "Conductividad: %s", +"jei.biggerreactors.classic.reactor_moderator_efficiency": "Eficiencia: %s", +}