From afb4adc32396a55fce01f867a35af6a45ec210e3 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 11:33:13 +0000 Subject: [PATCH 01/16] Port baseSteam to local Forge 1.20.6 --- CHANGELOG.txt | 6 + README.md | 159 +++++-------- build.gradle | 209 +++++++++++------- docs/PORT1206-STATUS.md | 65 ++++++ gradle.properties | 58 ++--- ...enizer.gradle => forge50-mavenizer.gradle} | 14 +- .../gametest/SteamNativeGameTests.java | 159 +++++++++++++ .../basesteam/structures/basesteam_empty.nbt | Bin 0 -> 109 bytes .../moddev/mc/basesteam/SteamAdvantage.java | 25 +-- .../basesteam/blocks/DrillBitTileEntity.java | 27 +-- .../mc/basesteam/compat/BaseMetalsCompat.java | 5 +- .../HighExplosiveEnchantment.java | 40 ---- .../enchantments/PowderlessEnchantment.java | 40 ---- .../enchantments/RapidReloadEnchantment.java | 40 ---- .../enchantments/RecoilEnchantment.java | 40 ---- .../graphics/ClientRegistration.java | 17 +- .../basesteam/graphics/DrillBitRenderer.java | 4 +- .../mc/basesteam/gui/BlastFurnaceGUI.java | 2 +- .../mc/basesteam/gui/CoalBoilerGUI.java | 2 +- .../mc/basesteam/gui/ElectricBoilerGUI.java | 2 +- .../mc/basesteam/gui/GeothermalBoilerGUI.java | 2 +- .../moddev/mc/basesteam/gui/OilBoilerGUI.java | 2 +- .../mc/basesteam/gui/RockCrusherGUI.java | 2 +- .../mc/basesteam/gui/SteamDrillGUI.java | 2 +- .../moddev/mc/basesteam/gui/SteamPumpGUI.java | 2 +- .../mc/basesteam/gui/SteamStillGUI.java | 2 +- .../moddev/mc/basesteam/gui/SteamTankGUI.java | 2 +- .../zone/moddev/mc/basesteam/init/Blocks.java | 4 +- .../mc/basesteam/init/Enchantments.java | 31 ++- .../moddev/mc/basesteam/init/Entities.java | 2 +- .../zone/moddev/mc/basesteam/init/Items.java | 2 +- .../zone/moddev/mc/basesteam/init/Power.java | 2 +- .../moddev/mc/basesteam/init/Villages.java | 5 +- .../moddev/mc/basesteam/items/MusketItem.java | 106 ++++----- .../machines/BlastFurnaceTileEntity.java | 13 +- .../machines/CoalBoilerTileEntity.java | 9 +- .../machines/ElectricBoilerTileEntity.java | 9 +- .../machines/GeothermalBoilerTileEntity.java | 9 +- .../machines/OilBoilerTileEntity.java | 9 +- .../machines/RockCrusherTileEntity.java | 11 +- .../basesteam/machines/SteamDrillBlock.java | 2 +- .../machines/SteamDrillTileEntity.java | 19 +- .../machines/SteamElevatorTileEntity.java | 9 +- .../machines/SteamPumpTileEntity.java | 11 +- .../machines/SteamStillTileEntity.java | 9 +- .../migration/SteamLegacyMigrations.java | 2 +- .../mc/basesteam/recipe/RecipeConditions.java | 77 ++++--- src/main/resources/META-INF/mods.toml | 4 +- .../recipes/blackpowder_cartridge.json | 2 +- .../recipes/musket_left_normal.json | 4 +- .../recipes/musket_left_tech.json | 4 +- .../recipes/musket_right_normal.json | 4 +- .../recipes/musket_right_tech.json | 4 +- .../recipes/steam_boiler_coal.json | 8 +- .../recipes/steam_boiler_electric.json | 8 +- .../recipes/steam_boiler_geothermal.json | 8 +- .../recipes/steam_boiler_oil.json | 6 +- .../advancements/recipes/steam_crusher.json | 8 +- .../advancements/recipes/steam_drill.json | 6 +- .../advancements/recipes/steam_drill_bit.json | 6 +- .../steam_drill_diamond_pickaxe_normal.json | 6 +- .../advancements/recipes/steam_elevator.json | 8 +- .../advancements/recipes/steam_furnace.json | 6 +- .../recipes/steam_governor_apocalyptic.json | 6 +- .../recipes/steam_governor_normal.json | 4 +- .../recipes/steam_governor_tech.json | 6 +- .../advancements/recipes/steam_pipe.json | 2 +- .../advancements/recipes/steam_pump.json | 6 +- .../advancements/recipes/steam_still.json | 6 +- .../advancements/recipes/steam_switch.json | 4 +- .../advancements/recipes/steam_tank.json | 6 +- .../loot_tables/chests/advantage_parts.json | 22 +- .../recipes/blackpowder_cartridge.json | 12 +- .../recipes/crushing_steam_boiler_coal.json | 23 +- .../crushing_steam_boiler_electric.json | 23 +- .../crushing_steam_boiler_geothermal.json | 23 +- .../recipes/crushing_steam_crusher.json | 23 +- .../recipes/crushing_steam_drill.json | 23 +- .../recipes/crushing_steam_elevator.json | 23 +- .../recipes/crushing_steam_furnace.json | 23 +- .../recipes/crushing_steam_governor.json | 23 +- .../recipes/crushing_steam_tank.json | 22 +- .../basesteam/recipes/musket_left_normal.json | 31 +-- .../basesteam/recipes/musket_left_tech.json | 31 +-- .../recipes/musket_right_normal.json | 31 +-- .../basesteam/recipes/musket_right_tech.json | 31 +-- .../basesteam/recipes/steam_boiler_coal.json | 41 ++-- .../recipes/steam_boiler_electric.json | 41 ++-- .../recipes/steam_boiler_geothermal.json | 41 ++-- .../basesteam/recipes/steam_boiler_oil.json | 33 +-- .../data/basesteam/recipes/steam_crusher.json | 41 ++-- .../data/basesteam/recipes/steam_drill.json | 33 +-- .../basesteam/recipes/steam_drill_bit.json | 33 +-- .../steam_drill_diamond_pickaxe_normal.json | 41 ++-- .../basesteam/recipes/steam_elevator.json | 41 ++-- .../data/basesteam/recipes/steam_furnace.json | 33 +-- .../recipes/steam_governor_apocalyptic.json | 41 ++-- .../recipes/steam_governor_normal.json | 33 +-- .../recipes/steam_governor_tech.json | 41 ++-- .../data/basesteam/recipes/steam_pipe.json | 12 +- .../data/basesteam/recipes/steam_pump.json | 33 +-- .../data/basesteam/recipes/steam_still.json | 33 +-- .../data/basesteam/recipes/steam_switch.json | 25 ++- .../data/basesteam/recipes/steam_tank.json | 33 +-- .../data/basesteam/recipes/steam_track.json | 2 +- .../data/basesteam/tags/items/muskets.json | 4 + .../tags/items/enchantable/durability.json | 4 + .../tags/items/enchantable/vanishing.json | 4 + src/main/resources/pack.mcmeta | 4 +- .../blocks/DrillBitPersistenceTest.java | 32 +-- .../items/MusketPersistenceTest.java | 28 ++- .../machines/SteamDrillPersistenceTest.java | 30 +-- .../machines/SteamMachinePersistenceTest.java | 32 +-- .../SteamOperationalPumpSourceTest.java | 4 +- .../migration/SteamLegacyMigrationsTest.java | 12 +- .../resources/BuildWorkflowContractTest.java | 75 ++----- .../resources/DedicatedSideContractTest.java | 53 +++++ .../NativeBlockEntityContractTest.java | 2 +- .../NativeDamageTypeContractTest.java | 2 +- .../resources/NativeFuelContractTest.java | 2 +- .../resources/NativeLootContractTest.java | 9 +- .../OptionalCrushingRecipeContractTest.java | 25 ++- .../RecipeRegistrationThreadTest.java | 59 +++-- .../resources/RecipeUnlockContractTest.java | 51 +++-- .../testing/NativeTestBootstrap.java | 6 + tools/generate-recipe-unlocks.js | 2 +- tools/run-packaged-server-smoke.ps1 | 142 ++++++++++++ tools/verify-native-port.js | 6 +- 128 files changed, 1731 insertions(+), 1253 deletions(-) create mode 100644 docs/PORT1206-STATUS.md rename gradle/{forge47-mavenizer.gradle => forge50-mavenizer.gradle} (60%) create mode 100644 src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java create mode 100644 src/gametest/resources/data/basesteam/structures/basesteam_empty.nbt delete mode 100644 src/main/java/zone/moddev/mc/basesteam/enchantments/HighExplosiveEnchantment.java delete mode 100644 src/main/java/zone/moddev/mc/basesteam/enchantments/PowderlessEnchantment.java delete mode 100644 src/main/java/zone/moddev/mc/basesteam/enchantments/RapidReloadEnchantment.java delete mode 100644 src/main/java/zone/moddev/mc/basesteam/enchantments/RecoilEnchantment.java create mode 100644 src/main/resources/data/basesteam/tags/items/muskets.json create mode 100644 src/main/resources/data/minecraft/tags/items/enchantable/durability.json create mode 100644 src/main/resources/data/minecraft/tags/items/enchantable/vanishing.json create mode 100644 src/test/java/zone/moddev/mc/basesteam/resources/DedicatedSideContractTest.java create mode 100644 tools/run-packaged-server-smoke.ps1 diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e0430b2..d791c6a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,9 @@ +baseSteam 2.2.14.120061 (local Minecraft 1.20.6 port) + +- Target Minecraft 1.20.6, Forge 50.2.0 and Java 21 with basePower 2.4.13.120061. +- Preserve musket loaded state and durability through native item components and legacy upgrades. +- Keep the Steam registry IDs and machine state while moving saves, packets and data packs to Forge 50. + baseSteam 2.2.13.120011 (local Minecraft 1.20.1 port) - Move to Minecraft 1.20.1, Forge 47.4.10 and Java 17 with basePower 2.4.12.120011. diff --git a/README.md b/README.md index 0b5159f..348c448 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,72 @@ # baseSteam -**Minecraft 1.20.1 (Forge), version 2.2.13.120011. Local port.** +**Minecraft 1.20.6 (Forge), version 2.2.14.120061. Local port.** baseSteam, formerly Steam Advantage, adds boilers, steam-powered machines, -pumps, storage, elevators and a blackpowder musket to basePower. Its items and -blocks use the shared basePower creative tab. This version is not published. - -## Upgrading a World - -Back up your world and test the upgrade on a copy. Replace Steam Advantage and -Power Advantage with baseSteam and basePower; do not install both sets of mods. -The migration recognizes old Steam Advantage IDs and keeps the registry paths, -machine settings and saved data used by earlier baseSteam versions. The -combined world upgrade and restart checks are run from the basePower test rig. - -Existing `basesteam-common.toml` settings take precedence. When that file is -absent, baseSteam can copy `steamadvantage-common.toml` or import settings from an -older `.cfg` file. The old config is left in place. +pumps, storage, elevators and a blackpowder musket to basePower. Items and +blocks use the shared basePower creative tab. This checkout is not a release. ## Build Target -Minecraft 1.20.1, Forge 47.4.10, official 1.20.1 mappings and MCP -20230612.114412. ForgeGradle 7.0.34 and Gradle 9.6.1 run on Java 17. -Production compilation and launches use Temurin 17, class major 61. -Mavenizer uses Java 25. The build requires the -checksum-verified Forge 47 compatibility JAR -from the local OreSpawn 1.20.1 checkout or `-Pforge47MavenizerJar=`. -It is not tracked here. -Java 8 is only for older build utilities. +Minecraft 1.20.6, Forge 50.2.0, official mappings and MCP 20240429.135109. +ForgeGradle 7.0.34 and the Gradle 9.6.1 wrapper use Temurin 21.0.7+6. +Mavenizer uses Java 25 and the checksum-verified fixture from the local OreSpawn +1.20.6 checkout. Set `-Pforge50MavenizerJar=` for a different layout. -The mod ID and resource namespace are `basesteam`; the Java implementation -namespace is `zone.moddev.mc.basesteam`. The shared `cyano.poweradvantage.api` -names remain in use. - -basePower 2.4.12.120011 is required. Base Metals 3.1.2.120011 remains optional -in Forge and requires OreSpawn 4.1.0.120011 when installed. The CurseForge -install metadata lists basePower and Base Metals. No dependency is embedded. +Forge 50 uses official names at runtime. Steam does not run an SRG renamer. +The required dependency is basePower 2.4.13.120061. Base Metals 3.1.1.120061 is +optional at runtime and uses OreSpawn 4.1.0.120061. The exact native companion +jars serve as both development and player inputs. No dependency is embedded. +The mod ID, data namespace, and registry paths remain `basesteam`. ## Local Verification -Use the checked-in Gradle wrapper. With the usual sibling checkout layout the -build finds the basePower, Base Metals and OreSpawn development jars and the -basePower test bootstrap. Use explicit properties for alternate checkout paths. -All dependency jars must match the pins in `gradle.properties`. Use a Steam-only Gradle user -home and the test-only Forge capability bootstrap. Player JARs are distinct -from development and published JARs. Before a packaged smoke, run -`verifyPlayerDependencies` with explicit `powerAdvantagePlayerJar`, -`baseMetalsPlayerJar` and `oreSpawnPlayerJar` project properties. The OreSpawn -paths default to `D:/MinecraftMineralogy/OS1201/OreSpawn` in the usual checkout -layout; the same SHA-256 checks apply to defaults and overrides. - -Use the coordinated basePower 1.20.1 candidate and matching frozen JARs. -Pending pins fail closed. No 1.19.4 artifacts may satisfy the 1.20.1 audits. +The default paths point to the coordinated local 1.20.6 checkouts. The +`*DeobfJar` project properties remain accepted path overrides even though the +target uses native jars. For packaged checks, the `*PlayerJar` overrides +are separate. Both paths must satisfy the pins in `gradle.properties`. +A pending Power pin fails closed. -For example, from the Steam checkout in PowerShell: +From this checkout in PowerShell, with the pinned local JDKs installed: ```powershell -$env:JAVA_HOME = $env:JAVA17_HOME -$jdks = @($env:JAVA17_HOME, $env:JAVA25_HOME, $env:JAVA8_HOME) -join ',' +$env:JAVA_HOME = "$env:USERPROFILE/.jdks/temurin-21.0.7+6" +$jdks = "$env:JAVA_HOME,$env:USERPROFILE/.jdks/jdk-25.0.3+9" $toolchains = @("-Porg.gradle.java.installations.paths=$jdks", '-Porg.gradle.java.installations.auto-detect=false', '-Porg.gradle.java.installations.auto-download=false') -$env:GRADLE_USER_HOME = $env:BASESTEAM_GRADLE_USER_HOME -./gradlew.bat @toolchains check build deobfJar javadoc ` - verifyReleaseDependencies verifyReleaseArtifacts writeReleaseChecksums ` - verifyEclipseProductionClasspath ` - "-PpowerAdvantageDeobfJar=$env:POWERADVANTAGE_DEOBF_JAR" ` - "-PbaseMetalsDeobfJar=$env:BASEMETALS_DEOBF_JAR" ` - "-PoreSpawnDeobfJar=$env:ORESPAWN_DEOBF_JAR" ` - "-PforgeCapabilityBootstrapJar=$env:FORGE_CAPABILITY_BOOTSTRAP_JAR" +./gradlew.bat @toolchains check build deobfJar verifyReleaseArtifacts writeReleaseChecksums +./gradlew.bat @toolchains verifyPlayerDependencies runGameTestServer +./tools/run-packaged-server-smoke.ps1 -ForgeInstall $env:FORGE_1206_SERVER_INSTALL -RunId candidate-with-basemetals ``` -On other platforms use `./gradlew`. The artifact family is -`baseSteam-2.2.13.120011.jar`, plus sources and Javadoc. The development jar -stays under `build/libs-dev`. - -`node tools/verify-native-port.js` and `node tools/generate-recipe-unlocks.js --check` -run without the dependency jars. The source check also verifies Java package -paths, which Buildship requires even when Gradle can compile misplaced files. -[1.19.4 port status](docs/PORT119-STATUS.md) is historical. [1.18.2 port status](docs/PORT118-STATUS.md) is historical. - -## Port Details +The GameTest run uses `build/steam-gametest-run` and a validation-only source +set. It checks drill-bit packets, legacy musket componentization, the shared +durability migration, and loaded recipe, advancement, and loot resources. +The packaged dedicated smoke is a separate gate. It checks the official Forge +server shim and the pinned player jars, then boots a fresh loopback-only world +under `evidence/packaged-server-`. Use a new run ID on each attempt. +The optional no-Base-Metals profile uses `-WithoutBaseMetals` and retains +OreSpawn because basePower requires it. +`node tools/verify-native-port.js` and +`node tools/generate-recipe-unlocks.js --check` are independent source checks. +See [local status](docs/PORT1206-STATUS.md) for evidence and open gates. -Native block-entity factories preserve their actual constructor position and -block state. Loading NBT does not replace that position, including when a drill -moves along a track. Power's shared native ticker retains per-tick work before -the eight-tick power update on both logical sides. The drill-bit helper has its -own native ticker. Minecraft 1.20.1 uses `saveAdditional` for native saves, -and the drill-bit direction packet carries the native block-entity type. - -The port retains first-loaded-tick redstone sampling in the crusher and furnace, -water-only boiler inputs, dirty-owner callbacks, finite energy and fluid -accounting, persistence aliases, helper state and GUI caption rows. Native -PoseStack and vertex consumers retain the drill geometry, UVs and animation. -Musket terrain traversal stops before unloaded chunks; sound dispatch still -uses loaded server players. High Explosive shots use the TNT drop policy, which -preserves full drops by default and honors the TNT drop-decay gamerule. - -Native pickaxe tags cover the metal machines and helpers without introducing -new minimum tool tiers or changing drop requirements. Ordinary blocks retain -their self-drop tables. Hidden helper block items retain their registry IDs, -stay out of the creative tab, and do not drop from their blocks. -Recipe ingredients, processing costs and quantities are unchanged. Recipe-book -advancements use native singleton `items` predicates; the ignored legacy `item` -field must not turn an ingredient discovery into an unrestricted predicate. -Optional Base Metals crushing recipes also require `forge:mod_loaded` before -their recipe-mode condition, so APOCALYPTIC loads safely without that serializer. - -Steam reads Base Metals' crushing recipes without overriding their balance. -Geothermal heat uses native Forge lava temperature, retaining the existing -1300 K input and resulting heat value. - -## Acceptance Still Required - -Historical results from earlier versions do not qualify this candidate. -Compilation, Java tests, repeat Eclipse refresh, packaged server/client checks, -world migration and manual gameplay are separate gates. - -Manual testing must cover all boilers, crusher and furnace reload/redstone, -drills in six directions and track moves with inventory and energy, helper -rotation and cleanup, pumps, stills, elevator rides, GUI captions and controls, -musket last-cartridge firing, terrain boundaries, sounds and enchantments, -multiplayer synchronization and capability unload/reload. -Check that steam tracks render with transparent gaps, and that ordinary musket -shots still break fragile blocks and ignite TNT without breaking solid stone. +## Upgrading a World -Use disposable whole-world copies for upgrades. Preserve original worlds and -backups; never reopen an upgraded world with an older Minecraft version. +Back up the world and upgrade a disposable copy. Do not install both Steam +Advantage and baseSteam or reopen an upgraded world on an older Minecraft +version. Use basePower's coordinated migration rig for whole-world checks. +Existing `basesteam-common.toml` settings take precedence over legacy settings. + +Vanilla's data fixer moves 1.20.1 item wear into the damage component and +retains the musket's loaded byte in custom data. The shared migration hook +also recognizes the old `steamadvantage:musket` ID and top-level wear. +Steam's load cycle changes only its loaded byte. Machines retain their +registry IDs, persistent keys, aliases and native factory coordinates. + +Before accepting the port, check boilers, crusher/furnace restart and +redstone, drill movement in all six directions, pumps, stills, elevator rides, +GUI captions, track transparency, and musket load, wear, and effects in-game. +Client presentation and multiplayer behavior need manual acceptance even +when automated checks pass. Earlier-version receipts do not qualify this port. diff --git a/build.gradle b/build.gradle index ade17f4..781e47e 100644 --- a/build.gradle +++ b/build.gradle @@ -10,11 +10,10 @@ plugins { id 'eclipse' id 'idea' id 'maven-publish' - id 'net.minecraftforge.renamer' version '1.1.5' id 'net.minecraftforge.gradle' version '7.0.34' } -apply from: 'gradle/forge47-mavenizer.gradle' +apply from: 'gradle/forge50-mavenizer.gradle' group = project.mod_group version = project.mod_version @@ -46,7 +45,7 @@ ext.release_tag = project.mod_version java { toolchain { - languageVersion = JavaLanguageVersion.of(17) + languageVersion = JavaLanguageVersion.of(21) vendor = JvmVendorSpec.ADOPTIUM } withSourcesJar() @@ -55,11 +54,11 @@ java { tasks.withType(JavaCompile).configureEach { javaCompiler = javaToolchains.compilerFor { - languageVersion = JavaLanguageVersion.of(17) + languageVersion = JavaLanguageVersion.of(21) vendor = JvmVendorSpec.ADOPTIUM } - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 options.encoding = 'UTF-8' options.compilerArgs.addAll(['-Xmaxerrs', '1000']) } @@ -89,6 +88,21 @@ def normalizeArchiveLineEndings = { details -> eof: FixCrLfFilter.AddAsisRemove.newInstance('asis')) } +sourceSets { + gameTestValidation { + java.srcDir 'src/gametest/java' + resources.srcDir 'src/gametest/resources' + compileClasspath += sourceSets.main.output + runtimeClasspath += sourceSets.main.output + } +} + +configurations { + gameTestValidationImplementation.extendsFrom implementation + gameTestValidationCompileOnly.extendsFrom compileOnly + gameTestValidationRuntimeOnly.extendsFrom runtimeOnly +} + minecraft { if (gradle.startParameter.offline) { mavenizerArguments.add('--offline') @@ -109,6 +123,12 @@ minecraft { register('server') { args '--nogui' } + register('gameTestServer') { + workingDir.set(layout.buildDirectory.dir('steam-gametest-run')) + systemProperty 'forge.enableGameTest', 'true' + systemProperty 'forge.enabledGameTestNamespaces', mod_id + mods { basesteam { source sourceSets.gameTestValidation } } + } register('data') { workingDir.convention layout.projectDirectory.dir('run-data') args '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/'), @@ -125,19 +145,37 @@ sourceSets.main.resources { def forgeRunModClassesDirectory = layout.buildDirectory.dir('forge-run-mod-classes/main') def prepareForgeRunModClasses = tasks.register('prepareForgeRunModClasses', Sync) { group = 'ide' - description = 'Merges classes and processed resources for Forge 47 launches.' + description = 'Merges classes and processed resources for Forge 50 launches.' dependsOn tasks.named('classes') from sourceSets.main.output into forgeRunModClassesDirectory } +def gameTestModClassesDirectory = layout.buildDirectory.dir('forge-run-mod-classes/gametest') +def prepareForgeGameTestModClasses = tasks.register('prepareForgeGameTestModClasses', Sync) { + dependsOn tasks.named('classes'), tasks.named('gameTestValidationClasses') + from sourceSets.main.output, sourceSets.gameTestValidation.output + into gameTestModClassesDirectory +} tasks.withType(JavaExec).configureEach { javaLauncher = javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(17) + languageVersion = JavaLanguageVersion.of(21) vendor = JvmVendorSpec.ADOPTIUM } - if (name in ['runClient', 'runServer', 'runData']) { - dependsOn prepareForgeRunModClasses - environment 'MOD_CLASSES', "${mod_id}%%${forgeRunModClassesDirectory.get().asFile.absolutePath}" + if (name in ['runClient', 'runServer', 'runData', 'runGameTestServer']) { + boolean gameTest = name == 'runGameTestServer' + def mergedOutput = gameTest ? gameTestModClassesDirectory : forgeRunModClassesDirectory + dependsOn gameTest ? prepareForgeGameTestModClasses : prepareForgeRunModClasses + environment 'MOD_CLASSES', "${mod_id}%%${mergedOutput.get().asFile.absolutePath}" + doFirst { + if (name == 'runClient') setArgs(['--launcher-side', 'client'] + args) + Set splitOutputs = [sourceSets.main, sourceSets.gameTestValidation].collectMany { + it.output.files + }.collect { it.canonicalFile } as Set + classpath = files(mergedOutput.get().asFile, classpath.files.findAll { + !splitOutputs.contains(it.canonicalFile) + }) + new File(workingDir, 'mods').mkdirs() + } } } @@ -164,17 +202,15 @@ repositories { // Only code and launch tasks require the exact jars; source/resource checks can run independently. def explicitJar = { String property -> providers.gradleProperty(property).map { file(it) }.getOrNull() } def powerRoot = '../../PowerAdvantage' -def baseMetalsRoot = '../../../../BaseMetals/BaseMetals 1201/BaseMetals' -def powerAdvantageDeobfJar = explicitJar('powerAdvantageDeobfJar') ?: file( - "${powerRoot}/build/libs-dev/basePower-${project.poweradvantage_version}-deobf.jar") +def baseMetalsRoot = '../../../../BaseMetals/BaseMetals 1206/BaseMetals' +def powerNativeJar = file("${powerRoot}/build/libs/basePower-${project.poweradvantage_version}.jar") +def powerAdvantageDeobfJar = explicitJar('powerAdvantageDeobfJar') ?: powerNativeJar def baseMetalsDeobfJar = explicitJar('baseMetalsDeobfJar') ?: file( - "${baseMetalsRoot}/build/libs-dev/BaseMetals-${project.basemetals_version}-deobf.jar") -def oreSpawnRoot = '../../../../MinecraftMineralogy/OS1201/OreSpawn' + "${baseMetalsRoot}/build/libs/BaseMetals-${project.basemetals_version}.jar") +def oreSpawnRoot = '../../../../MinecraftMineralogy/OS1206/OreSpawn' def oreSpawnJar = { String variant -> - String directory = variant == 'Deobf' ? 'libs-dev' : 'libs' - String classifier = variant == 'Deobf' ? '-deobf' : '' explicitJar("oreSpawn${variant}Jar") ?: file( - "${oreSpawnRoot}/build/${directory}/OreSpawn-${project.orespawn_version}${classifier}.jar") + "${oreSpawnRoot}/build/libs/OreSpawn-${project.orespawn_version}.jar") } def oreSpawnDeobfJar = oreSpawnJar('Deobf') def developmentJars = files(powerAdvantageDeobfJar, baseMetalsDeobfJar, oreSpawnDeobfJar) @@ -193,12 +229,14 @@ tasks.named('processResources', ProcessResources) { filteringCharset = 'UTF-8' inputs.properties([ version: project.version, + poweradvantage_version: project.poweradvantage_version, minecraft_version_range: project.minecraft_version_range, forge_version_range: project.forge_version_range, loader_version_range: project.loader_version_range ]) filesMatching('META-INF/mods.toml') { expand version: project.version, + poweradvantage_version: project.poweradvantage_version, minecraft_version_range: project.minecraft_version_range, forge_version_range: project.forge_version_range, loader_version_range: project.loader_version_range @@ -218,7 +256,8 @@ def committedPin = { String key, pattern -> def forgeCapabilityBootstrapJar = providers.gradleProperty('forgeCapabilityBootstrapJar') .map { file(it) } .orElse(file("${powerRoot}/build/unit-bootstrap/forge-native-unit-bootstrap.jar")) -tasks.withType(Test).configureEach { +tasks.named('test', Test) { + useJUnit() inputs.files(forgeCapabilityBootstrapJar) inputs.property('powerBootstrapSha256', providers.gradleProperty('poweradvantage_test_bootstrap_sha256')) doFirst { @@ -240,8 +279,11 @@ tasks.withType(Test).configureEach { } logger.lifecycle("basePower test bootstrap: ${bootstrapJar.canonicalPath} SHA-256 ${actualHash}") jvmArgs "-javaagent:${bootstrapJar.canonicalPath}" + jvmArgs '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED' } } +tasks.named('compileTestJava', JavaCompile) { options.compilerArgs.add('-proc:none') } +tasks.named('compileGameTestValidationJava', JavaCompile) { options.compilerArgs.add('-proc:none') } def prepareEclipseResources = tasks.register('prepareEclipseResources') { group = 'ide' @@ -274,23 +316,13 @@ tasks.named('jar', Jar) { } } -def renamedJar = renamer.classes(tasks.named('jar', Jar)) { - map.from minecraft.dependency.toSrgFile - archiveClassifier = 'renamed' - output.set(layout.buildDirectory.file( - "intermediates/renamed/${base.archivesName.get()}-${project.version}.jar")) -} - -// Renamer adds an internal Fernflower parameter map. Repack its output so the -// public jar is deterministic and contains only the mod plus its own manifest. +// Forge 50 runs official names. The player jar needs no SRG remapping. def releaseJar = tasks.register('releaseJar', Jar) { - dependsOn renamedJar, 'verifyReleaseDependencies' + dependsOn tasks.named('classes'), 'verifyReleaseDependencies' archiveClassifier = null destinationDirectory = layout.buildDirectory.dir('libs') - from({ zipTree(renamedJar.get().output.get().asFile) }) { - exclude 'META-INF/MANIFEST.MF' - exclude 'fernflower_abstract_parameter_names.txt' - } + from sourceSets.main.output + exclude 'fernflower_abstract_parameter_names.txt' manifest { attributes([ 'Maven-Artifact' : "${project.group}:${base.archivesName.get()}:${project.version}", @@ -361,9 +393,8 @@ def expectedReleaseFiles = providers.provider { def preparedReleaseDir = providers.gradleProperty('preparedReleaseDir') def verifyPackFormats = { pack -> - if (pack.pack_format != 15 || pack['forge:server_data_pack_format'] != 15 - || pack.containsKey('forge:resource_pack_format') || pack.containsKey('forge:data_pack_format')) { - throw new GradleException('Minecraft 1.20.1 requires resource and data pack format 15') + if (pack.pack_format != 32 || pack.supported_formats != [min_inclusive: 32, max_inclusive: 41]) { + throw new GradleException('Minecraft 1.20.6 requires resource format 32 and data format 41') } } @@ -372,22 +403,22 @@ tasks.register('verifyReleaseConfiguration') { description = 'Validates release identity, target metadata, and dependency policy.' doLast { verifyPackFormats(new JsonSlurper().parse(file('src/main/resources/pack.mcmeta')).pack) - if (project.mod_version != '2.2.13.120011') { + if (project.mod_version != '2.2.14.120061') { throw new GradleException("Unexpected baseSteam release version: ${project.mod_version}") } - if (project.minecraft_version != '1.20.1' || project.minecraft_version_range != '[1.20.1]' - || project.forge_version != '47.4.10' || project.forge_version_range != '[47.4.10,48)' - || project.loader_version_range != '[47,48)' + if (project.minecraft_version != '1.20.6' || project.minecraft_version_range != '[1.20.6]' + || project.forge_version != '50.2.0' || project.forge_version_range != '[50.2.0,51)' + || project.loader_version_range != '[50,51)' || project.mapping_channel != 'official' - || project.mapping_version != '1.20.1' - || project.mcp_version != '20230612.114412') { + || project.mapping_version != '1.20.6' + || project.mcp_version != '20240429.135109') { throw new GradleException('Unexpected Minecraft, Forge, or mappings target') } if (project.loader_name != 'forge' || project.loader_code != '1' - || project.java_version != '17' - || project.java_toolchain_version != '17.0.1+12' - || project.java_setup_version != '17.0.1+12' - || project.gradle_java_version != '17') { + || project.java_version != '21' + || project.java_toolchain_version != '21.0.7+6' + || project.java_setup_version != '21.0.7+6.0.LTS' + || project.gradle_java_version != '21') { throw new GradleException('Unexpected release dispatcher target metadata') } if (project.mod_id != 'basesteam' @@ -400,27 +431,26 @@ tasks.register('verifyReleaseConfiguration') { } if (project.cf_requirements != 'basepower,base-metals' || project.cf_optionals != '' - || project.cf_versions != '1.20.1') { + || project.cf_versions != '1.20.6') { throw new GradleException('Unexpected CurseForge dependency or game-version metadata') } - if (project.basemetals_version != '3.1.2.120011' - || project.orespawn_version != '4.1.0.120011') { + if (project.basemetals_version != '3.1.1.120061' + || project.orespawn_version != '4.1.0.120061') { throw new GradleException('Unexpected development API versions') } - if (project.poweradvantage_version != '2.4.12.120011' - || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/basePower') { + if (project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/basePower') { throw new GradleException('Unexpected basePower compile dependency identity') } String mainSource = file( 'src/main/java/zone/moddev/mc/basesteam/SteamAdvantage.java').getText('UTF-8') if (!mainSource.contains('MODID = "basesteam"') - || !mainSource.contains('VERSION = "2.2.13.120011"')) { + || !mainSource.contains('VERSION = "2.2.14.120061"')) { throw new GradleException('baseSteam source identity changed') } String metadata = file('src/main/resources/META-INF/mods.toml').getText('UTF-8').replace('\r\n', '\n') ['modId="basesteam"', 'displayName="baseSteam"', - 'modId="basepower"\nmandatory=true\nversionRange="[2.4.12.120011,3.0.0)"', - 'modId="basemetals"\nmandatory=false\nversionRange="[3.1.2.120011,4.0.0)"'].each { marker -> + 'modId="basepower"\nmandatory=true\nversionRange="[${poweradvantage_version},3.0.0)"', + 'modId="basemetals"\nmandatory=false\nversionRange="[3.1.1.120061,4.0.0)"'].each { marker -> if (!metadata.contains(marker)) { throw new GradleException("Source mods.toml is missing ${marker}") } @@ -448,8 +478,8 @@ def auditJar = { File jarFile, String property, String hashPin, String modId, St def manifest = new Manifest(zip.getInputStream(zip.getEntry('META-INF/MANIFEST.MF'))).mainAttributes if (manifest.getValue('Implementation-Version') != expectedVersion || manifest.getValue('Built-On') != "${project.minecraft_version}-${project.forge_version}" - || manifest.getValue('Built-On-Java') != '17') { - throw new GradleException("${modId} must be ${expectedVersion} for Forge ${project.forge_version} and Java 17") + || manifest.getValue('Built-On-Java') != '21') { + throw new GradleException("${modId} must be ${expectedVersion} for Forge ${project.forge_version} and Java 21") } String metadata = zip.getInputStream(zip.getEntry('META-INF/mods.toml')).getText('UTF-8') if (!metadata.readLines().any { it.startsWith("modId=\"${modId}\"") }) { @@ -459,10 +489,7 @@ def auditJar = { File jarFile, String property, String hashPin, String modId, St logger.lifecycle("${modId}: ${jarFile.canonicalPath} SHA-256 ${actualHash}") } -def baseMetalsApi = [ - 'zone/moddev/mc/basemetals/api/migration/Legacy112MigrationExtension.class', - 'zone/moddev/mc/basemetals/recipe/CrushingRecipe.class' -] +def baseMetalsApi = ['zone/moddev/mc/basemetals/recipe/CrushingRecipe.class'] def oreSpawnApi = ['zone/moddev/mc/orespawn/api/OreSpawnApi.class'] def powerApi = [ 'cyano/poweradvantage/api/PoweredEntity.class', @@ -481,7 +508,9 @@ def auditCompanions = { boolean player -> String pin = player ? 'player' : 'deobf' committedPin('basemetals_source_commit', /[a-f0-9]{40}/) committedPin('orespawn_source_commit', /[a-f0-9]{40}/) - auditJar(player ? explicitJar("baseMetals${variant}Jar") : baseMetalsDeobfJar, "baseMetals${variant}Jar", "basemetals_${pin}_sha256", + auditJar(player ? (explicitJar('baseMetalsPlayerJar') ?: + file("${baseMetalsRoot}/build/libs/BaseMetals-${project.basemetals_version}.jar")) : + baseMetalsDeobfJar, "baseMetals${variant}Jar", "basemetals_${pin}_sha256", 'basemetals', project.basemetals_version, baseMetalsApi) auditJar(oreSpawnJar(variant), "oreSpawn${variant}Jar", "orespawn_${pin}_sha256", 'orespawn', project.orespawn_version, oreSpawnApi) @@ -507,7 +536,8 @@ tasks.register('verifyPlayerDependencies') { dependsOn tasks.named('verifyCompanionPlayerDependencies') doLast { committedPin('poweradvantage_source_ref', /[a-f0-9]{40}/) - auditJar(explicitJar('powerAdvantagePlayerJar'), 'powerAdvantagePlayerJar', 'poweradvantage_player_sha256', + committedPin('poweradvantage_version', /\d+\.\d+\.\d+\.120061/) + auditJar(explicitJar('powerAdvantagePlayerJar') ?: powerNativeJar, 'powerAdvantagePlayerJar', 'poweradvantage_player_sha256', 'basepower', project.poweradvantage_version, powerApi) } } @@ -517,6 +547,8 @@ tasks.register('verifyNativeDevelopmentDependencies') { description = 'Resolves Forge and audits the exact development JARs.' dependsOn tasks.named('verifyCompanionDevelopmentDependencies') doLast { + committedPin('poweradvantage_version', /\d+\.\d+\.\d+\.120061/) + committedPin('poweradvantage_source_ref', /[a-f0-9]{40}/) auditJar(powerAdvantageDeobfJar, 'powerAdvantageDeobfJar', 'poweradvantage_deobf_sha256', 'basepower', project.poweradvantage_version, powerApi) @@ -618,6 +650,7 @@ tasks.register('verifyReleaseArtifacts') { 'zone/moddev/mc/basesteam/machines/SteamPumpTileEntity.class', 'zone/moddev/mc/basesteam/machines/GeothermalBoilerTileEntity.class', 'zone/moddev/mc/basesteam/migration/SteamLegacyMigrations.class', + 'data/basesteam/loot_tables/chests/advantage_parts.json', 'assets/basesteam/lang/en_us.json', 'data/basesteam/damage_type/musket.json', 'data/basesteam/damage_type/steam_machine.json', @@ -639,6 +672,7 @@ tasks.register('verifyReleaseArtifacts') { .getText(StandardCharsets.UTF_8.name())) verifyPackFormats(resourcePack.pack) ['agent-notes/', '.codex/', 'src/test/', 'zone/moddev/mc/basesteam/testing/', + 'zone/moddev/mc/basesteam/gametest/', 'data/basesteam/structures/basesteam_empty.nbt', 'fernflower_abstract_parameter_names.txt', 'cyano/poweradvantage/', 'zone/moddev/mc/basepower/', 'zone/moddev/mc/poweradvantage/', 'zone/moddev/mc/steamadvantage/', 'assets/steamadvantage/', 'data/steamadvantage/', @@ -674,8 +708,8 @@ tasks.register('verifyReleaseArtifacts') { } } int major = ((header[6] & 0xff) << 8) | (header[7] & 0xff) - if (major != 61) { - throw new GradleException("${entry.name} uses Java class major ${major}, expected 61") + if (major != 65) { + throw new GradleException("${entry.name} uses Java class major ${major}, expected 65") } } } @@ -933,6 +967,14 @@ tasks.register('isolateEclipseProductionRuns') { String mainOutput = file('bin/main').absolutePath String eclipseModClasses = "${project.mod_id}%%${mainOutput}" modClasses[0].@value = eclipseModClasses + if (launch.name == 'runClient.launch') { + def programArguments = launchXml.stringAttribute.find { + it.@key == 'org.eclipse.jdt.launching.PROGRAM_ARGUMENTS' + } + if (programArguments != null && !programArguments.@value.startsWith('--launcher-side client ')) { + programArguments.@value = '--launcher-side client ' + programArguments.@value + } + } def vmArguments = launchXml.stringAttribute.find { it.@key == 'org.eclipse.jdt.launching.VM_ARGUMENTS' } if (vmArguments != null) { // ForgeGradle leaves these path arguments bare even when a directory contains spaces. @@ -1069,16 +1111,16 @@ tasks.register('verifyEclipseProductionClasspath') { } def eclipseClasspath = new groovy.xml.XmlSlurper().parse(file('.classpath')) if (!eclipseClasspath.classpathentry.any { - it.@kind.text() == 'con' && it.@path.text().tokenize('/').last() == 'JavaSE-17' + it.@kind.text() == 'con' && it.@path.text().tokenize('/').last() == 'JavaSE-21' }) { - throw new GradleException('Eclipse must use the Java 17 production execution environment') + throw new GradleException('Eclipse must use the Java 21 production execution environment') } Properties jdt = new Properties() file('.settings/org.eclipse.jdt.core.prefs').withInputStream { jdt.load(it) } ['org.eclipse.jdt.core.compiler.codegen.targetPlatform', 'org.eclipse.jdt.core.compiler.source', 'org.eclipse.jdt.core.compiler.compliance'].each { key -> - if (jdt.getProperty(key) != '17') { - throw new GradleException("Eclipse ${key} must remain Java 17") + if (jdt.getProperty(key) != '21') { + throw new GradleException("Eclipse ${key} must remain Java 21") } } def processedResources = eclipseClasspath.classpathentry.findAll { @@ -1117,14 +1159,15 @@ tasks.register('verifyEclipseProductionClasspath') { it.@key.text() == 'org.eclipse.jdt.launching.VM_ARGUMENTS' }.@value.text() def legacyFile = vmArguments =~ /(?:^|\s)"-DlegacyClassPath\.file=([^"]+)"(?=\s|$)/ - if (!legacyFile.find() || !file(legacyFile.group(1)).isFile() - || !(vmArguments =~ /(?:^|\s)-p\s+"[^"]+"/).find()) { + if (vmArguments.contains('-DlegacyClassPath.file=') + && (!legacyFile.find() || !file(legacyFile.group(1)).isFile())) { throw new GradleException("${name} must quote the Forge classpath and module paths") } - if (!arguments.contains('--main cpw.mods.bootstraplauncher.BootstrapLauncher') + if (!arguments.contains('--main net.minecraftforge.bootstrap.ForgeBootstrap') + || (name == 'runClient.launch' && !arguments.startsWith('--launcher-side client ')) || !vmArguments.contains('--add-opens java.base/java.lang.invoke=ALL-UNNAMED') || contents.contains('net.minecraftforge.userdev.LaunchTesting')) { - throw new GradleException("${name} must retain the native Forge 47 bootstrap and Java 17 module access") + throw new GradleException("${name} must retain the native Forge 50 bootstrap and Java 21 module access") } if (launch.booleanAttribute.find { it.@key.text() == 'org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE' @@ -1179,12 +1222,10 @@ tasks.register('verifyEclipseProductionClasspath') { throw new GradleException( "${name} does not preserve the Forge bootstrap classpath order") } - String target = name == 'runClient.launch' ? 'forgeclientuserdev' : 'forgeserveruserdev' + String target = name == 'runClient.launch' ? 'forge_userdev_client' : 'forge_userdev_server' if (!arguments.contains("--launchTarget ${target}") - || !arguments.contains("--fml.mcVersion ${project.minecraft_version}") - || !arguments.contains("--fml.forgeVersion ${project.forge_version}") - || !arguments.contains("--fml.mcpVersion ${project.mcp_version}")) { - throw new GradleException("${name} does not target the exact Forge 47 development runtime") + || !arguments.contains("forge-${project.minecraft_version}-${project.forge_version}-metadata.zip")) { + throw new GradleException("${name} does not target the exact Forge 50 development runtime") } } } @@ -1336,7 +1377,7 @@ tasks.register('verifyRecipeTagGuards') { collectTags = { Object node, Set tags -> if (node instanceof Map) { node.each { key, value -> - if (key == 'conditions' || key == 'result') return + if (key == 'forge:condition' || key == 'result') return if (key == 'tag' && value instanceof String && value.startsWith('forge:')) { tags.add(value) } else { @@ -1351,7 +1392,15 @@ tasks.register('verifyRecipeTagGuards') { Map recipe = new JsonSlurper().parse(recipeFile) as Map Set tags = [] as Set collectTags(recipe, tags) - Collection conditions = (recipe.conditions ?: []) as Collection + if (recipe.containsKey('conditions')) { + throw new GradleException("${recipeFile.path} uses the obsolete Forge conditions array") + } + Map condition = recipe['forge:condition'] as Map + Collection conditions = condition == null ? [] : + condition.type == 'forge:and' ? condition.values : [condition] + if (conditions == null) { + throw new GradleException("${recipeFile.path} has no forge:and values") + } if (conditions.any { !(it instanceof Map) }) { throw new GradleException("${recipeFile.path} contains a non-object recipe condition") } diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md new file mode 100644 index 0000000..00e5452 --- /dev/null +++ b/docs/PORT1206-STATUS.md @@ -0,0 +1,65 @@ +# Steam 1.20.6 Local Status + +- Checkout: `D:/PowerAdvantage/PA1206/SteamAdvantage/SteamAdvantage`. +- Baseline: `master-1.20.6` at accepted Steam `17c6b8467d5c488e101b53b992537d6d9b251b87`. +- Work branch: `feature/basesteam-1.20.6-port`; no configured remotes, matching the source checkout. +- Target: baseSteam 2.2.14.120061, Forge 50.2.0, Java 21, official 1.20.6 mappings. +- Scope: Steam only. No push, tag, PR, deployment, publication, or use of existing worlds. + +## Coordinated Inputs + +| Input | Commit | Local native jar SHA-256 | +| --- | --- | --- | +| basePower 2.4.13.120061 | Pending final pin | Pending final pin | +| Base Metals 3.1.1.120061 | `ea326ef35c0b463d6297e374a53d5ddbfe4041af` | `08AC265C7284D18962A3DE91B7C267187AEF76ACF6AFE7BBA0729F5CED60A437` | +| OreSpawn 4.1.0.120061 | `4085315345ff043448b316d75e03f4b8da45402d` | `FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26` | + +The companions were read from their 1.20.6 checkouts' `build/libs` +directories. Their hashes and Forge/Java manifest identities passed both local +development and player checks. Steam's audit requires the actual Power commit, +native jar and test-bootstrap pins. It rejects pin overrides and does not use +any 1.20.1 or newer 1.20.6 mod artifacts. + +## Evidence + +- `build-steam1206-companions.log`: initial offline cache-only rejection. +- `build-steam1206-companions-normal.log`: Forge configured, then the stale + Base Metals migration-class marker failed. Steam only consumes the crushing API. +- `build-steam1206-static.log`: companion development/player and recipe guard + audits passed; the full check rejected the pending Power source pin as intended. +- `evidence/steam1206-native-data-third.log`: 15 independent Forge codec and + resource checks passed, plus the recipe guard, Java layout and hygiene tasks. + Earlier failures and their XML remain under `evidence/`. +- The source verifier passed and all 24 generated recipe unlocks matched. +- `evidence/steam1206-resource-parity.log`: all 33 recipes retain their exact + inputs, output counts, and ordered guards. Block loot and harvest tags + are byte-identical to the accepted source. +- `evidence/steam1206-provisional-compile-d.log`: Java 21 production, unit, + and GameTest sources compiled against the coordinated provisional Power + jar. Its SHA-256 before and after was + `FABB0EE5B742F5D7F36752C1730BE8253632D2761B27E28E307A08662372A4AC`. + The final Power audit was explicitly excluded for this compile only. + The compile-a through compile-c failures are retained. +- `evidence/steam1206-provisional-side-compile.log`: all three source sets + compiled after the side-only changes against provisional Power SHA-256 + `AF198E46C86FFC3F684C213F3A2A01F12D1A8D6AF12CD048877D10FBCE70DA6B`. +- `evidence/steam1206-independent-native-side.log`: 21 checks passed, + including the native drill renderer geometry and the client-only GUI + signature regression. Neither receipt is a packaged runtime pass. + +The isolated data checks use Forge 50.2.0 classes but do not start the Forge +mod loader or qualify Steam's production classes. The GameTest fixtures are +separate from packaged content. The empty test structure is a copy of the +minimal generated fixture from the local Base Metals 1.20.6 validation build +(SHA-256 `732772B538B1B647EACD1B7E5F27C74F5CB556B1C6BD91744008575331E7C9E2`). + +Steam's ten machine-menu decoration overrides were already client-only. +Client renderer registration is now also isolated in a client-only class. +The ASM side contract checks this without pretending to substitute for a +packaged dedicated launch. The smoke script copies the checked Forge install +and pinned player artifacts into a new, disposable Steam evidence directory. + +Exact pinned build, full unit suite, GameTest and packaged runtime remain +separate gates. Do not promote the provisional Power artifact to a final +pin. Manual client, multiplayer and historical world acceptance require +their own evidence. diff --git a/gradle.properties b/gradle.properties index 4f569ab..3f0f9e5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,57 +5,57 @@ org.gradle.caching=true org.gradle.parallel=false net.minecraftforge.gradle.merge-source-sets=false -minecraft_version=1.20.1 -minecraft_version_range=[1.20.1] -forge_version=47.4.10 -forge_installer_sha256=1912760B4CB6B803D8A826DE603C9076B1DA71EC2765E9A1F8C1CA78F65278E3 -forge_version_range=[47.4.10,48) -loader_version_range=[47,48) +minecraft_version=1.20.6 +minecraft_version_range=[1.20.6] +forge_version=50.2.0 +forge_installer_sha256=8789098B077F5486449311A11DC05E977FEB9430913CB15F30B21A2D8AA213EA +forge_version_range=[50.2.0,51) +loader_version_range=[50,51) mapping_channel=official -mapping_version=1.20.1 -mcp_version=20230612.114412 +mapping_version=1.20.6 +mcp_version=20240429.135109 loader_name=forge loader_code=1 -java_version=17 -java_toolchain_version=17.0.1+12 -java_setup_version=17.0.1+12 -gradle_java_version=17 +java_version=21 +java_toolchain_version=21.0.7+6 +java_setup_version=21.0.7+6.0.LTS +gradle_java_version=21 curseforge_project_id=1781373 mod_id=basesteam mod_name=baseSteam mod_license=GPL-3.0-only -mod_version=2.2.13.120011 +mod_version=2.2.14.120061 mod_group=zone.moddev.mc.basesteam mod_authors=DrCyano mod_description=Steam-powered machines and infrastructure for basePower. cf_requirements=basepower,base-metals cf_optionals= -cf_versions=1.20.1 +cf_versions=1.20.6 -poweradvantage_version=2.4.12.120011 +poweradvantage_version=2.4.13.120061 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower # Exact local checkpoints for coordinated testing, not published source pins. -poweradvantage_source_ref=83a3f028ffad220fe2f3cc4983a9340dde2295a8 -poweradvantage_deobf_sha256=21A2A3007BA076D219E6836707EF365E2031823A09D5E3DC2A92DD88BD67EA01 +poweradvantage_source_ref=PENDING +poweradvantage_deobf_sha256=PENDING # Player jar is a separate runtime input, not a development jar or publication claim. -poweradvantage_player_sha256=E6835ECB04D3F2D5F54731694F7B8D87F06B4A0A9DDB18AA5EDD70EE0E1B099A -poweradvantage_test_bootstrap_sha256=A93CD83EC42B09B730CB7715C10C6E53D47B22B557EFE68EDC95241D53BD4EB3 -poweradvantage_test_bootstrap_source_sha256=0FB05554D6446BD5561BF9DE47B9F173E6F6C28E39A2BC877D359BB363CB1ABE +poweradvantage_player_sha256=PENDING +poweradvantage_test_bootstrap_sha256=PENDING +poweradvantage_test_bootstrap_source_sha256=PENDING -basemetals_version=3.1.2.120011 -basemetals_source_commit=d9614e3d26a3b57ddff9703861f18a283c7e8358 -basemetals_deobf_sha256=A67EB0CB74971E53D528C4D4F1275AE007106D7F8F71DFE4A16FB50411BDCC28 -basemetals_player_sha256=30FC6777300E0E48FBB63E3250E86122DAFA38CCA5AD5878CB795C72B7CCCCDE +basemetals_version=3.1.1.120061 +basemetals_source_commit=ea326ef35c0b463d6297e374a53d5ddbfe4041af +basemetals_deobf_sha256=08AC265C7284D18962A3DE91B7C267187AEF76ACF6AFE7BBA0729F5CED60A437 +basemetals_player_sha256=08AC265C7284D18962A3DE91B7C267187AEF76ACF6AFE7BBA0729F5CED60A437 -orespawn_version=4.1.0.120011 -orespawn_source_commit=9d9db6cd315c9fce542808aa2551c94bf9267e93 -orespawn_deobf_sha256=A0B096894DC48308D59455F7EC67AB0BBF7EB02354D903024A9E9E876EB07CBB -orespawn_player_sha256=E6BDE47C1BB0BF4D08396F1D1FD5B1D2D3F8A5DF09905F279D39E2601D7FE4B0 +orespawn_version=4.1.0.120061 +orespawn_source_commit=4085315345ff043448b316d75e03f4b8da45402d +orespawn_deobf_sha256=FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26 +orespawn_player_sha256=FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26 # Published runtime bytes are distinct from development API jars. basemetals_public_sha256=PENDING -orespawn_public_sha256=E6BDE47C1BB0BF4D08396F1D1FD5B1D2D3F8A5DF09905F279D39E2601D7FE4B0 +orespawn_public_sha256=PENDING diff --git a/gradle/forge47-mavenizer.gradle b/gradle/forge50-mavenizer.gradle similarity index 60% rename from gradle/forge47-mavenizer.gradle rename to gradle/forge50-mavenizer.gradle index a3fd70d..9e993e7 100644 --- a/gradle/forge47-mavenizer.gradle +++ b/gradle/forge50-mavenizer.gradle @@ -1,18 +1,18 @@ import java.security.MessageDigest import org.gradle.jvm.toolchain.JvmVendorSpec -// OreSpawn's Forge 47 fixture fixes eight decompiled record accessors. +// Use the sealed OreSpawn 1.20.6 fixture; Forge 50 needs no source repairs. def tool = 'ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar' -def defaultJar = "../../../../MinecraftMineralogy/OS1201/OreSpawn/${tool}" -def fixture = file(providers.gradleProperty('forge47MavenizerJar').getOrElse(defaultJar)) -def expected = '416DCA4797BC55826F0DDCF03FDC405F1990FC15C2133FA27A1F143BF7976177' +def defaultJar = "../../../../MinecraftMineralogy/OS1206/OreSpawn/${tool}" +def fixture = file(providers.gradleProperty('forge50MavenizerJar').getOrElse(defaultJar)) +def expected = '4B14145595E900F178A082F2253A756F63897E6F61C2B8B5E7C819B82CD79E8C' if (!fixture.isFile()) { - throw new GradleException("Forge 47 requires OreSpawn's Mavenizer fixture: ${fixture}. " - + "Use -Pforge47MavenizerJar= for another checkout layout.") + throw new GradleException("Forge 50 requires OreSpawn's Mavenizer fixture: ${fixture}. " + + "Use -Pforge50MavenizerJar= for another checkout layout.") } def actual = MessageDigest.getInstance('SHA-256').digest(fixture.bytes).encodeHex().toString().toUpperCase(Locale.ROOT) if (actual != expected) { - throw new GradleException("Forge 47 Mavenizer fixture SHA-256 mismatch: expected ${expected}, got ${actual}") + throw new GradleException("Forge 50 Mavenizer fixture SHA-256 mismatch: expected ${expected}, got ${actual}") } fgtools.configure('mavenizer') { diff --git a/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java b/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java new file mode 100644 index 0000000..358b76a --- /dev/null +++ b/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java @@ -0,0 +1,159 @@ +package zone.moddev.mc.basesteam.gametest; + +import com.mojang.serialization.Dynamic; +import io.netty.buffer.Unpooled; +import net.minecraft.SharedConstants; +import net.minecraft.advancements.critereon.InventoryChangeTrigger; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.storage.loot.LootParams; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.gametest.GameTestDontPrefix; +import net.minecraftforge.gametest.GameTestHolder; +import zone.moddev.mc.basepower.migration.LegacyWorldDataHook; +import zone.moddev.mc.basepower.util.ItemData; +import zone.moddev.mc.basesteam.SteamAdvantage; +import zone.moddev.mc.basesteam.blocks.DrillBitTileEntity; +import zone.moddev.mc.basesteam.init.Blocks; +import zone.moddev.mc.basesteam.init.Entities; +import zone.moddev.mc.basesteam.init.Items; +import zone.moddev.mc.basesteam.items.MusketItem; + +@GameTestHolder(value = SteamAdvantage.MODID, namespace = SteamAdvantage.MODID) +@GameTestDontPrefix +public final class SteamNativeGameTests { + private SteamNativeGameTests() {} + + @GameTest(template = "basesteam_empty") + public static void drillBitPacketPreservesTypePositionAndDirection(GameTestHelper helper) { + BlockPos local = new BlockPos(1, 1, 1); + helper.setBlock(local, Blocks.drillbit); + DrillBitTileEntity source = (DrillBitTileEntity) helper.getBlockEntity(local); + var registries = helper.getLevel().registryAccess(); + for (Direction direction : Direction.values()) { + source.setDirection(direction); + RegistryFriendlyByteBuf buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), registries); + try { + ClientboundBlockEntityDataPacket.STREAM_CODEC.encode(buffer, source.getUpdatePacket()); + var received = ClientboundBlockEntityDataPacket.STREAM_CODEC.decode(buffer); + helper.assertTrue(received.getType() == Entities.DRILLBIT, "Wrong drill-bit packet type"); + helper.assertTrue(received.getPos().equals(helper.absolutePos(local)), "Wrong drill-bit position"); + DrillBitTileEntity destination = new DrillBitTileEntity(received.getPos(), source.getBlockState()); + destination.onDataPacket(null, received, registries); + helper.assertTrue(destination.getUpdateTag(registries).getByte("dir") == direction.get3DDataValue(), + "Lost drill-bit direction " + direction); + } finally { + buffer.release(); + } + } + helper.succeed(); + } + + @GameTest(template = "basesteam_empty") + public static void legacyMusketWearAndLoadedByteSurviveNativeComponentization(GameTestHelper helper) { + CompoundTag legacy = new CompoundTag(); + legacy.putString("id", "basesteam:musket"); + legacy.putByte("Count", (byte) 1); + CompoundTag tag = new CompoundTag(); + tag.putInt("Damage", 249); + tag.putByte("loaded", (byte) 1); + tag.putString("owner", "legacy fixture"); + legacy.put("tag", tag); + var registries = helper.getLevel().registryAccess(); + var fixed = DataFixers.getDataFixer().update(References.ITEM_STACK, + new Dynamic<>(NbtOps.INSTANCE, legacy), 3465, SharedConstants.getCurrentVersion().getDataVersion().getVersion()); + ItemStack stack = ItemStack.parse(registries, fixed.getValue()).orElseThrow(); + helper.assertTrue(stack.is(Items.blackpowder_musket), "Converted the wrong item"); + helper.assertTrue(stack.getDamageValue() == 249 && stack.getMaxDamage() == 250, "Lost legacy wear"); + helper.assertTrue(MusketItem.isLoaded(stack), "Lost the legacy loaded byte"); + MusketItem.unload(stack); + ItemStack reloaded = ItemStack.parse(registries, stack.save(registries)).orElseThrow(); + helper.assertTrue(MusketItem.isNotLoaded(reloaded) && reloaded.getDamageValue() == 249, + "Changing loaded state must not reset wear"); + helper.assertTrue("legacy fixture".equals(reloaded.get(DataComponents.CUSTOM_DATA).copyTag().getString("owner")), + "Changing loaded state must not discard unrelated legacy data"); + helper.succeed(); + } + + @GameTest(template = "basesteam_empty") + public static void olderMusketAliasAndTopLevelWearSurvivePowerMigration(GameTestHelper helper) { + CompoundTag legacy = new CompoundTag(); + legacy.putString("id", "steamadvantage:musket"); + legacy.putByte("Count", (byte) 1); + legacy.putShort("Damage", (short) 131); + CompoundTag tag = new CompoundTag(); + tag.putByte("loaded", (byte) 2); + legacy.put("tag", tag); + LegacyWorldDataHook.prepareLegacyChunk(legacy); + ItemStack migrated = ItemData.readStack(helper.getLevel().registryAccess(), legacy); + helper.assertTrue(migrated.is(Items.blackpowder_musket), "The old musket ID was not remapped"); + helper.assertTrue(migrated.getDamageValue() == 131, "The legacy Damage short was lost"); + helper.assertTrue(MusketItem.isAlmostLoaded(migrated), "The partial reload was lost"); + helper.succeed(); + } + + @GameTest(template = "basesteam_empty") + public static void nativeResourcesLoadWithExpectedIds(GameTestHelper helper) { + var level = helper.getLevel(); + var registries = level.registryAccess(); + var manager = level.getServer().getAdvancements(); + helper.assertTrue(manager.get(id("recipes/steam_pipe")) != null, "Missing Steam pipe recipe advancement"); + var unlock = manager.get(id("recipes/musket_right_normal")).value(); + var ingredient = (InventoryChangeTrigger.TriggerInstance) + unlock.criteria().get("has_ingredient_1").triggerInstance(); + var predicate = ingredient.items().getFirst(); + helper.assertTrue(predicate.test(new ItemStack(net.minecraft.world.item.Items.FLINT_AND_STEEL)), + "Musket discovery lost the matching ingredient"); + helper.assertTrue(!predicate.test(new ItemStack(net.minecraft.world.item.Items.STONE)), + "An unrelated item unlocked the musket recipe"); + var tagIngredient = (InventoryChangeTrigger.TriggerInstance) + unlock.criteria().get("has_ingredient_3").triggerInstance(); + helper.assertTrue(tagIngredient.items().getFirst().test(new ItemStack(net.minecraft.world.item.Items.OAK_PLANKS)), + "Musket discovery lost the plank tag predicate"); + var loot = level.getServer().reloadableRegistries(); + var chest = ResourceKey.create(Registries.LOOT_TABLE, id("chests/advantage_parts")); + LootTable chestTable = loot.getLootTable(chest); + helper.assertTrue(chestTable != LootTable.EMPTY && chestTable.getParamSet() == LootContextParamSets.CHEST, + "Missing Steam chest loot table"); + var params = new LootParams.Builder(level) + .withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(helper.absolutePos(BlockPos.ZERO))) + .create(LootContextParamSets.CHEST); + boolean foundSteamItem = false; + for (int seed = 1; seed <= 32; seed++) { + if (!chestTable.getRandomItems(params, seed).isEmpty()) foundSteamItem = true; + } + helper.assertTrue(foundSteamItem, "Steam chest rolls returned no items"); + helper.assertTrue(loot.getLootTable(Blocks.steam_pipe.getLootTable()) != LootTable.EMPTY, + "Missing Steam pipe block loot"); + var pipe = level.getRecipeManager().byKey(id("steam_pipe")); + var brass = net.minecraft.tags.ItemTags.create(ResourceLocation.fromNamespaceAndPath("forge", "ingots/brass")); + if (registries.lookupOrThrow(Registries.ITEM).get(brass).filter(tag -> tag.size() > 0).isPresent()) { + var result = pipe.orElseThrow().value().getResultItem(registries); + helper.assertTrue(result.is(Blocks.steam_pipe.asItem()) && result.getCount() == 6, + "Wrong Steam pipe recipe output"); + } else { + helper.assertTrue(pipe.isEmpty(), "Recipe must not load with an empty brass tag"); + } + helper.succeed(); + } + + private static ResourceLocation id(String path) { + return ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, path); + } +} diff --git a/src/gametest/resources/data/basesteam/structures/basesteam_empty.nbt b/src/gametest/resources/data/basesteam/structures/basesteam_empty.nbt new file mode 100644 index 0000000000000000000000000000000000000000..5081d2bfea3d43cba189a6ef2b1aead41cf7a284 GIT binary patch literal 109 zcmb2|=3oGW|GuX-@;NvNv^*3%B>S-OO4ic4*sx6pC+=Rm$3|W1s7U;?^^G!T9lV6w zHQL#C-CopDRM_|Z&)G#*naQE+gpHe%mdw5Q?$J%ws4eQ88#JE3Ey%7}ta3QcwblMH N fluidBurnValues = new HashMap<>(); - public SteamAdvantage() { + public SteamAdvantage(FMLJavaModLoadingContext context) { SteamLegacyMigrations.register(); migrateLegacyConfiguration(); - ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, SteamAdvantageConfig.SPEC); - FMLJavaModLoadingContext.get().getModEventBus().addListener(SteamAdvantageConfig::onConfigLoading); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup); + context.registerConfig(ModConfig.Type.COMMON, SteamAdvantageConfig.SPEC); + var modBus = context.getModEventBus(); + modBus.addListener(SteamAdvantageConfig::onConfigLoading); + modBus.addListener(this::commonSetup); + RecipeConditions.register(modBus); - DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { - FMLJavaModLoadingContext.get().getModEventBus().addListener( - zone.moddev.mc.basesteam.graphics.ClientRegistration::onClientSetup); - FMLJavaModLoadingContext.get().getModEventBus().addListener( - zone.moddev.mc.basesteam.graphics.ClientRegistration::registerRenderers); - }); + DistExecutor.runWhenOn(Dist.CLIENT, + () -> () -> zone.moddev.mc.basesteam.graphics.ClientRegistration.register(modBus)); } private static void migrateLegacyConfiguration() { @@ -79,8 +76,6 @@ private static void migrateLegacyConfiguration() { } private void commonSetup(FMLCommonSetupEvent event) { - // CraftingHelper's shared condition map is not safe during parallel loading. - event.enqueueWork(RecipeConditions::register); event.enqueueWork(GUI::init); SteamAdvantageConfig.apply(); Recipes.init(); diff --git a/src/main/java/zone/moddev/mc/basesteam/blocks/DrillBitTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/blocks/DrillBitTileEntity.java index 363a81c..06171b8 100644 --- a/src/main/java/zone/moddev/mc/basesteam/blocks/DrillBitTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/blocks/DrillBitTileEntity.java @@ -3,11 +3,11 @@ import zone.moddev.mc.basesteam.init.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.Connection; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.core.Direction; import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; import net.minecraft.world.level.Level; import java.util.ArrayList; import java.util.List; @@ -78,21 +78,23 @@ private void collectLine(List line, Direction f){ } @Override - protected void saveAdditional(CompoundTag root){ - super.saveAdditional(root); + protected void saveAdditional(CompoundTag root, HolderLookup.Provider registries){ + super.saveAdditional(root, registries); writeDirectionToNBT(root); } @Override - public void load(CompoundTag root){ - super.load(root); + protected void loadAdditional(CompoundTag root, HolderLookup.Provider registries){ + super.loadAdditional(root, registries); readDirectionFromNBT(root); } @Override - public CompoundTag getUpdateTag() { - return saveWithoutMetadata(); + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + CompoundTag tag = new CompoundTag(); + writeDirectionToNBT(tag); + return tag; } /** @@ -100,16 +102,7 @@ public CompoundTag getUpdateTag() { */ @Override public ClientboundBlockEntityDataPacket getUpdatePacket(){ - CompoundTag nbtTag = new CompoundTag(); - writeDirectionToNBT(nbtTag); - return ClientboundBlockEntityDataPacket.create(this, tile -> nbtTag); - } - /** - * Receives the network packet made by getDescriptionPacket() - */ - @Override - public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket packet) { - readDirectionFromNBT(packet.getTag()); + return ClientboundBlockEntityDataPacket.create(this); } private void writeDirectionToNBT(CompoundTag root) { diff --git a/src/main/java/zone/moddev/mc/basesteam/compat/BaseMetalsCompat.java b/src/main/java/zone/moddev/mc/basesteam/compat/BaseMetalsCompat.java index 5febe11..5ece19d 100644 --- a/src/main/java/zone/moddev/mc/basesteam/compat/BaseMetalsCompat.java +++ b/src/main/java/zone/moddev/mc/basesteam/compat/BaseMetalsCompat.java @@ -38,8 +38,9 @@ private static final class LoadedCrushingRecipes { private static ItemStack find(Level world, ItemStack input) { SimpleContainer inventory = new SimpleContainer(1); inventory.setItem(0, input.copy()); - for (var candidate : world.getRecipeManager().getRecipes()) { - if (candidate instanceof CrushingRecipe crushing && crushing.matches(inventory, world)) { + for (var candidate : world.getRecipeManager().getAllRecipesFor(CrushingRecipe.TYPE.get())) { + CrushingRecipe crushing = candidate.value(); + if (crushing.matches(inventory, world)) { return crushing.getResultItem(world.registryAccess()).copy(); } } diff --git a/src/main/java/zone/moddev/mc/basesteam/enchantments/HighExplosiveEnchantment.java b/src/main/java/zone/moddev/mc/basesteam/enchantments/HighExplosiveEnchantment.java deleted file mode 100644 index 7981c7c..0000000 --- a/src/main/java/zone/moddev/mc/basesteam/enchantments/HighExplosiveEnchantment.java +++ /dev/null @@ -1,40 +0,0 @@ -package zone.moddev.mc.basesteam.enchantments; - -import zone.moddev.mc.basesteam.init.Items; -import net.minecraft.world.item.enchantment.EnchantmentCategory; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.item.ItemStack; - -public class HighExplosiveEnchantment extends net.minecraft.world.item.enchantment.Enchantment{ - - public HighExplosiveEnchantment() { - super(Rarity.UNCOMMON,EnchantmentCategory.BREAKABLE,new EquipmentSlot[]{EquipmentSlot.MAINHAND}); - } - - - @Override - public boolean canEnchant(ItemStack item){ - return item.getItem() == Items.blackpowder_musket; - } - @Override - public boolean canApplyAtEnchantingTable(ItemStack item){ - return canEnchant(item); - } - - - - @Override - public int getMinCost(final int lvl) { - return lvl * 7; - } - - @Override - public int getMaxCost(final int lvl) { - return this.getMinCost(lvl) + 10; - } - - @Override - public int getMaxLevel() { - return 5; - } -} diff --git a/src/main/java/zone/moddev/mc/basesteam/enchantments/PowderlessEnchantment.java b/src/main/java/zone/moddev/mc/basesteam/enchantments/PowderlessEnchantment.java deleted file mode 100644 index 2eb00b1..0000000 --- a/src/main/java/zone/moddev/mc/basesteam/enchantments/PowderlessEnchantment.java +++ /dev/null @@ -1,40 +0,0 @@ -package zone.moddev.mc.basesteam.enchantments; - -import zone.moddev.mc.basesteam.init.Items; -import net.minecraft.world.item.enchantment.EnchantmentCategory; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.item.ItemStack; - -public class PowderlessEnchantment extends net.minecraft.world.item.enchantment.Enchantment{ - - public PowderlessEnchantment() { - super(Rarity.VERY_RARE,EnchantmentCategory.BREAKABLE,new EquipmentSlot[]{EquipmentSlot.MAINHAND}); - } - - - @Override - public boolean canEnchant(ItemStack item){ - return item.getItem() == Items.blackpowder_musket; - } - @Override - public boolean canApplyAtEnchantingTable(ItemStack item){ - return canEnchant(item); - } - - - - @Override - public int getMinCost(final int lvl) { - return 20; - } - - @Override - public int getMaxCost(final int lvl) { - return 50; - } - - @Override - public int getMaxLevel() { - return 1; - } -} diff --git a/src/main/java/zone/moddev/mc/basesteam/enchantments/RapidReloadEnchantment.java b/src/main/java/zone/moddev/mc/basesteam/enchantments/RapidReloadEnchantment.java deleted file mode 100644 index e7dc406..0000000 --- a/src/main/java/zone/moddev/mc/basesteam/enchantments/RapidReloadEnchantment.java +++ /dev/null @@ -1,40 +0,0 @@ -package zone.moddev.mc.basesteam.enchantments; - -import zone.moddev.mc.basesteam.init.Items; -import net.minecraft.world.item.enchantment.EnchantmentCategory; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.item.ItemStack; - -public class RapidReloadEnchantment extends net.minecraft.world.item.enchantment.Enchantment{ - - public RapidReloadEnchantment() { - super(Rarity.RARE,EnchantmentCategory.BREAKABLE,new EquipmentSlot[]{EquipmentSlot.MAINHAND}); - } - - - @Override - public boolean canEnchant(ItemStack item){ - return item.getItem() == Items.blackpowder_musket; - } - @Override - public boolean canApplyAtEnchantingTable(ItemStack item){ - return canEnchant(item); - } - - - - @Override - public int getMinCost(final int lvl) { - return 15; - } - - @Override - public int getMaxCost(final int lvl) { - return 50; - } - - @Override - public int getMaxLevel() { - return 1; - } -} diff --git a/src/main/java/zone/moddev/mc/basesteam/enchantments/RecoilEnchantment.java b/src/main/java/zone/moddev/mc/basesteam/enchantments/RecoilEnchantment.java deleted file mode 100644 index e75db1d..0000000 --- a/src/main/java/zone/moddev/mc/basesteam/enchantments/RecoilEnchantment.java +++ /dev/null @@ -1,40 +0,0 @@ -package zone.moddev.mc.basesteam.enchantments; - -import zone.moddev.mc.basesteam.init.Items; -import net.minecraft.world.item.enchantment.EnchantmentCategory; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.item.ItemStack; - -public class RecoilEnchantment extends net.minecraft.world.item.enchantment.Enchantment{ - - public RecoilEnchantment() { - super(Rarity.COMMON,EnchantmentCategory.BREAKABLE,new EquipmentSlot[]{EquipmentSlot.MAINHAND}); - } - - - @Override - public boolean canEnchant(ItemStack item){ - return item.getItem() == Items.blackpowder_musket; - } - @Override - public boolean canApplyAtEnchantingTable(ItemStack item){ - return canEnchant(item); - } - - - - @Override - public int getMinCost(final int lvl) { - return Math.max(1,lvl * 5 - 3); - } - - @Override - public int getMaxCost(final int lvl) { - return this.getMinCost(lvl) + 10; - } - - @Override - public int getMaxLevel() { - return 5; - } -} diff --git a/src/main/java/zone/moddev/mc/basesteam/graphics/ClientRegistration.java b/src/main/java/zone/moddev/mc/basesteam/graphics/ClientRegistration.java index 213a3a2..558b145 100644 --- a/src/main/java/zone/moddev/mc/basesteam/graphics/ClientRegistration.java +++ b/src/main/java/zone/moddev/mc/basesteam/graphics/ClientRegistration.java @@ -1,6 +1,9 @@ package zone.moddev.mc.basesteam.graphics; import net.minecraftforge.client.event.EntityRenderersEvent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraft.client.renderer.item.ItemProperties; import net.minecraft.resources.ResourceLocation; @@ -9,18 +12,24 @@ import zone.moddev.mc.basesteam.init.Entities; /** Client-only renderer registration. */ +@OnlyIn(Dist.CLIENT) public final class ClientRegistration { private ClientRegistration() {} - public static void registerRenderers(EntityRenderersEvent.RegisterRenderers event) { + public static void register(IEventBus modBus) { + modBus.addListener(ClientRegistration::onClientSetup); + modBus.addListener(ClientRegistration::registerRenderers); + } + + private static void registerRenderers(EntityRenderersEvent.RegisterRenderers event) { event.registerBlockEntityRenderer(Entities.DRILLBIT, DrillBitRenderer::new); } - public static void onClientSetup(FMLClientSetupEvent event) { + private static void onClientSetup(FMLClientSetupEvent event) { event.enqueueWork(() -> { - ItemProperties.register(Items.blackpowder_musket, new ResourceLocation("loaded"), + ItemProperties.register(Items.blackpowder_musket, ResourceLocation.withDefaultNamespace("loaded"), (item, world, entity, seed) -> MusketItem.isLoaded(item) ? 1.0F : 0.0F); - ItemProperties.register(Items.blackpowder_musket, new ResourceLocation("loading"), + ItemProperties.register(Items.blackpowder_musket, ResourceLocation.withDefaultNamespace("loading"), (item, world, entity, seed) -> entity != null && entity.isUsingItem() && entity.getUseItem() == item ? 1.0F : 0.0F); }); diff --git a/src/main/java/zone/moddev/mc/basesteam/graphics/DrillBitRenderer.java b/src/main/java/zone/moddev/mc/basesteam/graphics/DrillBitRenderer.java index 76114aa..4d7fad5 100644 --- a/src/main/java/zone/moddev/mc/basesteam/graphics/DrillBitRenderer.java +++ b/src/main/java/zone/moddev/mc/basesteam/graphics/DrillBitRenderer.java @@ -17,7 +17,7 @@ @OnlyIn(Dist.CLIENT) public class DrillBitRenderer implements BlockEntityRenderer { private static final ResourceLocation TEXTURE = - new ResourceLocation(SteamAdvantage.MODID, "textures/entity/drill_bit.png"); + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/entity/drill_bit.png"); public DrillBitRenderer(Context dispatcher) { } @@ -81,6 +81,6 @@ private static void vertex(PoseStack.Pose transform, VertexConsumer vertices, float normalX, float normalY, float normalZ, int light, int overlay) { vertices.vertex(transform.pose(), x, y, z).color(255, 255, 255, 255).uv(u, v) .overlayCoords(overlay).uv2(light) - .normal(transform.normal(), normalX, normalY, normalZ).endVertex(); + .normal(transform, normalX, normalY, normalZ).endVertex(); } } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/BlastFurnaceGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/BlastFurnaceGUI.java index 207b71a..499d7eb 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/BlastFurnaceGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/BlastFurnaceGUI.java @@ -14,7 +14,7 @@ public class BlastFurnaceGUI extends SimpleMachineGUI{ public BlastFurnaceGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/steam_furnace.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/steam_furnace.png"), Integer2D.fromCoordinates(29,80, 93,19, 111,19, 129,19, 93,80, 111,80, 129,80) ); for(int i = 4; i < 7; i++)super.specialSlots.put(i, (SlotContext c)->new Slot(c.machineInventory,c.slotIndex,c.screenPositionX,c.screenPositionY){ diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/CoalBoilerGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/CoalBoilerGUI.java index 7460705..c781a83 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/CoalBoilerGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/CoalBoilerGUI.java @@ -11,7 +11,7 @@ public class CoalBoilerGUI extends SimpleMachineGUI{ public CoalBoilerGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/coal_boiler.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/coal_boiler.png"), new Integer2D[] {new Integer2D(80,80)} ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/ElectricBoilerGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/ElectricBoilerGUI.java index cba6a30..4a205c0 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/ElectricBoilerGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/ElectricBoilerGUI.java @@ -11,7 +11,7 @@ public class ElectricBoilerGUI extends SimpleMachineGUI{ public ElectricBoilerGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/electric_boiler.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/electric_boiler.png"), new Integer2D[0] ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/GeothermalBoilerGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/GeothermalBoilerGUI.java index 25ecca3..8df9301 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/GeothermalBoilerGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/GeothermalBoilerGUI.java @@ -11,7 +11,7 @@ public class GeothermalBoilerGUI extends SimpleMachineGUI{ public GeothermalBoilerGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/geothermal_boiler.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/geothermal_boiler.png"), new Integer2D[0] ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/OilBoilerGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/OilBoilerGUI.java index 317348d..5ba8fc6 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/OilBoilerGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/OilBoilerGUI.java @@ -12,7 +12,7 @@ public class OilBoilerGUI extends SimpleMachineGUI{ public OilBoilerGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/oil_boiler.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/oil_boiler.png"), new Integer2D[0] ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/RockCrusherGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/RockCrusherGUI.java index 1dfe92f..68c0e25 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/RockCrusherGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/RockCrusherGUI.java @@ -11,7 +11,7 @@ public class RockCrusherGUI extends SimpleMachineGUI{ public RockCrusherGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/rock_crusher.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/rock_crusher.png"), Integer2D.fromCoordinates(44,19, 44,88, 62,88, 80,88, 98,88, 116,88) ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/SteamDrillGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/SteamDrillGUI.java index 8575d52..8c9b035 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/SteamDrillGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/SteamDrillGUI.java @@ -11,7 +11,7 @@ public class SteamDrillGUI extends SimpleMachineGUI{ public SteamDrillGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/steam_drill.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/steam_drill.png"), Integer2D.fromCoordinates(44,88, 62,88, 80,88, 98,88, 116,88) ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/SteamPumpGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/SteamPumpGUI.java index 79e72f1..51efb16 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/SteamPumpGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/SteamPumpGUI.java @@ -12,7 +12,7 @@ public class SteamPumpGUI extends SimpleMachineGUI{ public SteamPumpGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/steam_pump.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/steam_pump.png"), new Integer2D[0] ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/SteamStillGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/SteamStillGUI.java index 4c77f4c..2a9dbe5 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/SteamStillGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/SteamStillGUI.java @@ -12,7 +12,7 @@ public class SteamStillGUI extends SimpleMachineGUI{ public SteamStillGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/steam_still.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/steam_still.png"), new Integer2D[0] ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/SteamTankGUI.java b/src/main/java/zone/moddev/mc/basesteam/gui/SteamTankGUI.java index a4429c1..21f2a4b 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/SteamTankGUI.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/SteamTankGUI.java @@ -11,7 +11,7 @@ public class SteamTankGUI extends SimpleMachineGUI{ public SteamTankGUI() { super( - new ResourceLocation(SteamAdvantage.MODID+":textures/gui/container/steam_tank.png"), + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "textures/gui/container/steam_tank.png"), new Integer2D[0] ); } diff --git a/src/main/java/zone/moddev/mc/basesteam/init/Blocks.java b/src/main/java/zone/moddev/mc/basesteam/init/Blocks.java index 69b49b9..8aa0ade 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/Blocks.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/Blocks.java @@ -96,14 +96,14 @@ public static void registerBlocks(RegisterEvent event) { if (!ForgeRegistries.Keys.BLOCKS.equals(event.getRegistryKey())) return; init(); event.register(ForgeRegistries.Keys.BLOCKS, registry -> - ALL_BLOCKS.forEach((id, block) -> registry.register(new ResourceLocation(SteamAdvantage.MODID, id), block))); + ALL_BLOCKS.forEach((id, block) -> registry.register(ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, id), block))); } @SubscribeEvent public static void registerBlockItems(RegisterEvent event) { event.register(ForgeRegistries.Keys.ITEMS, registry -> ALL_BLOCKS.forEach((id, block) -> { BlockItem item = new BlockItem(block, new Item.Properties()); - registry.register(new ResourceLocation(SteamAdvantage.MODID, id), item); + registry.register(ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, id), item); if (!"pump_pipe_steam".equals(id) && !"drillbit".equals(id)) ItemGroups.show(item); })); } diff --git a/src/main/java/zone/moddev/mc/basesteam/init/Enchantments.java b/src/main/java/zone/moddev/mc/basesteam/init/Enchantments.java index 30d5cc6..b6aa983 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/Enchantments.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/Enchantments.java @@ -1,10 +1,10 @@ package zone.moddev.mc.basesteam.init; import zone.moddev.mc.basesteam.SteamAdvantage; -import zone.moddev.mc.basesteam.enchantments.HighExplosiveEnchantment; -import zone.moddev.mc.basesteam.enchantments.PowderlessEnchantment; -import zone.moddev.mc.basesteam.enchantments.RapidReloadEnchantment; -import zone.moddev.mc.basesteam.enchantments.RecoilEnchantment; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.Item; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.registries.ForgeRegistries; @@ -14,6 +14,7 @@ @Mod.EventBusSubscriber(modid = SteamAdvantage.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class Enchantments { + private static final TagKey MUSKETS = ItemTags.create(ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "muskets")); public static Enchantment rapid_reload; public static Enchantment powderless; @@ -29,19 +30,25 @@ public static void registerEnchantments(RegisterEvent event) { if (!ForgeRegistries.Keys.ENCHANTMENTS.equals(event.getRegistryKey())) return; init(); event.register(ForgeRegistries.Keys.ENCHANTMENTS, registry -> { - registry.register(new ResourceLocation(SteamAdvantage.MODID, "high_explosive"), high_explosive); - registry.register(new ResourceLocation(SteamAdvantage.MODID, "powderless"), powderless); - registry.register(new ResourceLocation(SteamAdvantage.MODID, "rapid_reload"), rapid_reload); - registry.register(new ResourceLocation(SteamAdvantage.MODID, "recoil"), recoil); + registry.register(ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "high_explosive"), high_explosive); + registry.register(ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "powderless"), powderless); + registry.register(ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "rapid_reload"), rapid_reload); + registry.register(ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "recoil"), recoil); }); } private static void createEnchantments() { if(high_explosive != null) return; - high_explosive = new HighExplosiveEnchantment(); - powderless = new PowderlessEnchantment(); - rapid_reload = new RapidReloadEnchantment(); - recoil = new RecoilEnchantment(); + high_explosive = musket(5, 5, Enchantment.dynamicCost(7, 7), Enchantment.dynamicCost(17, 7), 2); + powderless = musket(1, 1, Enchantment.constantCost(20), Enchantment.constantCost(50), 8); + rapid_reload = musket(2, 1, Enchantment.constantCost(15), Enchantment.constantCost(50), 4); + recoil = musket(10, 5, Enchantment.dynamicCost(2, 5), Enchantment.dynamicCost(12, 5), 1); } + + private static Enchantment musket(int weight, int maxLevel, Enchantment.Cost min, Enchantment.Cost max, + int anvilCost) { + return new Enchantment(Enchantment.definition(MUSKETS, weight, maxLevel, min, max, + anvilCost, EquipmentSlot.MAINHAND)); + } } diff --git a/src/main/java/zone/moddev/mc/basesteam/init/Entities.java b/src/main/java/zone/moddev/mc/basesteam/init/Entities.java index d547663..78cb371 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/Entities.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/Entities.java @@ -62,7 +62,7 @@ public static void register(RegisterEvent event) { private static BlockEntityType register( RegisterEvent event, String id, BlockEntityType.BlockEntitySupplier factory, Block block) { BlockEntityType type = BlockEntityType.Builder.of(factory, block).build(null); - event.register(ForgeRegistries.Keys.BLOCK_ENTITY_TYPES, new ResourceLocation(SteamAdvantage.MODID, id), () -> type); + event.register(ForgeRegistries.Keys.BLOCK_ENTITY_TYPES, ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, id), () -> type); return type; } } diff --git a/src/main/java/zone/moddev/mc/basesteam/init/Items.java b/src/main/java/zone/moddev/mc/basesteam/init/Items.java index 8ab01cf..846f63b 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/Items.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/Items.java @@ -45,7 +45,7 @@ public static void register(RegisterEvent event) { if (!ForgeRegistries.Keys.ITEMS.equals(event.getRegistryKey())) return; init(); event.register(ForgeRegistries.Keys.ITEMS, registry -> allItems.forEach((id, item) -> { - registry.register(new ResourceLocation(SteamAdvantage.MODID, id), item); + registry.register(ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, id), item); ItemGroups.show(item); })); } diff --git a/src/main/java/zone/moddev/mc/basesteam/init/Power.java b/src/main/java/zone/moddev/mc/basesteam/init/Power.java index 7767438..5a6d3ce 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/Power.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/Power.java @@ -28,7 +28,7 @@ public static DamageSource musketDamage(Level level) { } private static ResourceKey damageType(String id) { - return ResourceKey.create(Registries.DAMAGE_TYPE, new ResourceLocation(SteamAdvantage.MODID, id)); + return ResourceKey.create(Registries.DAMAGE_TYPE, ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, id)); } private static DamageSource damageSource(Level level, ResourceKey type) { diff --git a/src/main/java/zone/moddev/mc/basesteam/init/Villages.java b/src/main/java/zone/moddev/mc/basesteam/init/Villages.java index 9799d9b..0786e07 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/Villages.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/Villages.java @@ -8,6 +8,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.ItemCost; import net.minecraftforge.event.village.VillagerTradesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -35,7 +36,7 @@ public static void addTrades(VillagerTradesEvent event) { if (profession == VillagerProfession.CLERIC) { event.getTrades().get(3).add((trader, random) -> { int enchantmentLevel = 5 + random.nextInt(15); - ItemStack musket = EnchantmentHelper.enchantItem(random, + ItemStack musket = EnchantmentHelper.enchantItem(trader.level().enabledFeatures(), random, new ItemStack(Items.blackpowder_musket), enchantmentLevel, false); int price = Math.min(randomPrice(random, 15, 25) + enchantmentLevel, 64); return offer(price, musket); @@ -55,6 +56,6 @@ private static int randomPrice(RandomSource random, int min, int max) { } private static MerchantOffer offer(int emeralds, ItemStack output) { - return new MerchantOffer(new ItemStack(net.minecraft.world.item.Items.EMERALD, emeralds), output, 7, 1, 0.0F); + return new MerchantOffer(new ItemCost(net.minecraft.world.item.Items.EMERALD, emeralds), output, 7, 1, 0.0F); } } diff --git a/src/main/java/zone/moddev/mc/basesteam/items/MusketItem.java b/src/main/java/zone/moddev/mc/basesteam/items/MusketItem.java index 563018a..9f4f866 100644 --- a/src/main/java/zone/moddev/mc/basesteam/items/MusketItem.java +++ b/src/main/java/zone/moddev/mc/basesteam/items/MusketItem.java @@ -6,30 +6,30 @@ import java.util.List; import java.util.Optional; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; - import zone.moddev.mc.basesteam.SteamAdvantage; import zone.moddev.mc.basesteam.init.Enchantments; import zone.moddev.mc.basesteam.init.Power; import net.minecraft.world.level.block.TntBlock; import net.minecraft.world.level.block.SoundType; import net.minecraft.core.registries.Registries; +import net.minecraft.core.component.DataComponents; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.player.Player; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.EquipmentSlotGroup; import net.minecraft.world.item.UseAnim; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Item; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ItemAttributeModifiers; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; @@ -57,18 +57,22 @@ @SuppressWarnings("deprecation") public class MusketItem extends net.minecraft.world.item.Item{ private static final TagKey FRAGILE_TARGETS = TagKey.create(Registries.BLOCK, - new ResourceLocation(SteamAdvantage.MODID, "musket_fragile")); + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, "musket_fragile")); public static final String NBT_DATA_KEY_LOADED = "loaded"; public static final double MAX_RANGE = 64; private static final int maxUseTime = 7200; - private static final TagKey BLACKPOWDER_AMMO_TAG = ItemTags.create(new ResourceLocation("forge", "ammo/blackpowder")); - private static final TagKey STEEL_INGOT_TAG = ItemTags.create(new ResourceLocation("forge", "ingots/steel")); + private static final TagKey BLACKPOWDER_AMMO_TAG = ItemTags.create(ResourceLocation.fromNamespaceAndPath("forge", "ammo/blackpowder")); + private static final TagKey STEEL_INGOT_TAG = ItemTags.create(ResourceLocation.fromNamespaceAndPath("forge", "ingots/steel")); public MusketItem(Item.Properties properties){ - super(properties.defaultDurability(250)); + super(properties.durability(250).attributes(ItemAttributeModifiers.builder() + .add(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, + "Weapon modifier", getMeleeDamage(), AttributeModifier.Operation.ADD_VALUE), + EquipmentSlotGroup.MAINHAND) + .build())); } @@ -147,9 +151,11 @@ public void releaseUsing(ItemStack stack, Level worldIn, LivingEntity playerIn, protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, Level world) { final boolean isPlayer = playerEntity instanceof Player; + int explosive = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack); + int recoil = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.recoil, srcItemStack); unload(srcItemStack); if(isPlayer && !((Player)playerEntity).isCreative()){ - srcItemStack.hurtAndBreak(1, playerEntity, entity -> entity.broadcastBreakEvent(EquipmentSlot.MAINHAND)); + srcItemStack.hurtAndBreak(1, playerEntity, EquipmentSlot.MAINHAND); } Vec3 lookVector = playerEntity.getLookAngle(); spawnParticle(ParticleTypes.EXPLOSION_EMITTER, world, @@ -174,8 +180,8 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, if(rayTrace instanceof EntityHitResult){ Entity e = ((EntityHitResult) rayTrace).getEntity(); e.hurt(Power.musketDamage(world), getShotDamage()); - if(EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack) > 0){ - int lvl = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack); + if(explosive > 0){ + int lvl = explosive; world.explode(playerEntity, e.getX(), e.getY()+0.5, e.getZ(), explodeFactor * lvl, explosionInteraction); @@ -183,7 +189,7 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, e.getX()+lvl, e.getY()+lvl, e.getZ()+lvl); List collateralDamage = world.getEntitiesOfClass(LivingEntity.class, fireArea); for(LivingEntity victim : collateralDamage){ - victim.setSecondsOnFire(lvl); + victim.igniteForSeconds(lvl); } } } else if(rayTrace.getType() == HitResult.Type.BLOCK){ @@ -199,8 +205,8 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, world.removeBlock(coord, false); } } - if(EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack) > 0){ - int lvl = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack); + if(explosive > 0){ + int lvl = explosive; world.explode(playerEntity, rayTrace.getLocation().x, rayTrace.getLocation().y, rayTrace.getLocation().z, explodeFactor * lvl, explosionInteraction); @@ -208,7 +214,7 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, rayTrace.getLocation().x+lvl, rayTrace.getLocation().y+lvl, rayTrace.getLocation().z+lvl); List collateralDamage = world.getEntitiesOfClass(LivingEntity.class, fireArea); for(LivingEntity victim : collateralDamage){ - victim.setSecondsOnFire(lvl); + victim.igniteForSeconds(lvl); } } } @@ -220,7 +226,6 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, } // recoil enchantment kicks you back - int recoil = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.recoil, srcItemStack); if(recoil > 0){ double c = -0.3; double lateral = 2.0; @@ -246,7 +251,7 @@ private void spawnParticle(ParticleOptions p, Level w, double x, double y, doubl @Override public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { - stack.hurtAndBreak(1, attacker, entity -> entity.broadcastBreakEvent(EquipmentSlot.MAINHAND)); + stack.hurtAndBreak(1, attacker, EquipmentSlot.MAINHAND); return true; } @@ -259,54 +264,37 @@ protected void playSound(SoundEvent sound, Level world, Entity e){ } public static void startLoad(ItemStack musket){ - CompoundTag data; - if(musket.hasTag()){ - data = musket.getTag(); - } else { - data = new CompoundTag(); - } - data.putByte(NBT_DATA_KEY_LOADED, (byte)2); - musket.setTag(data); + setLoadedState(musket, (byte)2); } public static void finishLoad(ItemStack musket){ - CompoundTag data; - if(musket.hasTag()){ - data = musket.getTag(); - } else { - data = new CompoundTag(); - } - data.putByte(NBT_DATA_KEY_LOADED, (byte)1); - musket.setTag(data); + setLoadedState(musket, (byte)1); } public static void unload(ItemStack musket){ - CompoundTag data; - if(musket.hasTag()){ - data = musket.getTag(); - } else { - data = new CompoundTag(); - } - data.putByte(NBT_DATA_KEY_LOADED, (byte)0); - musket.setTag(data); + setLoadedState(musket, (byte)0); + } + + private static void setLoadedState(ItemStack musket, byte state) { + CustomData.update(DataComponents.CUSTOM_DATA, musket, tag -> tag.putByte(NBT_DATA_KEY_LOADED, state)); + } + + private static byte loadedState(ItemStack musket) { + CustomData data = musket.get(DataComponents.CUSTOM_DATA); + return data == null ? 0 : data.copyTag().getByte(NBT_DATA_KEY_LOADED); } public static boolean isLoaded(ItemStack musket){ - CompoundTag data = musket.getTag(); - if(data == null) return false; - return data.contains(NBT_DATA_KEY_LOADED) && data.getByte(NBT_DATA_KEY_LOADED) == 1; + return loadedState(musket) == 1; } public static boolean isNotLoaded(ItemStack musket){ - CompoundTag data = musket.getTag(); - if(data == null || !data.contains(NBT_DATA_KEY_LOADED)) return true; - return data.contains(NBT_DATA_KEY_LOADED) && data.getByte(NBT_DATA_KEY_LOADED) == 0; + byte state = loadedState(musket); + return state != 1 && state != 2; } public static boolean isAlmostLoaded(ItemStack musket){ - CompoundTag data = musket.getTag(); - if(data == null) return false; - return data.contains(NBT_DATA_KEY_LOADED) && data.getByte(NBT_DATA_KEY_LOADED) == 2; + return loadedState(musket) == 2; } @@ -315,7 +303,7 @@ public static boolean hasAmmo(LivingEntity e, ItemStack musket) { if(e instanceof Player) { Player playerEntity = (Player) e; if (playerEntity.isCreative() - || EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY_ARROWS, musket) > 0 + || EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, musket) > 0 || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.powderless, musket) > 0) return true; for (int i = 0; i < playerEntity.getInventory().items.size(); i++) { ItemStack inventoryStack = playerEntity.getInventory().items.get(i); @@ -331,7 +319,7 @@ public static void decrementAmmo(LivingEntity e, ItemStack musket) { if(e instanceof Player) { Player playerEntity = (Player) e; if (playerEntity.isCreative() - || EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY_ARROWS, musket) > 0 + || EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, musket) > 0 || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.powderless, musket) > 0) return; for (int i = 0; i < playerEntity.getInventory().items.size(); i++) { ItemStack inventoryStack = playerEntity.getInventory().items.get(i); @@ -439,8 +427,8 @@ private static double min(double a, double b){ } @Override - public void appendHoverText(ItemStack stack, Level world, List list, net.minecraft.world.item.TooltipFlag flag){ - super.appendHoverText(stack,world,list,flag); + public void appendHoverText(ItemStack stack, TooltipContext context, List list, net.minecraft.world.item.TooltipFlag flag){ + super.appendHoverText(stack,context,list,flag); list.add(Component.translatable("tooltip.musket.damage", (int)MusketItem.getShotDamage())); if(isLoaded(stack)){ list.add(Component.translatable("tooltip.musket.loaded")); @@ -450,16 +438,6 @@ public void appendHoverText(ItemStack stack, Level world, List list, } } - /** Sets melee attack damage */ - @Override - public Multimap getAttributeModifiers(EquipmentSlot slot, ItemStack stack) - { - Multimap multimap = HashMultimap.create(); - if(slot != EquipmentSlot.MAINHAND) return multimap; - multimap.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Weapon modifier", (double)getMeleeDamage(), AttributeModifier.Operation.ADDITION)); - return multimap; - } - @Override public int getUseDuration(ItemStack stack) { diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/BlastFurnaceTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/BlastFurnaceTileEntity.java index 21af33e..4d63bfb 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/BlastFurnaceTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/BlastFurnaceTileEntity.java @@ -2,6 +2,7 @@ import cyano.poweradvantage.api.ConduitType; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.entity.player.Player; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.item.ItemStack; @@ -141,7 +142,7 @@ private boolean canSmelt(int slot) { if(output.isEmpty()) return false; ItemStack outputSlot = inventory[slot+3]; if(outputSlot == null) return true; - return (ItemStack.isSameItemSameTags(output, outputSlot) + return (ItemStack.isSameItemSameComponents(output, outputSlot) && (output.getCount() + outputSlot.getCount()) <= outputSlot.getMaxStackSize()); } @@ -267,15 +268,15 @@ public void onDataFieldUpdate() { @Override - protected void saveAdditional(CompoundTag tagRoot){ - super.saveAdditional(tagRoot); + protected void saveAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ + super.saveAdditional(tagRoot, registries); prepareDataFieldsForSync(); tagRoot.putIntArray("Data", getDataFieldArray()); } @Override - public void load(CompoundTag tagRoot){ - super.load(tagRoot); + protected void loadAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ + super.loadAdditional(tagRoot, registries); if(tagRoot.contains("Data")){ int[] data = tagRoot.getIntArray("Data"); System.arraycopy(data, 0, this.getDataFieldArray(), 0, Math.min(data.length,this.getDataFieldArray().length)); @@ -335,7 +336,7 @@ private ItemStack getSmeltingResult(ItemStack input) { SimpleContainer inventory = new SimpleContainer(1); inventory.setItem(0, input); return getLevel().getRecipeManager().getRecipeFor(RecipeType.SMELTING, inventory, getLevel()) - .map(recipe -> recipe.assemble(inventory, getLevel().registryAccess())).orElse(ItemStack.EMPTY); + .map(recipe -> recipe.value().assemble(inventory, getLevel().registryAccess())).orElse(ItemStack.EMPTY); } diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/CoalBoilerTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/CoalBoilerTileEntity.java index 487ec0b..ab01420 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/CoalBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/CoalBoilerTileEntity.java @@ -7,6 +7,7 @@ import cyano.poweradvantage.api.fluid.FluidRequest; import zone.moddev.mc.basepower.init.Fluids; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.entity.player.Player; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.item.ItemStack; @@ -214,8 +215,8 @@ public void onDataFieldUpdate() { * @param tagRoot An NBT tag */ @Override - protected void saveAdditional(final CompoundTag tagRoot) { - super.saveAdditional(tagRoot); + protected void saveAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.saveAdditional(tagRoot, registries); CompoundTag tankTag = new CompoundTag(); this.getTank().writeToNBT(tankTag); tagRoot.put("Tank", tankTag); @@ -227,8 +228,8 @@ protected void saveAdditional(final CompoundTag tagRoot) { * @param tagRoot An NBT tag */ @Override - public void load(final CompoundTag tagRoot) { - super.load(tagRoot); + protected void loadAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.loadAdditional(tagRoot, registries); if (tagRoot.contains("Tank")) { CompoundTag tankTag = tagRoot.getCompound("Tank"); getTank().readFromNBT(tankTag); diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/ElectricBoilerTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/ElectricBoilerTileEntity.java index a976e1f..882dfa1 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/ElectricBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/ElectricBoilerTileEntity.java @@ -7,6 +7,7 @@ import cyano.poweradvantage.api.fluid.FluidRequest; import zone.moddev.mc.basepower.init.Fluids; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.entity.player.Player; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.item.ItemStack; @@ -187,8 +188,8 @@ public void onDataFieldUpdate() { * @param tagRoot An NBT tag */ @Override - protected void saveAdditional(final CompoundTag tagRoot) { - super.saveAdditional(tagRoot); + protected void saveAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.saveAdditional(tagRoot, registries); CompoundTag tankTag = new CompoundTag(); this.getTank().writeToNBT(tankTag); tagRoot.put("Tank", tankTag); @@ -199,8 +200,8 @@ protected void saveAdditional(final CompoundTag tagRoot) { * @param tagRoot An NBT tag */ @Override - public void load(final CompoundTag tagRoot) { - super.load(tagRoot); + protected void loadAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.loadAdditional(tagRoot, registries); if (tagRoot.contains("Tank")) { CompoundTag tankTag = tagRoot.getCompound("Tank"); getTank().readFromNBT(tankTag); diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/GeothermalBoilerTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/GeothermalBoilerTileEntity.java index facaf4d..001480b 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/GeothermalBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/GeothermalBoilerTileEntity.java @@ -7,6 +7,7 @@ import cyano.poweradvantage.api.fluid.FluidRequest; import zone.moddev.mc.basepower.init.Fluids; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.entity.player.Player; @@ -220,8 +221,8 @@ public void onDataFieldUpdate() { * @param tagRoot An NBT tag */ @Override - protected void saveAdditional(final CompoundTag tagRoot) { - super.saveAdditional(tagRoot); + protected void saveAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.saveAdditional(tagRoot, registries); CompoundTag tankTag = new CompoundTag(); this.getTank().writeToNBT(tankTag); tagRoot.put("Tank", tankTag); @@ -232,8 +233,8 @@ protected void saveAdditional(final CompoundTag tagRoot) { * @param tagRoot An NBT tag */ @Override - public void load(final CompoundTag tagRoot) { - super.load(tagRoot); + protected void loadAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.loadAdditional(tagRoot, registries); if (tagRoot.contains("Tank")) { CompoundTag tankTag = tagRoot.getCompound("Tank"); getTank().readFromNBT(tankTag); diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/OilBoilerTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/OilBoilerTileEntity.java index a01b369..8342b17 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/OilBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/OilBoilerTileEntity.java @@ -12,6 +12,7 @@ import zone.moddev.mc.basepower.registry.FuelRegistry; import zone.moddev.mc.basesteam.SteamAdvantage; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.entity.player.Player; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.item.ItemStack; @@ -263,8 +264,8 @@ public void onDataFieldUpdate() { * @param tagRoot An NBT tag */ @Override - protected void saveAdditional(final CompoundTag tagRoot) { - super.saveAdditional(tagRoot); + protected void saveAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.saveAdditional(tagRoot, registries); CompoundTag tankTag = new CompoundTag(); this.getWaterTank().writeToNBT(tankTag); tagRoot.put("WaterTank", tankTag); @@ -279,8 +280,8 @@ protected void saveAdditional(final CompoundTag tagRoot) { * @param tagRoot An NBT tag */ @Override - public void load(final CompoundTag tagRoot) { - super.load(tagRoot); + protected void loadAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.loadAdditional(tagRoot, registries); if (tagRoot.contains("WaterTank")) { CompoundTag tankTag = tagRoot.getCompound("WaterTank"); getWaterTank().readFromNBT(tankTag); diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/RockCrusherTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/RockCrusherTileEntity.java index 53227d5..5145c2d 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/RockCrusherTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/RockCrusherTileEntity.java @@ -1,6 +1,7 @@ package zone.moddev.mc.basesteam.machines; import cyano.poweradvantage.api.ConduitType; +import net.minecraft.core.HolderLookup; import net.minecraft.world.entity.player.Player; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.item.ItemStack; @@ -190,7 +191,7 @@ public void onDataFieldUpdate() { private int canAddToOutputInventory(ItemStack output) { for(int i = 1; i < inventory.length; i++){ if(inventory[i] == null) {return i;} - if(ItemStack.isSameItemSameTags(output, inventory[i]) + if(ItemStack.isSameItemSameComponents(output, inventory[i]) && (inventory[i].getCount() + output.getCount()) <= inventory[i].getMaxStackSize()){ return i; } @@ -199,14 +200,14 @@ private int canAddToOutputInventory(ItemStack output) { } @Override - protected void saveAdditional(CompoundTag tagRoot){ - super.saveAdditional(tagRoot); + protected void saveAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ + super.saveAdditional(tagRoot, registries); tagRoot.putShort("progress",(short)progress); } @Override - public void load(CompoundTag tagRoot){ - super.load(tagRoot); + protected void loadAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ + super.loadAdditional(tagRoot, registries); if(tagRoot.contains("progress")){ progress = tagRoot.getShort("progress"); } diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/SteamDrillBlock.java b/src/main/java/zone/moddev/mc/basesteam/machines/SteamDrillBlock.java index edeb118..8e32125 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/SteamDrillBlock.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/SteamDrillBlock.java @@ -129,7 +129,7 @@ public BlockState getStateForPlacement(final BlockPlaceContext context) { @Override public void setPlacedBy(final Level world, final BlockPos coord, final BlockState bs, final LivingEntity placer, final ItemStack srcItemStack) { - if (srcItemStack.hasCustomHoverName()) { + if (srcItemStack.has(net.minecraft.core.component.DataComponents.CUSTOM_NAME)) { final BlockEntity tileEntity = world.getBlockEntity(coord); if (tileEntity instanceof PoweredEntity){ ((PoweredEntity)tileEntity).setCustomInventoryName(srcItemStack.getDisplayName().getString()); diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/SteamDrillTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/SteamDrillTileEntity.java index 52097ad..9c52cb9 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/SteamDrillTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/SteamDrillTileEntity.java @@ -6,6 +6,7 @@ import zone.moddev.mc.basesteam.compat.BaseMetalsCompat; import zone.moddev.mc.basesteam.init.Blocks; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.entity.player.Player; @@ -131,7 +132,7 @@ private boolean hasSpaceForItems(List items) { private boolean canStack(ItemStack newItem, ItemStack slot) { if(slot == null || newItem == null) return true; - return ItemStack.isSameItemSameTags(newItem, slot) + return ItemStack.isSameItemSameComponents(newItem, slot) && (newItem.getCount() + slot.getCount() <= slot.getMaxStackSize()); } @@ -140,7 +141,7 @@ public ItemStack addItem(ItemStack in){ if(inventory[i] == null){ inventory[i] = in; return null; - } else if(ItemStack.isSameItemSameTags(in, inventory[i])){ + } else if(ItemStack.isSameItemSameComponents(in, inventory[i])){ // are stackable int maxStackSize = inventory[i].getMaxStackSize(); if(inventory[i].getCount() >= maxStackSize){ @@ -188,11 +189,11 @@ private boolean followTrack(){ return false; } SteamDrillTileEntity te = (SteamDrillTileEntity)movedTile; - CompoundTag dataTransfer = saveWithFullMetadata(); + CompoundTag dataTransfer = saveWithFullMetadata(w.registryAccess()); dataTransfer.putInt("x", nextPos.getX()); dataTransfer.putInt("y", nextPos.getY()); dataTransfer.putInt("z", nextPos.getZ()); - te.load(dataTransfer); + te.loadWithComponents(dataTransfer, w.registryAccess()); te.clearRemoved(); te.subtractEnergy(ENERGY_COST_MOVE, Power.steam_power); te.setChanged(); @@ -449,7 +450,7 @@ private void inventoryTransfer(BlockPos adj, Direction otherFace) { inv.setChanged(); this.setChanged(); return; - } else if(ItemStack.isSameItemSameTags(theirItem, inventory[mySlot]) + } else if(ItemStack.isSameItemSameComponents(theirItem, inventory[mySlot]) && theirItem.getCount() < theirItem.getMaxStackSize() && theirItem.getCount() < inv.getMaxStackSize()){ theirItem.grow(1); @@ -467,8 +468,8 @@ private void inventoryTransfer(BlockPos adj, Direction otherFace) { } @Override - protected void saveAdditional(CompoundTag tagRoot){ - super.saveAdditional(tagRoot); + protected void saveAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ + super.saveAdditional(tagRoot, registries); tagRoot.putShort("progress",(short)progress); // getFacing refreshes this during normal ticks. World lookups here can // synchronously reload a chunk while its unload-save is in progress. @@ -482,8 +483,8 @@ protected void saveAdditional(CompoundTag tagRoot){ } @Override - public void load(CompoundTag tagRoot){ - super.load(tagRoot); + protected void loadAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ + super.loadAdditional(tagRoot, registries); untargetBlock(); savedFacing = null; oldDir = null; diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/SteamElevatorTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/SteamElevatorTileEntity.java index f92ef8f..051e3f4 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/SteamElevatorTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/SteamElevatorTileEntity.java @@ -3,6 +3,7 @@ import cyano.poweradvantage.api.ConduitType; import zone.moddev.mc.basesteam.init.Blocks; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.sounds.SoundEvents; @@ -172,14 +173,14 @@ public void onDataFieldUpdate() { @Override - protected void saveAdditional(CompoundTag tagRoot){ - super.saveAdditional(tagRoot); + protected void saveAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ + super.saveAdditional(tagRoot, registries); tagRoot.putBoolean("up",above); } @Override - public void load(CompoundTag tagRoot){ - super.load(tagRoot); + protected void loadAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ + super.loadAdditional(tagRoot, registries); if(tagRoot.contains("up")){ above = tagRoot.getBoolean("up"); } diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/SteamPumpTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/SteamPumpTileEntity.java index 452c076..83427d9 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/SteamPumpTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/SteamPumpTileEntity.java @@ -10,6 +10,7 @@ import zone.moddev.mc.basepower.init.Fluids; import zone.moddev.mc.basepower.util.FluidHandlerHelper; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.BucketPickup; import net.minecraft.world.entity.player.Player; @@ -134,7 +135,7 @@ static Fluid pickupSource(LevelAccessor world, BlockPos pos, BlockState state) { return net.minecraft.world.level.material.Fluids.EMPTY; } // Native pickup preserves waterlogged hosts; unsupported blocks have no destructive fallback. - ItemStack collected = ((BucketPickup)state.getBlock()).pickupBlock(world, pos, state); + ItemStack collected = ((BucketPickup)state.getBlock()).pickupBlock(null, world, pos, state); return collected.isEmpty() ? net.minecraft.world.level.material.Fluids.EMPTY : state.getFluidState().getType(); } @@ -284,8 +285,8 @@ public void onDataFieldUpdate() { * @param tagRoot An NBT tag */ @Override - protected void saveAdditional(final CompoundTag tagRoot) { - super.saveAdditional(tagRoot); + protected void saveAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.saveAdditional(tagRoot, registries); CompoundTag tankTag = new CompoundTag(); this.getTank().writeToNBT(tankTag); tagRoot.put("Tank", tankTag); @@ -296,8 +297,8 @@ protected void saveAdditional(final CompoundTag tagRoot) { * @param tagRoot An NBT tag */ @Override - public void load(final CompoundTag tagRoot) { - super.load(tagRoot); + protected void loadAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.loadAdditional(tagRoot, registries); String tankKey = tagRoot.contains("Tank") ? "Tank" : "TankOut"; if (tagRoot.contains(tankKey)) { CompoundTag tankTag = tagRoot.getCompound(tankKey); diff --git a/src/main/java/zone/moddev/mc/basesteam/machines/SteamStillTileEntity.java b/src/main/java/zone/moddev/mc/basesteam/machines/SteamStillTileEntity.java index 968223c..97907a5 100644 --- a/src/main/java/zone/moddev/mc/basesteam/machines/SteamStillTileEntity.java +++ b/src/main/java/zone/moddev/mc/basesteam/machines/SteamStillTileEntity.java @@ -12,6 +12,7 @@ import zone.moddev.mc.basepower.registry.still.recipe.DistillationRecipe; import zone.moddev.mc.basepower.registry.still.recipe.DistillationRecipeRegistry; import zone.moddev.mc.basesteam.init.Power; +import net.minecraft.core.HolderLookup; import net.minecraft.world.entity.player.Player; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.item.ItemStack; @@ -176,8 +177,8 @@ public void onDataFieldUpdate() { * @param tagRoot An NBT tag */ @Override - protected void saveAdditional(final CompoundTag tagRoot) { - super.saveAdditional(tagRoot); + protected void saveAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.saveAdditional(tagRoot, registries); CompoundTag tankTag = new CompoundTag(); this.getOutputTank().writeToNBT(tankTag); tagRoot.put("TankOut", tankTag); @@ -190,8 +191,8 @@ protected void saveAdditional(final CompoundTag tagRoot) { * @param tagRoot An NBT tag */ @Override - public void load(final CompoundTag tagRoot) { - super.load(tagRoot); + protected void loadAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { + super.loadAdditional(tagRoot, registries); if (tagRoot.contains("TankOut")) { CompoundTag tankTag = tagRoot.getCompound("TankOut"); getOutputTank().readFromNBT(tankTag); diff --git a/src/main/java/zone/moddev/mc/basesteam/migration/SteamLegacyMigrations.java b/src/main/java/zone/moddev/mc/basesteam/migration/SteamLegacyMigrations.java index c11864a..88b7d80 100644 --- a/src/main/java/zone/moddev/mc/basesteam/migration/SteamLegacyMigrations.java +++ b/src/main/java/zone/moddev/mc/basesteam/migration/SteamLegacyMigrations.java @@ -105,6 +105,6 @@ private static boolean matchesTileId(String value, String namespace, String path } private static ResourceLocation id(String path) { - return new ResourceLocation(SteamAdvantage.MODID, path); + return ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, path); } } diff --git a/src/main/java/zone/moddev/mc/basesteam/recipe/RecipeConditions.java b/src/main/java/zone/moddev/mc/basesteam/recipe/RecipeConditions.java index e1ce67c..a4ef06c 100644 --- a/src/main/java/zone/moddev/mc/basesteam/recipe/RecipeConditions.java +++ b/src/main/java/zone/moddev/mc/basesteam/recipe/RecipeConditions.java @@ -1,52 +1,59 @@ package zone.moddev.mc.basesteam.recipe; -import com.google.gson.JsonObject; -import java.util.Locale; -import net.minecraft.util.GsonHelper; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.crafting.CraftingHelper; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.MapCodec; import net.minecraftforge.common.crafting.conditions.ICondition; -import net.minecraftforge.common.crafting.conditions.IConditionSerializer; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; import zone.moddev.mc.basepower.PowerAdvantage; import zone.moddev.mc.basepower.RecipeMode; import zone.moddev.mc.basesteam.SteamAdvantage; +import java.util.Locale; -/** Registers the data-pack conditions used by SteamAdvantage recipes. */ +/** Registers the Forge data-pack conditions used by Steam recipes. */ public final class RecipeConditions { - private static boolean registered; + private static final DeferredRegister> SERIALIZERS = + DeferredRegister.create(ForgeRegistries.Keys.CONDITION_SERIALIZERS, SteamAdvantage.MODID); + + static { + SERIALIZERS.register("recipe_mode", () -> ModeCondition.CODEC); + SERIALIZERS.register("musket_enabled", () -> MusketCondition.CODEC); + } private RecipeConditions() {} - public static synchronized void register() { - if (registered) return; - CraftingHelper.register(new IConditionSerializer() { - @Override public ResourceLocation getID() { return ModeCondition.ID; } - @Override public ModeCondition read(JsonObject json) { - return new ModeCondition(RecipeMode.valueOf(GsonHelper.getAsString(json, "mode").toUpperCase(Locale.ROOT))); - } - @Override public void write(JsonObject json, ModeCondition condition) { - json.addProperty("mode", condition.mode.name()); - } - }); - CraftingHelper.register(new IConditionSerializer() { - @Override public ResourceLocation getID() { return MusketCondition.ID; } - @Override public MusketCondition read(JsonObject json) { return new MusketCondition(); } - @Override public void write(JsonObject json, MusketCondition condition) {} - }); - registered = true; + public static void register(IEventBus bus) { + SERIALIZERS.register(bus); } - private static final class ModeCondition implements ICondition { - private static final ResourceLocation ID = new ResourceLocation(SteamAdvantage.MODID, "recipe_mode"); - private final RecipeMode mode; - private ModeCondition(RecipeMode mode) { this.mode = mode; } - @Override public ResourceLocation getID() { return ID; } - @Override public boolean test(IContext context) { return PowerAdvantage.recipeMode == mode; } + private record ModeCondition(RecipeMode mode) implements ICondition { + private static final MapCodec CODEC = Codec.STRING + .comapFlatMap(ModeCondition::parseMode, RecipeMode::name) + .fieldOf("mode").xmap(ModeCondition::new, ModeCondition::mode); + + private static DataResult parseMode(String value) { + try { + return DataResult.success(RecipeMode.valueOf(value.toUpperCase(Locale.ROOT))); + } catch (IllegalArgumentException exception) { + return DataResult.error(() -> "Unknown baseSteam recipe mode: " + value); + } + } + + @Override public MapCodec codec() { return CODEC; } + @Override public boolean test(IContext context, DynamicOps ops) { + return PowerAdvantage.recipeMode == mode; + } } - private static final class MusketCondition implements ICondition { - private static final ResourceLocation ID = new ResourceLocation(SteamAdvantage.MODID, "musket_enabled"); - @Override public ResourceLocation getID() { return ID; } - @Override public boolean test(IContext context) { return SteamAdvantage.MUSKET_ENABLE; } + private record MusketCondition() implements ICondition { + private static final MapCodec CODEC = MapCodec.unit(new MusketCondition()); + + @Override public MapCodec codec() { return CODEC; } + @Override public boolean test(IContext context, DynamicOps ops) { + return SteamAdvantage.MUSKET_ENABLE; + } } } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 789343a..75e873c 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -14,14 +14,14 @@ description='''Steam-powered machines and infrastructure for basePower.''' [[dependencies.basesteam]] modId="basepower" mandatory=true -versionRange="[2.4.12.120011,3.0.0)" +versionRange="[${poweradvantage_version},3.0.0)" ordering="AFTER" side="BOTH" [[dependencies.basesteam]] modId="basemetals" mandatory=false -versionRange="[3.1.2.120011,4.0.0)" +versionRange="[3.1.1.120061,4.0.0)" ordering="AFTER" side="BOTH" diff --git a/src/main/resources/data/basesteam/advancements/recipes/blackpowder_cartridge.json b/src/main/resources/data/basesteam/advancements/recipes/blackpowder_cartridge.json index 9a653eb..9f14b8b 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/blackpowder_cartridge.json +++ b/src/main/resources/data/basesteam/advancements/recipes/blackpowder_cartridge.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:nuggets/lead" + "items": "#forge:nuggets/lead" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/musket_left_normal.json b/src/main/resources/data/basesteam/advancements/recipes/musket_left_normal.json index 04b53e5..b2be3a7 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/musket_left_normal.json +++ b/src/main/resources/data/basesteam/advancements/recipes/musket_left_normal.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/steel" + "items": "#forge:ingots/steel" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "minecraft:planks" + "items": "#minecraft:planks" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/musket_left_tech.json b/src/main/resources/data/basesteam/advancements/recipes/musket_left_tech.json index 915f749..e467d8c 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/musket_left_tech.json +++ b/src/main/resources/data/basesteam/advancements/recipes/musket_left_tech.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/steel" + "items": "#forge:ingots/steel" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "minecraft:planks" + "items": "#minecraft:planks" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/musket_right_normal.json b/src/main/resources/data/basesteam/advancements/recipes/musket_right_normal.json index 4985bb5..fb62d78 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/musket_right_normal.json +++ b/src/main/resources/data/basesteam/advancements/recipes/musket_right_normal.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/steel" + "items": "#forge:ingots/steel" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "minecraft:planks" + "items": "#minecraft:planks" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/musket_right_tech.json b/src/main/resources/data/basesteam/advancements/recipes/musket_right_tech.json index cb87d9a..8d21d79 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/musket_right_tech.json +++ b/src/main/resources/data/basesteam/advancements/recipes/musket_right_tech.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/steel" + "items": "#forge:ingots/steel" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "minecraft:planks" + "items": "#minecraft:planks" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_coal.json b/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_coal.json index c5cf8b8..3a08628 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_coal.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_coal.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:conduits/steam" + "items": "#forge:conduits/steam" } ] } @@ -16,7 +16,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -26,7 +26,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -36,7 +36,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_electric.json b/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_electric.json index ee88613..1aead67 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_electric.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_electric.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:wires" + "items": "#forge:wires" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -38,7 +38,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -48,7 +48,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_geothermal.json b/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_geothermal.json index 8b237ae..8721d49 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_geothermal.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_geothermal.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:conduits/steam" + "items": "#forge:conduits/steam" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -38,7 +38,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -48,7 +48,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_oil.json b/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_oil.json index fcb4908..a708574 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_oil.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_oil.json @@ -30,7 +30,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -40,7 +40,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -50,7 +50,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_crusher.json b/src/main/resources/data/basesteam/advancements/recipes/steam_crusher.json index fc6b38b..ce5366b 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_crusher.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_crusher.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:storage_blocks/steel" + "items": "#forge:storage_blocks/steel" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -38,7 +38,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -48,7 +48,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_drill.json b/src/main/resources/data/basesteam/advancements/recipes/steam_drill.json index 98c6f52..121abec 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_drill.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_drill.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -38,7 +38,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_drill_bit.json b/src/main/resources/data/basesteam/advancements/recipes/steam_drill_bit.json index 172d81a..1c5ab80 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_drill_bit.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_drill_bit.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:sprockets" + "items": "#forge:sprockets" } ] } @@ -16,7 +16,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/steel" + "items": "#forge:ingots/steel" } ] } @@ -26,7 +26,7 @@ "conditions": { "items": [ { - "tag": "forge:gems/diamond" + "items": "#forge:gems/diamond" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_drill_diamond_pickaxe_normal.json b/src/main/resources/data/basesteam/advancements/recipes/steam_drill_diamond_pickaxe_normal.json index 64c6670..4aca801 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_drill_diamond_pickaxe_normal.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_drill_diamond_pickaxe_normal.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -38,7 +38,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_elevator.json b/src/main/resources/data/basesteam/advancements/recipes/steam_elevator.json index 4fc3417..5b65061 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_elevator.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_elevator.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:sprockets" + "items": "#forge:sprockets" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -38,7 +38,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -48,7 +48,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_furnace.json b/src/main/resources/data/basesteam/advancements/recipes/steam_furnace.json index e51aa11..5344d67 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_furnace.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_furnace.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -38,7 +38,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_apocalyptic.json b/src/main/resources/data/basesteam/advancements/recipes/steam_governor_apocalyptic.json index 5e20e0e..9f3f319 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_apocalyptic.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_governor_apocalyptic.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:sprockets" + "items": "#forge:sprockets" } ] } @@ -16,7 +16,7 @@ "conditions": { "items": [ { - "tag": "forge:rods" + "items": "#forge:rods" } ] } @@ -26,7 +26,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/brass" + "items": "#forge:ingots/brass" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_normal.json b/src/main/resources/data/basesteam/advancements/recipes/steam_governor_normal.json index 72d611a..c7bea69 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_normal.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_governor_normal.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:nuggets/iron" + "items": "#forge:nuggets/iron" } ] } @@ -16,7 +16,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/brass" + "items": "#forge:ingots/brass" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_tech.json b/src/main/resources/data/basesteam/advancements/recipes/steam_governor_tech.json index b6192ba..6b1dc60 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_tech.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_governor_tech.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:sprockets" + "items": "#forge:sprockets" } ] } @@ -16,7 +16,7 @@ "conditions": { "items": [ { - "tag": "forge:rods" + "items": "#forge:rods" } ] } @@ -26,7 +26,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/brass" + "items": "#forge:ingots/brass" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_pipe.json b/src/main/resources/data/basesteam/advancements/recipes/steam_pipe.json index 7e3b4ca..73839ba 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_pipe.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_pipe.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:ingots/brass" + "items": "#forge:ingots/brass" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_pump.json b/src/main/resources/data/basesteam/advancements/recipes/steam_pump.json index 8998c41..098492b 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_pump.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_pump.json @@ -30,7 +30,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -40,7 +40,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -50,7 +50,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_still.json b/src/main/resources/data/basesteam/advancements/recipes/steam_still.json index c72229f..6cb6d31 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_still.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_still.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/iron" + "items": "#forge:plates/iron" } ] } @@ -38,7 +38,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_switch.json b/src/main/resources/data/basesteam/advancements/recipes/steam_switch.json index db368c6..8be2206 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_switch.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_switch.json @@ -18,7 +18,7 @@ "conditions": { "items": [ { - "tag": "forge:conduits/steam" + "items": "#forge:conduits/steam" } ] } @@ -28,7 +28,7 @@ "conditions": { "items": [ { - "tag": "forge:frames/steel" + "items": "#forge:frames/steel" } ] } diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_tank.json b/src/main/resources/data/basesteam/advancements/recipes/steam_tank.json index 56abcab..e2b10c9 100644 --- a/src/main/resources/data/basesteam/advancements/recipes/steam_tank.json +++ b/src/main/resources/data/basesteam/advancements/recipes/steam_tank.json @@ -6,7 +6,7 @@ "conditions": { "items": [ { - "tag": "forge:plates/copper" + "items": "#forge:plates/copper" } ] } @@ -16,7 +16,7 @@ "conditions": { "items": [ { - "tag": "forge:conduits/steam" + "items": "#forge:conduits/steam" } ] } @@ -26,7 +26,7 @@ "conditions": { "items": [ { - "tag": "forge:governors" + "items": "#forge:governors" } ] } diff --git a/src/main/resources/data/basesteam/loot_tables/chests/advantage_parts.json b/src/main/resources/data/basesteam/loot_tables/chests/advantage_parts.json index 6980d6b..3873eb5 100644 --- a/src/main/resources/data/basesteam/loot_tables/chests/advantage_parts.json +++ b/src/main/resources/data/basesteam/loot_tables/chests/advantage_parts.json @@ -1,20 +1,20 @@ { + "type": "minecraft:chest", "pools": [ { - "__comment": "25% chance of a baseSteam item", "rolls": 1, "entries": [ { - "type": "empty", + "type": "minecraft:empty", "weight": 135 }, { - "type": "item", + "type": "minecraft:item", "name": "basesteam:steam_governor", "weight": 50, "functions": [ { - "function": "set_count", + "function": "minecraft:set_count", "count": { "min": 1, "max": 6 @@ -23,12 +23,12 @@ ] }, { - "type": "item", + "type": "minecraft:item", "name": "basesteam:steam_pipe", "weight": 25, "functions": [ { - "function": "set_count", + "function": "minecraft:set_count", "count": { "min": 3, "max": 6 @@ -37,12 +37,12 @@ ] }, { - "type": "item", + "type": "minecraft:item", "name": "basesteam:blackpowder_cartridge", "weight": 50, "functions": [ { - "function": "set_count", + "function": "minecraft:set_count", "count": { "min": 5, "max": 15 @@ -51,15 +51,13 @@ ] }, { - "type": "item", + "type": "minecraft:item", "name": "basesteam:musket", - "entryName": "basesteam:musket_plain", "weight": 18 }, { - "type": "item", + "type": "minecraft:item", "name": "basesteam:musket", - "entryName": "basesteam:musket_enchanted", "weight": 2, "functions": [ { diff --git a/src/main/resources/data/basesteam/recipes/blackpowder_cartridge.json b/src/main/resources/data/basesteam/recipes/blackpowder_cartridge.json index 818807a..3be805a 100644 --- a/src/main/resources/data/basesteam/recipes/blackpowder_cartridge.json +++ b/src/main/resources/data/basesteam/recipes/blackpowder_cartridge.json @@ -17,13 +17,11 @@ } }, "result": { - "item": "basesteam:blackpowder_cartridge" + "id": "basesteam:blackpowder_cartridge" }, "group": "basesteam:blackpowder_cartridge", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:nuggets/lead" - } - ] + "forge:condition": { + "type": "basepower:tag_not_empty", + "tag": "forge:nuggets/lead" + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_coal.json b/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_coal.json index 3bfe4ee..3dc84d1 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_coal.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_coal.json @@ -1,6 +1,23 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_boiler_coal" }, - "result": { "item": "basesteam:steam_governor", "count": 2 }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_boiler_coal" + }, + "result": { + "id": "basesteam:steam_governor", + "count": 2 + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_electric.json b/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_electric.json index 5f93ca7..5975cb1 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_electric.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_electric.json @@ -1,6 +1,23 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_boiler_electric" }, - "result": { "item": "basesteam:steam_governor", "count": 2 }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_boiler_electric" + }, + "result": { + "id": "basesteam:steam_governor", + "count": 2 + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_geothermal.json b/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_geothermal.json index b629b3e..088b861 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_geothermal.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_geothermal.json @@ -1,6 +1,23 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_boiler_geothermal" }, - "result": { "item": "basesteam:steam_governor", "count": 2 }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_boiler_geothermal" + }, + "result": { + "id": "basesteam:steam_governor", + "count": 2 + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_crusher.json b/src/main/resources/data/basesteam/recipes/crushing_steam_crusher.json index b0ba42c..6605395 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_crusher.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_crusher.json @@ -1,6 +1,23 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_crusher" }, - "result": { "item": "basesteam:steam_governor", "count": 2 }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_crusher" + }, + "result": { + "id": "basesteam:steam_governor", + "count": 2 + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_drill.json b/src/main/resources/data/basesteam/recipes/crushing_steam_drill.json index 63e3603..fbe25f9 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_drill.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_drill.json @@ -1,6 +1,23 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_drill" }, - "result": { "item": "basesteam:steam_governor", "count": 2 }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_drill" + }, + "result": { + "id": "basesteam:steam_governor", + "count": 2 + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_elevator.json b/src/main/resources/data/basesteam/recipes/crushing_steam_elevator.json index 6088244..85317da 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_elevator.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_elevator.json @@ -1,6 +1,23 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_elevator" }, - "result": { "item": "basesteam:steam_governor", "count": 3 }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_elevator" + }, + "result": { + "id": "basesteam:steam_governor", + "count": 3 + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_furnace.json b/src/main/resources/data/basesteam/recipes/crushing_steam_furnace.json index 3d826a5..8eaecb9 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_furnace.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_furnace.json @@ -1,6 +1,23 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_furnace" }, - "result": { "item": "basesteam:steam_governor", "count": 2 }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_furnace" + }, + "result": { + "id": "basesteam:steam_governor", + "count": 2 + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_governor.json b/src/main/resources/data/basesteam/recipes/crushing_steam_governor.json index 5b044fc..ed3f560 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_governor.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_governor.json @@ -1,6 +1,23 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_governor" }, - "result": { "item": "basepower:sprocket", "count": 2 }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_governor" + }, + "result": { + "id": "basepower:sprocket", + "count": 2 + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_tank.json b/src/main/resources/data/basesteam/recipes/crushing_steam_tank.json index e773c7b..db592dc 100644 --- a/src/main/resources/data/basesteam/recipes/crushing_steam_tank.json +++ b/src/main/resources/data/basesteam/recipes/crushing_steam_tank.json @@ -1,6 +1,22 @@ { "type": "basemetals:crushing", - "ingredient": { "item": "basesteam:steam_tank" }, - "result": { "item": "basesteam:steam_governor" }, - "conditions": [{ "type": "forge:mod_loaded", "modid": "basemetals" }, { "type": "basesteam:recipe_mode", "mode": "APOCALYPTIC" }] + "ingredient": { + "item": "basesteam:steam_tank" + }, + "result": { + "id": "basesteam:steam_governor" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "forge:mod_loaded", + "modid": "basemetals" + }, + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/musket_left_normal.json b/src/main/resources/data/basesteam/recipes/musket_left_normal.json index daff48a..7221dfc 100644 --- a/src/main/resources/data/basesteam/recipes/musket_left_normal.json +++ b/src/main/resources/data/basesteam/recipes/musket_left_normal.json @@ -16,20 +16,23 @@ } }, "result": { - "item": "basesteam:musket" + "id": "basesteam:musket" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basesteam:recipe_mode", + "mode": "NORMAL" + }, + { + "type": "basesteam:musket_enabled" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/steel" + } + ] }, - "conditions": [ - { - "type": "basesteam:recipe_mode", - "mode": "NORMAL" - }, - { - "type": "basesteam:musket_enabled" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/steel" - } - ], "group": "basesteam:musket" } diff --git a/src/main/resources/data/basesteam/recipes/musket_left_tech.json b/src/main/resources/data/basesteam/recipes/musket_left_tech.json index ede6426..6667b33 100644 --- a/src/main/resources/data/basesteam/recipes/musket_left_tech.json +++ b/src/main/resources/data/basesteam/recipes/musket_left_tech.json @@ -16,20 +16,23 @@ } }, "result": { - "item": "basesteam:musket" + "id": "basesteam:musket" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basesteam:recipe_mode", + "mode": "TECH_PROGRESSION" + }, + { + "type": "basesteam:musket_enabled" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/steel" + } + ] }, - "conditions": [ - { - "type": "basesteam:recipe_mode", - "mode": "TECH_PROGRESSION" - }, - { - "type": "basesteam:musket_enabled" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/steel" - } - ], "group": "basesteam:musket" } diff --git a/src/main/resources/data/basesteam/recipes/musket_right_normal.json b/src/main/resources/data/basesteam/recipes/musket_right_normal.json index a195847..794f2d2 100644 --- a/src/main/resources/data/basesteam/recipes/musket_right_normal.json +++ b/src/main/resources/data/basesteam/recipes/musket_right_normal.json @@ -16,20 +16,23 @@ } }, "result": { - "item": "basesteam:musket" + "id": "basesteam:musket" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basesteam:recipe_mode", + "mode": "NORMAL" + }, + { + "type": "basesteam:musket_enabled" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/steel" + } + ] }, - "conditions": [ - { - "type": "basesteam:recipe_mode", - "mode": "NORMAL" - }, - { - "type": "basesteam:musket_enabled" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/steel" - } - ], "group": "basesteam:musket" } diff --git a/src/main/resources/data/basesteam/recipes/musket_right_tech.json b/src/main/resources/data/basesteam/recipes/musket_right_tech.json index 8c9650d..a04b48c 100644 --- a/src/main/resources/data/basesteam/recipes/musket_right_tech.json +++ b/src/main/resources/data/basesteam/recipes/musket_right_tech.json @@ -16,20 +16,23 @@ } }, "result": { - "item": "basesteam:musket" + "id": "basesteam:musket" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basesteam:recipe_mode", + "mode": "TECH_PROGRESSION" + }, + { + "type": "basesteam:musket_enabled" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/steel" + } + ] }, - "conditions": [ - { - "type": "basesteam:recipe_mode", - "mode": "TECH_PROGRESSION" - }, - { - "type": "basesteam:musket_enabled" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/steel" - } - ], "group": "basesteam:musket" } diff --git a/src/main/resources/data/basesteam/recipes/steam_boiler_coal.json b/src/main/resources/data/basesteam/recipes/steam_boiler_coal.json index 5e8d3f4..662396d 100644 --- a/src/main/resources/data/basesteam/recipes/steam_boiler_coal.json +++ b/src/main/resources/data/basesteam/recipes/steam_boiler_coal.json @@ -19,25 +19,28 @@ } }, "result": { - "item": "basesteam:steam_boiler_coal" + "id": "basesteam:steam_boiler_coal" }, "group": "basesteam:steam_boiler_coal", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:conduits/steam" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:conduits/steam" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_boiler_electric.json b/src/main/resources/data/basesteam/recipes/steam_boiler_electric.json index e522c0c..0c3ae8a 100644 --- a/src/main/resources/data/basesteam/recipes/steam_boiler_electric.json +++ b/src/main/resources/data/basesteam/recipes/steam_boiler_electric.json @@ -23,25 +23,28 @@ } }, "result": { - "item": "basesteam:steam_boiler_electric" + "id": "basesteam:steam_boiler_electric" }, "group": "basesteam:steam_boiler_electric", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:wires" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:wires" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_boiler_geothermal.json b/src/main/resources/data/basesteam/recipes/steam_boiler_geothermal.json index 0ed84b3..1a5f586 100644 --- a/src/main/resources/data/basesteam/recipes/steam_boiler_geothermal.json +++ b/src/main/resources/data/basesteam/recipes/steam_boiler_geothermal.json @@ -23,25 +23,28 @@ } }, "result": { - "item": "basesteam:steam_boiler_geothermal" + "id": "basesteam:steam_boiler_geothermal" }, "group": "basesteam:steam_boiler_geothermal", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:conduits/steam" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:conduits/steam" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_boiler_oil.json b/src/main/resources/data/basesteam/recipes/steam_boiler_oil.json index 9197d3f..544b0c2 100644 --- a/src/main/resources/data/basesteam/recipes/steam_boiler_oil.json +++ b/src/main/resources/data/basesteam/recipes/steam_boiler_oil.json @@ -23,21 +23,24 @@ } }, "result": { - "item": "basesteam:steam_boiler_oil" + "id": "basesteam:steam_boiler_oil" }, "group": "basesteam:steam_boiler_oil", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_crusher.json b/src/main/resources/data/basesteam/recipes/steam_crusher.json index 86f52b9..96ebf20 100644 --- a/src/main/resources/data/basesteam/recipes/steam_crusher.json +++ b/src/main/resources/data/basesteam/recipes/steam_crusher.json @@ -23,25 +23,28 @@ } }, "result": { - "item": "basesteam:steam_crusher" + "id": "basesteam:steam_crusher" }, "group": "basesteam:steam_crusher", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:storage_blocks/steel" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:storage_blocks/steel" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_drill.json b/src/main/resources/data/basesteam/recipes/steam_drill.json index 66a8ab0..b0dba7d 100644 --- a/src/main/resources/data/basesteam/recipes/steam_drill.json +++ b/src/main/resources/data/basesteam/recipes/steam_drill.json @@ -19,21 +19,24 @@ } }, "result": { - "item": "basesteam:steam_drill" + "id": "basesteam:steam_drill" }, "group": "basesteam:steam_drill", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_drill_bit.json b/src/main/resources/data/basesteam/recipes/steam_drill_bit.json index 28e9cfd..f75189c 100644 --- a/src/main/resources/data/basesteam/recipes/steam_drill_bit.json +++ b/src/main/resources/data/basesteam/recipes/steam_drill_bit.json @@ -17,21 +17,24 @@ } }, "result": { - "item": "basesteam:steam_drill_bit" + "id": "basesteam:steam_drill_bit" }, "group": "basesteam:steam_drill_bit", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:gems/diamond" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:sprockets" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:gems/diamond" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:sprockets" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_drill_diamond_pickaxe_normal.json b/src/main/resources/data/basesteam/recipes/steam_drill_diamond_pickaxe_normal.json index d433383..296056f 100644 --- a/src/main/resources/data/basesteam/recipes/steam_drill_diamond_pickaxe_normal.json +++ b/src/main/resources/data/basesteam/recipes/steam_drill_diamond_pickaxe_normal.json @@ -19,25 +19,28 @@ } }, "result": { - "item": "basesteam:steam_drill" + "id": "basesteam:steam_drill" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basesteam:recipe_mode", + "mode": "NORMAL" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + } + ] }, - "conditions": [ - { - "type": "basesteam:recipe_mode", - "mode": "NORMAL" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - } - ], "group": "basesteam:steam_drill" } diff --git a/src/main/resources/data/basesteam/recipes/steam_elevator.json b/src/main/resources/data/basesteam/recipes/steam_elevator.json index 7b5bc50..82709ed 100644 --- a/src/main/resources/data/basesteam/recipes/steam_elevator.json +++ b/src/main/resources/data/basesteam/recipes/steam_elevator.json @@ -23,25 +23,28 @@ } }, "result": { - "item": "basesteam:steam_elevator" + "id": "basesteam:steam_elevator" }, "group": "basesteam:steam_elevator", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:sprockets" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:sprockets" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_furnace.json b/src/main/resources/data/basesteam/recipes/steam_furnace.json index 7ae6714..e7006eb 100644 --- a/src/main/resources/data/basesteam/recipes/steam_furnace.json +++ b/src/main/resources/data/basesteam/recipes/steam_furnace.json @@ -19,21 +19,24 @@ } }, "result": { - "item": "basesteam:steam_furnace" + "id": "basesteam:steam_furnace" }, "group": "basesteam:steam_furnace", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_governor_apocalyptic.json b/src/main/resources/data/basesteam/recipes/steam_governor_apocalyptic.json index 171a860..cb9bfc8 100644 --- a/src/main/resources/data/basesteam/recipes/steam_governor_apocalyptic.json +++ b/src/main/resources/data/basesteam/recipes/steam_governor_apocalyptic.json @@ -20,25 +20,28 @@ } }, "result": { - "item": "basesteam:steam_governor" + "id": "basesteam:steam_governor" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basesteam:recipe_mode", + "mode": "APOCALYPTIC" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/brass" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:rods" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:sprockets" + } + ] }, - "conditions": [ - { - "type": "basesteam:recipe_mode", - "mode": "APOCALYPTIC" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/brass" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:rods" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:sprockets" - } - ], "group": "basesteam:steam_governor" } diff --git a/src/main/resources/data/basesteam/recipes/steam_governor_normal.json b/src/main/resources/data/basesteam/recipes/steam_governor_normal.json index 230f301..ebe3123 100644 --- a/src/main/resources/data/basesteam/recipes/steam_governor_normal.json +++ b/src/main/resources/data/basesteam/recipes/steam_governor_normal.json @@ -20,21 +20,24 @@ } }, "result": { - "item": "basesteam:steam_governor" + "id": "basesteam:steam_governor" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basesteam:recipe_mode", + "mode": "NORMAL" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/brass" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:nuggets/iron" + } + ] }, - "conditions": [ - { - "type": "basesteam:recipe_mode", - "mode": "NORMAL" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/brass" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:nuggets/iron" - } - ], "group": "basesteam:steam_governor" } diff --git a/src/main/resources/data/basesteam/recipes/steam_governor_tech.json b/src/main/resources/data/basesteam/recipes/steam_governor_tech.json index c831ace..62e0121 100644 --- a/src/main/resources/data/basesteam/recipes/steam_governor_tech.json +++ b/src/main/resources/data/basesteam/recipes/steam_governor_tech.json @@ -20,25 +20,28 @@ } }, "result": { - "item": "basesteam:steam_governor" + "id": "basesteam:steam_governor" + }, + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basesteam:recipe_mode", + "mode": "TECH_PROGRESSION" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/brass" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:rods" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:sprockets" + } + ] }, - "conditions": [ - { - "type": "basesteam:recipe_mode", - "mode": "TECH_PROGRESSION" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/brass" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:rods" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:sprockets" - } - ], "group": "basesteam:steam_governor" } diff --git a/src/main/resources/data/basesteam/recipes/steam_pipe.json b/src/main/resources/data/basesteam/recipes/steam_pipe.json index d2ee4bf..e36a495 100644 --- a/src/main/resources/data/basesteam/recipes/steam_pipe.json +++ b/src/main/resources/data/basesteam/recipes/steam_pipe.json @@ -11,14 +11,12 @@ } }, "result": { - "item": "basesteam:steam_pipe", + "id": "basesteam:steam_pipe", "count": 6 }, "group": "basesteam:steam_pipe", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:ingots/brass" - } - ] + "forge:condition": { + "type": "basepower:tag_not_empty", + "tag": "forge:ingots/brass" + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_pump.json b/src/main/resources/data/basesteam/recipes/steam_pump.json index a3b22c0..8caa905 100644 --- a/src/main/resources/data/basesteam/recipes/steam_pump.json +++ b/src/main/resources/data/basesteam/recipes/steam_pump.json @@ -23,21 +23,24 @@ } }, "result": { - "item": "basesteam:steam_pump" + "id": "basesteam:steam_pump" }, "group": "basesteam:steam_pump", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_still.json b/src/main/resources/data/basesteam/recipes/steam_still.json index 049a2b6..5749711 100644 --- a/src/main/resources/data/basesteam/recipes/steam_still.json +++ b/src/main/resources/data/basesteam/recipes/steam_still.json @@ -23,21 +23,24 @@ } }, "result": { - "item": "basesteam:steam_still" + "id": "basesteam:steam_still" }, "group": "basesteam:steam_still", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/iron" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/iron" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_switch.json b/src/main/resources/data/basesteam/recipes/steam_switch.json index 69b8889..a3984b5 100644 --- a/src/main/resources/data/basesteam/recipes/steam_switch.json +++ b/src/main/resources/data/basesteam/recipes/steam_switch.json @@ -16,17 +16,20 @@ } }, "result": { - "item": "basesteam:steam_switch" + "id": "basesteam:steam_switch" }, "group": "basesteam:steam_switch", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:conduits/steam" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:frames/steel" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:conduits/steam" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:frames/steel" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_tank.json b/src/main/resources/data/basesteam/recipes/steam_tank.json index acf8b40..6c55bb7 100644 --- a/src/main/resources/data/basesteam/recipes/steam_tank.json +++ b/src/main/resources/data/basesteam/recipes/steam_tank.json @@ -17,21 +17,24 @@ } }, "result": { - "item": "basesteam:steam_tank" + "id": "basesteam:steam_tank" }, "group": "basesteam:steam_tank", - "conditions": [ - { - "type": "basepower:tag_not_empty", - "tag": "forge:conduits/steam" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:governors" - }, - { - "type": "basepower:tag_not_empty", - "tag": "forge:plates/copper" - } - ] + "forge:condition": { + "type": "forge:and", + "values": [ + { + "type": "basepower:tag_not_empty", + "tag": "forge:conduits/steam" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:governors" + }, + { + "type": "basepower:tag_not_empty", + "tag": "forge:plates/copper" + } + ] + } } diff --git a/src/main/resources/data/basesteam/recipes/steam_track.json b/src/main/resources/data/basesteam/recipes/steam_track.json index 725fb3e..97ee6ee 100644 --- a/src/main/resources/data/basesteam/recipes/steam_track.json +++ b/src/main/resources/data/basesteam/recipes/steam_track.json @@ -9,7 +9,7 @@ } ], "result": { - "item": "basesteam:steam_track" + "id": "basesteam:steam_track" }, "group": "basesteam:steam_track" } diff --git a/src/main/resources/data/basesteam/tags/items/muskets.json b/src/main/resources/data/basesteam/tags/items/muskets.json new file mode 100644 index 0000000..92bce1d --- /dev/null +++ b/src/main/resources/data/basesteam/tags/items/muskets.json @@ -0,0 +1,4 @@ +{ + "replace": false, + "values": ["basesteam:musket"] +} diff --git a/src/main/resources/data/minecraft/tags/items/enchantable/durability.json b/src/main/resources/data/minecraft/tags/items/enchantable/durability.json new file mode 100644 index 0000000..bbb26f6 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/items/enchantable/durability.json @@ -0,0 +1,4 @@ +{ + "replace": false, + "values": ["#basesteam:muskets"] +} diff --git a/src/main/resources/data/minecraft/tags/items/enchantable/vanishing.json b/src/main/resources/data/minecraft/tags/items/enchantable/vanishing.json new file mode 100644 index 0000000..bbb26f6 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/items/enchantable/vanishing.json @@ -0,0 +1,4 @@ +{ + "replace": false, + "values": ["#basesteam:muskets"] +} diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index d432f64..3486300 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,7 +1,7 @@ { "pack":{ - "pack_format":15, - "forge:server_data_pack_format":15, + "pack_format":32, + "supported_formats":{"min_inclusive":32,"max_inclusive":41}, "description":"baseSteam" } } diff --git a/src/test/java/zone/moddev/mc/basesteam/blocks/DrillBitPersistenceTest.java b/src/test/java/zone/moddev/mc/basesteam/blocks/DrillBitPersistenceTest.java index 45dba4a..8ab0ee7 100644 --- a/src/test/java/zone/moddev/mc/basesteam/blocks/DrillBitPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/blocks/DrillBitPersistenceTest.java @@ -11,33 +11,21 @@ public class DrillBitPersistenceTest { NativeTestBootstrap.start(); } - @Test public void allSixDirectionsSurviveNativeUpdatePackets() { - for (Direction direction : Direction.values()) { - DrillBitTileEntity tile = new DrillBitTileEntity(); - tile.setDirection(direction); - CompoundTag packet = tile.getUpdatePacket().getTag(); - assertEquals(direction.get3DDataValue(), packet.getByte("dir")); - DrillBitTileEntity restored = new DrillBitTileEntity(); - restored.onDataPacket(null, tile.getUpdatePacket()); - assertEquals(direction.getAxis(), restored.getDirection()); - assertEquals(direction.get3DDataValue(), restored.getUpdatePacket().getTag().getByte("dir")); - } - } - @Test public void allSixDirectionsSurviveNativeSaveAndChunkUpdateTag() { for (Direction direction : Direction.values()) { DrillBitTileEntity tile = new DrillBitTileEntity(); tile.setDirection(direction); - CompoundTag saved = tile.saveWithoutMetadata(); + var registries = NativeTestBootstrap.registries(); + CompoundTag saved = tile.saveWithoutMetadata(registries); assertEquals(direction.get3DDataValue(), saved.getByte("dir")); DrillBitTileEntity restored = new DrillBitTileEntity(); - restored.load(saved); - assertEquals(direction.get3DDataValue(), restored.getUpdateTag().getByte("dir")); + restored.loadWithComponents(saved, registries); + assertEquals(direction.get3DDataValue(), restored.getUpdateTag(registries).getByte("dir")); DrillBitTileEntity client = new DrillBitTileEntity(); - client.handleUpdateTag(tile.getUpdateTag()); - assertEquals(direction.get3DDataValue(), client.getUpdatePacket().getTag().getByte("dir")); + client.handleUpdateTag(tile.getUpdateTag(registries), registries); + assertEquals(direction.get3DDataValue(), client.getUpdateTag(registries).getByte("dir")); } } @@ -45,10 +33,10 @@ public class DrillBitPersistenceTest { CompoundTag tag = new CompoundTag(); tag.putByte("d", (byte) Direction.EAST.get3DDataValue()); DrillBitTileEntity tile = new DrillBitTileEntity(); - tile.load(tag); + tile.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(Direction.Axis.X, tile.getDirection()); tag.putByte("dir", (byte) Direction.NORTH.get3DDataValue()); - tile.load(tag); + tile.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(Direction.Axis.Z, tile.getDirection()); } @@ -56,7 +44,7 @@ public class DrillBitPersistenceTest { CompoundTag tag = new CompoundTag(); tag.putByte("dir", (byte) 127); DrillBitTileEntity tile = new DrillBitTileEntity(); - tile.load(tag); - assertEquals(Direction.DOWN.get3DDataValue(), tile.getUpdatePacket().getTag().getByte("dir")); + tile.loadWithComponents(tag, NativeTestBootstrap.registries()); + assertEquals(Direction.DOWN.get3DDataValue(), tile.getUpdateTag(NativeTestBootstrap.registries()).getByte("dir")); } } diff --git a/src/test/java/zone/moddev/mc/basesteam/items/MusketPersistenceTest.java b/src/test/java/zone/moddev/mc/basesteam/items/MusketPersistenceTest.java index 46a890d..154079c 100644 --- a/src/test/java/zone/moddev/mc/basesteam/items/MusketPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/items/MusketPersistenceTest.java @@ -2,6 +2,9 @@ import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.component.CustomData; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; @@ -14,22 +17,33 @@ public class MusketPersistenceTest { NativeTestBootstrap.start(); } - @Test public void loadingCycleKeepsLegacyByteValuesAndOtherNbt() { - ItemStack stack = new ItemStack(net.minecraft.world.item.Items.STICK); + @Test public void loadingCycleKeepsLegacyByteValuesWearAndOtherComponents() { + ItemStack stack = new ItemStack(Items.CROSSBOW); CompoundTag tag = new CompoundTag(); tag.putString("owner", "legacy"); - stack.setTag(tag); + stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + stack.setDamageValue(123); assertTrue(MusketItem.isNotLoaded(stack)); MusketItem.startLoad(stack); - assertEquals(2, stack.getTag().getByte("loaded")); + assertEquals(2, data(stack).getByte("loaded")); assertTrue(MusketItem.isAlmostLoaded(stack)); MusketItem.finishLoad(stack); - assertEquals(1, stack.getTag().getByte("loaded")); + assertEquals(1, data(stack).getByte("loaded")); assertTrue(MusketItem.isLoaded(stack.copy())); + var registries = NativeTestBootstrap.registries(); + ItemStack restored = ItemStack.parse(registries, stack.save(registries)).orElseThrow(); + assertTrue(MusketItem.isLoaded(restored)); + assertEquals(123, restored.getDamageValue()); MusketItem.unload(stack); - assertEquals(0, stack.getTag().getByte("loaded")); + assertEquals(0, data(stack).getByte("loaded")); assertTrue(MusketItem.isNotLoaded(stack)); - assertEquals("legacy", stack.getTag().getString("owner")); + assertEquals("legacy", data(stack).getString("owner")); + assertEquals(123, stack.getDamageValue()); + assertTrue(MusketItem.isLoaded(restored)); + } + + private static CompoundTag data(ItemStack stack) { + return stack.get(DataComponents.CUSTOM_DATA).copyTag(); } @Test public void rayIntersectionSupportsEveryAxisAndRejectsTargetsBehind() { diff --git a/src/test/java/zone/moddev/mc/basesteam/machines/SteamDrillPersistenceTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/SteamDrillPersistenceTest.java index 1da373c..6a87b4b 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/SteamDrillPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/SteamDrillPersistenceTest.java @@ -3,6 +3,8 @@ import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.ItemStack; import net.minecraft.core.Direction; import net.minecraft.core.BlockPos; @@ -31,15 +33,15 @@ public class SteamDrillPersistenceTest { @Test public void retainsLegacyProgressUntilWorldIsAttached() { SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.load(target(94)); + drill.loadWithComponents(target(94), NativeTestBootstrap.registries()); drill.prepareDataFieldsForSync(); assertEquals(94, drill.getDataFieldArray()[1]); } @Test public void clearsPreviousProgressOnReadingAnUntargetedTile() { SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.load(target(94)); - drill.load(new CompoundTag()); + drill.loadWithComponents(target(94), NativeTestBootstrap.registries()); + drill.loadWithComponents(new CompoundTag(), NativeTestBootstrap.registries()); drill.prepareDataFieldsForSync(); assertEquals(0, drill.getDataFieldArray()[1]); } @@ -52,7 +54,7 @@ public class SteamDrillPersistenceTest { state.putString("Name", "minecraft:stone"); tag.put("TargetState", state); SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.load(tag); + drill.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(facing, field(drill, "savedFacing")); assertEquals(new BlockPos(2048, 80, 2049), field(drill, "targetBlockCoord")); assertEquals(state, field(drill, "savedTargetState")); @@ -66,11 +68,11 @@ public class SteamDrillPersistenceTest { SteamDrillTileEntity drill = new SteamDrillTileEntity(); CompoundTag tag = target(94); tag.putByte("Facing", (byte) Direction.UP.get3DDataValue()); - drill.load(tag); - drill.load(target(12)); + drill.loadWithComponents(tag, NativeTestBootstrap.registries()); + drill.loadWithComponents(target(12), NativeTestBootstrap.registries()); assertNull(field(drill, "savedFacing")); tag.putByte("Facing", (byte) 127); - drill.load(tag); + drill.loadWithComponents(tag, NativeTestBootstrap.registries()); assertNull(field(drill, "savedFacing")); } @@ -85,19 +87,19 @@ public class SteamDrillPersistenceTest { items.add(stack); tag.put("Items", items); SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.load(tag); + drill.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(37.5F, drill.getEnergy(Power.steam_power), 0.0F); ItemStack output = drill.getItem(4); assertEquals(net.minecraft.world.item.Items.COBBLESTONE, output.getItem()); assertEquals(23, output.getCount()); } - @Test public void drillOutputDoesNotMergeStacksWithDifferentTags() { + @Test public void drillOutputDoesNotMergeStacksWithDifferentComponents() { SteamDrillTileEntity drill = new SteamDrillTileEntity(); ItemStack first = new ItemStack(net.minecraft.world.item.Items.COBBLESTONE, 8); - first.getOrCreateTag().putString("source", "first"); + CustomData.update(DataComponents.CUSTOM_DATA, first, tag -> tag.putString("source", "first")); ItemStack different = new ItemStack(net.minecraft.world.item.Items.COBBLESTONE, 4); - different.getOrCreateTag().putString("source", "second"); + CustomData.update(DataComponents.CUSTOM_DATA, different, tag -> tag.putString("source", "second")); ItemStack matching = first.copy(); matching.setCount(3); @@ -105,9 +107,9 @@ public class SteamDrillPersistenceTest { assertNull(drill.addItem(different)); assertNull(drill.addItem(matching)); assertEquals(11, drill.getItem(0).getCount()); - assertEquals("first", drill.getItem(0).getTag().getString("source")); + assertEquals("first", drill.getItem(0).get(DataComponents.CUSTOM_DATA).copyTag().getString("source")); assertEquals(4, drill.getItem(1).getCount()); - assertEquals("second", drill.getItem(1).getTag().getString("source")); + assertEquals("second", drill.getItem(1).get(DataComponents.CUSTOM_DATA).copyTag().getString("source")); } @Test public void serializationNeverLooksUpTheWorldOrInfersNeighbours() throws Exception { @@ -144,7 +146,7 @@ public class SteamDrillPersistenceTest { tag.putInt("targetY", target.getY()); tag.putInt("targetZ", target.getZ()); SteamDrillTileEntity drill = new SteamDrillTileEntity(origin, new SteamDrillBlock().defaultBlockState()); - drill.load(tag); + drill.loadWithComponents(tag, NativeTestBootstrap.registries()); assertNull(field(drill, "savedFacing")); assertEquals(direction, infer.invoke(drill)); } diff --git a/src/test/java/zone/moddev/mc/basesteam/machines/SteamMachinePersistenceTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/SteamMachinePersistenceTest.java index 387e515..d512b8f 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/SteamMachinePersistenceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/SteamMachinePersistenceTest.java @@ -57,20 +57,20 @@ public class SteamMachinePersistenceTest { tag.putInt("BurnTime", 127); tag.putInt("BurnTimeTotal", 1600); CoalBoilerTileEntity coal = new CoalBoilerTileEntity(); - coal.load(tag); - CompoundTag saved = coal.saveWithFullMetadata(); + coal.loadWithComponents(tag, NativeTestBootstrap.registries()); + CompoundTag saved = coal.saveWithFullMetadata(NativeTestBootstrap.registries()); assertEquals("basesteam:steam_boiler_coal", saved.getString("id")); assertEquals(127, saved.getInt("BurnTime")); assertEquals(1600, saved.getInt("BurnTimeTotal")); CoalBoilerTileEntity restored = new CoalBoilerTileEntity(); - restored.load(saved); + restored.loadWithComponents(saved, NativeTestBootstrap.registries()); assertEquals(37.5F, restored.getEnergy(Power.steam_power), 0.0F); assertEquals(1500, restored.getTank().getFluidAmount()); tag.putFloat("Electricity", 60.0F); ElectricBoilerTileEntity electric = new ElectricBoilerTileEntity(); - electric.load(tag); + electric.loadWithComponents(tag, NativeTestBootstrap.registries()); ElectricBoilerTileEntity electricRestored = new ElectricBoilerTileEntity(); - electricRestored.load(electric.saveWithoutMetadata()); + electricRestored.loadWithComponents(electric.saveWithoutMetadata(NativeTestBootstrap.registries()), NativeTestBootstrap.registries()); assertEquals(37.5F, electricRestored.getEnergy(Power.steam_power), 0.0F); assertEquals(60.0F, electricRestored.getEnergy(ElectricBoilerTileEntity.ELECTRIC_POWER), 0.0F); assertEquals(1500, electricRestored.getTank().getFluidAmount()); @@ -81,21 +81,21 @@ public class SteamMachinePersistenceTest { tag.put("TankOut", water(750)); tag.putByte("NextPump", (byte) 11); SteamPumpTileEntity pump = new SteamPumpTileEntity(); - pump.load(tag); - CompoundTag saved = pump.saveWithoutMetadata(); + pump.loadWithComponents(tag, NativeTestBootstrap.registries()); + CompoundTag saved = pump.saveWithoutMetadata(NativeTestBootstrap.registries()); assertEquals(750, saved.getCompound("Tank").getInt("Amount")); assertEquals(11, saved.getByte("NextPump")); SteamPumpTileEntity pumpRestored = new SteamPumpTileEntity(); - pumpRestored.load(saved); + pumpRestored.loadWithComponents(saved, NativeTestBootstrap.registries()); assertEquals(750, pumpRestored.getTank().getFluidAmount()); assertEquals(37.5F, pumpRestored.getEnergy(Power.steam_power), 0.0F); tag.putFloat("Tempoerature", 412.5F); GeothermalBoilerTileEntity geothermal = new GeothermalBoilerTileEntity(); - geothermal.load(tag); - assertEquals(412.5F, geothermal.saveWithoutMetadata().getFloat("Temperature"), 0.0F); + geothermal.loadWithComponents(tag, NativeTestBootstrap.registries()); + assertEquals(412.5F, geothermal.saveWithoutMetadata(NativeTestBootstrap.registries()).getFloat("Temperature"), 0.0F); tag.putFloat("Temperature", 500.0F); - geothermal.load(tag); - assertEquals(500.0F, geothermal.saveWithoutMetadata().getFloat("Temperature"), 0.0F); + geothermal.loadWithComponents(tag, NativeTestBootstrap.registries()); + assertEquals(500.0F, geothermal.saveWithoutMetadata(NativeTestBootstrap.registries()).getFloat("Temperature"), 0.0F); } @Test public void stillKeepsSeparateTanksAndExplicitlyEmptyReloads() { @@ -103,15 +103,15 @@ public class SteamMachinePersistenceTest { tag.put("TankIn", water(625)); tag.put("TankOut", water(375)); SteamStillTileEntity still = new SteamStillTileEntity(); - still.load(tag); + still.loadWithComponents(tag, NativeTestBootstrap.registries()); SteamStillTileEntity restored = new SteamStillTileEntity(); - restored.load(still.saveWithoutMetadata()); + restored.loadWithComponents(still.saveWithoutMetadata(NativeTestBootstrap.registries()), NativeTestBootstrap.registries()); assertEquals(625, restored.getInputTank().getFluidAmount()); assertEquals(375, restored.getOutputTank().getFluidAmount()); assertEquals(37.5F, restored.getEnergy(Power.steam_power), 0.0F); tag.put("TankIn", water(0)); tag.put("TankOut", water(0)); - restored.load(tag); + restored.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(0, restored.getInputTank().getFluidAmount()); assertEquals(0, restored.getOutputTank().getFluidAmount()); } @@ -136,7 +136,7 @@ private static BlockEntityType type(String id, BlockE registry.unfreeze(); try { BlockEntityType type = BlockEntityType.Builder.of(factory, Blocks.STONE).build(null); - registry.register(new ResourceLocation("basesteam", id), type); + registry.register(ResourceLocation.fromNamespaceAndPath("basesteam", id), type); return type; } finally { if (locked) registry.freeze(); diff --git a/src/test/java/zone/moddev/mc/basesteam/machines/SteamOperationalPumpSourceTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/SteamOperationalPumpSourceTest.java index b680e99..08cd263 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/SteamOperationalPumpSourceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/SteamOperationalPumpSourceTest.java @@ -131,7 +131,9 @@ private static final class RefusingSource extends Block implements BucketPickup private int pickups; private RefusingSource() { super(Block.Properties.of()); } @Override public FluidState getFluidState(BlockState state) { return Fluids.WATER.defaultFluidState(); } - @Override public net.minecraft.world.item.ItemStack pickupBlock(LevelAccessor world, BlockPos pos, BlockState state) { + @Override public net.minecraft.world.item.ItemStack pickupBlock( + net.minecraft.world.entity.player.Player player, LevelAccessor world, BlockPos pos, BlockState state) { + assertNull("Automated pickup has no acting player", player); pickups++; return net.minecraft.world.item.ItemStack.EMPTY; } diff --git a/src/test/java/zone/moddev/mc/basesteam/migration/SteamLegacyMigrationsTest.java b/src/test/java/zone/moddev/mc/basesteam/migration/SteamLegacyMigrationsTest.java index cb378ab..0a694cb 100644 --- a/src/test/java/zone/moddev/mc/basesteam/migration/SteamLegacyMigrationsTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/migration/SteamLegacyMigrationsTest.java @@ -65,15 +65,15 @@ public class SteamLegacyMigrationsTest { "steam_boiler_geothermal", "steam_tank", "steam_furnace", "steam_crusher", "steam_drill", "drillbit", "platform", "steam_elevator", "steam_switch", "pump_pipe_steam", "steam_still", "steam_pump", "steam_boiler_oil"}) { - ResourceLocation current = new ResourceLocation("basesteam", path); - assertEquals(current, LegacyMigrationApi.blockTarget(new ResourceLocation("steamadvantage", path))); + ResourceLocation current = ResourceLocation.fromNamespaceAndPath("basesteam", path); + assertEquals(current, LegacyMigrationApi.blockTarget(ResourceLocation.fromNamespaceAndPath("steamadvantage", path))); assertTrue(path, LegacyMigrationApi.blockStateCodecs().containsKey(current)); } - ResourceLocation oldMusket = new ResourceLocation("steamadvantage:musket"); - assertEquals(new ResourceLocation("basesteam:musket"), LegacyMigrationApi.itemTarget(oldMusket)); + ResourceLocation oldMusket = ResourceLocation.parse("steamadvantage:musket"); + assertEquals(ResourceLocation.parse("basesteam:musket"), LegacyMigrationApi.itemTarget(oldMusket)); assertTrue(LegacyMigrationApi.isDurableItem(oldMusket)); - assertEquals(new ResourceLocation("basesteam:rapid_reload"), - LegacyMigrationApi.registryTarget(new ResourceLocation("steamadvantage:rapid_reload"))); + assertEquals(ResourceLocation.parse("basesteam:rapid_reload"), + LegacyMigrationApi.registryTarget(ResourceLocation.parse("steamadvantage:rapid_reload"))); } @Test public void repairsOldKeysForBothNamespacesWithoutDependingOnRemapOrder() { diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java index 034ecd6..3adc3aa 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java @@ -1,18 +1,23 @@ package zone.moddev.mc.basesteam.resources; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; +import java.util.Properties; import org.junit.Test; import static org.junit.Assert.*; public class BuildWorkflowContractTest { - @Test public void everyHostedBuildUsesPinnedToolchainProjectProperties() throws Exception { - assertTrue(Files.isRegularFile(Paths.get("gradle/forge47-mavenizer.gradle"))); - java.util.Properties pins = new java.util.Properties(); - try (java.io.Reader reader = Files.newBufferedReader(Paths.get("gradle.properties"), StandardCharsets.UTF_8)) { + @Test public void localPortUsesOfficialRuntimeMappingsAndRetainsExactPins() throws Exception { + Properties pins = new Properties(); + try (var reader = Files.newBufferedReader(Path.of("gradle.properties"))) { pins.load(reader); } + assertEquals("1.20.6", pins.getProperty("minecraft_version")); + assertEquals("50.2.0", pins.getProperty("forge_version")); + assertEquals("21", pins.getProperty("java_version")); + assertEquals("official", pins.getProperty("mapping_channel")); + assertEquals("1.20.6", pins.getProperty("mapping_version")); + assertEquals("2.4.13.120061", pins.getProperty("poweradvantage_version")); for (String key : new String[] {"poweradvantage_source_ref", "poweradvantage_deobf_sha256", "poweradvantage_player_sha256", "poweradvantage_test_bootstrap_sha256", "poweradvantage_test_bootstrap_source_sha256", "basemetals_source_commit", "basemetals_deobf_sha256", @@ -21,51 +26,19 @@ public class BuildWorkflowContractTest { assertTrue(key, pins.getProperty(key, "").matches( key.endsWith("_sha256") ? "[A-F0-9]{64}" : "[a-f0-9]{40}")); } - for (String name : new String[] {"ci.yml", "codeql-analysis.yml"}) { - String source = new String(Files.readAllBytes(Paths.get(".github/workflows", name)), - StandardCharsets.UTF_8); - assertTrue(name, source.contains("ref: ${{ env.BASEMETALS_SOURCE_REF }}")); - assertTrue(name, source.contains("sed -n 's/^basemetals_version=//p'")); - assertTrue(name, source.contains("BaseMetals-$bm_version-deobf.jar")); - assertTrue(name, source.contains("repository: " + pins.getProperty("poweradvantage_source_repository"))); - assertTrue(name, source.contains("basePower-" + pins.getProperty("poweradvantage_version") + "-deobf.jar")); - assertTrue(name, source.contains("ref: ${{ env.ORESPAWN_SOURCE_REF }}")); - assertTrue(name, source.contains("ref: ${{ env.POWERADVANTAGE_SOURCE_REF }}")); - assertTrue(name, source.contains("The exact basePower 1.20.1 dependency pin is pending.")); - assertTrue(name, source.contains("The exact Base Metals 1.20.1 dependency pin is pending.")); - assertTrue(name, source.contains("The exact OreSpawn 1.20.1 dependency pin is pending.")); - assertTrue(name, source.contains("^[a-f0-9]{40}$")); - assertTrue(name, source.contains("^[A-F0-9]{64}$")); - int pinCheck = source.indexOf("Validate coordinated dependency pins"); - assertTrue(name, pinCheck >= 0 && pinCheck < source.indexOf("Check out pinned Base Metals") - && pinCheck < source.indexOf("Check out basePower 1.20.1")); - assertFalse(name, source.contains("-Ppoweradvantage_source_ref=")); - assertTrue(name, source.contains("-Porg.gradle.java.installations.paths=")); - assertTrue(name, source.contains("-Porg.gradle.java.installations.auto-detect=false")); - assertTrue(name, source.contains("-Porg.gradle.java.installations.auto-download=false")); - assertFalse(name, source.contains("-Dorg.gradle.java.installations.")); - assertTrue(name, source.contains("jar unitBootstrapJar verifyReleaseDependencies")); - assertTrue(name, source.contains("-PforgeCapabilityBootstrapJar=${{ steps.dependencies.outputs.bootstrap }}")); - assertTrue(name, source.contains("mavenizer=\"$orespawn/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar\"")); - assertTrue(name, source.contains("416DCA4797BC55826F0DDCF03FDC405F1990FC15C2133FA27A1F143BF7976177")); - int toolCheck = source.indexOf("| sha256sum -c -"); - assertTrue(name, toolCheck >= 0 && toolCheck < source.indexOf("(cd \"$basemetals\"")); - assertTrue(name, source.contains( - "(cd \"$basemetals\" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar --no-daemon --stacktrace)")); - String toolArg = "\"-Pforge47MavenizerJar=$mavenizer\""; - int powerStart = source.indexOf("(cd \"$power\""); - int powerEnd = source.indexOf("\n powerjar=", powerStart); - assertTrue(name, powerStart >= 0 && powerEnd > powerStart); - String powerBuild = source.substring(powerStart, powerEnd); - assertTrue(name, powerBuild.contains(toolArg)); - assertFalse(name, powerBuild.contains("MavenizerScript")); - assertEquals(name, 1L, source.lines().filter(line -> line.contains(toolArg)).count()); - assertTrue(name, source.contains("\"-Pforge47MavenizerJar=${{ steps.dependencies.outputs.mavenizer }}\"")); - for (String line : source.split("\\R")) { - if (line.contains("./gradlew ") && !line.contains("chmod")) { - assertTrue(name + ": " + line, line.contains("./gradlew $MMD_GRADLE_TOOLCHAINS ")); - } - } + assertEquals(pins.getProperty("poweradvantage_deobf_sha256"), pins.getProperty("poweradvantage_player_sha256")); + String build = Files.readString(Path.of("build.gradle")); + assertTrue(build.contains("apply from: 'gradle/forge50-mavenizer.gradle'")); + assertFalse(build.contains("renamer.classes(")); + assertFalse(build.contains("toSrgFile")); + assertTrue(build.contains("basePower-${project.poweradvantage_version}.jar")); + } + + @Test public void thisLocalPortDoesNotOptIntoTheHistoricalHostedJobs() throws Exception { + for (String name : new String[] {"ci.yml", "codeql-analysis.yml", "validate-gradle-build.yml"}) { + String source = Files.readString(Path.of(".github/workflows", name)); + assertFalse(name, source.contains("master-1.20.6")); + assertFalse(name, source.contains("feature/basesteam-1.20.6-port")); } } } diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/DedicatedSideContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/DedicatedSideContractTest.java new file mode 100644 index 0000000..a535a9c --- /dev/null +++ b/src/test/java/zone/moddev/mc/basesteam/resources/DedicatedSideContractTest.java @@ -0,0 +1,53 @@ +package zone.moddev.mc.basesteam.resources; + +import java.io.InputStream; +import java.util.List; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.ClassNode; +import static org.junit.Assert.*; + +public class DedicatedSideContractTest { + private static final String ROOT = "/zone/moddev/mc/basesteam/"; + private static final String ONLY_IN = "Lnet/minecraftforge/api/distmarker/OnlyIn;"; + + @Test public void machineMenusStayCommonAndDecorationMethodsStayClientOnly() throws Exception { + for (String name : List.of("BlastFurnace", "CoalBoiler", "ElectricBoiler", "GeothermalBoiler", + "OilBoiler", "RockCrusher", "SteamDrill", "SteamPump", "SteamStill", "SteamTank")) { + ClassNode menu = read("gui/" + name + "GUI"); + assertFalse("Common menu must remain loadable on the server: " + name, + clientOnly(menu.visibleAnnotations) || clientOnly(menu.invisibleAnnotations)); + var clientSignatures = menu.methods.stream() + .filter(method -> method.desc.contains("GUIContainer") || method.desc.contains("net/minecraft/client/")) + .toList(); + assertFalse("Expected at least the decoration override: " + name, clientSignatures.isEmpty()); + for (var method : clientSignatures) { + assertTrue(name + "#" + method.name + " leaks a client class on the server", + clientOnly(method.visibleAnnotations) || clientOnly(method.invisibleAnnotations)); + } + } + } + + @Test public void renderingHelpersAndRegistrationAreEntirelyClientOnly() throws Exception { + for (String name : List.of("gui/GUIHelper", "graphics/ClientRegistration", "graphics/DrillBitRenderer")) { + ClassNode node = read(name); + assertTrue(name, clientOnly(node.visibleAnnotations) || clientOnly(node.invisibleAnnotations)); + } + } + + private static boolean clientOnly(List annotations) { + return annotations != null && annotations.stream().anyMatch(annotation -> ONLY_IN.equals(annotation.desc) + && annotation.values != null && annotation.values.stream() + .anyMatch(value -> value instanceof String[] marker && marker[1].equals("CLIENT"))); + } + + private static ClassNode read(String path) throws Exception { + try (InputStream input = DedicatedSideContractTest.class.getResourceAsStream(ROOT + path + ".class")) { + assertNotNull(path, input); + ClassNode node = new ClassNode(); + new ClassReader(input).accept(node, ClassReader.SKIP_CODE); + return node; + } + } +} diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/NativeBlockEntityContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/NativeBlockEntityContractTest.java index ce3d49b..da44be5 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/NativeBlockEntityContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeBlockEntityContractTest.java @@ -44,7 +44,7 @@ public class NativeBlockEntityContractTest { saved.putInt("x", 7); saved.putInt("y", 9); saved.putInt("z", 11); saved.putIntArray("Energy", new int[] { Float.floatToIntBits(37.5F) }); saved.putByte("Facing", (byte) direction.get3DDataValue()); - drill.load(saved); + drill.loadWithComponents(saved, NativeTestBootstrap.registries()); assertEquals(destination, drill.getBlockPos()); assertSame(state, drill.getBlockState()); assertEquals(direction, drill.getBlockState().getValue(SteamDrillBlock.FACING)); diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/NativeDamageTypeContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/NativeDamageTypeContractTest.java index b1e6d3c..50baabe 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/NativeDamageTypeContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeDamageTypeContractTest.java @@ -19,7 +19,7 @@ public class NativeDamageTypeContractTest { for (String id : new String[] { "steam_machine", "musket" }) { Path path = Path.of("src/main/resources/data/basesteam/damage_type", id + ".json"); try (Reader reader = Files.newBufferedReader(path)) { - DamageType type = DamageType.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)) + DamageType type = DamageType.DIRECT_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)) .result().orElseThrow(() -> new AssertionError("Invalid native damage type " + id)); assertEquals(id, type.msgId()); assertEquals(DamageScaling.NEVER, type.scaling()); diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/NativeFuelContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/NativeFuelContractTest.java index a083efc..75b2ed0 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/NativeFuelContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeFuelContractTest.java @@ -70,7 +70,7 @@ public class NativeFuelContractTest { return 237; } }; - ForgeRegistries.ITEMS.register(new ResourceLocation("basesteam_test", "fuel_override"), item); + ForgeRegistries.ITEMS.register(ResourceLocation.fromNamespaceAndPath("basesteam_test", "fuel_override"), item); assertEquals(237, FurnaceFuelHelper.getBurnTime(new ItemStack(item))); } } diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/NativeLootContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/NativeLootContractTest.java index 12b5f70..a8ef27d 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/NativeLootContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeLootContractTest.java @@ -39,10 +39,13 @@ public class NativeLootContractTest { } } - @Test public void packUsesNative1201ResourceAndDataFormats() throws Exception { + @Test public void packUsesNative1206ResourceAndDataFormats() throws Exception { JsonObject pack = read(ROOT.resolve("pack.mcmeta")).getAsJsonObject("pack"); - assertEquals(15, pack.get("pack_format").getAsInt()); - assertEquals(15, pack.get("forge:server_data_pack_format").getAsInt()); + assertEquals(32, pack.get("pack_format").getAsInt()); + JsonObject supported = pack.getAsJsonObject("supported_formats"); + assertEquals(32, supported.get("min_inclusive").getAsInt()); + assertEquals(41, supported.get("max_inclusive").getAsInt()); + assertFalse(pack.has("forge:server_data_pack_format")); assertFalse(pack.has("forge:resource_pack_format")); assertFalse(pack.has("forge:data_pack_format")); } diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/OptionalCrushingRecipeContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/OptionalCrushingRecipeContractTest.java index 805e7e7..b3d0a39 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/OptionalCrushingRecipeContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/OptionalCrushingRecipeContractTest.java @@ -4,6 +4,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.mojang.serialization.JsonOps; import java.io.Reader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -64,10 +65,14 @@ private static boolean baseGuard(JsonElement value) { String name = "crushing_" + machine + ".json"; JsonObject recipe = recipes.get(name); assertNotNull(name, recipe); - assertEquals(name, 2, recipe.getAsJsonArray("conditions").size()); + assertFalse(name, recipe.has("conditions")); + JsonObject condition = recipe.getAsJsonObject("forge:condition"); + assertEquals("forge:and", condition.get("type").getAsString()); + var guards = condition.getAsJsonArray("values"); + assertEquals(name, 2, guards.size()); assertTrue(name + " must skip the unavailable serializer", baseGuard( - recipe.getAsJsonArray("conditions").get(0))); - JsonObject mode = recipe.getAsJsonArray("conditions").get(1).getAsJsonObject(); + guards.get(0))); + JsonObject mode = guards.get(1).getAsJsonObject(); assertEquals(name, 2, mode.size()); assertEquals("basesteam:recipe_mode", mode.get("type").getAsString()); assertEquals("APOCALYPTIC", mode.get("mode").getAsString()); @@ -86,14 +91,14 @@ private static boolean baseGuard(JsonElement value) { assertFalse(condition, baseGuard(json(condition))); } - @Test public void nativeForge37SerializerRetainsTheExactProviderIdentity() { + @Test public void nativeForge50CodecRetainsTheExactProviderIdentity() { JsonObject guard = json("{\"type\":\"forge:mod_loaded\",\"modid\":\"basemetals\"}"); - ModLoadedCondition condition = ModLoadedCondition.Serializer.INSTANCE.read(guard); - assertEquals("forge:mod_loaded", ModLoadedCondition.Serializer.INSTANCE.getID().toString()); - JsonObject encoded = new JsonObject(); - ModLoadedCondition.Serializer.INSTANCE.write(encoded, condition); + ModLoadedCondition condition = ModLoadedCondition.CODEC.codec().parse(JsonOps.INSTANCE, guard).getOrThrow(); + assertSame(ModLoadedCondition.CODEC, condition.codec()); + JsonObject encoded = ModLoadedCondition.CODEC.codec().encodeStart(JsonOps.INSTANCE, condition) + .getOrThrow().getAsJsonObject(); assertEquals("basemetals", encoded.get("modid").getAsString()); - assertThrows(RuntimeException.class, () -> ModLoadedCondition.Serializer.INSTANCE.read(json("{}"))); + assertTrue(ModLoadedCondition.CODEC.codec().parse(JsonOps.INSTANCE, json("{}")).error().isPresent()); } @Test public void processingInputsOutputsAndQuantitiesRemainExactlyTheSame() throws Exception { @@ -107,7 +112,7 @@ private static boolean baseGuard(JsonElement value) { JsonObject output = recipe.getAsJsonObject("result"); assertEquals(machine.equals("steam_tank") ? 1 : 2, output.size()); assertEquals(machine.equals("steam_governor") ? "basepower:sprocket" - : "basesteam:steam_governor", output.get("item").getAsString()); + : "basesteam:steam_governor", output.get("id").getAsString()); int amount = machine.equals("steam_tank") ? 1 : machine.equals("steam_elevator") ? 3 : 2; assertEquals(!machine.equals("steam_tank"), output.has("count")); assertEquals(amount, output.has("count") ? output.get("count").getAsInt() : 1); diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/RecipeRegistrationThreadTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/RecipeRegistrationThreadTest.java index a0fe2b8..d7b0cd9 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/RecipeRegistrationThreadTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/RecipeRegistrationThreadTest.java @@ -1,49 +1,44 @@ package zone.moddev.mc.basesteam.resources; import java.io.InputStream; +import java.util.Arrays; import org.junit.Test; import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Handle; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import static org.junit.Assert.*; public class RecipeRegistrationThreadTest { - @Test public void sharedForgeConditionsAreRegisteredAfterParallelSetup() throws Exception { + private static final String CONDITIONS = "zone/moddev/mc/basesteam/recipe/RecipeConditions"; + + @Test public void codecRegistrationUsesTheForgeModEventBusExactlyOnce() throws Exception { + ClassNode mod = read("zone/moddev/mc/basesteam/SteamAdvantage"); + assertEquals(1L, mod.methods.stream().filter(method -> method.name.equals("")) + .flatMap(RecipeRegistrationThreadTest::calls) + .filter(call -> call.owner.equals(CONDITIONS) && call.name.equals("register") + && call.desc.equals("(Lnet/minecraftforge/eventbus/api/IEventBus;)V")) + .count()); + assertFalse(mod.methods.stream().filter(method -> method.name.equals("commonSetup")) + .flatMap(RecipeRegistrationThreadTest::calls).anyMatch(call -> call.owner.equals(CONDITIONS))); + ClassNode conditions = read(CONDITIONS); + assertTrue(conditions.methods.stream().filter(method -> method.name.equals("register")) + .flatMap(RecipeRegistrationThreadTest::calls) + .anyMatch(call -> call.owner.equals("net/minecraftforge/registries/DeferredRegister") + && call.name.equals("register"))); + } + + private static java.util.stream.Stream calls(MethodNode method) { + return Arrays.stream(method.instructions.toArray()).filter(MethodInsnNode.class::isInstance) + .map(MethodInsnNode.class::cast); + } + + private static ClassNode read(String name) throws Exception { ClassNode node = new ClassNode(); - try (InputStream input = getClass().getResourceAsStream("/zone/moddev/mc/basesteam/SteamAdvantage.class")) { + try (InputStream input = RecipeRegistrationThreadTest.class.getResourceAsStream("/" + name + ".class")) { assertNotNull(input); new ClassReader(input).accept(node, 0); } - String conditions = "zone/moddev/mc/basesteam/recipe/RecipeConditions"; - int queued = 0; - for (MethodNode method : node.methods) { - boolean registrationRunnable = false; - for (AbstractInsnNode instruction : method.instructions.toArray()) { - if (instruction instanceof MethodInsnNode) { - MethodInsnNode call = (MethodInsnNode) instruction; - assertFalse("Forge's condition HashMap is not safe during parallel loading", - call.owner.equals(conditions) && call.name.equals("register")); - if (call.owner.equals("net/minecraftforge/fml/event/lifecycle/FMLCommonSetupEvent") - && call.name.equals("enqueueWork") && registrationRunnable) { - assertEquals("Register conditions during common setup", "commonSetup", method.name); - queued++; - registrationRunnable = false; - } - } - if (instruction instanceof InvokeDynamicInsnNode) { - for (Object argument : ((InvokeDynamicInsnNode) instruction).bsmArgs) { - if (argument instanceof Handle && ((Handle) argument).getOwner().equals(conditions) - && ((Handle) argument).getName().equals("register")) { - registrationRunnable = true; - } - } - } - } - } - assertEquals("Queue registration exactly once on Forge's loading thread", 1, queued); + return node; } } diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/RecipeUnlockContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/RecipeUnlockContractTest.java index b8c5ce0..4a7a056 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/RecipeUnlockContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/RecipeUnlockContractTest.java @@ -5,6 +5,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.mojang.serialization.JsonOps; import java.io.IOException; import java.io.Reader; import java.nio.charset.StandardCharsets; @@ -19,7 +20,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import net.minecraft.advancements.critereon.ItemPredicate; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import org.junit.BeforeClass; import org.junit.Test; @@ -100,9 +100,9 @@ public class RecipeUnlockContractTest { for (Path file : files(DATA.resolve("recipes"))) { JsonObject recipe = read(file); if (!crafting(recipe)) continue; - JsonElement result = recipe.get("result"); - String output = result.isJsonPrimitive() ? result.getAsString() - : result.getAsJsonObject().get("item").getAsString(); + JsonObject result = recipe.getAsJsonObject("result"); + assertFalse("Legacy recipe result item field", result.has("item")); + String output = result.get("id").getAsString(); assertTrue("Missing output-specific group: " + file, recipe.has("group")); assertEquals("Different items must not share a recipe-book cell: " + file, output, recipe.get("group").getAsString()); @@ -115,8 +115,9 @@ public class RecipeUnlockContractTest { assertEquals("item:minecraft:string", predicateKey(predicate)); assertEquals(ingredientKey(ingredient), predicateKey(predicate)); JsonObject tag = new JsonParser().parse("{\"tag\":\"minecraft:planks\"}").getAsJsonObject(); - assertEquals("tag:minecraft:planks", predicateKey(tag)); - assertEquals(ingredientKey(tag), predicateKey(tag)); + JsonObject nativeTag = new JsonParser().parse("{\"items\":\"#minecraft:planks\"}").getAsJsonObject(); + assertEquals("tag:minecraft:planks", predicateKey(nativeTag)); + assertEquals(ingredientKey(tag), predicateKey(nativeTag)); assertThrows("Legacy item predicates must not compare equal to native predicates", AssertionError.class, () -> predicateKey(ingredient)); } @@ -125,7 +126,7 @@ public class RecipeUnlockContractTest { for (String json : new String[]{"{}", "{\"items\":[]}", "{\"items\":[\"minecraft:string\",\"minecraft:stone\"]}", "{\"items\":\"minecraft:string\"}", "{\"items\":[1]}", "{\"items\":[null]}", - "{\"tag\":[\"minecraft:planks\"]}", + "{\"tag\":\"minecraft:planks\"}", "{\"items\":\"#\"}", "{\"items\":[\"minecraft:string\"],\"item\":\"minecraft:stone\"}", "{\"items\":[\"minecraft:string\"],\"tag\":\"minecraft:planks\"}"}) { JsonObject predicate = new JsonParser().parse(json).getAsJsonObject(); @@ -138,21 +139,29 @@ public class RecipeUnlockContractTest { JsonObject predicate = unlock.getAsJsonObject("criteria").getAsJsonObject("has_ingredient_1") .getAsJsonObject("conditions").getAsJsonArray("items").get(0).getAsJsonObject(); assertEquals("item:minecraft:flint_and_steel", predicateKey(predicate)); - ItemPredicate nativePredicate = ItemPredicate.fromJson(predicate); - assertTrue(nativePredicate.matches(new ItemStack(Items.FLINT_AND_STEEL))); - assertFalse("String alone must not unlock a musket", nativePredicate.matches(new ItemStack(Items.STRING))); - assertFalse("Unrelated inventory must not act as an ANY predicate", nativePredicate.matches(new ItemStack(Items.STONE))); + ItemPredicate nativePredicate = decode(predicate); + var accepted = nativePredicate.items().orElseThrow(); + assertTrue(accepted.contains(Items.FLINT_AND_STEEL.builtInRegistryHolder())); + assertFalse("String alone must not unlock a musket", accepted.contains(Items.STRING.builtInRegistryHolder())); + assertFalse("Unrelated inventory must not act as an ANY predicate", + accepted.contains(Items.STONE.builtInRegistryHolder())); } @Test public void nativeParserNegativeControlExposesIgnoredLegacyItemField() { JsonObject legacy = new JsonParser().parse("{\"item\":\"minecraft:string\"}").getAsJsonObject(); - ItemPredicate unrestricted = ItemPredicate.fromJson(legacy); - assertTrue("The old field is ignored by the native parser", unrestricted.matches(new ItemStack(Items.STONE))); + ItemPredicate unrestricted = decode(legacy); + assertTrue("The old field is ignored by the native parser", unrestricted.items().isEmpty()); assertThrows(AssertionError.class, () -> predicateKey(legacy)); JsonObject singleton = new JsonParser().parse("{\"items\":[\"minecraft:string\"]}").getAsJsonObject(); - ItemPredicate restricted = ItemPredicate.fromJson(singleton); - assertTrue(restricted.matches(new ItemStack(Items.STRING))); - assertFalse("Native singleton must not become ANY", restricted.matches(new ItemStack(Items.STONE))); + ItemPredicate restricted = decode(singleton); + var accepted = restricted.items().orElseThrow(); + assertTrue(accepted.contains(Items.STRING.builtInRegistryHolder())); + assertFalse("Native singleton must not become ANY", accepted.contains(Items.STONE.builtInRegistryHolder())); + } + + private static ItemPredicate decode(JsonObject json) { + return ItemPredicate.CODEC.parse(NativeTestBootstrap.registries().createSerializationContext(JsonOps.INSTANCE), json) + .getOrThrow(); } private static boolean crafting(JsonObject recipe) { @@ -164,10 +173,12 @@ private static boolean crafting(JsonObject recipe) { private static String predicateKey(JsonObject predicate) { assertEquals("Only one native item or tag predicate is expected", 1, predicate.size()); assertFalse("Native advancement predicates must not use the ignored legacy item field", predicate.has("item")); - if (predicate.has("tag")) { - JsonElement tag = predicate.get("tag"); - assertTrue("Tag predicate must contain a string", tag.isJsonPrimitive() && tag.getAsJsonPrimitive().isString()); - return "tag:" + tag.getAsString(); + assertFalse("Native tag predicates must also use the items field", predicate.has("tag")); + JsonElement selection = predicate.get("items"); + if (selection != null && selection.isJsonPrimitive() && selection.getAsJsonPrimitive().isString()) { + String tag = selection.getAsString(); + assertTrue("Native tag predicate must use a #namespace:path", tag.matches("#[a-z0-9_.-]+:[a-z0-9/_.-]+")); + return "tag:" + tag.substring(1); } assertTrue("Native item predicate requires an items array", predicate.has("items") && predicate.get("items").isJsonArray()); JsonArray items = predicate.getAsJsonArray("items"); diff --git a/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java b/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java index 7684189..61ccbb4 100644 --- a/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java +++ b/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java @@ -1,6 +1,8 @@ package zone.moddev.mc.basesteam.testing; import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.SharedConstants; import net.minecraft.server.Bootstrap; @@ -21,6 +23,10 @@ public static void start() { GameData.unfreezeData(); } + public static RegistryAccess.Frozen registries() { + return RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY); + } + public static synchronized void registerVanillaFluidTypes() throws ReflectiveOperationException { start(); if (ForgeMod.LAVA_TYPE.isPresent()) return; diff --git a/tools/generate-recipe-unlocks.js b/tools/generate-recipe-unlocks.js index 4c3e37c..34ed7e9 100644 --- a/tools/generate-recipe-unlocks.js +++ b/tools/generate-recipe-unlocks.js @@ -31,7 +31,7 @@ for (const file of fs.readdirSync(recipes).filter(name => name.endsWith('.json') unique.forEach((ingredient, index) => { criteria[`has_ingredient_${index + 1}`] = { trigger: 'minecraft:inventory_changed', - conditions: {items: [ingredient.item ? {items: [ingredient.item]} : ingredient]} + conditions: {items: [ingredient.item ? {items: [ingredient.item]} : {items: `#${ingredient.tag}`}]} }; }); criteria.has_recipe = {trigger: 'minecraft:recipe_unlocked', conditions: {recipe: id}}; diff --git a/tools/run-packaged-server-smoke.ps1 b/tools/run-packaged-server-smoke.ps1 new file mode 100644 index 0000000..4a0707a --- /dev/null +++ b/tools/run-packaged-server-smoke.ps1 @@ -0,0 +1,142 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory)][string]$ForgeInstall, + [Parameter(Mandatory)][ValidatePattern('^[a-zA-Z0-9_-]+$')][string]$RunId, + [string]$JavaExe = "$env:USERPROFILE/.jdks/temurin-21.0.7+6/bin/java.exe", + [string]$PowerJar, + [string]$BaseMetalsJar, + [string]$OreSpawnJar, + [switch]$WithoutBaseMetals +) + +$ErrorActionPreference = 'Stop' +$project = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '..')).Path +$forge = (Resolve-Path -LiteralPath $ForgeInstall).Path +$pins = Get-Content -Raw -LiteralPath (Join-Path $project 'gradle.properties') | ConvertFrom-StringData +if ($pins.minecraft_version -ne '1.20.6' -or $pins.forge_version -ne '50.2.0' -or + $pins.poweradvantage_source_ref -cnotmatch '^[0-9a-f]{40}$') { + throw 'An exact Forge 50.2.0 candidate and committed Power source pin are required.' +} +$java = (Resolve-Path -LiteralPath $JavaExe).Path +$javaVersion = (& $java -version 2>&1 | Out-String).Trim() +if ($LASTEXITCODE -ne 0 -or $javaVersion -notmatch 'Temurin-21\.0\.7\+6') { + throw "Unexpected test JVM: $javaVersion" +} + +$steamName = "baseSteam-$($pins.mod_version).jar" +$checksums = Join-Path $project 'build/release/SHA256SUMS' +$checksum = Get-Content -LiteralPath $checksums | Where-Object { $_.EndsWith(" $steamName") } +if (@($checksum).Count -ne 1 -or $checksum -cnotmatch '^[A-F0-9]{64} ') { + throw 'Run writeReleaseChecksums for the audited Steam candidate first.' +} +$steamSha = $checksum.Substring(0, 64) +if (!$PowerJar) { + $PowerJar = Join-Path $project "../../PowerAdvantage/build/libs/basePower-$($pins.poweradvantage_version).jar" +} +if (!$BaseMetalsJar) { + $BaseMetalsJar = Join-Path $project "../../../../BaseMetals/BaseMetals 1206/BaseMetals/build/libs/BaseMetals-$($pins.basemetals_version).jar" +} +if (!$OreSpawnJar) { + $OreSpawnJar = Join-Path $project "../../../../MinecraftMineralogy/OS1206/OreSpawn/build/libs/OreSpawn-$($pins.orespawn_version).jar" +} +$mods = [ordered]@{ + $steamName = @{ Path = (Join-Path $project "build/libs/$steamName"); Sha256 = $steamSha } + "basePower-$($pins.poweradvantage_version).jar" = @{ Path = $PowerJar; Sha256 = $pins.poweradvantage_player_sha256 } + "OreSpawn-$($pins.orespawn_version).jar" = @{ Path = $OreSpawnJar; Sha256 = $pins.orespawn_player_sha256 } +} +if (!$WithoutBaseMetals) { + $mods["BaseMetals-$($pins.basemetals_version).jar"] = @{ Path = $BaseMetalsJar; Sha256 = $pins.basemetals_player_sha256 } +} +$forgeVersion = "$($pins.minecraft_version)-$($pins.forge_version)" +$shim = "forge-$forgeVersion-shim.jar" +$forgeLib = "libraries/net/minecraftforge/forge/$forgeVersion" +$forgeJars = [ordered]@{ + $shim = '7BECDDA6D36C8359EADA6018C2EDB21C5914C50028C191BE09A39FF9F516E10C' + "$forgeLib/forge-$forgeVersion-server.jar" = 'C6F04A819A973CF95159F9C8F7441B0602A9632587F779D712A190A0474AF254' + "$forgeLib/forge-$forgeVersion-universal.jar" = 'F6DC2ACAD898F74C716F5F0BC7290463823090A29F4C9FBE12A58B0FD1C5D524' +} +foreach ($file in $forgeJars.Keys) { + if ((Get-FileHash -LiteralPath (Join-Path $forge $file)).Hash -cne $forgeJars[$file]) { + throw "Installed Forge runtime hash mismatch: $file" + } +} +foreach ($name in $mods.Keys) { + $inputJar = $mods[$name] + $inputJar.Path = (Resolve-Path -LiteralPath $inputJar.Path).Path + if ((Get-FileHash -LiteralPath $inputJar.Path).Hash -cne $inputJar.Sha256) { + throw "Pinned player hash mismatch: $name" + } +} + +$run = Join-Path $project "evidence/packaged-server-$RunId" +if (Test-Path -LiteralPath $run) { throw "Run directory already exists: $run" } +New-Item -ItemType Directory -Path (Join-Path $run 'mods') | Out-Null +$receipt = [ordered]@{ + status = 'FAILED' + steamCommit = (& git -C $project rev-parse HEAD) + steamStatus = @(& git -C $project status --porcelain) + powerCommit = $pins.poweradvantage_source_ref + forge = $forgeVersion + forgeJars = $forgeJars + java = $javaVersion + mods = $mods + world = (Join-Path $run 'steam-smoke') + finishedUtc = $null +} +$process = $null +try { + Copy-Item -LiteralPath (Join-Path $forge 'libraries') -Destination $run -Recurse + Copy-Item -LiteralPath (Join-Path $forge $shim) -Destination $run + foreach ($name in $mods.Keys) { + $destination = Join-Path $run "mods/$name" + Copy-Item -LiteralPath $mods[$name].Path -Destination $destination + if ((Get-FileHash -LiteralPath $destination).Hash -cne $mods[$name].Sha256) { + throw "Player jar changed while copying: $name" + } + } + Set-Content -LiteralPath (Join-Path $run 'eula.txt') -Value 'eula=true' -Encoding ascii + Set-Content -LiteralPath (Join-Path $run 'server.properties') -Encoding ascii -Value @( + 'server-ip=127.0.0.1', 'server-port=0', 'level-name=steam-smoke', + 'level-type=minecraft:flat', 'generate-structures=false', 'view-distance=2', 'simulation-distance=2' + ) + $start = [System.Diagnostics.ProcessStartInfo]::new($java) + $start.WorkingDirectory = $run + $start.UseShellExecute = $false + $start.CreateNoWindow = $true + $start.RedirectStandardInput = $true + $start.RedirectStandardOutput = $true + $start.RedirectStandardError = $true + foreach ($argument in @('-Xms512m', '-Xmx3g', '-Djava.net.preferIPv6Addresses=system', '-jar', $shim, '--nogui')) { + $start.ArgumentList.Add($argument) + } + $process = [System.Diagnostics.Process]::Start($start) + $stdout = $process.StandardOutput.ReadToEndAsync() + $stderr = $process.StandardError.ReadToEndAsync() + $latest = Join-Path $run 'logs/latest.log' + $deadline = [DateTime]::UtcNow.AddMinutes(3) + do { + if ($process.HasExited) { throw "Forge exited before ready: $($process.ExitCode)" } + $log = if (Test-Path -LiteralPath $latest) { Get-Content -Raw -LiteralPath $latest } + if ($log -match 'Done \([^)]+\)!') { break } + Start-Sleep -Seconds 1 + } while ([DateTime]::UtcNow -lt $deadline) + if ($log -notmatch 'Done \([^)]+\)!') { throw 'Timed out waiting for a fresh Forge world.' } + $process.StandardInput.WriteLine('stop') + if (!$process.WaitForExit(60000) -or $process.ExitCode -ne 0) { throw 'Forge did not stop cleanly.' } + $log = Get-Content -Raw -LiteralPath $latest + if ($log -notmatch "baseSteam $([regex]::Escape($pins.mod_version)) common setup complete" -or + $log -match 'NoClassDefFoundError|Failed to create mod instance|Exception caught during firing event|Failed to load registries|(?:Parsing error|Couldn.t parse|Failed to parse)[^\r\n]*basesteam:') { + throw 'Missing Steam setup or a relevant loader/data error appeared in the server log.' + } + $receipt.status = 'PACKAGED_DEDICATED_SERVER_PASS' + Write-Output "$($receipt.status): $run" +} finally { + if ($process) { + if (!$process.HasExited) { $process.Kill($true); $process.WaitForExit() } + Set-Content -LiteralPath (Join-Path $run 'stdout.log') -Value $stdout.GetAwaiter().GetResult() + Set-Content -LiteralPath (Join-Path $run 'stderr.log') -Value $stderr.GetAwaiter().GetResult() + $process.Dispose() + } + $receipt.finishedUtc = [DateTime]::UtcNow.ToString('o') + $receipt | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $run 'receipt.json') +} diff --git a/tools/verify-native-port.js b/tools/verify-native-port.js index 1ee06be..4f5e7b8 100644 --- a/tools/verify-native-port.js +++ b/tools/verify-native-port.js @@ -23,11 +23,11 @@ for (const name of files(resources).filter(name => /\.(json|mcmeta)$/.test(name) json.set(name, JSON.parse(text)); } assert.deepEqual(json.get(`${resources}/pack.mcmeta`).pack, { - pack_format: 15, 'forge:server_data_pack_format': 15, description: 'baseSteam' + pack_format: 32, supported_formats: {min_inclusive: 32, max_inclusive: 41}, description: 'baseSteam' }); const metadata = read(`${resources}/META-INF/mods.toml`); assert.match(metadata, /modId="basesteam"/); -assert.match(metadata, /modId="basepower"\r?\nmandatory=true\r?\nversionRange="\[2\.4\.12\.120011,3\.0\.0\)"/); +assert.match(metadata, /modId="basepower"\r?\nmandatory=true\r?\nversionRange="\[\$\{poweradvantage_version\},3\.0\.0\)"/); assert.match(metadata, /modId="basemetals"\r?\nmandatory=false/); assert.doesNotMatch(metadata, /dependencies\.steamadvantage|modId="(?:steamadvantage|poweradvantage)"/); @@ -103,5 +103,5 @@ for (const id of pickaxe.values.map(value => value.split(':')[1]).filter(id => ! } const tests = files('src/test/java').filter(name => name.endsWith('.java')); const testCount = tests.reduce((sum, name) => sum + (read(name).match(/@Test\b/g) || []).length, 0); -console.log(`BASESTEAM_NATIVE1201_SOURCE_PASS json=${json.size} java=${source.length} factories=${ids.length} harvest=${pickaxe.values.length} testMethods=${testCount}`); +console.log(`BASESTEAM_NATIVE1206_SOURCE_PASS json=${json.size} java=${source.length} factories=${ids.length} harvest=${pickaxe.values.length} testMethods=${testCount}`); console.log('Source checks only. Compilation, executed tests, packaged runtime and manual acceptance are separate.'); From cc464fd7a47aab78cc17022dd39539dcc99dec8f Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 11:41:38 +0000 Subject: [PATCH 02/16] Adapt Steam verification to the Forge 50 loader --- README.md | 9 ++- build.gradle | 14 ++++- docs/PORT1206-STATUS.md | 12 ++++ .../testing/NativeTestBootstrap.java | 55 ++++++++++++++++--- 4 files changed, 77 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 348c448..b504950 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ Minecraft 1.20.6, Forge 50.2.0, official mappings and MCP 20240429.135109. ForgeGradle 7.0.34 and the Gradle 9.6.1 wrapper use Temurin 21.0.7+6. Mavenizer uses Java 25 and the checksum-verified fixture from the local OreSpawn 1.20.6 checkout. Set `-Pforge50MavenizerJar=` for a different layout. +ForgeGradle's Slime Launcher also locates a Java 8 toolchain while generating +runs. The game itself runs on Java 21. Forge 50 uses official names at runtime. Steam does not run an SRG renamer. The required dependency is basePower 2.4.13.120061. Base Metals 3.1.1.120061 is @@ -31,16 +33,17 @@ From this checkout in PowerShell, with the pinned local JDKs installed: ```powershell $env:JAVA_HOME = "$env:USERPROFILE/.jdks/temurin-21.0.7+6" -$jdks = "$env:JAVA_HOME,$env:USERPROFILE/.jdks/jdk-25.0.3+9" +$jdk8 = "$env:USERPROFILE/.jdks/temurin-8.0.502+7/jdk8u502-b07" +$jdks = "$env:JAVA_HOME,$env:USERPROFILE/.jdks/jdk-25.0.3+9,$jdk8" $toolchains = @("-Porg.gradle.java.installations.paths=$jdks", '-Porg.gradle.java.installations.auto-detect=false', '-Porg.gradle.java.installations.auto-download=false') ./gradlew.bat @toolchains check build deobfJar verifyReleaseArtifacts writeReleaseChecksums -./gradlew.bat @toolchains verifyPlayerDependencies runGameTestServer +./gradlew.bat @toolchains -PsteamGameTestRunId=candidate verifyPlayerDependencies runGameTestServer ./tools/run-packaged-server-smoke.ps1 -ForgeInstall $env:FORGE_1206_SERVER_INSTALL -RunId candidate-with-basemetals ``` -The GameTest run uses `build/steam-gametest-run` and a validation-only source +The GameTest run uses `build/steam-gametest-` and a validation-only source set. It checks drill-bit packets, legacy musket componentization, the shared durability migration, and loaded recipe, advancement, and loot resources. The packaged dedicated smoke is a separate gate. It checks the official Forge diff --git a/build.gradle b/build.gradle index 781e47e..e97f7f2 100644 --- a/build.gradle +++ b/build.gradle @@ -124,7 +124,9 @@ minecraft { args '--nogui' } register('gameTestServer') { - workingDir.set(layout.buildDirectory.dir('steam-gametest-run')) + String runId = providers.gradleProperty('steamGameTestRunId').getOrElse('run') + if (!(runId ==~ /[A-Za-z0-9_-]+/)) throw new GradleException('Invalid Steam GameTest run ID') + workingDir.set(layout.buildDirectory.dir("steam-gametest-${runId}")) systemProperty 'forge.enableGameTest', 'true' systemProperty 'forge.enabledGameTestNamespaces', mod_id mods { basesteam { source sourceSets.gameTestValidation } } @@ -167,6 +169,9 @@ tasks.withType(JavaExec).configureEach { dependsOn gameTest ? prepareForgeGameTestModClasses : prepareForgeRunModClasses environment 'MOD_CLASSES', "${mod_id}%%${mergedOutput.get().asFile.absolutePath}" doFirst { + if (gameTest && new File(workingDir, 'logs/latest.log').exists()) { + throw new GradleException('Choose a fresh -PsteamGameTestRunId to preserve the existing receipt') + } if (name == 'runClient') setArgs(['--launcher-side', 'client'] + args) Set splitOutputs = [sourceSets.main, sourceSets.gameTestValidation].collectMany { it.output.files @@ -176,6 +181,13 @@ tasks.withType(JavaExec).configureEach { }) new File(workingDir, 'mods').mkdirs() } + if (gameTest) doLast { + // Forge can exit zero after a loader failure; require the actual test result. + File receipt = new File(workingDir, 'logs/latest.log') + if (!receipt.isFile() || !receipt.getText('UTF-8').contains('All 4 required tests passed')) { + throw new GradleException("The four Steam GameTests did not pass; see ${receipt}") + } + } } } diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index 00e5452..3fc44de 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -46,6 +46,18 @@ any 1.20.1 or newer 1.20.6 mod artifacts. - `evidence/steam1206-independent-native-side.log`: 21 checks passed, including the native drill renderer geometry and the client-only GUI signature regression. Neither receipt is a packaged runtime pass. +- `evidence/steam1206-provisional-unit-d.log` and its XML results: 219 passed, + none failed or skipped. Only the two final pin-contract tests were excluded. + Inputs included provisional Power `82B1554AF83DF6FF2D737FA22D8548736B7F23BC182659A12DEAB254ED4CA6C6` + and the local Base Metals shared-hook candidate + `FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417`. + The a through c fixture failures and XML are preserved. +- `evidence/steam1206-provisional-gametest-c.log`: Forge reached the dedicated + development loader, but provisional Power's `MachineGUIRegistry` auto + subscriber was rejected for carrying `@OnlyIn` methods. No Steam tests ran, + despite the launcher returning zero. The new task gate requires the actual + four-test pass marker and a fresh run ID. The crash is under + `build/steam-gametest-provisional-c/crash-reports`. The isolated data checks use Forge 50.2.0 classes but do not start the Forge mod loader or qualify Steam's production classes. The GameTest fixtures are diff --git a/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java b/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java index 61ccbb4..01f5621 100644 --- a/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java +++ b/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java @@ -1,5 +1,8 @@ package zone.moddev.mc.basesteam.testing; +import java.util.List; +import java.util.Optional; +import cpw.mods.modlauncher.api.IModuleLayerManager; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; @@ -7,6 +10,9 @@ import net.minecraft.SharedConstants; import net.minecraft.server.Bootstrap; import net.minecraftforge.common.ForgeMod; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.fml.loading.LoadingModList; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistry; @@ -33,12 +39,14 @@ public static synchronized void registerVanillaFluidTypes() throws ReflectiveOpe // Plain JUnit has no mod loader to dispatch these two Forge registry phases. if (ForgeRegistries.FLUID_TYPES.get() == null) { + var registries = ForgeRegistries.class.getDeclaredField("registries"); + registries.setAccessible(true); + DeferredRegister fluidTypes = ((List) registries.get(null)).stream() + .map(DeferredRegister.class::cast) + .filter(registry -> ForgeRegistries.Keys.FLUID_TYPES.equals(registry.getRegistryKey())) + .findFirst().orElseThrow(); var event = new NewRegistryEvent(); - var fluidTypes = ForgeRegistries.class.getDeclaredField("DEFERRED_FLUID_TYPES"); - fluidTypes.setAccessible(true); - var create = DeferredRegister.class.getDeclaredMethod("createRegistry", NewRegistryEvent.class); - create.setAccessible(true); - create.invoke(fluidTypes.get(null), event); + invokeRegistryPhase(fluidTypes, "createRegistry", event); var fill = NewRegistryEvent.class.getDeclaredMethod("fill"); fill.setAccessible(true); fill.invoke(event); @@ -46,20 +54,49 @@ public static synchronized void registerVanillaFluidTypes() throws ReflectiveOpe var vanillaTypes = ForgeMod.class.getDeclaredField("VANILLA_FLUID_TYPES"); vanillaTypes.setAccessible(true); - var addEntries = DeferredRegister.class.getDeclaredMethod("addEntries", RegisterEvent.class); - addEntries.setAccessible(true); var event = RegisterEvent.class.getDeclaredConstructor(ResourceKey.class, ForgeRegistry.class, Registry.class); event.setAccessible(true); - addEntries.invoke(vanillaTypes.get(null), event.newInstance( - ForgeRegistries.Keys.FLUID_TYPES, ForgeRegistries.FLUID_TYPES.get(), null)); + invokeRegistryPhase((DeferredRegister) vanillaTypes.get(null), "handleEvent", + event.newInstance(ForgeRegistries.Keys.FLUID_TYPES, ForgeRegistries.FLUID_TYPES.get(), null)); + } + + private static void invokeRegistryPhase(DeferredRegister register, String phase, Event event) + throws ReflectiveOperationException { + // The launch-only EventBus transform is not present in plain JUnit. + Class dispatcher = Class.forName(DeferredRegister.class.getName() + "$EventDispatcher"); + var constructor = dispatcher.getDeclaredConstructor(DeferredRegister.class); + constructor.setAccessible(true); + var method = dispatcher.getDeclaredMethod(phase, event.getClass()); + method.setAccessible(true); + method.invoke(constructor.newInstance(register), event); } private static final class NativeRegistries { static { + initializeEmptyForgeDiscovery(); SharedConstants.tryDetectVersion(); Bootstrap.bootStrap(); } private static void ensureStarted() {} + + private static void initializeEmptyForgeDiscovery() { + if (FMLLoader.getLoadingModList() != null) return; + // Forge 50 lazily gathers item components through ForgeEventFactory. + // Plain JUnit has no launch discovery, so give the native loader an empty list. + var list = LoadingModList.of(List.of(), List.of(), null); + list.setBrokenFiles(List.of()); + try { + var field = FMLLoader.class.getDeclaredField("loadingModList"); + field.setAccessible(true); + field.set(null, list); + var layers = FMLLoader.class.getDeclaredField("moduleLayerManager"); + layers.setAccessible(true); + layers.set(null, (IModuleLayerManager) layer -> layer == IModuleLayerManager.Layer.GAME + ? Optional.of(ModuleLayer.empty()) : Optional.empty()); + } catch (ReflectiveOperationException exception) { + throw new IllegalStateException("Could not initialize the Forge 50 unit fixture", exception); + } + } } } From 20934ca6f078d4170668e1a5e20dea58803431a2 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 11:44:20 +0000 Subject: [PATCH 03/16] Preserve the musket fragile-block tag on Forge 50 --- build.gradle | 3 ++- docs/PORT1206-STATUS.md | 6 ++++++ .../basesteam/gametest/SteamNativeGameTests.java | 6 ++++++ .../basesteam/tags/blocks/musket_fragile.json | 2 +- .../resources/MusketFragileTagContractTest.java | 15 ++++++++++++++- tools/run-packaged-server-smoke.ps1 | 5 +++-- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index e97f7f2..0f5c4f4 100644 --- a/build.gradle +++ b/build.gradle @@ -184,7 +184,8 @@ tasks.withType(JavaExec).configureEach { if (gameTest) doLast { // Forge can exit zero after a loader failure; require the actual test result. File receipt = new File(workingDir, 'logs/latest.log') - if (!receipt.isFile() || !receipt.getText('UTF-8').contains('All 4 required tests passed')) { + String output = receipt.isFile() ? receipt.getText('UTF-8') : '' + if (!output.contains('All 4 required tests passed') || (output =~ /\[[^\]\r\n]*\/(?:ERROR|FATAL)\]/).find()) { throw new GradleException("The four Steam GameTests did not pass; see ${receipt}") } } diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index 3fc44de..0c81c1c 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -58,6 +58,12 @@ any 1.20.1 or newer 1.20.6 mod artifacts. despite the launcher returning zero. The new task gate requires the actual four-test pass marker and a fresh run ID. The crash is under `build/steam-gametest-provisional-c/crash-reports`. +- `evidence/packaged-server-provisional-a`: the real packaged Forge server + reached Steam common setup, `Done`, and a clean stop without a client-side + class error. Its original startup-only receipt is preserved, but the full + log rejects this as a clean data smoke: Forge could not bind the fragile + block tag because Minecraft renamed `grass` to `short_grass`. The smoke + now fails on error logs and the registry test checks every required ID. The isolated data checks use Forge 50.2.0 classes but do not start the Forge mod loader or qualify Steam's production classes. The GameTest fixtures are diff --git a/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java b/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java index 358b76a..afe8620 100644 --- a/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java +++ b/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java @@ -16,6 +16,7 @@ import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.ItemStack; @@ -112,6 +113,11 @@ public static void olderMusketAliasAndTopLevelWearSurvivePowerMigration(GameTest public static void nativeResourcesLoadWithExpectedIds(GameTestHelper helper) { var level = helper.getLevel(); var registries = level.registryAccess(); + var fragile = TagKey.create(Registries.BLOCK, id("musket_fragile")); + helper.assertTrue(net.minecraft.world.level.block.Blocks.SHORT_GRASS.defaultBlockState().is(fragile), + "The 1.20.6 short grass ID must bind the fragile block tag"); + helper.assertTrue(!net.minecraft.world.level.block.Blocks.STONE.defaultBlockState().is(fragile), + "The fragile block tag must not include solid stone"); var manager = level.getServer().getAdvancements(); helper.assertTrue(manager.get(id("recipes/steam_pipe")) != null, "Missing Steam pipe recipe advancement"); var unlock = manager.get(id("recipes/musket_right_normal")).value(); diff --git a/src/main/resources/data/basesteam/tags/blocks/musket_fragile.json b/src/main/resources/data/basesteam/tags/blocks/musket_fragile.json index 7603842..559a067 100644 --- a/src/main/resources/data/basesteam/tags/blocks/musket_fragile.json +++ b/src/main/resources/data/basesteam/tags/blocks/musket_fragile.json @@ -68,7 +68,6 @@ "minecraft:glass_pane", "minecraft:glow_lichen", "minecraft:glowstone", - "minecraft:grass", "minecraft:gray_candle", "minecraft:gray_stained_glass", "minecraft:gray_stained_glass_pane", @@ -176,6 +175,7 @@ "minecraft:rose_bush", "minecraft:scaffolding", "minecraft:sea_lantern", + "minecraft:short_grass", "minecraft:skeleton_skull", "minecraft:skeleton_wall_skull", "minecraft:small_dripleaf", diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/MusketFragileTagContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/MusketFragileTagContractTest.java index 456fb87..1190564 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/MusketFragileTagContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/MusketFragileTagContractTest.java @@ -7,10 +7,16 @@ import java.security.MessageDigest; import java.util.HexFormat; import java.util.TreeSet; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import org.junit.BeforeClass; import org.junit.Test; +import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import static org.junit.Assert.*; public class MusketFragileTagContractTest { + @BeforeClass public static void bootstrap() { NativeTestBootstrap.start(); } + @Test public void vanillaDefaultsMatchThePreviousMaterialRule() throws Exception { Path path = Path.of("src/main/resources/data/basesteam/tags/blocks/musket_fragile.json"); try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { @@ -22,12 +28,19 @@ public class MusketFragileTagContractTest { assertTrue(blocks.contains("minecraft:glass_pane")); assertTrue(blocks.contains("minecraft:oak_leaves")); assertTrue(blocks.contains("minecraft:torch")); + assertTrue(blocks.contains("minecraft:short_grass")); + for (String id : blocks) { + assertTrue("Unregistered Forge 50 block would invalidate the tag: " + id, + BuiltInRegistries.BLOCK.containsKey(ResourceLocation.parse(id))); + } assertFalse(blocks.contains("minecraft:tnt")); assertFalse(blocks.contains("minecraft:stone")); assertFalse(blocks.contains("minecraft:water")); // Oracle: the sorted vanilla block IDs matching the six fragile Material - // values, read from the actual Forge 45.4.0 block registry. + // values, read from Forge 45.4.0. Normalize the one known vanilla rename. assertEquals(216, blocks.size()); + blocks.remove("minecraft:short_grass"); + blocks.add("minecraft:grass"); byte[] digest = MessageDigest.getInstance("SHA-256") .digest(String.join("\n", blocks).getBytes(StandardCharsets.UTF_8)); assertEquals("F8C8CC9719BEEE0926FA793229D0C190A2EEEF514E0F6500CC4D3C50D61FF2BE", HexFormat.of().withUpperCase().formatHex(digest)); diff --git a/tools/run-packaged-server-smoke.ps1 b/tools/run-packaged-server-smoke.ps1 index 4a0707a..649e0a1 100644 --- a/tools/run-packaged-server-smoke.ps1 +++ b/tools/run-packaged-server-smoke.ps1 @@ -97,7 +97,8 @@ try { Set-Content -LiteralPath (Join-Path $run 'eula.txt') -Value 'eula=true' -Encoding ascii Set-Content -LiteralPath (Join-Path $run 'server.properties') -Encoding ascii -Value @( 'server-ip=127.0.0.1', 'server-port=0', 'level-name=steam-smoke', - 'level-type=minecraft:flat', 'generate-structures=false', 'view-distance=2', 'simulation-distance=2' + 'level-type=minecraft:flat', 'generate-structures=false', 'view-distance=2', 'simulation-distance=2', + 'generator-settings={"layers":[{"height":1,"block":"minecraft:bedrock"},{"height":2,"block":"minecraft:dirt"},{"height":1,"block":"minecraft:grass_block"}],"biome":"minecraft:plains"}' ) $start = [System.Diagnostics.ProcessStartInfo]::new($java) $start.WorkingDirectory = $run @@ -125,7 +126,7 @@ try { if (!$process.WaitForExit(60000) -or $process.ExitCode -ne 0) { throw 'Forge did not stop cleanly.' } $log = Get-Content -Raw -LiteralPath $latest if ($log -notmatch "baseSteam $([regex]::Escape($pins.mod_version)) common setup complete" -or - $log -match 'NoClassDefFoundError|Failed to create mod instance|Exception caught during firing event|Failed to load registries|(?:Parsing error|Couldn.t parse|Failed to parse)[^\r\n]*basesteam:') { + $log -match '\[[^\]\r\n]*/(?:ERROR|FATAL)\]|NoClassDefFoundError') { throw 'Missing Steam setup or a relevant loader/data error appeared in the server log.' } $receipt.status = 'PACKAGED_DEDICATED_SERVER_PASS' From cdce53929c8368c49e343845d9b21f7d62ee8a53 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 11:47:45 +0000 Subject: [PATCH 04/16] Use the shared Forge 50 JUnit bootstrap --- docs/PORT1206-STATUS.md | 14 +++++++++++ .../testing/NativeTestBootstrap.java | 24 ------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index 0c81c1c..34456d9 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -52,6 +52,12 @@ any 1.20.1 or newer 1.20.6 mod artifacts. and the local Base Metals shared-hook candidate `FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417`. The a through c fixture failures and XML are preserved. +- `evidence/steam1206-provisional-unit-f.log` and its XML results: the same + 219 tests passed after the fragile-block fix, using the updated shared + Forge 50 JUnit agent + `96752A443070E117EED9308ABC9C2009BD3533F121C9594A7108908E104673C9`. + The e-run exposed overlapping loader initialization, so Steam now lets + the shared agent own that setup and retains only its fluid registry fixture. - `evidence/steam1206-provisional-gametest-c.log`: Forge reached the dedicated development loader, but provisional Power's `MachineGUIRegistry` auto subscriber was rejected for carrying `@OnlyIn` methods. No Steam tests ran, @@ -64,6 +70,14 @@ any 1.20.1 or newer 1.20.6 mod artifacts. log rejects this as a clean data smoke: Forge could not bind the fragile block tag because Minecraft renamed `grass` to `short_grass`. The smoke now fails on error logs and the registry test checks every required ID. +- `evidence/packaged-server-provisional-b/receipt.json` and + `evidence/packaged-server-provisional-c-no-basemetals/receipt.json`: + the corrected packaged Steam jar + `6AF7260CF4950998816246029FB9F5C3E5A424512A173E46DD6A80E41ED76A8C` + booted and stopped cleanly on Forge 50.2.0 in both profiles, with no + ERROR/FATAL records. These runs used the frozen provisional Power jar + `82B1554AF83DF6FF2D737FA22D8548736B7F23BC182659A12DEAB254ED4CA6C6`, + not a final Power source pin. The isolated data checks use Forge 50.2.0 classes but do not start the Forge mod loader or qualify Steam's production classes. The GameTest fixtures are diff --git a/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java b/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java index 01f5621..0af43f8 100644 --- a/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java +++ b/src/test/java/zone/moddev/mc/basesteam/testing/NativeTestBootstrap.java @@ -1,8 +1,6 @@ package zone.moddev.mc.basesteam.testing; import java.util.List; -import java.util.Optional; -import cpw.mods.modlauncher.api.IModuleLayerManager; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; @@ -11,8 +9,6 @@ import net.minecraft.server.Bootstrap; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.eventbus.api.Event; -import net.minecraftforge.fml.loading.FMLLoader; -import net.minecraftforge.fml.loading.LoadingModList; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistry; @@ -73,30 +69,10 @@ private static void invokeRegistryPhase(DeferredRegister register, String pha private static final class NativeRegistries { static { - initializeEmptyForgeDiscovery(); SharedConstants.tryDetectVersion(); Bootstrap.bootStrap(); } private static void ensureStarted() {} - - private static void initializeEmptyForgeDiscovery() { - if (FMLLoader.getLoadingModList() != null) return; - // Forge 50 lazily gathers item components through ForgeEventFactory. - // Plain JUnit has no launch discovery, so give the native loader an empty list. - var list = LoadingModList.of(List.of(), List.of(), null); - list.setBrokenFiles(List.of()); - try { - var field = FMLLoader.class.getDeclaredField("loadingModList"); - field.setAccessible(true); - field.set(null, list); - var layers = FMLLoader.class.getDeclaredField("moduleLayerManager"); - layers.setAccessible(true); - layers.set(null, (IModuleLayerManager) layer -> layer == IModuleLayerManager.Layer.GAME - ? Optional.of(ModuleLayer.empty()) : Optional.empty()); - } catch (ReflectiveOperationException exception) { - throw new IllegalStateException("Could not initialize the Forge 50 unit fixture", exception); - } - } } } From 8bfc4b59c377c6c0c316db40d6d49d2e931f685e Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 12:05:38 +0000 Subject: [PATCH 05/16] Pin Steam to the coordinated Forge 50 candidate --- README.md | 8 ++++--- build.gradle | 22 +++++++++++++++--- docs/PORT1206-STATUS.md | 14 +++++------ gradle.properties | 23 ++++++++++--------- src/main/resources/META-INF/mods.toml | 2 +- .../resources/BuildWorkflowContractTest.java | 3 ++- tools/run-packaged-server-smoke.ps1 | 2 +- 7 files changed, 47 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index b504950..c941147 100644 --- a/README.md +++ b/README.md @@ -16,18 +16,20 @@ ForgeGradle's Slime Launcher also locates a Java 8 toolchain while generating runs. The game itself runs on Java 21. Forge 50 uses official names at runtime. Steam does not run an SRG renamer. -The required dependency is basePower 2.4.13.120061. Base Metals 3.1.1.120061 is +The required dependency is basePower 2.4.13.120061. Base Metals 3.1.2.120061 is optional at runtime and uses OreSpawn 4.1.0.120061. The exact native companion jars serve as both development and player inputs. No dependency is embedded. The mod ID, data namespace, and registry paths remain `basesteam`. ## Local Verification -The default paths point to the coordinated local 1.20.6 checkouts. The +The default paths point to the coordinated local 1.20.6 checkouts, including +the Base Metals shared-hook checkout. The `*DeobfJar` project properties remain accepted path overrides even though the target uses native jars. For packaged checks, the `*PlayerJar` overrides are separate. Both paths must satisfy the pins in `gradle.properties`. -A pending Power pin fails closed. +The unit gate also verifies the Power bootstrap jar and both source hashes. +Absent or mismatched inputs fail closed. From this checkout in PowerShell, with the pinned local JDKs installed: diff --git a/build.gradle b/build.gradle index 0f5c4f4..d3920a4 100644 --- a/build.gradle +++ b/build.gradle @@ -215,7 +215,7 @@ repositories { // Only code and launch tasks require the exact jars; source/resource checks can run independently. def explicitJar = { String property -> providers.gradleProperty(property).map { file(it) }.getOrNull() } def powerRoot = '../../PowerAdvantage' -def baseMetalsRoot = '../../../../BaseMetals/BaseMetals 1206/BaseMetals' +def baseMetalsRoot = '../../../../BaseMetals/.verification-basemetals1206/Advantage shared hook' def powerNativeJar = file("${powerRoot}/build/libs/basePower-${project.poweradvantage_version}.jar") def powerAdvantageDeobfJar = explicitJar('powerAdvantageDeobfJar') ?: powerNativeJar def baseMetalsDeobfJar = explicitJar('baseMetalsDeobfJar') ?: file( @@ -269,10 +269,18 @@ def committedPin = { String key, pattern -> def forgeCapabilityBootstrapJar = providers.gradleProperty('forgeCapabilityBootstrapJar') .map { file(it) } .orElse(file("${powerRoot}/build/unit-bootstrap/forge-native-unit-bootstrap.jar")) +def unitBootstrapSources = [ + poweradvantage_test_bootstrap_source_sha256: explicitJar('forgeCapabilityBootstrapSource') ?: + file("${powerRoot}/test-rig/unit-bootstrap/ForgeCapabilityBootstrap.java"), + poweradvantage_test_registry_source_sha256: explicitJar('forgeUnitRegistriesSource') ?: + file("${powerRoot}/test-rig/unit-support/zone/moddev/mc/advantageworks/unit/ForgeUnitRegistries.java") +] tasks.named('test', Test) { useJUnit() inputs.files(forgeCapabilityBootstrapJar) + inputs.files(unitBootstrapSources.values()) inputs.property('powerBootstrapSha256', providers.gradleProperty('poweradvantage_test_bootstrap_sha256')) + unitBootstrapSources.keySet().each { inputs.property(it, providers.gradleProperty(it)) } doFirst { File bootstrapJar = forgeCapabilityBootstrapJar.getOrNull() if (bootstrapJar == null || !bootstrapJar.isFile()) { @@ -284,6 +292,14 @@ tasks.named('test', Test) { if (actualHash != expectedHash) { throw new GradleException("basePower test bootstrap SHA-256 is ${actualHash}, expected ${expectedHash}") } + unitBootstrapSources.each { key, source -> + String expected = committedPin(key, /[A-F0-9]{64}/) + if (!source.isFile() || MessageDigest.getInstance('SHA-256').digest(source.bytes) + .encodeHex().toString().toUpperCase(Locale.ROOT) != expected) { + throw new GradleException("Missing or mismatched basePower test source: ${source} (expected ${expected})") + } + logger.lifecycle("basePower test source: ${source.canonicalPath} SHA-256 ${expected}") + } new ZipFile(bootstrapJar).withCloseable { zip -> def manifest = new Manifest(zip.getInputStream(zip.getEntry('META-INF/MANIFEST.MF'))).mainAttributes if (manifest.getValue('Premain-Class') != 'zone.moddev.mc.advantageworks.unit.ForgeCapabilityBootstrap') { @@ -447,7 +463,7 @@ tasks.register('verifyReleaseConfiguration') { || project.cf_versions != '1.20.6') { throw new GradleException('Unexpected CurseForge dependency or game-version metadata') } - if (project.basemetals_version != '3.1.1.120061' + if (project.basemetals_version != '3.1.2.120061' || project.orespawn_version != '4.1.0.120061') { throw new GradleException('Unexpected development API versions') } @@ -463,7 +479,7 @@ tasks.register('verifyReleaseConfiguration') { String metadata = file('src/main/resources/META-INF/mods.toml').getText('UTF-8').replace('\r\n', '\n') ['modId="basesteam"', 'displayName="baseSteam"', 'modId="basepower"\nmandatory=true\nversionRange="[${poweradvantage_version},3.0.0)"', - 'modId="basemetals"\nmandatory=false\nversionRange="[3.1.1.120061,4.0.0)"'].each { marker -> + 'modId="basemetals"\nmandatory=false\nversionRange="[3.1.2.120061,4.0.0)"'].each { marker -> if (!metadata.contains(marker)) { throw new GradleException("Source mods.toml is missing ${marker}") } diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index 34456d9..6a98373 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -10,15 +10,15 @@ | Input | Commit | Local native jar SHA-256 | | --- | --- | --- | -| basePower 2.4.13.120061 | Pending final pin | Pending final pin | -| Base Metals 3.1.1.120061 | `ea326ef35c0b463d6297e374a53d5ddbfe4041af` | `08AC265C7284D18962A3DE91B7C267187AEF76ACF6AFE7BBA0729F5CED60A437` | +| basePower 2.4.13.120061 | `5fdbb2c2b2d9bbc760aca3919e5b5b648f4545e2` | `E192657CC426BC8CD0E3809F6CBF53A135E5C49C6E34A8936DE2DD034D701A04` | +| Base Metals 3.1.2.120061 (local shared hook) | `0c2cdd4d0e8c3bf2e5fa234d49e57960bbf80bde` | `FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417` | | OreSpawn 4.1.0.120061 | `4085315345ff043448b316d75e03f4b8da45402d` | `FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26` | -The companions were read from their 1.20.6 checkouts' `build/libs` -directories. Their hashes and Forge/Java manifest identities passed both local -development and player checks. Steam's audit requires the actual Power commit, -native jar and test-bootstrap pins. It rejects pin overrides and does not use -any 1.20.1 or newer 1.20.6 mod artifacts. +The native jars serve as both development and packaged inputs. The Power +JUnit bootstrap is pinned to +`96752A443070E117EED9308ABC9C2009BD3533F121C9594A7108908E104673C9`; +both bootstrap source hashes are recorded in `gradle.properties`. +No dependency is embedded or promoted to a publication claim. ## Evidence diff --git a/gradle.properties b/gradle.properties index 3f0f9e5..3a0cba1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,17 +38,18 @@ cf_versions=1.20.6 poweradvantage_version=2.4.13.120061 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower # Exact local checkpoints for coordinated testing, not published source pins. -poweradvantage_source_ref=PENDING -poweradvantage_deobf_sha256=PENDING -# Player jar is a separate runtime input, not a development jar or publication claim. -poweradvantage_player_sha256=PENDING -poweradvantage_test_bootstrap_sha256=PENDING -poweradvantage_test_bootstrap_source_sha256=PENDING - -basemetals_version=3.1.1.120061 -basemetals_source_commit=ea326ef35c0b463d6297e374a53d5ddbfe4041af -basemetals_deobf_sha256=08AC265C7284D18962A3DE91B7C267187AEF76ACF6AFE7BBA0729F5CED60A437 -basemetals_player_sha256=08AC265C7284D18962A3DE91B7C267187AEF76ACF6AFE7BBA0729F5CED60A437 +poweradvantage_source_ref=5fdbb2c2b2d9bbc760aca3919e5b5b648f4545e2 +poweradvantage_deobf_sha256=E192657CC426BC8CD0E3809F6CBF53A135E5C49C6E34A8936DE2DD034D701A04 +# Forge 50 uses the same native jar for development and packaged runtime. +poweradvantage_player_sha256=E192657CC426BC8CD0E3809F6CBF53A135E5C49C6E34A8936DE2DD034D701A04 +poweradvantage_test_bootstrap_sha256=96752A443070E117EED9308ABC9C2009BD3533F121C9594A7108908E104673C9 +poweradvantage_test_bootstrap_source_sha256=9E0EFE07A889726489810AA960FECD0387F35B6BF44085E03C68EEE011D62693 +poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF56CD6203C9CD692CAC1531D0981F + +basemetals_version=3.1.2.120061 +basemetals_source_commit=0c2cdd4d0e8c3bf2e5fa234d49e57960bbf80bde +basemetals_deobf_sha256=FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417 +basemetals_player_sha256=FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417 orespawn_version=4.1.0.120061 orespawn_source_commit=4085315345ff043448b316d75e03f4b8da45402d diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 75e873c..df9c59a 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -21,7 +21,7 @@ side="BOTH" [[dependencies.basesteam]] modId="basemetals" mandatory=false -versionRange="[3.1.1.120061,4.0.0)" +versionRange="[3.1.2.120061,4.0.0)" ordering="AFTER" side="BOTH" diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java index 3adc3aa..db80934 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java @@ -20,7 +20,8 @@ public class BuildWorkflowContractTest { assertEquals("2.4.13.120061", pins.getProperty("poweradvantage_version")); for (String key : new String[] {"poweradvantage_source_ref", "poweradvantage_deobf_sha256", "poweradvantage_player_sha256", "poweradvantage_test_bootstrap_sha256", - "poweradvantage_test_bootstrap_source_sha256", "basemetals_source_commit", "basemetals_deobf_sha256", + "poweradvantage_test_bootstrap_source_sha256", "poweradvantage_test_registry_source_sha256", + "basemetals_source_commit", "basemetals_deobf_sha256", "basemetals_player_sha256", "orespawn_source_commit", "orespawn_deobf_sha256", "orespawn_player_sha256"}) { assertTrue(key, pins.getProperty(key, "").matches( diff --git a/tools/run-packaged-server-smoke.ps1 b/tools/run-packaged-server-smoke.ps1 index 649e0a1..8e2f4ba 100644 --- a/tools/run-packaged-server-smoke.ps1 +++ b/tools/run-packaged-server-smoke.ps1 @@ -34,7 +34,7 @@ if (!$PowerJar) { $PowerJar = Join-Path $project "../../PowerAdvantage/build/libs/basePower-$($pins.poweradvantage_version).jar" } if (!$BaseMetalsJar) { - $BaseMetalsJar = Join-Path $project "../../../../BaseMetals/BaseMetals 1206/BaseMetals/build/libs/BaseMetals-$($pins.basemetals_version).jar" + $BaseMetalsJar = Join-Path $project "../../../../BaseMetals/.verification-basemetals1206/Advantage shared hook/build/libs/BaseMetals-$($pins.basemetals_version).jar" } if (!$OreSpawnJar) { $OreSpawnJar = Join-Path $project "../../../../MinecraftMineralogy/OS1206/OreSpawn/build/libs/OreSpawn-$($pins.orespawn_version).jar" From 756fd62385806644c2475fe6a4d9cbe9290b12d7 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 12:06:16 +0000 Subject: [PATCH 06/16] Build the development jar before auditing Steam archives --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index d3920a4..178ff2b 100644 --- a/build.gradle +++ b/build.gradle @@ -639,6 +639,7 @@ tasks.register('verifyReleaseArtifacts') { description = 'Audits the exact three distributable jars and release-critical contents.' dependsOn tasks.named('verifyReleaseDependencies') dependsOn tasks.named('assemble') + dependsOn tasks.named('jar') doLast { File libs = layout.buildDirectory.dir('libs').get().asFile List jars = (libs.listFiles() ?: [] as File[]) From dd64db984954cbce93f602f4a7b951055888197f Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 12:10:34 +0000 Subject: [PATCH 07/16] Run Steam GameTests in a fresh Forge 50 fixture --- build.gradle | 29 ++++++++++++++----- ci-fixtures/steam-gametest-server.properties | 7 +++++ .../gametest/SteamNativeGameTests.java | 8 ++--- 3 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 ci-fixtures/steam-gametest-server.properties diff --git a/build.gradle b/build.gradle index 178ff2b..16fa8a4 100644 --- a/build.gradle +++ b/build.gradle @@ -103,6 +103,12 @@ configurations { gameTestValidationRuntimeOnly.extendsFrom runtimeOnly } +def steamGameTestRunDirectory = layout.buildDirectory.dir( + providers.gradleProperty('steamGameTestRunId').orElse('run').map { runId -> + if (!(runId ==~ /[A-Za-z0-9_-]+/)) throw new GradleException('Invalid Steam GameTest run ID') + "steam-gametest-${runId}" + }) + minecraft { if (gradle.startParameter.offline) { mavenizerArguments.add('--offline') @@ -124,9 +130,7 @@ minecraft { args '--nogui' } register('gameTestServer') { - String runId = providers.gradleProperty('steamGameTestRunId').getOrElse('run') - if (!(runId ==~ /[A-Za-z0-9_-]+/)) throw new GradleException('Invalid Steam GameTest run ID') - workingDir.set(layout.buildDirectory.dir("steam-gametest-${runId}")) + workingDir.set(steamGameTestRunDirectory) systemProperty 'forge.enableGameTest', 'true' systemProperty 'forge.enabledGameTestNamespaces', mod_id mods { basesteam { source sourceSets.gameTestValidation } } @@ -169,8 +173,12 @@ tasks.withType(JavaExec).configureEach { dependsOn gameTest ? prepareForgeGameTestModClasses : prepareForgeRunModClasses environment 'MOD_CLASSES', "${mod_id}%%${mergedOutput.get().asFile.absolutePath}" doFirst { - if (gameTest && new File(workingDir, 'logs/latest.log').exists()) { - throw new GradleException('Choose a fresh -PsteamGameTestRunId to preserve the existing receipt') + File runDirectory = gameTest ? steamGameTestRunDirectory.get().asFile : workingDir + if (gameTest) { + if (new File(runDirectory, 'logs/latest.log').exists()) { + throw new GradleException("Choose a fresh -PsteamGameTestRunId to preserve ${runDirectory}") + } + workingDir(runDirectory) } if (name == 'runClient') setArgs(['--launcher-side', 'client'] + args) Set splitOutputs = [sourceSets.main, sourceSets.gameTestValidation].collectMany { @@ -179,11 +187,18 @@ tasks.withType(JavaExec).configureEach { classpath = files(mergedOutput.get().asFile, classpath.files.findAll { !splitOutputs.contains(it.canonicalFile) }) - new File(workingDir, 'mods').mkdirs() + new File(runDirectory, 'mods').mkdirs() + if (gameTest) { + File settings = new File(runDirectory, 'server.properties') + if (!settings.exists()) { + java.nio.file.Files.copy(file('ci-fixtures/steam-gametest-server.properties').toPath(), + settings.toPath()) + } + } } if (gameTest) doLast { // Forge can exit zero after a loader failure; require the actual test result. - File receipt = new File(workingDir, 'logs/latest.log') + File receipt = new File(steamGameTestRunDirectory.get().asFile, 'logs/latest.log') String output = receipt.isFile() ? receipt.getText('UTF-8') : '' if (!output.contains('All 4 required tests passed') || (output =~ /\[[^\]\r\n]*\/(?:ERROR|FATAL)\]/).find()) { throw new GradleException("The four Steam GameTests did not pass; see ${receipt}") diff --git a/ci-fixtures/steam-gametest-server.properties b/ci-fixtures/steam-gametest-server.properties new file mode 100644 index 0000000..b1a5e01 --- /dev/null +++ b/ci-fixtures/steam-gametest-server.properties @@ -0,0 +1,7 @@ +server-ip=127.0.0.1 +server-port=0 +level-type=minecraft:flat +generate-structures=false +view-distance=2 +simulation-distance=2 +generator-settings={"layers":[{"height":1,"block":"minecraft:bedrock"},{"height":2,"block":"minecraft:dirt"},{"height":1,"block":"minecraft:grass_block"}],"biome":"minecraft:plains"} diff --git a/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java b/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java index afe8620..837a33d 100644 --- a/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java +++ b/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java @@ -41,7 +41,7 @@ public final class SteamNativeGameTests { private SteamNativeGameTests() {} - @GameTest(template = "basesteam_empty") + @GameTest(batch = SteamAdvantage.MODID, template = "basesteam_empty") public static void drillBitPacketPreservesTypePositionAndDirection(GameTestHelper helper) { BlockPos local = new BlockPos(1, 1, 1); helper.setBlock(local, Blocks.drillbit); @@ -66,7 +66,7 @@ public static void drillBitPacketPreservesTypePositionAndDirection(GameTestHelpe helper.succeed(); } - @GameTest(template = "basesteam_empty") + @GameTest(batch = SteamAdvantage.MODID, template = "basesteam_empty") public static void legacyMusketWearAndLoadedByteSurviveNativeComponentization(GameTestHelper helper) { CompoundTag legacy = new CompoundTag(); legacy.putString("id", "basesteam:musket"); @@ -92,7 +92,7 @@ public static void legacyMusketWearAndLoadedByteSurviveNativeComponentization(Ga helper.succeed(); } - @GameTest(template = "basesteam_empty") + @GameTest(batch = SteamAdvantage.MODID, template = "basesteam_empty") public static void olderMusketAliasAndTopLevelWearSurvivePowerMigration(GameTestHelper helper) { CompoundTag legacy = new CompoundTag(); legacy.putString("id", "steamadvantage:musket"); @@ -109,7 +109,7 @@ public static void olderMusketAliasAndTopLevelWearSurvivePowerMigration(GameTest helper.succeed(); } - @GameTest(template = "basesteam_empty") + @GameTest(batch = SteamAdvantage.MODID, template = "basesteam_empty") public static void nativeResourcesLoadWithExpectedIds(GameTestHelper helper) { var level = helper.getLevel(); var registries = level.registryAccess(); From f598839e7fa129fbd187bf0f0ddaa3a49589c100 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 12:13:06 +0000 Subject: [PATCH 08/16] Record exact Steam candidate qualification --- build.gradle | 19 ++++++++++++++----- docs/PORT1206-STATUS.md | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 16fa8a4..a61c914 100644 --- a/build.gradle +++ b/build.gradle @@ -1003,15 +1003,24 @@ tasks.register('isolateEclipseProductionRuns') { if (launch.name in ['runClient.launch', 'runServer.launch', 'runData.launch']) { // Eclipse compiles into bin/main, not Gradle's merged run output. def launchXml = new groovy.xml.XmlParser().parseText(contents) - def modClasses = launchXml.mapAttribute.find { + def environmentVariables = launchXml.mapAttribute.find { it.@key == 'org.eclipse.debug.core.environmentVariables' - }.mapEntry.findAll { it.@key == 'MOD_CLASSES' } - if (modClasses.size() != 1) { - throw new GradleException("${launch.name} must define one MOD_CLASSES entry") + } + if (environmentVariables == null) { + environmentVariables = launchXml.appendNode('mapAttribute', + [key: 'org.eclipse.debug.core.environmentVariables']) + } + def modClasses = environmentVariables.mapEntry.findAll { it.@key == 'MOD_CLASSES' } + if (modClasses.size() > 1) { + throw new GradleException("${launch.name} must not duplicate MOD_CLASSES") } String mainOutput = file('bin/main').absolutePath String eclipseModClasses = "${project.mod_id}%%${mainOutput}" - modClasses[0].@value = eclipseModClasses + if (modClasses.isEmpty()) { + environmentVariables.appendNode('mapEntry', [key: 'MOD_CLASSES', value: eclipseModClasses]) + } else { + modClasses[0].@value = eclipseModClasses + } if (launch.name == 'runClient.launch') { def programArguments = launchXml.stringAttribute.find { it.@key == 'org.eclipse.jdt.launching.PROGRAM_ARGUMENTS' diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index 6a98373..da2ec52 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -20,7 +20,34 @@ JUnit bootstrap is pinned to both bootstrap source hashes are recorded in `gradle.properties`. No dependency is embedded or promoted to a publication claim. -## Evidence +## Exact Candidate Verification + +The frozen `baseSteam-2.2.14.120061.jar` is in +`evidence/steam1206-exact-5fdbb2c/candidate/`. It was built from Steam commit +`756fd62385806644c2475fe6a4d9cbe9290b12d7` and has SHA-256 +`5DDABC83B01A8CC8BAE3188BAAACE01BDCF6F756B7049DADF1ADAA3F9CF480FD`. +Later commits only changed verification, Eclipse generation, and documentation. +The ordinary `build/libs` jar matched the frozen bytes before and after both +packaged runs. + +| Gate | Result | Receipt | +| --- | --- | --- | +| Exact development and player dependencies; archive audit | Passed | `evidence/steam1206-exact-5fdbb2c/build-audit-b.log` and `input-checksums.json` | +| Full Gradle suite | 221 JUnit tests passed, none failed or skipped; asset, recipe, and repository checks passed | `evidence/steam1206-exact-5fdbb2c/full-suite.log` and `junit-summary.json` | +| Forge 50 development GameTests | All four required tests passed; no ERROR/FATAL records | `evidence/steam1206-exact-5fdbb2c/gametest-c-server.log` | +| Packaged Forge dedicated server, with Base Metals | Clean boot and shutdown | `evidence/packaged-server-exact-5fdbb2c-with-basemetals/receipt.json` | +| Packaged Forge dedicated server, without Base Metals | Clean boot and shutdown; OreSpawn retained | `evidence/packaged-server-exact-5fdbb2c-without-basemetals/receipt.json` | +| Eclipse generation and production classpath | Passed; no Eclipse client was launched | `evidence/steam1206-exact-5fdbb2c/eclipse-b.log` | +| Source parity | All 33 recipes and 24 unlocks verified; block loot and harvest tags unchanged | `evidence/steam1206-exact-5fdbb2c/static-parity.log` | + +The initial archive audit lacked a task dependency on the development jar. +The two initial GameTest runs stopped before tests on scratch-directory and +batch selection issues; the final run seeded server properties and used the +explicit `basesteam` batch. Initial Eclipse generation omitted `MOD_CLASSES`. +These are verification fixes, not production changes. Failed attempts remain +in the evidence directory alongside the passing receipts. + +## Provisional Evidence - `build-steam1206-companions.log`: initial offline cache-only rejection. - `build-steam1206-companions-normal.log`: Forge configured, then the stale @@ -91,7 +118,7 @@ The ASM side contract checks this without pretending to substitute for a packaged dedicated launch. The smoke script copies the checked Forge install and pinned player artifacts into a new, disposable Steam evidence directory. -Exact pinned build, full unit suite, GameTest and packaged runtime remain -separate gates. Do not promote the provisional Power artifact to a final -pin. Manual client, multiplayer and historical world acceptance require -their own evidence. +The exact candidate above is ready for shared live validation, not manual +acceptance. Combined Power/Steam/Electric validation, manual client and +multiplayer checks, and historical world acceptance require their own +evidence. No release or publication was performed. From 23cb29f9328bc52ebb0a95ae4df7f7e765cf71b7 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 12:24:43 +0000 Subject: [PATCH 09/16] Repin Steam to the Power datapack loot fix --- gradle.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 3a0cba1..a0cb0d0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,10 +38,10 @@ cf_versions=1.20.6 poweradvantage_version=2.4.13.120061 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower # Exact local checkpoints for coordinated testing, not published source pins. -poweradvantage_source_ref=5fdbb2c2b2d9bbc760aca3919e5b5b648f4545e2 -poweradvantage_deobf_sha256=E192657CC426BC8CD0E3809F6CBF53A135E5C49C6E34A8936DE2DD034D701A04 +poweradvantage_source_ref=75297fd9f4ce679aca95c2948e81bbef7633b976 +poweradvantage_deobf_sha256=29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181 # Forge 50 uses the same native jar for development and packaged runtime. -poweradvantage_player_sha256=E192657CC426BC8CD0E3809F6CBF53A135E5C49C6E34A8936DE2DD034D701A04 +poweradvantage_player_sha256=29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181 poweradvantage_test_bootstrap_sha256=96752A443070E117EED9308ABC9C2009BD3533F121C9594A7108908E104673C9 poweradvantage_test_bootstrap_source_sha256=9E0EFE07A889726489810AA960FECD0387F35B6BF44085E03C68EEE011D62693 poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF56CD6203C9CD692CAC1531D0981F From ff7db2555ad4e33a1b3616bb15debd00e6180ac3 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 12:27:58 +0000 Subject: [PATCH 10/16] Record Steam qualification after the Power loot repin --- docs/PORT1206-STATUS.md | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index da2ec52..a605fdd 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -10,7 +10,7 @@ | Input | Commit | Local native jar SHA-256 | | --- | --- | --- | -| basePower 2.4.13.120061 | `5fdbb2c2b2d9bbc760aca3919e5b5b648f4545e2` | `E192657CC426BC8CD0E3809F6CBF53A135E5C49C6E34A8936DE2DD034D701A04` | +| basePower 2.4.13.120061 | `75297fd9f4ce679aca95c2948e81bbef7633b976` | `29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181` | | Base Metals 3.1.2.120061 (local shared hook) | `0c2cdd4d0e8c3bf2e5fa234d49e57960bbf80bde` | `FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417` | | OreSpawn 4.1.0.120061 | `4085315345ff043448b316d75e03f4b8da45402d` | `FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26` | @@ -20,13 +20,40 @@ JUnit bootstrap is pinned to both bootstrap source hashes are recorded in `gradle.properties`. No dependency is embedded or promoted to a publication claim. -## Exact Candidate Verification +## Repinned Candidate Verification + +Steam commit `23cb29f9328bc52ebb0a95ae4df7f7e765cf71b7` pins the Power +datapack loot fix. Steam production sources, the bootstrap, Base Metals and +OreSpawn did not change. A forced rebuild and direct byte comparison confirmed +that the Steam jar is identical to the first exact candidate: +`5DDABC83B01A8CC8BAE3188BAAACE01BDCF6F756B7049DADF1ADAA3F9CF480FD`. + +The current frozen artifact is +`evidence/steam1206-exact-75297fd/candidate/baseSteam-2.2.14.120061.jar`. +Its receipt records both Power and Steam hashes and the byte comparison. + +| Gate | Result | Receipt | +| --- | --- | --- | +| Forced rebuild, exact development and player inputs, archive audit | Passed | `evidence/steam1206-exact-75297fd/build-audit.log` and `input-checksums.json` | +| Full Gradle and Eclipse checks | 221 JUnit tests passed; no failures or skips | `evidence/steam1206-exact-75297fd/full-suite.log` and `junit-summary.json` | +| Forge development GameTests | All four passed | `evidence/steam1206-exact-75297fd/gametest-server.log` | +| Packaged dedicated server | Clean boot and shutdown in both profiles | `evidence/packaged-server-exact-75297fd-with-basemetals/receipt.json` and `evidence/packaged-server-exact-75297fd-without-basemetals/receipt.json` | +| Source parity | 33 recipes and 24 unlocks verified; block loot and harvest tags unchanged | `evidence/steam1206-exact-75297fd/static-parity.log` | + +## First Exact Snapshot + +These receipts apply to Power commit `5fdbb2c2b2d9bbc760aca3919e5b5b648f4545e2` +and jar SHA-256 `E192657CC426BC8CD0E3809F6CBF53A135E5C49C6E34A8936DE2DD034D701A04`. +The Steam checks below passed for that snapshot. Integrated results on that +Power jar remain provisional because live progression found that an overridden +dungeon loot table was augmented. No old receipt was promoted or replaced. The frozen `baseSteam-2.2.14.120061.jar` is in `evidence/steam1206-exact-5fdbb2c/candidate/`. It was built from Steam commit `756fd62385806644c2475fe6a4d9cbe9290b12d7` and has SHA-256 `5DDABC83B01A8CC8BAE3188BAAACE01BDCF6F756B7049DADF1ADAA3F9CF480FD`. -Later commits only changed verification, Eclipse generation, and documentation. +Before the repin, later Steam commits changed only verification, Eclipse +generation, and documentation. The ordinary `build/libs` jar matched the frozen bytes before and after both packaged runs. @@ -118,7 +145,7 @@ The ASM side contract checks this without pretending to substitute for a packaged dedicated launch. The smoke script copies the checked Forge install and pinned player artifacts into a new, disposable Steam evidence directory. -The exact candidate above is ready for shared live validation, not manual +The `75297fd` candidate is ready for shared endurance, not manual acceptance. Combined Power/Steam/Electric validation, manual client and multiplayer checks, and historical world acceptance require their own evidence. No release or publication was performed. From e023a2f349ee1aa06ef874ae99242b47b5a6ca68 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 12:37:32 +0000 Subject: [PATCH 11/16] Pin Steam to final Power and Base Metals candidates --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index a0cb0d0..454d5a1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,7 +38,7 @@ cf_versions=1.20.6 poweradvantage_version=2.4.13.120061 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower # Exact local checkpoints for coordinated testing, not published source pins. -poweradvantage_source_ref=75297fd9f4ce679aca95c2948e81bbef7633b976 +poweradvantage_source_ref=e6ecfb341006186d0adba9dcc3f296297cd34aec poweradvantage_deobf_sha256=29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181 # Forge 50 uses the same native jar for development and packaged runtime. poweradvantage_player_sha256=29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181 @@ -47,9 +47,9 @@ poweradvantage_test_bootstrap_source_sha256=9E0EFE07A889726489810AA960FECD0387F3 poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF56CD6203C9CD692CAC1531D0981F basemetals_version=3.1.2.120061 -basemetals_source_commit=0c2cdd4d0e8c3bf2e5fa234d49e57960bbf80bde -basemetals_deobf_sha256=FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417 -basemetals_player_sha256=FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417 +basemetals_source_commit=9e706db5c85fa2bc7f36dee94f39a5f2fa8ab367 +basemetals_deobf_sha256=6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D +basemetals_player_sha256=6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D orespawn_version=4.1.0.120061 orespawn_source_commit=4085315345ff043448b316d75e03f4b8da45402d From cb094004cdd3081e66868e187d48580ead172183 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 12:41:09 +0000 Subject: [PATCH 12/16] Record Steam qualification on final local pins --- docs/PORT1206-STATUS.md | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index a605fdd..fa28756 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -10,8 +10,8 @@ | Input | Commit | Local native jar SHA-256 | | --- | --- | --- | -| basePower 2.4.13.120061 | `75297fd9f4ce679aca95c2948e81bbef7633b976` | `29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181` | -| Base Metals 3.1.2.120061 (local shared hook) | `0c2cdd4d0e8c3bf2e5fa234d49e57960bbf80bde` | `FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417` | +| basePower 2.4.13.120061 | `e6ecfb341006186d0adba9dcc3f296297cd34aec` | `29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181` | +| Base Metals 3.1.2.120061 (local shared hook) | `9e706db5c85fa2bc7f36dee94f39a5f2fa8ab367` | `6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D` | | OreSpawn 4.1.0.120061 | `4085315345ff043448b316d75e03f4b8da45402d` | `FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26` | The native jars serve as both development and packaged inputs. The Power @@ -20,7 +20,29 @@ JUnit bootstrap is pinned to both bootstrap source hashes are recorded in `gradle.properties`. No dependency is embedded or promoted to a publication claim. -## Repinned Candidate Verification +## Final Repin Verification + +Steam commit `e023a2f349ee1aa06ef874ae99242b47b5a6ca68` updates the Power source +pin and the Base Metals source and jar pins. The Power native jar, unit test +bootstrap and its sources, and OreSpawn are unchanged. All checks below used +the frozen inputs in `evidence/steam1206-exact-e6ecfb3/inputs/`, including the +Base Metals jar from `evidence/player-pre-components-20261110/candidate/` in +the local shared-hook checkout. + +The Steam release, sources and Javadoc jars and their `SHA256SUMS` are frozen +in `evidence/steam1206-exact-e6ecfb3/candidate/`. Direct byte comparisons of the +native Steam jar against both earlier exact Steam jars passed. Its SHA-256 is +`5DDABC83B01A8CC8BAE3188BAAACE01BDCF6F756B7049DADF1ADAA3F9CF480FD`. + +| Gate | Result | Receipt | +| --- | --- | --- | +| Forced rebuild, exact development and player inputs, release archive audit | Passed | `evidence/steam1206-exact-e6ecfb3/build-audit.log`, `input-checksums.json` and `candidate/candidate-receipt.json` | +| Full Gradle suite, Java 21 and Eclipse production classpath | 221 JUnit tests passed; no failures or skips; Eclipse generation and audit passed | `evidence/steam1206-exact-e6ecfb3/full-suite.log` and `junit-summary.json` | +| Forge 50.2.0 development GameTests | All four passed, no ERROR/FATAL records | `evidence/steam1206-exact-e6ecfb3/gametest-server.log` | +| Packaged Forge 50.2.0 dedicated server | Clean boot and shutdown with and without Base Metals; OreSpawn retained in both | `evidence/packaged-server-exact-e6ecfb3-with-basemetals/receipt.json` and `evidence/packaged-server-exact-e6ecfb3-without-basemetals/receipt.json` | +| Native source and recipe unlock checks | Passed; all 24 unlocks verified, no source or resource changes since the previous repin | `evidence/steam1206-exact-e6ecfb3/static-checks.log` | + +## Power Loot Fix Snapshot Steam commit `23cb29f9328bc52ebb0a95ae4df7f7e765cf71b7` pins the Power datapack loot fix. Steam production sources, the bootstrap, Base Metals and @@ -28,7 +50,7 @@ OreSpawn did not change. A forced rebuild and direct byte comparison confirmed that the Steam jar is identical to the first exact candidate: `5DDABC83B01A8CC8BAE3188BAAACE01BDCF6F756B7049DADF1ADAA3F9CF480FD`. -The current frozen artifact is +The frozen artifact from this snapshot is `evidence/steam1206-exact-75297fd/candidate/baseSteam-2.2.14.120061.jar`. Its receipt records both Power and Steam hashes and the byte comparison. @@ -145,7 +167,7 @@ The ASM side contract checks this without pretending to substitute for a packaged dedicated launch. The smoke script copies the checked Forge install and pinned player artifacts into a new, disposable Steam evidence directory. -The `75297fd` candidate is ready for shared endurance, not manual +The `e6ecfb3` candidate is ready for shared endurance, not manual acceptance. Combined Power/Steam/Electric validation, manual client and multiplayer checks, and historical world acceptance require their own evidence. No release or publication was performed. From b611186aea6e338403cd1ea2a63b1ac35c23a5f3 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 13:15:29 +0000 Subject: [PATCH 13/16] Record the combined 1.20.6 test results --- docs/PORT1206-STATUS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index fa28756..87878db 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -167,7 +167,7 @@ The ASM side contract checks this without pretending to substitute for a packaged dedicated launch. The smoke script copies the checked Forge install and pinned player artifacts into a new, disposable Steam evidence directory. -The `e6ecfb3` candidate is ready for shared endurance, not manual -acceptance. Combined Power/Steam/Electric validation, manual client and -multiplayer checks, and historical world acceptance require their own -evidence. No release or publication was performed. +The jar pinned to Power `e6ecfb3` passed the combined 21-station rig and +the two 30-minute runs on fresh and migrated worlds, including a full +restart. The combined Eclipse client also passed its resource and screen +checks. It is ready for manual testing on a disposable copy, not a release. From a2a56a37eff281aaedadcb87f9c12ccc57d614c3 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 14:14:02 +0000 Subject: [PATCH 14/16] Use the corrected basePower fluid gauge build --- build.gradle | 2 +- gradle.properties | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index a61c914..486d147 100644 --- a/build.gradle +++ b/build.gradle @@ -1296,7 +1296,7 @@ tasks.register('verifyModelAssets') { File steamAtlas = new File(resourceRoot, blocksAtlasPath) inputs.dir(assetRoot) inputs.files(fileTree(resourceRoot) { include blocksAtlasPath }) - inputs.files(providers.gradleProperty('powerAdvantageDeobfJar').map { file(it) }) + inputs.file(powerAdvantageDeobfJar) doLast { fileTree(assetRoot) { include '**/*.json' }.files.sort().each { File jsonFile -> diff --git a/gradle.properties b/gradle.properties index 454d5a1..2649cb7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,10 +38,10 @@ cf_versions=1.20.6 poweradvantage_version=2.4.13.120061 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower # Exact local checkpoints for coordinated testing, not published source pins. -poweradvantage_source_ref=e6ecfb341006186d0adba9dcc3f296297cd34aec -poweradvantage_deobf_sha256=29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181 +poweradvantage_source_ref=41427a5260658fd452477c88498e7ff82552e48a +poweradvantage_deobf_sha256=E53BDD64776741B2EBAE36A646049DC98487E1BAD1CF69F1E3FCD95188F907F1 # Forge 50 uses the same native jar for development and packaged runtime. -poweradvantage_player_sha256=29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181 +poweradvantage_player_sha256=E53BDD64776741B2EBAE36A646049DC98487E1BAD1CF69F1E3FCD95188F907F1 poweradvantage_test_bootstrap_sha256=96752A443070E117EED9308ABC9C2009BD3533F121C9594A7108908E104673C9 poweradvantage_test_bootstrap_source_sha256=9E0EFE07A889726489810AA960FECD0387F35B6BF44085E03C68EEE011D62693 poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF56CD6203C9CD692CAC1531D0981F From 91e14a3ba1ce99d3d8455f6ccf631a7b498090ad Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 14:30:55 +0000 Subject: [PATCH 15/16] Prepare baseSteam for the Minecraft 1.20.6 release --- .github/verify-published-pins.sh | 63 +++++--- .github/workflows/ci.yml | 146 ++++++------------ .github/workflows/codeql-analysis.yml | 116 ++++---------- .github/workflows/validate-gradle-build.yml | 6 +- CHANGELOG.txt | 5 +- README.md | 4 +- gradle.properties | 10 +- .../resources/BuildWorkflowContractTest.java | 18 ++- 8 files changed, 150 insertions(+), 218 deletions(-) diff --git a/.github/verify-published-pins.sh b/.github/verify-published-pins.sh index d8b13b8..a949ce1 100644 --- a/.github/verify-published-pins.sh +++ b/.github/verify-published-pins.sh @@ -6,28 +6,55 @@ value() { sed -n "s/^$1=//p" gradle.properties | tr -d '\r'; } require_merged() { local repo="$1" ref="$2" status [[ "$ref" =~ ^[a-f0-9]{40}$ ]] - status="$(gh api "repos/MinecraftModDevelopmentMods/$repo/compare/$ref...master-1.20.1" --jq '.status')" + status="$(gh api "repos/MinecraftModDevelopmentMods/$repo/compare/$ref...master-1.20.6" --jq '.status')" case "$status" in identical|ahead) ;; - *) echo "::error::$repo $ref is not on upstream master-1.20.1 ($status)."; exit 1 ;; + *) echo "::error::$repo $ref is not on upstream master-1.20.6 ($status)."; exit 1 ;; esac } -file_id="$(value poweradvantage_public_file_id)" -expected="$(value poweradvantage_player_sha256)" -if [[ ! "$file_id" =~ ^[1-9][0-9]*$ || ! "$expected" =~ ^[A-F0-9]{64}$ ]]; then - echo '::error::A verified public basePower 1.20.1 file ID and player checksum are required.' - exit 1 -fi -require_merged basePower "$(value poweradvantage_source_ref)" +download() { + local url="$1" expected="$2" path="$3" + [[ "$expected" =~ ^[A-F0-9]{64}$ ]] + curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' \ + --retry 3 --output "$path" "$url" + printf '%s %s\n' "$expected" "$path" | sha256sum -c - +} + +public_jar() { + local name="$1" project="$2" id="$3" sha="$4" jar="$5" + if [[ ! "$id" =~ ^[1-9][0-9]*$ ]]; then + echo "::error::A verified public $name file ID is required." + exit 1 + fi + download "https://www.curseforge.com/api/v1/mods/$project/files/$id/download" "$sha" "$jar" +} + +power_ref="$(value poweradvantage_source_ref)" +orespawn_ref="$(value orespawn_source_commit)" +require_merged basePower "$power_ref" require_merged BaseMetals "$(value basemetals_source_commit)" +require_merged OreSpawn "$orespawn_ref" + +inputs="${RUNNER_TEMP:?}/forge50-release-dependencies" +mkdir -p "$inputs" +power="$inputs/basePower-$(value poweradvantage_version).jar" +metals="$inputs/BaseMetals-$(value basemetals_version).jar" +orespawn="$inputs/OreSpawn-$(value orespawn_version).jar" +public_jar basePower 1780140 "$(value poweradvantage_public_file_id)" "$(value poweradvantage_deobf_sha256)" "$power" +public_jar BaseMetals 240967 "$(value basemetals_public_file_id)" "$(value basemetals_deobf_sha256)" "$metals" +public_jar OreSpawn 245586 "$(value orespawn_public_file_id)" "$(value orespawn_deobf_sha256)" "$orespawn" -player="${RUNNER_TEMP:?}/basePower-public-player.jar" -curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' \ - --output "$player" "https://www.curseforge.com/api/v1/mods/1780140/files/$file_id/download" -read -r actual _ < <(sha256sum < "$player") -if [[ "${actual^^}" != "$expected" ]]; then - echo "::error::Public basePower file $file_id SHA-256 is ${actual^^}, expected $expected." - exit 1 -fi -printf 'power_player=%s\n' "$player" >> "${GITHUB_OUTPUT:?}" +installer="$inputs/forge-1.20.6-50.2.0-installer.jar" +download 'https://maven.minecraftforge.net/net/minecraftforge/forge/1.20.6-50.2.0/forge-1.20.6-50.2.0-installer.jar' \ + "$(value forge_installer_sha256)" "$installer" +{ + printf 'power_ref=%s\n' "$power_ref" + printf 'orespawn_ref=%s\n' "$orespawn_ref" +} >> "${GITHUB_OUTPUT:?}" +{ + printf 'POWER_PLAYER=%s\n' "$power" + printf 'METALS_PLAYER=%s\n' "$metals" + printf 'ORESPAWN_PLAYER=%s\n' "$orespawn" + printf 'FORGE_INSTALLER=%s\n' "$installer" +} >> "${GITHUB_ENV:?}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ece00a6..4182095 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,173 +1,119 @@ -name: baseSteam 1.20 CI +name: baseSteam 1.20.6 CI on: push: - branches: [master-1.20.1, feature/basesteam-1.20.1-port, feature/prepare-basesteam-1.20.1] + branches: [master-1.20.6, 'feature/**'] pull_request: - branches: [master-1.20.1] + branches: [master-1.20.6] permissions: contents: read concurrency: - group: basesteam-1.20-${{ github.workflow }}-${{ github.ref }} + group: basesteam-1.20.6-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: name: Build, test, and audit runs-on: ubuntu-latest - timeout-minutes: 105 + timeout-minutes: 75 steps: - name: Check out baseSteam uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Verify merged dependency pins and public basePower bytes + - name: Use canonical LF dependency inputs + run: git config --global core.autocrlf false + - name: Verify merged and public dependency pins id: public-pins env: GH_TOKEN: ${{ github.token }} run: bash .github/verify-published-pins.sh - - name: Validate coordinated dependency pins - shell: bash - run: | - set -euo pipefail - power_ref=$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r') - power_hash=$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r') - if [[ ! "$power_ref" =~ ^[a-f0-9]{40}$ || ! "$power_hash" =~ ^[A-F0-9]{64}$ ]]; then - echo "::error::The exact basePower 1.20.1 dependency pin is pending." - exit 1 - fi - bm_ref=$(sed -n 's/^basemetals_source_commit=//p' gradle.properties | tr -d '\r') - bm_hash=$(sed -n 's/^basemetals_deobf_sha256=//p' gradle.properties | tr -d '\r') - if [[ ! "$bm_ref" =~ ^[a-f0-9]{40}$ || ! "$bm_hash" =~ ^[A-F0-9]{64}$ ]]; then - echo "::error::The exact Base Metals 1.20.1 dependency pin is pending." - exit 1 - fi - os_ref=$(sed -n 's/^orespawn_source_commit=//p' gradle.properties | tr -d '\r') - os_hash=$(sed -n 's/^orespawn_deobf_sha256=//p' gradle.properties | tr -d '\r') - if [[ ! "$os_ref" =~ ^[a-f0-9]{40}$ || ! "$os_hash" =~ ^[A-F0-9]{64}$ ]]; then - echo "::error::The exact OreSpawn 1.20.1 dependency pin is pending." - exit 1 - fi - echo "ORESPAWN_SOURCE_REF=$os_ref" >> "$GITHUB_ENV" - echo "POWERADVANTAGE_SOURCE_REF=$power_ref" >> "$GITHUB_ENV" - echo "BASEMETALS_SOURCE_REF=$bm_ref" >> "$GITHUB_ENV" - - name: Check out pinned OreSpawn + - name: Check out pinned OreSpawn tool source uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/OreSpawn - ref: ${{ env.ORESPAWN_SOURCE_REF }} + ref: ${{ steps.public-pins.outputs.orespawn_ref }} path: .ci-dependencies/OreSpawn - - name: Use canonical LF dependency inputs - # Use the same source bytes on hosted and local dependency builds. - run: git config --global core.autocrlf false - - name: Check out pinned Base Metals - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - repository: MinecraftModDevelopmentMods/BaseMetals - ref: ${{ env.BASEMETALS_SOURCE_REF }} - path: .ci-dependencies/BaseMetals - - name: Check out basePower 1.20.1 + - name: Check out released basePower source uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/basePower - ref: ${{ env.POWERADVANTAGE_SOURCE_REF }} + ref: ${{ steps.public-pins.outputs.power_ref }} path: .ci-dependencies/basePower - - name: Install pinned Java 25 Mavenizer runtime + - name: Install Java 25 for Mavenizer uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin java-version: '25.0.3+9.0.LTS' - - name: Install Java 8 for legacy build utilities + - name: Install Java 8 for the launcher helper uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin java-version: '8.0.502+7' - - name: Install Java 17 for Gradle + - name: Install Java 21 for Gradle and production uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin - java-version: '17.0.1+12' + java-version: '21.0.7+6.0.LTS' - name: Use pinned build toolchains - # These are Gradle project properties, not JVM system properties. - shell: bash run: >- echo "MMD_GRADLE_TOOLCHAINS=-Porg.gradle.java.installations.paths=$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64 -Porg.gradle.java.installations.auto-detect=false -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Build 1.20.1 dependency chain - id: dependencies + - name: Verify the Forge 50 build inputs shell: bash + env: + ORESPAWN_REF: ${{ steps.public-pins.outputs.orespawn_ref }} + POWER_REF: ${{ steps.public-pins.outputs.power_ref }} run: | set -euo pipefail orespawn="$GITHUB_WORKSPACE/.ci-dependencies/OreSpawn" - basemetals="$GITHUB_WORKSPACE/.ci-dependencies/BaseMetals" power="$GITHUB_WORKSPACE/.ci-dependencies/basePower" - test "$(git -C "$orespawn" rev-parse HEAD)" = "$ORESPAWN_SOURCE_REF" - test "$(git -C "$power" rev-parse HEAD)" = "$POWERADVANTAGE_SOURCE_REF" - test "$(git -C "$basemetals" rev-parse HEAD)" = "$BASEMETALS_SOURCE_REF" + test "$(git -C "$orespawn" rev-parse HEAD)" = "$ORESPAWN_REF" + test "$(git -C "$power" rev-parse HEAD)" = "$POWER_REF" mavenizer="$orespawn/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar" - printf '%s %s\n' '416DCA4797BC55826F0DDCF03FDC405F1990FC15C2133FA27A1F143BF7976177' "$mavenizer" | sha256sum -c - - (cd "$orespawn" && ./gradlew $MMD_GRADLE_TOOLCHAINS assemble --no-daemon --stacktrace) - (cd "$basemetals" && ./gradlew $MMD_GRADLE_TOOLCHAINS assemble --no-daemon --stacktrace) - osjar="$orespawn/build/libs-dev/OreSpawn-4.1.0.120011-deobf.jar" - bm_version=$(sed -n 's/^basemetals_version=//p' "$GITHUB_WORKSPACE/gradle.properties" | tr -d '\r') - bmjar="$basemetals/build/libs-dev/BaseMetals-$bm_version-deobf.jar" - (cd "$power" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar unitBootstrapJar verifyReleaseDependencies \ - "-Pforge47MavenizerJar=$mavenizer" \ - -PbaseMetalsDeobfJar="$bmjar" -PoreSpawnDeobfJar="$osjar" \ - --no-daemon --stacktrace) - powerjar="$power/build/libs-dev/basePower-2.4.12.120011-deobf.jar" - bootstrap="$power/build/unit-bootstrap/forge-native-unit-bootstrap.jar" - test -f "$osjar" && test -f "$bmjar" && test -f "$powerjar" && test -f "$bootstrap" - echo "orespawn=$osjar" >> "$GITHUB_OUTPUT" - echo "basemetals=$bmjar" >> "$GITHUB_OUTPUT" - echo "orespawn_player=$orespawn/build/libs/OreSpawn-4.1.0.120011.jar" >> "$GITHUB_OUTPUT" - echo "basemetals_player=$basemetals/build/libs/BaseMetals-$bm_version.jar" >> "$GITHUB_OUTPUT" - echo "power=$powerjar" >> "$GITHUB_OUTPUT" - echo "bootstrap=$bootstrap" >> "$GITHUB_OUTPUT" - echo "mavenizer=$mavenizer" >> "$GITHUB_OUTPUT" - - name: Verify source layout and recipe unlocks + printf '%s %s\n' '4B14145595E900F178A082F2253A756F63897E6F61C2B8B5E7C819B82CD79E8C' "$mavenizer" | sha256sum -c - + echo "MAVENIZER=$mavenizer" >> "$GITHUB_ENV" + - name: Build the released basePower test bootstrap + shell: bash run: | - node tools/verify-native-port.js - node tools/generate-recipe-unlocks.js --check + set -euo pipefail + power="$GITHUB_WORKSPACE/.ci-dependencies/basePower" + (cd "$power" && bash ./gradlew $MMD_GRADLE_TOOLCHAINS unitBootstrapJar \ + "-Pforge50MavenizerJar=$MAVENIZER" "-PbaseMetalsDeobfJar=$METALS_PLAYER" "-PoreSpawnDeobfJar=$ORESPAWN_PLAYER" --no-daemon) + echo "POWER_BOOTSTRAP=$power/build/unit-bootstrap/forge-native-unit-bootstrap.jar" >> "$GITHUB_ENV" + echo "POWER_BOOTSTRAP_SOURCE=$power/test-rig/unit-bootstrap/ForgeCapabilityBootstrap.java" >> "$GITHUB_ENV" + echo "POWER_REGISTRY_SOURCE=$power/test-rig/unit-support/zone/moddev/mc/advantageworks/unit/ForgeUnitRegistries.java" >> "$GITHUB_ENV" - name: Build and audit release artifacts - run: >- - ./gradlew $MMD_GRADLE_TOOLCHAINS clean check build javadoc verifyReleaseDependencies verifyPlayerDependencies verifyReleaseArtifacts - writeReleaseChecksums verifyEclipseProductionClasspath - "-Pforge47MavenizerJar=${{ steps.dependencies.outputs.mavenizer }}" - "-PpowerAdvantagePlayerJar=${{ steps.public-pins.outputs.power_player }}" - "-PbaseMetalsPlayerJar=${{ steps.dependencies.outputs.basemetals_player }}" - "-PoreSpawnPlayerJar=${{ steps.dependencies.outputs.orespawn_player }}" - -PforgeCapabilityBootstrapJar=${{ steps.dependencies.outputs.bootstrap }} - -PpowerAdvantageDeobfJar=${{ steps.dependencies.outputs.power }} - -PbaseMetalsDeobfJar=${{ steps.dependencies.outputs.basemetals }} - -PoreSpawnDeobfJar=${{ steps.dependencies.outputs.orespawn }} - --no-daemon --stacktrace + shell: bash + run: | + ./gradlew $MMD_GRADLE_TOOLCHAINS clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts \ + writeReleaseChecksums verifyEclipseProductionClasspath --no-build-cache --no-daemon --stacktrace \ + "-Pforge50MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ + "-PbaseMetalsDeobfJar=$METALS_PLAYER" "-PoreSpawnDeobfJar=$ORESPAWN_PLAYER" \ + "-PforgeCapabilityBootstrapJar=$POWER_BOOTSTRAP" "-PforgeCapabilityBootstrapSource=$POWER_BOOTSTRAP_SOURCE" \ + "-PforgeUnitRegistriesSource=$POWER_REGISTRY_SOURCE" - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: baseSteam-1.20.1-${{ github.sha }} + name: baseSteam-1.20.6-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/baseSteam-2.2.13.120011.jar - build/libs/baseSteam-2.2.13.120011-sources.jar - build/libs/baseSteam-2.2.13.120011-javadoc.jar + build/libs/baseSteam-2.2.14.120061.jar + build/libs/baseSteam-2.2.14.120061-sources.jar + build/libs/baseSteam-2.2.14.120061-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt - name: Upload diagnostics on failure if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: baseSteam-1.20.1-diagnostics-${{ github.sha }} + name: baseSteam-1.20.6-diagnostics-${{ github.sha }} if-no-files-found: ignore retention-days: 14 path: | build/test-results/** build/reports/** - build/*-run/logs/** - build/problems/** - .ci-dependencies/basePower/build/reports/** - .ci-dependencies/basePower/build/libs-dev/*.jar diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 85b0f0e..838d738 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,142 +2,92 @@ name: CodeQL on: push: - branches: [master-1.20.1, feature/basesteam-1.20.1-port, feature/prepare-basesteam-1.20.1] + branches: [master-1.20.6, 'feature/**'] pull_request: - branches: [master-1.20.1] - schedule: - - cron: '53 7 * * 4' + branches: [master-1.20.6] permissions: - actions: read contents: read + actions: read security-events: write +concurrency: + group: basesteam-1.20.6-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: analyze: name: Analyze Java runs-on: ubuntu-latest - timeout-minutes: 90 + timeout-minutes: 75 steps: - name: Check out baseSteam uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Verify merged dependency pins and public basePower bytes + - name: Use canonical LF dependency inputs + run: git config --global core.autocrlf false + - name: Verify merged and public dependency pins id: public-pins env: GH_TOKEN: ${{ github.token }} run: bash .github/verify-published-pins.sh - - name: Validate coordinated dependency pins - shell: bash - run: | - set -euo pipefail - power_ref=$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r') - power_hash=$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r') - if [[ ! "$power_ref" =~ ^[a-f0-9]{40}$ || ! "$power_hash" =~ ^[A-F0-9]{64}$ ]]; then - echo "::error::The exact basePower 1.20.1 dependency pin is pending." - exit 1 - fi - bm_ref=$(sed -n 's/^basemetals_source_commit=//p' gradle.properties | tr -d '\r') - bm_hash=$(sed -n 's/^basemetals_deobf_sha256=//p' gradle.properties | tr -d '\r') - if [[ ! "$bm_ref" =~ ^[a-f0-9]{40}$ || ! "$bm_hash" =~ ^[A-F0-9]{64}$ ]]; then - echo "::error::The exact Base Metals 1.20.1 dependency pin is pending." - exit 1 - fi - os_ref=$(sed -n 's/^orespawn_source_commit=//p' gradle.properties | tr -d '\r') - os_hash=$(sed -n 's/^orespawn_deobf_sha256=//p' gradle.properties | tr -d '\r') - if [[ ! "$os_ref" =~ ^[a-f0-9]{40}$ || ! "$os_hash" =~ ^[A-F0-9]{64}$ ]]; then - echo "::error::The exact OreSpawn 1.20.1 dependency pin is pending." - exit 1 - fi - echo "ORESPAWN_SOURCE_REF=$os_ref" >> "$GITHUB_ENV" - echo "POWERADVANTAGE_SOURCE_REF=$power_ref" >> "$GITHUB_ENV" - echo "BASEMETALS_SOURCE_REF=$bm_ref" >> "$GITHUB_ENV" - - name: Check out pinned OreSpawn + - name: Check out pinned OreSpawn tool source uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/OreSpawn - ref: ${{ env.ORESPAWN_SOURCE_REF }} + ref: ${{ steps.public-pins.outputs.orespawn_ref }} path: .ci-dependencies/OreSpawn - - name: Use canonical LF dependency inputs - # Use the same source bytes on hosted and local dependency builds. - run: git config --global core.autocrlf false - - name: Check out pinned Base Metals - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - repository: MinecraftModDevelopmentMods/BaseMetals - ref: ${{ env.BASEMETALS_SOURCE_REF }} - path: .ci-dependencies/BaseMetals - - name: Check out basePower 1.20.1 + - name: Check out released basePower source uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/basePower - ref: ${{ env.POWERADVANTAGE_SOURCE_REF }} + ref: ${{ steps.public-pins.outputs.power_ref }} path: .ci-dependencies/basePower - - name: Install pinned Java 25 Mavenizer runtime + - name: Install Java 25 for Mavenizer uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin java-version: '25.0.3+9.0.LTS' - - name: Install Java 8 for legacy build utilities + - name: Install Java 8 for the launcher helper uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin java-version: '8.0.502+7' - - name: Install Java 17 for Gradle + - name: Install Java 21 for Gradle and production uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin - java-version: '17.0.1+12' + java-version: '21.0.7+6.0.LTS' - name: Use pinned build toolchains - # These are Gradle project properties, not JVM system properties. - shell: bash run: >- echo "MMD_GRADLE_TOOLCHAINS=-Porg.gradle.java.installations.paths=$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64 -Porg.gradle.java.installations.auto-detect=false -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Build 1.20.1 dependency chain - id: dependencies + - name: Verify the Forge 50 build inputs shell: bash + env: + ORESPAWN_REF: ${{ steps.public-pins.outputs.orespawn_ref }} + POWER_REF: ${{ steps.public-pins.outputs.power_ref }} run: | set -euo pipefail orespawn="$GITHUB_WORKSPACE/.ci-dependencies/OreSpawn" - basemetals="$GITHUB_WORKSPACE/.ci-dependencies/BaseMetals" power="$GITHUB_WORKSPACE/.ci-dependencies/basePower" - test "$(git -C "$orespawn" rev-parse HEAD)" = "$ORESPAWN_SOURCE_REF" - test "$(git -C "$power" rev-parse HEAD)" = "$POWERADVANTAGE_SOURCE_REF" - test "$(git -C "$basemetals" rev-parse HEAD)" = "$BASEMETALS_SOURCE_REF" + test "$(git -C "$orespawn" rev-parse HEAD)" = "$ORESPAWN_REF" + test "$(git -C "$power" rev-parse HEAD)" = "$POWER_REF" mavenizer="$orespawn/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar" - printf '%s %s\n' '416DCA4797BC55826F0DDCF03FDC405F1990FC15C2133FA27A1F143BF7976177' "$mavenizer" | sha256sum -c - - (cd "$orespawn" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar --no-daemon --stacktrace) - (cd "$basemetals" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar --no-daemon --stacktrace) - osjar="$orespawn/build/libs-dev/OreSpawn-4.1.0.120011-deobf.jar" - bm_version=$(sed -n 's/^basemetals_version=//p' "$GITHUB_WORKSPACE/gradle.properties" | tr -d '\r') - bmjar="$basemetals/build/libs-dev/BaseMetals-$bm_version-deobf.jar" - (cd "$power" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar unitBootstrapJar verifyReleaseDependencies \ - "-Pforge47MavenizerJar=$mavenizer" \ - -PbaseMetalsDeobfJar="$bmjar" -PoreSpawnDeobfJar="$osjar" \ - --no-daemon --stacktrace) - powerjar="$power/build/libs-dev/basePower-2.4.12.120011-deobf.jar" - bootstrap="$power/build/unit-bootstrap/forge-native-unit-bootstrap.jar" - test -f "$osjar" && test -f "$bmjar" && test -f "$powerjar" && test -f "$bootstrap" - echo "orespawn=$osjar" >> "$GITHUB_OUTPUT" - echo "basemetals=$bmjar" >> "$GITHUB_OUTPUT" - echo "power=$powerjar" >> "$GITHUB_OUTPUT" - echo "bootstrap=$bootstrap" >> "$GITHUB_OUTPUT" - echo "mavenizer=$mavenizer" >> "$GITHUB_OUTPUT" + printf '%s %s\n' '4B14145595E900F178A082F2253A756F63897E6F61C2B8B5E7C819B82CD79E8C' "$mavenizer" | sha256sum -c - + echo "MAVENIZER=$mavenizer" >> "$GITHUB_ENV" - name: Initialize CodeQL uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 with: languages: java-kotlin - - name: Compile baseSteam production code + build-mode: manual + - name: Compile production code + shell: bash run: | - chmod +x ./gradlew - ./gradlew $MMD_GRADLE_TOOLCHAINS clean classes --rerun-tasks --no-build-cache --no-daemon --stacktrace \ - "-Pforge47MavenizerJar=${{ steps.dependencies.outputs.mavenizer }}" \ - -PforgeCapabilityBootstrapJar=${{ steps.dependencies.outputs.bootstrap }} \ - -PpowerAdvantageDeobfJar=${{ steps.dependencies.outputs.power }} \ - -PbaseMetalsDeobfJar=${{ steps.dependencies.outputs.basemetals }} \ - -PoreSpawnDeobfJar=${{ steps.dependencies.outputs.orespawn }} + ./gradlew $MMD_GRADLE_TOOLCHAINS classes verifyReleaseDependencies --rerun-tasks --no-build-cache --no-daemon --stacktrace \ + "-Pforge50MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ + "-PbaseMetalsDeobfJar=$METALS_PLAYER" "-PoreSpawnDeobfJar=$ORESPAWN_PLAYER" - name: Analyze uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index b641914..2c47d12 100644 --- a/.github/workflows/validate-gradle-build.yml +++ b/.github/workflows/validate-gradle-build.yml @@ -3,11 +3,11 @@ name: Validate Gradle Wrapper on: push: branches: - - master-1.20.1 - - feature/basesteam-1.20.1-port + - master-1.20.6 + - 'feature/**' pull_request: branches: - - master-1.20.1 + - master-1.20.6 permissions: contents: read diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 2d3bb78..2580113 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,10 +1,11 @@ -baseSteam 2.2.14.120061 (local Minecraft 1.20.6 port) +baseSteam 2.2.14.120061 (Minecraft 1.20.6 / Forge) - Target Minecraft 1.20.6, Forge 50.2.0 and Java 21 with basePower 2.4.13.120061. - Preserve musket loaded state and durability through native item components and legacy upgrades. - Keep the Steam registry IDs and machine state while moving saves, packets and data packs to Forge 50. +- Use the fixed basePower renderer for fluid gauges on boilers, pumps and stills. -baseSteam 2.2.13.120011 (local Minecraft 1.20.1 port) +baseSteam 2.2.13.120011 (Minecraft 1.20.1 / Forge) - Move to Minecraft 1.20.1, Forge 47.4.10 and Java 17 with basePower 2.4.12.120011. - Keep Steam machines, recipes, saves and the shared creative tab as before. diff --git a/README.md b/README.md index c941147..a861d0c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # baseSteam -**Minecraft 1.20.6 (Forge), version 2.2.14.120061. Local port.** +**Minecraft 1.20.6 (Forge), version 2.2.14.120061.** baseSteam, formerly Steam Advantage, adds boilers, steam-powered machines, pumps, storage, elevators and a blackpowder musket to basePower. Items and -blocks use the shared basePower creative tab. This checkout is not a release. +blocks use the shared basePower creative tab. ## Build Target diff --git a/gradle.properties b/gradle.properties index 2649cb7..f8f42ff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -37,8 +37,9 @@ cf_versions=1.20.6 poweradvantage_version=2.4.13.120061 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower -# Exact local checkpoints for coordinated testing, not published source pins. +# Native release provenance is checked before a hosted build. poweradvantage_source_ref=41427a5260658fd452477c88498e7ff82552e48a +poweradvantage_public_file_id=PENDING poweradvantage_deobf_sha256=E53BDD64776741B2EBAE36A646049DC98487E1BAD1CF69F1E3FCD95188F907F1 # Forge 50 uses the same native jar for development and packaged runtime. poweradvantage_player_sha256=E53BDD64776741B2EBAE36A646049DC98487E1BAD1CF69F1E3FCD95188F907F1 @@ -48,15 +49,12 @@ poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF5 basemetals_version=3.1.2.120061 basemetals_source_commit=9e706db5c85fa2bc7f36dee94f39a5f2fa8ab367 +basemetals_public_file_id=PENDING basemetals_deobf_sha256=6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D basemetals_player_sha256=6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D orespawn_version=4.1.0.120061 orespawn_source_commit=4085315345ff043448b316d75e03f4b8da45402d +orespawn_public_file_id=9183384 orespawn_deobf_sha256=FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26 orespawn_player_sha256=FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26 - - -# Published runtime bytes are distinct from development API jars. -basemetals_public_sha256=PENDING -orespawn_public_sha256=PENDING diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java index db80934..b15d7c0 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java @@ -35,11 +35,21 @@ public class BuildWorkflowContractTest { assertTrue(build.contains("basePower-${project.poweradvantage_version}.jar")); } - @Test public void thisLocalPortDoesNotOptIntoTheHistoricalHostedJobs() throws Exception { - for (String name : new String[] {"ci.yml", "codeql-analysis.yml", "validate-gradle-build.yml"}) { + @Test public void hostedJobsCheckPublishedNativeInputsBeforeCompiling() throws Exception { + for (String name : new String[] {"ci.yml", "codeql-analysis.yml"}) { String source = Files.readString(Path.of(".github/workflows", name)); - assertFalse(name, source.contains("master-1.20.6")); - assertFalse(name, source.contains("feature/basesteam-1.20.6-port")); + int pinCheck = source.indexOf("bash .github/verify-published-pins.sh"); + assertTrue(name, pinCheck > 0 && pinCheck < source.indexOf("Check out released basePower source")); + assertTrue(name, source.contains("branches: [master-1.20.6")); + assertTrue(name, source.contains("java-version: '21.0.7+6.0.LTS'")); + assertTrue(name, source.contains("-Pforge50MavenizerJar=$MAVENIZER")); + assertTrue(name, source.contains("-PpowerAdvantageDeobfJar=$POWER_PLAYER")); + assertFalse(name, source.contains("forge47")); } + String script = Files.readString(Path.of(".github/verify-published-pins.sh")); + assertTrue(script.contains("$(value poweradvantage_public_file_id)")); + assertTrue(script.contains("$(value basemetals_public_file_id)")); + assertTrue(script.contains("$(value orespawn_public_file_id)")); + assertTrue(script.contains("sha256sum -c -")); } } From 1de10a3784c74957ac49c849b4c3901a4fe8a260 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 10 Nov 2026 18:52:23 +0000 Subject: [PATCH 16/16] Pin the Minecraft 1.20.6 release to public basePower --- README.md | 10 ++- docs/PORT1206-STATUS.md | 184 ++++------------------------------------ gradle.properties | 8 +- 3 files changed, 28 insertions(+), 174 deletions(-) diff --git a/README.md b/README.md index a861d0c..5d1a3c5 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,11 @@ ForgeGradle's Slime Launcher also locates a Java 8 toolchain while generating runs. The game itself runs on Java 21. Forge 50 uses official names at runtime. Steam does not run an SRG renamer. -The required dependency is basePower 2.4.13.120061. Base Metals 3.1.2.120061 is -optional at runtime and uses OreSpawn 4.1.0.120061. The exact native companion -jars serve as both development and player inputs. No dependency is embedded. +Install [basePower 2.4.13.120061](https://www.curseforge.com/minecraft/mc-mods/basepower/files/9545972) +for Minecraft 1.20.6. CurseForge also installs +[Base Metals](https://www.curseforge.com/minecraft/mc-mods/base-metals); this +build was tested with 3.1.2.120061 and OreSpawn 4.1.0.120061. The same native +jars are used for play and development, and none are bundled. The mod ID, data namespace, and registry paths remain `basesteam`. ## Local Verification @@ -55,7 +57,7 @@ The optional no-Base-Metals profile uses `-WithoutBaseMetals` and retains OreSpawn because basePower requires it. `node tools/verify-native-port.js` and `node tools/generate-recipe-unlocks.js --check` are independent source checks. -See [local status](docs/PORT1206-STATUS.md) for evidence and open gates. +See the [1.20.6 notes](docs/PORT1206-STATUS.md) for save compatibility and test coverage. ## Upgrading a World diff --git a/docs/PORT1206-STATUS.md b/docs/PORT1206-STATUS.md index 87878db..cc25c4f 100644 --- a/docs/PORT1206-STATUS.md +++ b/docs/PORT1206-STATUS.md @@ -1,173 +1,25 @@ -# Steam 1.20.6 Local Status +# Steam on Minecraft 1.20.6 -- Checkout: `D:/PowerAdvantage/PA1206/SteamAdvantage/SteamAdvantage`. -- Baseline: `master-1.20.6` at accepted Steam `17c6b8467d5c488e101b53b992537d6d9b251b87`. -- Work branch: `feature/basesteam-1.20.6-port`; no configured remotes, matching the source checkout. -- Target: baseSteam 2.2.14.120061, Forge 50.2.0, Java 21, official 1.20.6 mappings. -- Scope: Steam only. No push, tag, PR, deployment, publication, or use of existing worlds. +This version uses Forge 50.2.0, Java 21 and basePower 2.4.13.120061. +The Steam jar uses Forge's official runtime names and is also the development +dependency. Power, Base Metals and OreSpawn remain separate jars. -## Coordinated Inputs +## Bringing an old world forward -| Input | Commit | Local native jar SHA-256 | -| --- | --- | --- | -| basePower 2.4.13.120061 | `e6ecfb341006186d0adba9dcc3f296297cd34aec` | `29C1BD5EF384F8BB2441029061615E52A4B7302B9FC5480F2CE9C84C357A3181` | -| Base Metals 3.1.2.120061 (local shared hook) | `9e706db5c85fa2bc7f36dee94f39a5f2fa8ab367` | `6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D` | -| OreSpawn 4.1.0.120061 | `4085315345ff043448b316d75e03f4b8da45402d` | `FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26` | +Make a backup and test with a copy first. Replace Steam Advantage and Power +Advantage with baseSteam and basePower. Don't install both generations of the +mods or reopen an upgraded world in an older version of Minecraft. -The native jars serve as both development and packaged inputs. The Power -JUnit bootstrap is pinned to -`96752A443070E117EED9308ABC9C2009BD3533F121C9594A7108908E104673C9`; -both bootstrap source hashes are recorded in `gradle.properties`. -No dependency is embedded or promoted to a publication claim. +Machine IDs and saved fields are unchanged. Old drill state and inventories +continue through the shared world migration. The musket's wear is now a +Minecraft item component, while its loaded state stays in its custom data. +An existing `basesteam-common.toml` still takes precedence over older settings. -## Final Repin Verification +## Checks -Steam commit `e023a2f349ee1aa06ef874ae99242b47b5a6ca68` updates the Power source -pin and the Base Metals source and jar pins. The Power native jar, unit test -bootstrap and its sources, and OreSpawn are unchanged. All checks below used -the frozen inputs in `evidence/steam1206-exact-e6ecfb3/inputs/`, including the -Base Metals jar from `evidence/player-pre-components-20261110/candidate/` in -the local shared-hook checkout. +The Steam tests cover saved and moving drills, musket wear and loading, and +native recipe, advancement and loot registration. The packaged server smoke +uses a fresh world, with a separate run available without Base Metals. It +doesn't replace basePower's world-upgrade tests or an in-game visual check. -The Steam release, sources and Javadoc jars and their `SHA256SUMS` are frozen -in `evidence/steam1206-exact-e6ecfb3/candidate/`. Direct byte comparisons of the -native Steam jar against both earlier exact Steam jars passed. Its SHA-256 is -`5DDABC83B01A8CC8BAE3188BAAACE01BDCF6F756B7049DADF1ADAA3F9CF480FD`. - -| Gate | Result | Receipt | -| --- | --- | --- | -| Forced rebuild, exact development and player inputs, release archive audit | Passed | `evidence/steam1206-exact-e6ecfb3/build-audit.log`, `input-checksums.json` and `candidate/candidate-receipt.json` | -| Full Gradle suite, Java 21 and Eclipse production classpath | 221 JUnit tests passed; no failures or skips; Eclipse generation and audit passed | `evidence/steam1206-exact-e6ecfb3/full-suite.log` and `junit-summary.json` | -| Forge 50.2.0 development GameTests | All four passed, no ERROR/FATAL records | `evidence/steam1206-exact-e6ecfb3/gametest-server.log` | -| Packaged Forge 50.2.0 dedicated server | Clean boot and shutdown with and without Base Metals; OreSpawn retained in both | `evidence/packaged-server-exact-e6ecfb3-with-basemetals/receipt.json` and `evidence/packaged-server-exact-e6ecfb3-without-basemetals/receipt.json` | -| Native source and recipe unlock checks | Passed; all 24 unlocks verified, no source or resource changes since the previous repin | `evidence/steam1206-exact-e6ecfb3/static-checks.log` | - -## Power Loot Fix Snapshot - -Steam commit `23cb29f9328bc52ebb0a95ae4df7f7e765cf71b7` pins the Power -datapack loot fix. Steam production sources, the bootstrap, Base Metals and -OreSpawn did not change. A forced rebuild and direct byte comparison confirmed -that the Steam jar is identical to the first exact candidate: -`5DDABC83B01A8CC8BAE3188BAAACE01BDCF6F756B7049DADF1ADAA3F9CF480FD`. - -The frozen artifact from this snapshot is -`evidence/steam1206-exact-75297fd/candidate/baseSteam-2.2.14.120061.jar`. -Its receipt records both Power and Steam hashes and the byte comparison. - -| Gate | Result | Receipt | -| --- | --- | --- | -| Forced rebuild, exact development and player inputs, archive audit | Passed | `evidence/steam1206-exact-75297fd/build-audit.log` and `input-checksums.json` | -| Full Gradle and Eclipse checks | 221 JUnit tests passed; no failures or skips | `evidence/steam1206-exact-75297fd/full-suite.log` and `junit-summary.json` | -| Forge development GameTests | All four passed | `evidence/steam1206-exact-75297fd/gametest-server.log` | -| Packaged dedicated server | Clean boot and shutdown in both profiles | `evidence/packaged-server-exact-75297fd-with-basemetals/receipt.json` and `evidence/packaged-server-exact-75297fd-without-basemetals/receipt.json` | -| Source parity | 33 recipes and 24 unlocks verified; block loot and harvest tags unchanged | `evidence/steam1206-exact-75297fd/static-parity.log` | - -## First Exact Snapshot - -These receipts apply to Power commit `5fdbb2c2b2d9bbc760aca3919e5b5b648f4545e2` -and jar SHA-256 `E192657CC426BC8CD0E3809F6CBF53A135E5C49C6E34A8936DE2DD034D701A04`. -The Steam checks below passed for that snapshot. Integrated results on that -Power jar remain provisional because live progression found that an overridden -dungeon loot table was augmented. No old receipt was promoted or replaced. - -The frozen `baseSteam-2.2.14.120061.jar` is in -`evidence/steam1206-exact-5fdbb2c/candidate/`. It was built from Steam commit -`756fd62385806644c2475fe6a4d9cbe9290b12d7` and has SHA-256 -`5DDABC83B01A8CC8BAE3188BAAACE01BDCF6F756B7049DADF1ADAA3F9CF480FD`. -Before the repin, later Steam commits changed only verification, Eclipse -generation, and documentation. -The ordinary `build/libs` jar matched the frozen bytes before and after both -packaged runs. - -| Gate | Result | Receipt | -| --- | --- | --- | -| Exact development and player dependencies; archive audit | Passed | `evidence/steam1206-exact-5fdbb2c/build-audit-b.log` and `input-checksums.json` | -| Full Gradle suite | 221 JUnit tests passed, none failed or skipped; asset, recipe, and repository checks passed | `evidence/steam1206-exact-5fdbb2c/full-suite.log` and `junit-summary.json` | -| Forge 50 development GameTests | All four required tests passed; no ERROR/FATAL records | `evidence/steam1206-exact-5fdbb2c/gametest-c-server.log` | -| Packaged Forge dedicated server, with Base Metals | Clean boot and shutdown | `evidence/packaged-server-exact-5fdbb2c-with-basemetals/receipt.json` | -| Packaged Forge dedicated server, without Base Metals | Clean boot and shutdown; OreSpawn retained | `evidence/packaged-server-exact-5fdbb2c-without-basemetals/receipt.json` | -| Eclipse generation and production classpath | Passed; no Eclipse client was launched | `evidence/steam1206-exact-5fdbb2c/eclipse-b.log` | -| Source parity | All 33 recipes and 24 unlocks verified; block loot and harvest tags unchanged | `evidence/steam1206-exact-5fdbb2c/static-parity.log` | - -The initial archive audit lacked a task dependency on the development jar. -The two initial GameTest runs stopped before tests on scratch-directory and -batch selection issues; the final run seeded server properties and used the -explicit `basesteam` batch. Initial Eclipse generation omitted `MOD_CLASSES`. -These are verification fixes, not production changes. Failed attempts remain -in the evidence directory alongside the passing receipts. - -## Provisional Evidence - -- `build-steam1206-companions.log`: initial offline cache-only rejection. -- `build-steam1206-companions-normal.log`: Forge configured, then the stale - Base Metals migration-class marker failed. Steam only consumes the crushing API. -- `build-steam1206-static.log`: companion development/player and recipe guard - audits passed; the full check rejected the pending Power source pin as intended. -- `evidence/steam1206-native-data-third.log`: 15 independent Forge codec and - resource checks passed, plus the recipe guard, Java layout and hygiene tasks. - Earlier failures and their XML remain under `evidence/`. -- The source verifier passed and all 24 generated recipe unlocks matched. -- `evidence/steam1206-resource-parity.log`: all 33 recipes retain their exact - inputs, output counts, and ordered guards. Block loot and harvest tags - are byte-identical to the accepted source. -- `evidence/steam1206-provisional-compile-d.log`: Java 21 production, unit, - and GameTest sources compiled against the coordinated provisional Power - jar. Its SHA-256 before and after was - `FABB0EE5B742F5D7F36752C1730BE8253632D2761B27E28E307A08662372A4AC`. - The final Power audit was explicitly excluded for this compile only. - The compile-a through compile-c failures are retained. -- `evidence/steam1206-provisional-side-compile.log`: all three source sets - compiled after the side-only changes against provisional Power SHA-256 - `AF198E46C86FFC3F684C213F3A2A01F12D1A8D6AF12CD048877D10FBCE70DA6B`. -- `evidence/steam1206-independent-native-side.log`: 21 checks passed, - including the native drill renderer geometry and the client-only GUI - signature regression. Neither receipt is a packaged runtime pass. -- `evidence/steam1206-provisional-unit-d.log` and its XML results: 219 passed, - none failed or skipped. Only the two final pin-contract tests were excluded. - Inputs included provisional Power `82B1554AF83DF6FF2D737FA22D8548736B7F23BC182659A12DEAB254ED4CA6C6` - and the local Base Metals shared-hook candidate - `FC6DE01771ED9CD799D946A0ED4B6782B289C47AA8CFCA7753F9E102DD0F0417`. - The a through c fixture failures and XML are preserved. -- `evidence/steam1206-provisional-unit-f.log` and its XML results: the same - 219 tests passed after the fragile-block fix, using the updated shared - Forge 50 JUnit agent - `96752A443070E117EED9308ABC9C2009BD3533F121C9594A7108908E104673C9`. - The e-run exposed overlapping loader initialization, so Steam now lets - the shared agent own that setup and retains only its fluid registry fixture. -- `evidence/steam1206-provisional-gametest-c.log`: Forge reached the dedicated - development loader, but provisional Power's `MachineGUIRegistry` auto - subscriber was rejected for carrying `@OnlyIn` methods. No Steam tests ran, - despite the launcher returning zero. The new task gate requires the actual - four-test pass marker and a fresh run ID. The crash is under - `build/steam-gametest-provisional-c/crash-reports`. -- `evidence/packaged-server-provisional-a`: the real packaged Forge server - reached Steam common setup, `Done`, and a clean stop without a client-side - class error. Its original startup-only receipt is preserved, but the full - log rejects this as a clean data smoke: Forge could not bind the fragile - block tag because Minecraft renamed `grass` to `short_grass`. The smoke - now fails on error logs and the registry test checks every required ID. -- `evidence/packaged-server-provisional-b/receipt.json` and - `evidence/packaged-server-provisional-c-no-basemetals/receipt.json`: - the corrected packaged Steam jar - `6AF7260CF4950998816246029FB9F5C3E5A424512A173E46DD6A80E41ED76A8C` - booted and stopped cleanly on Forge 50.2.0 in both profiles, with no - ERROR/FATAL records. These runs used the frozen provisional Power jar - `82B1554AF83DF6FF2D737FA22D8548736B7F23BC182659A12DEAB254ED4CA6C6`, - not a final Power source pin. - -The isolated data checks use Forge 50.2.0 classes but do not start the Forge -mod loader or qualify Steam's production classes. The GameTest fixtures are -separate from packaged content. The empty test structure is a copy of the -minimal generated fixture from the local Base Metals 1.20.6 validation build -(SHA-256 `732772B538B1B647EACD1B7E5F27C74F5CB556B1C6BD91744008575331E7C9E2`). - -Steam's ten machine-menu decoration overrides were already client-only. -Client renderer registration is now also isolated in a client-only class. -The ASM side contract checks this without pretending to substitute for a -packaged dedicated launch. The smoke script copies the checked Forge install -and pinned player artifacts into a new, disposable Steam evidence directory. - -The jar pinned to Power `e6ecfb3` passed the combined 21-station rig and -the two 30-minute runs on fresh and migrated worlds, including a full -restart. The combined Eclipse client also passed its resource and screen -checks. It is ready for manual testing on a disposable copy, not a release. +See the [README](../README.md) for the commands and exact dependency pins. diff --git a/gradle.properties b/gradle.properties index f8f42ff..63e284e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,8 +38,8 @@ cf_versions=1.20.6 poweradvantage_version=2.4.13.120061 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower # Native release provenance is checked before a hosted build. -poweradvantage_source_ref=41427a5260658fd452477c88498e7ff82552e48a -poweradvantage_public_file_id=PENDING +poweradvantage_source_ref=d1cdc73d19551786ab4524879cb9abca8c881251 +poweradvantage_public_file_id=9545972 poweradvantage_deobf_sha256=E53BDD64776741B2EBAE36A646049DC98487E1BAD1CF69F1E3FCD95188F907F1 # Forge 50 uses the same native jar for development and packaged runtime. poweradvantage_player_sha256=E53BDD64776741B2EBAE36A646049DC98487E1BAD1CF69F1E3FCD95188F907F1 @@ -48,8 +48,8 @@ poweradvantage_test_bootstrap_source_sha256=9E0EFE07A889726489810AA960FECD0387F3 poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF56CD6203C9CD692CAC1531D0981F basemetals_version=3.1.2.120061 -basemetals_source_commit=9e706db5c85fa2bc7f36dee94f39a5f2fa8ab367 -basemetals_public_file_id=PENDING +basemetals_source_commit=e9d92f157ee5056a31e479d5b8f9dca8f0648c12 +basemetals_public_file_id=9543397 basemetals_deobf_sha256=6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D basemetals_player_sha256=6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D