From b311d9517943cb702660d8b616224adc6bfd7c76 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 11 Nov 2026 10:59:05 +0000 Subject: [PATCH 1/4] Port baseSteam to Forge 1.21.1 --- .github/verify-published-pins.sh | 15 ++- .github/workflows/ci.yml | 26 ++-- .github/workflows/codeql-analysis.yml | 12 +- .github/workflows/release-on-tag.yml | 5 + .github/workflows/validate-gradle-build.yml | 4 +- CHANGELOG.txt | 6 + README.md | 92 ++++++------- build.gradle | 102 ++++++++++---- docs/PORT1211-STATUS.md | 24 ++++ gradle.properties | 63 +++++---- ...enizer.gradle => forge52-mavenizer.gradle} | 14 +- .../gametest/SteamNativeGameTests.java | 43 +++++- .../basesteam_empty.nbt | Bin .../moddev/mc/basesteam/SteamAdvantage.java | 4 +- .../mc/basesteam/compat/BaseMetalsCompat.java | 5 +- .../basesteam/graphics/DrillBitRenderer.java | 6 +- .../moddev/mc/basesteam/gui/GUIHelper.java | 8 +- .../mc/basesteam/init/Enchantments.java | 64 +++------ .../mc/basesteam/init/TreasureChests.java | 3 +- .../moddev/mc/basesteam/init/Villages.java | 8 +- .../moddev/mc/basesteam/items/MusketItem.java | 21 ++- .../machines/BlastFurnaceTileEntity.java | 5 +- src/main/resources/META-INF/mods.toml | 2 +- .../recipes/blackpowder_cartridge.json | 0 .../recipes/musket_left_normal.json | 0 .../recipes/musket_left_tech.json | 0 .../recipes/musket_right_normal.json | 0 .../recipes/musket_right_tech.json | 0 .../recipes/steam_boiler_coal.json | 0 .../recipes/steam_boiler_electric.json | 0 .../recipes/steam_boiler_geothermal.json | 0 .../recipes/steam_boiler_oil.json | 0 .../recipes/steam_crusher.json | 0 .../recipes/steam_drill.json | 0 .../recipes/steam_drill_bit.json | 0 .../steam_drill_diamond_pickaxe_normal.json | 0 .../recipes/steam_elevator.json | 0 .../recipes/steam_furnace.json | 0 .../recipes/steam_governor_apocalyptic.json | 0 .../recipes/steam_governor_normal.json | 0 .../recipes/steam_governor_tech.json | 0 .../recipes/steam_pipe.json | 0 .../recipes/steam_pump.json | 0 .../recipes/steam_still.json | 0 .../recipes/steam_switch.json | 0 .../recipes/steam_tank.json | 0 .../recipes/steam_track.json | 0 .../basesteam/enchantment/high_explosive.json | 21 +++ .../basesteam/enchantment/powderless.json | 21 +++ .../basesteam/enchantment/rapid_reload.json | 21 +++ .../data/basesteam/enchantment/recoil.json | 21 +++ .../blocks/steam_boiler_coal.json | 0 .../blocks/steam_boiler_electric.json | 0 .../blocks/steam_boiler_geothermal.json | 0 .../blocks/steam_boiler_oil.json | 0 .../blocks/steam_crusher.json | 0 .../blocks/steam_drill.json | 0 .../blocks/steam_elevator.json | 0 .../blocks/steam_furnace.json | 0 .../blocks/steam_pipe.json | 0 .../blocks/steam_pump.json | 0 .../blocks/steam_still.json | 0 .../blocks/steam_switch.json | 0 .../blocks/steam_tank.json | 0 .../blocks/steam_track.json | 0 .../chests/advantage_parts.json | 3 +- .../blackpowder_cartridge.json | 0 .../crushing_steam_boiler_coal.json | 0 .../crushing_steam_boiler_electric.json | 0 .../crushing_steam_boiler_geothermal.json | 0 .../crushing_steam_crusher.json | 0 .../crushing_steam_drill.json | 0 .../crushing_steam_elevator.json | 0 .../crushing_steam_furnace.json | 0 .../crushing_steam_governor.json | 0 .../crushing_steam_tank.json | 0 .../musket_left_normal.json | 0 .../{recipes => recipe}/musket_left_tech.json | 0 .../musket_right_normal.json | 0 .../musket_right_tech.json | 0 .../steam_boiler_coal.json | 0 .../steam_boiler_electric.json | 0 .../steam_boiler_geothermal.json | 0 .../{recipes => recipe}/steam_boiler_oil.json | 0 .../{recipes => recipe}/steam_crusher.json | 0 .../{recipes => recipe}/steam_drill.json | 0 .../{recipes => recipe}/steam_drill_bit.json | 0 .../steam_drill_diamond_pickaxe_normal.json | 0 .../{recipes => recipe}/steam_elevator.json | 0 .../{recipes => recipe}/steam_furnace.json | 0 .../steam_governor_apocalyptic.json | 0 .../steam_governor_normal.json | 0 .../steam_governor_tech.json | 0 .../{recipes => recipe}/steam_pipe.json | 0 .../{recipes => recipe}/steam_pump.json | 0 .../{recipes => recipe}/steam_still.json | 0 .../{recipes => recipe}/steam_switch.json | 0 .../{recipes => recipe}/steam_tank.json | 0 .../{recipes => recipe}/steam_track.json | 0 .../{blocks => block}/musket_fragile.json | 0 .../tags/{items => item}/muskets.json | 0 .../{items => item}/ammo/blackpowder.json | 0 .../tags/{items => item}/conduits/steam.json | 0 .../forge/tags/{items => item}/governors.json | 0 .../tags/{items => item}/governors/brass.json | 0 .../data/forge/tags/{items => item}/guns.json | 0 .../forge/tags/{items => item}/wires.json | 0 .../{blocks => block}/mineable/pickaxe.json | 0 .../tags/enchantment/non_treasure.json | 9 ++ .../tags/enchantment/tooltip_order.json | 9 ++ .../enchantable/durability.json | 0 .../enchantable/vanishing.json | 0 src/main/resources/pack.mcmeta | 4 +- .../blocks/DrillBitPersistenceTest.java | 13 +- .../graphics/DrillBitRendererTest.java | 27 ++-- .../CoalBoilerFillPersistenceTest.java | 6 +- .../machines/RockCrusherComparatorTest.java | 7 +- .../RockCrusherReloadRedstoneTest.java | 9 +- .../machines/SteamDrillPersistenceTest.java | 17 ++- .../machines/SteamMachinePersistenceTest.java | 46 +++---- .../SteamOperationalStillCapacityTest.java | 10 +- .../WaterBoilerFluidBoundaryTest.java | 11 +- .../WaterBoilerTankNotificationTest.java | 9 +- .../resources/BuildWorkflowContractTest.java | 14 +- .../MusketFragileTagContractTest.java | 4 +- .../NativeBlockEntityContractTest.java | 20 ++- .../NativeEnchantmentContractTest.java | 126 ++++++++++++++++++ .../resources/NativeFuelContractTest.java | 2 +- .../resources/NativeLootContractTest.java | 10 +- .../NativeRegistrationLifecycleTest.java | 6 +- .../OptionalCrushingRecipeContractTest.java | 2 +- .../resources/RecipeModeContractTest.java | 59 ++++++++ .../resources/RecipeUnlockContractTest.java | 14 +- .../testing/NativeMachineFixture.java | 118 ++++++++++++++++ .../testing/NativeMachineFixtureTest.java | 42 ++++++ tools/generate-recipe-unlocks.js | 4 +- tools/run-packaged-server-smoke.ps1 | 17 ++- tools/verify-enchantment-data.js | 35 +++++ tools/verify-native-port.js | 13 +- 139 files changed, 929 insertions(+), 353 deletions(-) create mode 100644 docs/PORT1211-STATUS.md rename gradle/{forge50-mavenizer.gradle => forge52-mavenizer.gradle} (60%) rename src/gametest/resources/data/basesteam/{structures => structure}/basesteam_empty.nbt (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/blackpowder_cartridge.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/musket_left_normal.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/musket_left_tech.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/musket_right_normal.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/musket_right_tech.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_boiler_coal.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_boiler_electric.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_boiler_geothermal.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_boiler_oil.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_crusher.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_drill.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_drill_bit.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_drill_diamond_pickaxe_normal.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_elevator.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_furnace.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_governor_apocalyptic.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_governor_normal.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_governor_tech.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_pipe.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_pump.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_still.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_switch.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_tank.json (100%) rename src/main/resources/data/basesteam/{advancements => advancement}/recipes/steam_track.json (100%) create mode 100644 src/main/resources/data/basesteam/enchantment/high_explosive.json create mode 100644 src/main/resources/data/basesteam/enchantment/powderless.json create mode 100644 src/main/resources/data/basesteam/enchantment/rapid_reload.json create mode 100644 src/main/resources/data/basesteam/enchantment/recoil.json rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_boiler_coal.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_boiler_electric.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_boiler_geothermal.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_boiler_oil.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_crusher.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_drill.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_elevator.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_furnace.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_pipe.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_pump.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_still.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_switch.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_tank.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/blocks/steam_track.json (100%) rename src/main/resources/data/basesteam/{loot_tables => loot_table}/chests/advantage_parts.json (96%) rename src/main/resources/data/basesteam/{recipes => recipe}/blackpowder_cartridge.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_boiler_coal.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_boiler_electric.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_boiler_geothermal.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_crusher.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_drill.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_elevator.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_furnace.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_governor.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/crushing_steam_tank.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/musket_left_normal.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/musket_left_tech.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/musket_right_normal.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/musket_right_tech.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_boiler_coal.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_boiler_electric.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_boiler_geothermal.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_boiler_oil.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_crusher.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_drill.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_drill_bit.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_drill_diamond_pickaxe_normal.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_elevator.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_furnace.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_governor_apocalyptic.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_governor_normal.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_governor_tech.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_pipe.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_pump.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_still.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_switch.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_tank.json (100%) rename src/main/resources/data/basesteam/{recipes => recipe}/steam_track.json (100%) rename src/main/resources/data/basesteam/tags/{blocks => block}/musket_fragile.json (100%) rename src/main/resources/data/basesteam/tags/{items => item}/muskets.json (100%) rename src/main/resources/data/forge/tags/{items => item}/ammo/blackpowder.json (100%) rename src/main/resources/data/forge/tags/{items => item}/conduits/steam.json (100%) rename src/main/resources/data/forge/tags/{items => item}/governors.json (100%) rename src/main/resources/data/forge/tags/{items => item}/governors/brass.json (100%) rename src/main/resources/data/forge/tags/{items => item}/guns.json (100%) rename src/main/resources/data/forge/tags/{items => item}/wires.json (100%) rename src/main/resources/data/minecraft/tags/{blocks => block}/mineable/pickaxe.json (100%) create mode 100644 src/main/resources/data/minecraft/tags/enchantment/non_treasure.json create mode 100644 src/main/resources/data/minecraft/tags/enchantment/tooltip_order.json rename src/main/resources/data/minecraft/tags/{items => item}/enchantable/durability.json (100%) rename src/main/resources/data/minecraft/tags/{items => item}/enchantable/vanishing.json (100%) create mode 100644 src/test/java/zone/moddev/mc/basesteam/resources/NativeEnchantmentContractTest.java create mode 100644 src/test/java/zone/moddev/mc/basesteam/resources/RecipeModeContractTest.java create mode 100644 src/test/java/zone/moddev/mc/basesteam/testing/NativeMachineFixture.java create mode 100644 src/test/java/zone/moddev/mc/basesteam/testing/NativeMachineFixtureTest.java create mode 100644 tools/verify-enchantment-data.js diff --git a/.github/verify-published-pins.sh b/.github/verify-published-pins.sh index a949ce1..4e2361e 100644 --- a/.github/verify-published-pins.sh +++ b/.github/verify-published-pins.sh @@ -5,11 +5,14 @@ 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.6" --jq '.status')" + if [[ ! "$ref" =~ ^[a-f0-9]{40}$ ]]; then + echo "::error::$repo needs an exact source pin. A pending local candidate is not a public dependency." + exit 1 + fi + status="$(gh api "repos/MinecraftModDevelopmentMods/$repo/compare/$ref...master-1.21.1" --jq '.status')" case "$status" in identical|ahead) ;; - *) echo "::error::$repo $ref is not on upstream master-1.20.6 ($status)."; exit 1 ;; + *) echo "::error::$repo $ref is not on upstream master-1.21.1 ($status)."; exit 1 ;; esac } @@ -36,7 +39,7 @@ require_merged basePower "$power_ref" require_merged BaseMetals "$(value basemetals_source_commit)" require_merged OreSpawn "$orespawn_ref" -inputs="${RUNNER_TEMP:?}/forge50-release-dependencies" +inputs="${RUNNER_TEMP:?}/forge52-release-dependencies" mkdir -p "$inputs" power="$inputs/basePower-$(value poweradvantage_version).jar" metals="$inputs/BaseMetals-$(value basemetals_version).jar" @@ -45,8 +48,8 @@ public_jar basePower 1780140 "$(value poweradvantage_public_file_id)" "$(value p 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" -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' \ +installer="$inputs/forge-1.21.1-52.1.0-installer.jar" +download 'https://maven.minecraftforge.net/net/minecraftforge/forge/1.21.1-52.1.0/forge-1.21.1-52.1.0-installer.jar' \ "$(value forge_installer_sha256)" "$installer" { printf 'power_ref=%s\n' "$power_ref" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4182095..99c0d8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,16 +1,16 @@ -name: baseSteam 1.20.6 CI +name: baseSteam 1.21.1 CI on: push: - branches: [master-1.20.6, 'feature/**'] + branches: [master-1.21.1, 'feature/**'] pull_request: - branches: [master-1.20.6] + branches: [master-1.21.1] permissions: contents: read concurrency: - group: basesteam-1.20.6-${{ github.workflow }}-${{ github.ref }} + group: basesteam-1.21.1-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -62,7 +62,7 @@ jobs: -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Verify the Forge 50 build inputs + - name: Verify the Forge 52 build inputs shell: bash env: ORESPAWN_REF: ${{ steps.public-pins.outputs.orespawn_ref }} @@ -74,7 +74,7 @@ jobs: 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' '4B14145595E900F178A082F2253A756F63897E6F61C2B8B5E7C819B82CD79E8C' "$mavenizer" | sha256sum -c - + printf '%s %s\n' '019032A4A26ECB473D403EF017054D5892CE59A9904E8831B452287CD756397E' "$mavenizer" | sha256sum -c - echo "MAVENIZER=$mavenizer" >> "$GITHUB_ENV" - name: Build the released basePower test bootstrap shell: bash @@ -82,7 +82,7 @@ jobs: 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) + "-Pforge52MavenizerJar=$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" @@ -91,27 +91,27 @@ jobs: run: | ./gradlew $MMD_GRADLE_TOOLCHAINS clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts \ writeReleaseChecksums verifyEclipseProductionClasspath --no-build-cache --no-daemon --stacktrace \ - "-Pforge50MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ + "-Pforge52MavenizerJar=$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.6-${{ github.sha }} + name: baseSteam-1.21.1-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - 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/libs/baseSteam-2.2.15.121011.jar + build/libs/baseSteam-2.2.15.121011-sources.jar + build/libs/baseSteam-2.2.15.121011-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.6-diagnostics-${{ github.sha }} + name: baseSteam-1.21.1-diagnostics-${{ github.sha }} if-no-files-found: ignore retention-days: 14 path: | diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 838d738..f3faaa9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,9 +2,9 @@ name: CodeQL on: push: - branches: [master-1.20.6, 'feature/**'] + branches: [master-1.21.1, 'feature/**'] pull_request: - branches: [master-1.20.6] + branches: [master-1.21.1] permissions: contents: read @@ -12,7 +12,7 @@ permissions: security-events: write concurrency: - group: basesteam-1.20.6-${{ github.workflow }}-${{ github.ref }} + group: basesteam-1.21.1-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -64,7 +64,7 @@ jobs: -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Verify the Forge 50 build inputs + - name: Verify the Forge 52 build inputs shell: bash env: ORESPAWN_REF: ${{ steps.public-pins.outputs.orespawn_ref }} @@ -76,7 +76,7 @@ jobs: 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' '4B14145595E900F178A082F2253A756F63897E6F61C2B8B5E7C819B82CD79E8C' "$mavenizer" | sha256sum -c - + printf '%s %s\n' '019032A4A26ECB473D403EF017054D5892CE59A9904E8831B452287CD756397E' "$mavenizer" | sha256sum -c - echo "MAVENIZER=$mavenizer" >> "$GITHUB_ENV" - name: Initialize CodeQL uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 @@ -87,7 +87,7 @@ jobs: shell: bash run: | ./gradlew $MMD_GRADLE_TOOLCHAINS classes verifyReleaseDependencies --rerun-tasks --no-build-cache --no-daemon --stacktrace \ - "-Pforge50MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ + "-Pforge52MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ "-PbaseMetalsDeobfJar=$METALS_PLAYER" "-PoreSpawnDeobfJar=$ORESPAWN_PLAYER" - name: Analyze uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 diff --git a/.github/workflows/release-on-tag.yml b/.github/workflows/release-on-tag.yml index 2d1fca3..94ce821 100644 --- a/.github/workflows/release-on-tag.yml +++ b/.github/workflows/release-on-tag.yml @@ -37,6 +37,11 @@ jobs: minecraft_version="$(value minecraft_version)" loader_name="$(value loader_name)" loader_code="$(value loader_code)" + if [[ "$minecraft_version" != '1.21.1' || "$(value forge_version)" != '52.1.0' || + "$(value mapping_version)" != '1.21.1' || "$(value mcp_version)" != '20240808.132146' ]]; then + echo 'Expected the exact Minecraft 1.21.1 Forge 52.1.0 release target' >&2 + exit 1 + fi IFS=. read -r mc_major mc_minor mc_patch extra <<<"$minecraft_version" if [[ -n "${extra:-}" || -z "${mc_major:-}" || -z "${mc_minor:-}" ]]; then diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index 2c47d12..2f2c732 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.6 + - master-1.21.1 - 'feature/**' pull_request: branches: - - master-1.20.6 + - master-1.21.1 permissions: contents: read diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 2580113..cde438f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,9 @@ +baseSteam 2.2.15.121011 (local Minecraft 1.21.1 candidate) + +- Target Forge 52.1.0 and Java 21 with basePower 2.4.14.121011. +- Keep machine balance, saved state, recipes and the whole fluid gauges unchanged. +- Move musket enchantments to native data while retaining all four IDs and effects. + 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. diff --git a/README.md b/README.md index 5d1a3c5..ba7f0ea 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,31 @@ # baseSteam -**Minecraft 1.20.6 (Forge), version 2.2.14.120061.** +**Minecraft 1.21.1 (Forge), local candidate 2.2.15.121011.** -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. +baseSteam adds boilers, steam-powered machines, pumps, storage, elevators +and a blackpowder musket to basePower. Items and blocks share the basePower +creative tab. The mod ID and resource namespace remain `basesteam`. -## Build Target +## Build -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. +Target: Forge 52.1.0, official Minecraft 1.21.1 mappings and MCP +20240808.132146. ForgeGradle 7.0.34 and the checksum-pinned Gradle 9.6.1 +wrapper use Temurin 21.0.7+6. Mavenizer uses Java 25; the launcher helper +also needs Java 8. Minecraft itself runs on Java 21. -Forge 50 uses official names at runtime. Steam does not run an SRG renamer. -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`. +The default dependency paths use the coordinated 1.21.1 checkouts. This +candidate needs basePower 2.4.14.121011, Base Metals 3.1.2.121011 and +OreSpawn 4.1.0.121011 as separate native jars, not bundled copies. +Exact local source, jar and test-bootstrap pins are in `gradle.properties`. +They are checked before compilation and tests. Local approval does not +establish public availability. -## Local Verification +The Mavenizer fixture comes from OreSpawn's OS1211 checkout. Another layout +can use `-Pforge52MavenizerJar=`. The `*DeobfJar` and `*PlayerJar` +properties select separate development and packaged inputs; both must +satisfy the committed checksums. -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`. -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: +With the pinned local dependencies available: ```powershell $env:JAVA_HOME = "$env:USERPROFILE/.jdks/temurin-21.0.7+6" @@ -43,37 +35,29 @@ $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 verifyEclipseProductionClasspath ./gradlew.bat @toolchains -PsteamGameTestRunId=candidate verifyPlayerDependencies runGameTestServer -./tools/run-packaged-server-smoke.ps1 -ForgeInstall $env:FORGE_1206_SERVER_INSTALL -RunId candidate-with-basemetals +./tools/run-packaged-server-smoke.ps1 -ForgeInstall $env:FORGE_1211_SERVER_INSTALL -RunId candidate-with-metals +./tools/run-packaged-server-smoke.ps1 -ForgeInstall $env:FORGE_1211_SERVER_INSTALL -RunId candidate-without-metals -WithoutBaseMetals ``` -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 -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 the [1.20.6 notes](docs/PORT1206-STATUS.md) for save compatibility and test coverage. +Independent source checks: `node tools/verify-native-port.js` and +`node tools/generate-recipe-unlocks.js --check`. +Hosted CI and CodeQL require merged sources and checksum-matching public +downloads before compiling. Pending local pins cannot pass that gate. -## Upgrading a World +## Old Worlds -Back up the world and upgrade a disposable copy. Do not install both Steam +Back up worlds and upgrade disposable copies. 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. +version. Existing `basesteam-common.toml` settings take precedence. -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. +Steam retains machine IDs and saved fields, drill directions, musket wear +and loading, and all four musket enchantments. The singular datapack folders +do not change logical recipe or advancement identities. -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. +Use basePower's migration rig for whole-world checks. Before accepting the +port, check machines, restarts, redstone, all drill directions, elevators, +GUI captions, whole fluid gauges, track transparency and musket effects +in-game. Automated, packaged and manual acceptance are separate gates. +See the [1.21.1 notes](docs/PORT1211-STATUS.md). diff --git a/build.gradle b/build.gradle index 486d147..a8f4d9b 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ plugins { id 'net.minecraftforge.gradle' version '7.0.34' } -apply from: 'gradle/forge50-mavenizer.gradle' +apply from: 'gradle/forge52-mavenizer.gradle' group = project.mod_group version = project.mod_version @@ -151,7 +151,7 @@ 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 50 launches.' + description = 'Merges classes and processed resources for Forge 52 launches.' dependsOn tasks.named('classes') from sourceSets.main.output into forgeRunModClassesDirectory @@ -230,12 +230,12 @@ 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/.verification-basemetals1206/Advantage shared hook' +def baseMetalsRoot = '../../../../BaseMetals/.verification-basemetals1211/Advantage shared hook' def powerNativeJar = file("${powerRoot}/build/libs/basePower-${project.poweradvantage_version}.jar") def powerAdvantageDeobfJar = explicitJar('powerAdvantageDeobfJar') ?: powerNativeJar def baseMetalsDeobfJar = explicitJar('baseMetalsDeobfJar') ?: file( "${baseMetalsRoot}/build/libs/BaseMetals-${project.basemetals_version}.jar") -def oreSpawnRoot = '../../../../MinecraftMineralogy/OS1206/OreSpawn' +def oreSpawnRoot = '../../../../MinecraftMineralogy/OS1211/OreSpawn' def oreSpawnJar = { String variant -> explicitJar("oreSpawn${variant}Jar") ?: file( "${oreSpawnRoot}/build/libs/OreSpawn-${project.orespawn_version}.jar") @@ -360,7 +360,7 @@ tasks.named('jar', Jar) { } } -// Forge 50 runs official names. The player jar needs no SRG remapping. +// Forge 52 runs official names. The player jar needs no SRG remapping. def releaseJar = tasks.register('releaseJar', Jar) { dependsOn tasks.named('classes'), 'verifyReleaseDependencies' archiveClassifier = null @@ -437,8 +437,8 @@ def expectedReleaseFiles = providers.provider { def preparedReleaseDir = providers.gradleProperty('preparedReleaseDir') def verifyPackFormats = { pack -> - 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') + if (pack.pack_format != 34 || pack.supported_formats != [min_inclusive: 34, max_inclusive: 48]) { + throw new GradleException('Minecraft 1.21.1 requires resource format 34 and data format 48') } } @@ -447,15 +447,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.14.120061') { + Properties wrapper = new Properties() + file('gradle/wrapper/gradle-wrapper.properties').withInputStream { wrapper.load(it) } + if (wrapper.getProperty('distributionUrl') != 'https://services.gradle.org/distributions/gradle-9.6.1-bin.zip' + || wrapper.getProperty('distributionSha256Sum') != + '9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14') { + throw new GradleException('Use the checksum-pinned Gradle 9.6.1 wrapper') + } + if (project.mod_version != '2.2.15.121011') { throw new GradleException("Unexpected baseSteam release version: ${project.mod_version}") } - 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)' + if (project.minecraft_version != '1.21.1' || project.minecraft_version_range != '[1.21.1]' + || project.forge_version != '52.1.0' || project.forge_version_range != '[52.1.0,53)' + || project.loader_version_range != '[52,53)' || project.mapping_channel != 'official' - || project.mapping_version != '1.20.6' - || project.mcp_version != '20240429.135109') { + || project.mapping_version != '1.21.1' + || project.mcp_version != '20240808.132146') { throw new GradleException('Unexpected Minecraft, Forge, or mappings target') } if (project.loader_name != 'forge' || project.loader_code != '1' @@ -475,11 +482,11 @@ tasks.register('verifyReleaseConfiguration') { } if (project.cf_requirements != 'basepower,base-metals' || project.cf_optionals != '' - || project.cf_versions != '1.20.6') { + || project.cf_versions != '1.21.1') { throw new GradleException('Unexpected CurseForge dependency or game-version metadata') } - if (project.basemetals_version != '3.1.2.120061' - || project.orespawn_version != '4.1.0.120061') { + if (project.basemetals_version != '3.1.2.121011' + || project.orespawn_version != '4.1.0.121011') { throw new GradleException('Unexpected development API versions') } if (project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/basePower') { @@ -488,13 +495,13 @@ tasks.register('verifyReleaseConfiguration') { 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.14.120061"')) { + || !mainSource.contains('VERSION = "2.2.15.121011"')) { 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="[${poweradvantage_version},3.0.0)"', - 'modId="basemetals"\nmandatory=false\nversionRange="[3.1.2.120061,4.0.0)"'].each { marker -> + 'modId="basemetals"\nmandatory=false\nversionRange="[3.1.2.121011,4.0.0)"'].each { marker -> if (!metadata.contains(marker)) { throw new GradleException("Source mods.toml is missing ${marker}") } @@ -580,7 +587,7 @@ tasks.register('verifyPlayerDependencies') { dependsOn tasks.named('verifyCompanionPlayerDependencies') doLast { committedPin('poweradvantage_source_ref', /[a-f0-9]{40}/) - committedPin('poweradvantage_version', /\d+\.\d+\.\d+\.120061/) + committedPin('poweradvantage_version', /\d+\.\d+\.\d+\.121011/) auditJar(explicitJar('powerAdvantagePlayerJar') ?: powerNativeJar, 'powerAdvantagePlayerJar', 'poweradvantage_player_sha256', 'basepower', project.poweradvantage_version, powerApi) } @@ -591,7 +598,7 @@ 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_version', /\d+\.\d+\.\d+\.121011/) committedPin('poweradvantage_source_ref', /[a-f0-9]{40}/) auditJar(powerAdvantageDeobfJar, 'powerAdvantageDeobfJar', 'poweradvantage_deobf_sha256', 'basepower', project.poweradvantage_version, powerApi) @@ -695,12 +702,19 @@ 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', + 'data/basesteam/loot_table/chests/advantage_parts.json', 'assets/basesteam/lang/en_us.json', 'data/basesteam/damage_type/musket.json', 'data/basesteam/damage_type/steam_machine.json', - 'data/basesteam/recipes/steam_pipe.json', - 'data/basesteam/advancements/recipes/steam_pipe.json'].each { required -> + 'data/basesteam/recipe/steam_pipe.json', + 'data/basesteam/enchantment/high_explosive.json', + 'data/basesteam/enchantment/powderless.json', + 'data/basesteam/enchantment/rapid_reload.json', + 'data/basesteam/enchantment/recoil.json', + 'data/basesteam/tags/item/muskets.json', + 'data/minecraft/tags/enchantment/non_treasure.json', + 'data/minecraft/tags/enchantment/tooltip_order.json', + 'data/basesteam/advancement/recipes/steam_pipe.json'].each { required -> if (!names.contains(required)) { throw new GradleException("Release jar is missing ${required}") } @@ -709,7 +723,7 @@ tasks.register('verifyReleaseArtifacts') { 'steam_boiler_geothermal', 'steam_tank', 'steam_furnace', 'steam_crusher', 'steam_drill', 'steam_elevator', 'steam_switch', 'steam_still', 'steam_pump', 'steam_boiler_oil'].each { id -> - if (!names.contains("data/basesteam/loot_tables/blocks/${id}.json".toString())) { + if (!names.contains("data/basesteam/loot_table/blocks/${id}.json".toString())) { throw new GradleException("Release jar is missing native block loot for ${id}") } } @@ -717,7 +731,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', + 'zone/moddev/mc/basesteam/gametest/', 'data/basesteam/structure/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/', @@ -728,6 +742,10 @@ tasks.register('verifyReleaseArtifacts') { throw new GradleException("Release jar contains forbidden entry matching ${forbidden}") } } + if (names.any { it ==~ /data\/[^\/]+\/(?:recipes|advancements|loot_tables|structures)\/.*/ + || it ==~ /data\/[^\/]+\/tags\/(?:items|blocks)\/.*/ }) { + throw new GradleException('Release jar contains pre-1.21 datapack registry directories') + } String metadata = zip.getInputStream(zip.getEntry('META-INF/mods.toml')) .getText(StandardCharsets.UTF_8.name()) if (!metadata.contains('modId="basesteam"') @@ -1221,7 +1239,7 @@ tasks.register('verifyEclipseProductionClasspath') { || (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 50 bootstrap and Java 21 module access") + throw new GradleException("${name} must retain the native Forge 52 bootstrap and Java 21 module access") } if (launch.booleanAttribute.find { it.@key.text() == 'org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE' @@ -1279,7 +1297,7 @@ tasks.register('verifyEclipseProductionClasspath') { String target = name == 'runClient.launch' ? 'forge_userdev_client' : 'forge_userdev_server' if (!arguments.contains("--launchTarget ${target}") || !arguments.contains("forge-${project.minecraft_version}-${project.forge_version}-metadata.zip")) { - throw new GradleException("${name} does not target the exact Forge 50 development runtime") + throw new GradleException("${name} does not target the exact Forge 52 development runtime") } } } @@ -1424,7 +1442,7 @@ tasks.register('verifyRepositoryHygiene') { tasks.register('verifyRecipeTagGuards') { group = 'verification' description = 'Rejects recipes that can collapse when a Forge material tag is empty.' - File recipeRoot = file("src/main/resources/data/${project.mod_id}/recipes") + File recipeRoot = file("src/main/resources/data/${project.mod_id}/recipe") inputs.dir(recipeRoot) doLast { Closure collectTags @@ -1474,7 +1492,35 @@ tasks.register('verifyRecipeTagGuards') { } } +tasks.register('verifyDataPackLayout') { + group = 'verification' + description = 'Rejects obsolete datapack paths and missing data-driven musket enchantments.' + inputs.dir('src/main/resources/data') + inputs.dir('src/gametest/resources/data') + doLast { + List obsolete = files(fileTree('src/main/resources/data'), + fileTree('src/gametest/resources/data')).files.collect { + relativePath(it).replace('\\', '/') + }.findAll { it ==~ /.*\/data\/[^\/]+\/(?:recipes|advancements|loot_tables|structures)\/.*/ + || it ==~ /.*\/data\/[^\/]+\/tags\/(?:items|blocks)\/.*/ } + if (!obsolete.isEmpty()) throw new GradleException("Obsolete datapack directories: ${obsolete}") + if (!file('src/gametest/resources/data/basesteam/structure/basesteam_empty.nbt').isFile()) { + throw new GradleException('Missing native GameTest structure path') + } + ['high_explosive', 'powderless', 'rapid_reload', 'recoil'].each { id -> + File definition = file("src/main/resources/data/basesteam/enchantment/${id}.json") + if (!definition.isFile()) throw new GradleException("Missing musket enchantment: ${id}") + Map value = new JsonSlurper().parse(definition) as Map + if (value.supported_items != '#basesteam:muskets' || value.slots != ['mainhand'] + || value.effects != [:]) { + throw new GradleException("Unexpected native musket enchantment contract: ${id}") + } + } + } +} + tasks.named('check') { + dependsOn tasks.named('verifyDataPackLayout') dependsOn verifyJavaSourceLayout dependsOn tasks.named('verifyReleaseConfiguration') dependsOn tasks.named('verifyModelAssets') diff --git a/docs/PORT1211-STATUS.md b/docs/PORT1211-STATUS.md new file mode 100644 index 0000000..cc2a9ef --- /dev/null +++ b/docs/PORT1211-STATUS.md @@ -0,0 +1,24 @@ +# Steam on Minecraft 1.21.1 + +Local candidate 2.2.15.121011 targets Forge 52.1.0 and Java 21. +The build pins the coordinated local basePower commit `72fd326b9a9c` and +its exact native jar. Public CI still requires merged sources and verified +public files. Nothing has been published. + +Steam keeps its mod ID, packages, registry paths, configuration and machine +balance. Datapack registry folders use the native singular names, without +changing logical recipe or advancement IDs. All recipe modes and ingredient +guards remain in place. + +The four musket enchantments now load from data and resolve real registry +holders. Their IDs, costs, levels and effects are unchanged. Migration tests +cover their legacy names alongside wear and the loaded byte. Machine state, +drill packets, server-side menus and the whole fluid gauges remain covered +by the Steam tests. The pinned local suite passes 228 tests without skips, +plus four native GameTests, archive audits and the Eclipse classpath gate. +Fresh packaged dedicated servers also start and stop cleanly with and +without Base Metals. + +Back up old worlds and use disposable copies with basePower's coordinated +migration rig. These Steam checks do not establish combined world-upgrade, +multiplayer or manual visual acceptance. diff --git a/gradle.properties b/gradle.properties index 63e284e..228f56a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,15 +5,19 @@ org.gradle.caching=true org.gradle.parallel=false net.minecraftforge.gradle.merge-source-sets=false -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) +minecraft_version=1.21.1 +minecraft_version_range=[1.21.1] +forge_version=52.1.0 +forge_installer_sha256=F1B620F2879AD6A5BBE15DABA4D8F81EAB9F5E08004967604960B98996BDEBC4 +# Packaged smoke requires hashes from the coordinated, verified Forge 52 installation. +forge_server_shim_sha256=F7B706C79896728723DA0E4E8C5A6ECDB6A617AD4DF9D7EA1DDC6367187BC291 +forge_server_sha256=2DEA3FEFAD7DDF03E0A609CB2084A651732A35AE46DCF1D949D9359405A8621F +forge_universal_sha256=88EF6625122CFDB9D7B3176BD61B8C0692A191BAD0EDD77FFDDC6A765EE4979C +forge_version_range=[52.1.0,53) +loader_version_range=[52,53) mapping_channel=official -mapping_version=1.20.6 -mcp_version=20240429.135109 +mapping_version=1.21.1 +mcp_version=20240808.132146 loader_name=forge loader_code=1 @@ -26,35 +30,36 @@ curseforge_project_id=1781373 mod_id=basesteam mod_name=baseSteam mod_license=GPL-3.0-only -mod_version=2.2.14.120061 +mod_version=2.2.15.121011 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.6 +cf_versions=1.21.1 -poweradvantage_version=2.4.13.120061 +poweradvantage_version=2.4.14.121011 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower -# Native release provenance is checked before a hosted build. -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 -poweradvantage_test_bootstrap_sha256=96752A443070E117EED9308ABC9C2009BD3533F121C9594A7108908E104673C9 -poweradvantage_test_bootstrap_source_sha256=9E0EFE07A889726489810AA960FECD0387F35B6BF44085E03C68EEE011D62693 +# Exact coordinated local candidate. Source and jar checks reject overrides. +# Public file IDs await independent public download verification; local approval is not publication. +poweradvantage_source_ref=72fd326b9a9c28e1b2447dfc5ebed99677f09872 +poweradvantage_public_file_id= +poweradvantage_deobf_sha256=76CF79E04F36947D25535B982099B31AA88907448959F063BEA617644B7179F7 +# Forge 52 uses the same native jar for development and packaged runtime. +poweradvantage_player_sha256=76CF79E04F36947D25535B982099B31AA88907448959F063BEA617644B7179F7 +poweradvantage_test_bootstrap_sha256=6AF174EBBBF2501457CE4786A130AFDB6ED92CC47DD105465F9EF8685ECE90E3 +poweradvantage_test_bootstrap_source_sha256=CCEB755FDA6D38C492124DC122C993FA7EDA2A945CB603573D4CD9562B6AE280 poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF56CD6203C9CD692CAC1531D0981F -basemetals_version=3.1.2.120061 -basemetals_source_commit=e9d92f157ee5056a31e479d5b8f9dca8f0648c12 -basemetals_public_file_id=9543397 -basemetals_deobf_sha256=6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D -basemetals_player_sha256=6186AC62C7E2E333373EA0D8AD8DE53FF859C520EBF568DFB47517C4F77C8C5D +basemetals_version=3.1.2.121011 +basemetals_source_commit=b42b92b0e6f60ac5baf07a6b74042b2fa8427904 +basemetals_public_file_id= +basemetals_deobf_sha256=7C0B961A8D4991C9B69379518AAD700A71C1E4B2076CF5DEF292C58029408A07 +basemetals_player_sha256=7C0B961A8D4991C9B69379518AAD700A71C1E4B2076CF5DEF292C58029408A07 -orespawn_version=4.1.0.120061 -orespawn_source_commit=4085315345ff043448b316d75e03f4b8da45402d -orespawn_public_file_id=9183384 -orespawn_deobf_sha256=FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26 -orespawn_player_sha256=FAA7107B9FB84E2C62ED847CAFD880AA3C4238A37799BAD955EA9602A944AA26 +orespawn_version=4.1.0.121011 +orespawn_source_commit=62c08169c71f4d4fd8f107289e63fd2a4c7c655c +orespawn_public_file_id= +orespawn_deobf_sha256=EB369B7D7CE6D6C453658347A420C2F0783B7F4D1AC7383C87176AC05192B5A0 +orespawn_player_sha256=EB369B7D7CE6D6C453658347A420C2F0783B7F4D1AC7383C87176AC05192B5A0 diff --git a/gradle/forge50-mavenizer.gradle b/gradle/forge52-mavenizer.gradle similarity index 60% rename from gradle/forge50-mavenizer.gradle rename to gradle/forge52-mavenizer.gradle index 9e993e7..9031f95 100644 --- a/gradle/forge50-mavenizer.gradle +++ b/gradle/forge52-mavenizer.gradle @@ -1,18 +1,18 @@ import java.security.MessageDigest import org.gradle.jvm.toolchain.JvmVendorSpec -// Use the sealed OreSpawn 1.20.6 fixture; Forge 50 needs no source repairs. +// Use OreSpawn's checksum-verified fixture for the native Forge 52 toolchain. def tool = 'ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar' -def defaultJar = "../../../../MinecraftMineralogy/OS1206/OreSpawn/${tool}" -def fixture = file(providers.gradleProperty('forge50MavenizerJar').getOrElse(defaultJar)) -def expected = '4B14145595E900F178A082F2253A756F63897E6F61C2B8B5E7C819B82CD79E8C' +def defaultJar = "../../../../MinecraftMineralogy/OS1211/OreSpawn/${tool}" +def fixture = file(providers.gradleProperty('forge52MavenizerJar').getOrElse(defaultJar)) +def expected = '019032A4A26ECB473D403EF017054D5892CE59A9904E8831B452287CD756397E' if (!fixture.isFile()) { - throw new GradleException("Forge 50 requires OreSpawn's Mavenizer fixture: ${fixture}. " - + "Use -Pforge50MavenizerJar= for another checkout layout.") + throw new GradleException("Forge 52 requires OreSpawn's Mavenizer fixture: ${fixture}. " + + "Use -Pforge52MavenizerJar= 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 50 Mavenizer fixture SHA-256 mismatch: expected ${expected}, got ${actual}") + throw new GradleException("Forge 52 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 index 837a33d..479c474 100644 --- a/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java +++ b/src/gametest/java/zone/moddev/mc/basesteam/gametest/SteamNativeGameTests.java @@ -11,6 +11,7 @@ import net.minecraft.gametest.framework.GameTest; import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; @@ -34,6 +35,7 @@ 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.init.Enchantments; import zone.moddev.mc.basesteam.items.MusketItem; @GameTestHolder(value = SteamAdvantage.MODID, namespace = SteamAdvantage.MODID) @@ -75,6 +77,7 @@ public static void legacyMusketWearAndLoadedByteSurviveNativeComponentization(Ga tag.putInt("Damage", 249); tag.putByte("loaded", (byte) 1); tag.putString("owner", "legacy fixture"); + tag.put("Enchantments", legacyEnchantments("basesteam")); legacy.put("tag", tag); var registries = helper.getLevel().registryAccess(); var fixed = DataFixers.getDataFixer().update(References.ITEM_STACK, @@ -83,12 +86,14 @@ public static void legacyMusketWearAndLoadedByteSurviveNativeComponentization(Ga 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"); + assertMusketEnchantments(helper, stack); 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"); + assertMusketEnchantments(helper, reloaded); helper.succeed(); } @@ -100,12 +105,14 @@ public static void olderMusketAliasAndTopLevelWearSurvivePowerMigration(GameTest legacy.putShort("Damage", (short) 131); CompoundTag tag = new CompoundTag(); tag.putByte("loaded", (byte) 2); + tag.put("Enchantments", legacyEnchantments("steamadvantage")); 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"); + assertMusketEnchantments(helper, migrated); helper.succeed(); } @@ -113,9 +120,22 @@ public static void olderMusketAliasAndTopLevelWearSurvivePowerMigration(GameTest public static void nativeResourcesLoadWithExpectedIds(GameTestHelper helper) { var level = helper.getLevel(); var registries = level.registryAccess(); + var nativeEnchantments = registries.registryOrThrow(Registries.ENCHANTMENT); + for (var key : java.util.List.of(Enchantments.high_explosive, Enchantments.powderless, + Enchantments.rapid_reload, Enchantments.recoil)) { + var holder = nativeEnchantments.getHolderOrThrow(key); + helper.assertTrue(holder.is(net.minecraft.tags.EnchantmentTags.IN_ENCHANTING_TABLE), + "Missing table discovery for " + key.location()); + helper.assertTrue(holder.is(net.minecraft.tags.EnchantmentTags.TRADEABLE), + "Missing enchanted-book trade discovery for " + key.location()); + helper.assertTrue(holder.is(net.minecraft.tags.EnchantmentTags.ON_RANDOM_LOOT), + "Missing random loot discovery for " + key.location()); + helper.assertTrue(holder.value().isPrimaryItem(new ItemStack(Items.blackpowder_musket)), + "Native musket support tag was not bound for " + key.location()); + } 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"); + "The 1.21.1 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(); @@ -162,4 +182,25 @@ public static void nativeResourcesLoadWithExpectedIds(GameTestHelper helper) { private static ResourceLocation id(String path) { return ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, path); } + + private static ListTag legacyEnchantments(String namespace) { + ListTag result = new ListTag(); + for (String path : java.util.List.of("high_explosive", "powderless", "rapid_reload", "recoil")) { + CompoundTag enchantment = new CompoundTag(); + enchantment.putString("id", namespace + ":" + path); + enchantment.putShort("lvl", (short) (path.equals("high_explosive") || path.equals("recoil") ? 5 : 1)); + result.add(enchantment); + } + return result; + } + + private static void assertMusketEnchantments(GameTestHelper helper, ItemStack stack) { + var registries = helper.getLevel().registryAccess(); + for (var key : java.util.List.of(Enchantments.high_explosive, Enchantments.powderless, + Enchantments.rapid_reload, Enchantments.recoil)) { + int expected = key.equals(Enchantments.high_explosive) || key.equals(Enchantments.recoil) ? 5 : 1; + helper.assertTrue(Enchantments.level(key, stack, registries) == expected, + "Lost legacy enchantment holder or level: " + key.location()); + } + } } diff --git a/src/gametest/resources/data/basesteam/structures/basesteam_empty.nbt b/src/gametest/resources/data/basesteam/structure/basesteam_empty.nbt similarity index 100% rename from src/gametest/resources/data/basesteam/structures/basesteam_empty.nbt rename to src/gametest/resources/data/basesteam/structure/basesteam_empty.nbt diff --git a/src/main/java/zone/moddev/mc/basesteam/SteamAdvantage.java b/src/main/java/zone/moddev/mc/basesteam/SteamAdvantage.java index 4e698d8..0afc165 100644 --- a/src/main/java/zone/moddev/mc/basesteam/SteamAdvantage.java +++ b/src/main/java/zone/moddev/mc/basesteam/SteamAdvantage.java @@ -27,12 +27,12 @@ import zone.moddev.mc.basesteam.migration.SteamConfigMigration; import zone.moddev.mc.basesteam.recipe.RecipeConditions; -/** Forge 1.20.6 entry point for baseSteam. */ +/** Forge 1.21.1 entry point for baseSteam. */ @Mod(SteamAdvantage.MODID) public final class SteamAdvantage { public static final String MODID = "basesteam"; public static final String NAME = "baseSteam"; - public static final String VERSION = "2.2.14.120061"; + public static final String VERSION = "2.2.15.121011"; public static final Logger LOGGER = LogManager.getLogger(MODID); public static float MUSKET_DAMAGE = 20.0F; 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 5ece19d..6d79986 100644 --- a/src/main/java/zone/moddev/mc/basesteam/compat/BaseMetalsCompat.java +++ b/src/main/java/zone/moddev/mc/basesteam/compat/BaseMetalsCompat.java @@ -2,7 +2,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.SimpleContainer; +import net.minecraft.world.item.crafting.SingleRecipeInput; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -36,8 +36,7 @@ public static ItemStack getCrusherRecipeOutput(Level world, ItemStack input) { // Resolve the optional recipe type only after Forge confirms Base Metals is installed. private static final class LoadedCrushingRecipes { private static ItemStack find(Level world, ItemStack input) { - SimpleContainer inventory = new SimpleContainer(1); - inventory.setItem(0, input.copy()); + SingleRecipeInput inventory = new SingleRecipeInput(input.copy()); for (var candidate : world.getRecipeManager().getAllRecipesFor(CrushingRecipe.TYPE.get())) { CrushingRecipe crushing = candidate.value(); if (crushing.matches(inventory, world)) { 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 4d7fad5..94dfb6e 100644 --- a/src/main/java/zone/moddev/mc/basesteam/graphics/DrillBitRenderer.java +++ b/src/main/java/zone/moddev/mc/basesteam/graphics/DrillBitRenderer.java @@ -79,8 +79,8 @@ static void renderGeometry(Direction.Axis axis, float rotation, PoseStack matric private static void vertex(PoseStack.Pose transform, VertexConsumer vertices, float x, float y, float z, float u, float v, 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, normalX, normalY, normalZ).endVertex(); + vertices.addVertex(transform.pose(), x, y, z).setColor(255, 255, 255, 255).setUv(u, v) + .setOverlay(overlay).setLight(light) + .setNormal(transform, normalX, normalY, normalZ); } } diff --git a/src/main/java/zone/moddev/mc/basesteam/gui/GUIHelper.java b/src/main/java/zone/moddev/mc/basesteam/gui/GUIHelper.java index 127d292..d1f5976 100644 --- a/src/main/java/zone/moddev/mc/basesteam/gui/GUIHelper.java +++ b/src/main/java/zone/moddev/mc/basesteam/gui/GUIHelper.java @@ -66,7 +66,6 @@ public static void drawNeedle(float pivotX, float pivotY, float zLevel, float angle = (1f - value) * PI; float offsetX = pivotX; float offsetY = pivotY; - BufferBuilder renderer = Tesselator.getInstance().getBuilder(); float sin = Mth.sin(angle); float cos = Mth.cos(angle); @@ -101,13 +100,14 @@ public static void drawNeedle(float pivotX, float pivotY, float zLevel, v[3] = v[0]; com.mojang.blaze3d.systems.RenderSystem.setShader(net.minecraft.client.renderer.GameRenderer::getPositionTexShader); - renderer.begin(com.mojang.blaze3d.vertex.VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); + BufferBuilder renderer = Tesselator.getInstance().begin( + com.mojang.blaze3d.vertex.VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); // (x, y, z, u, v) for(int i = 3; i >= 0; i--){ - renderer.vertex(x[i], y[i], zLevel).uv(u[i],v[i]).endVertex();; + renderer.addVertex(x[i], y[i], zLevel).setUv(u[i],v[i]); } - com.mojang.blaze3d.vertex.Tesselator.getInstance().end(); + com.mojang.blaze3d.vertex.BufferUploader.drawWithShader(renderer.buildOrThrow()); } 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 b6aa983..8bec0b5 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/Enchantments.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/Enchantments.java @@ -1,54 +1,30 @@ package zone.moddev.mc.basesteam.init; import zone.moddev.mc.basesteam.SteamAdvantage; -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.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegisterEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.eventbus.api.SubscribeEvent; -@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")); +/** Stable save identities; holders belong to the current world's data-driven registry. */ +public final class Enchantments { + public static final ResourceKey rapid_reload = key("rapid_reload"); + public static final ResourceKey powderless = key("powderless"); + public static final ResourceKey high_explosive = key("high_explosive"); + public static final ResourceKey recoil = key("recoil"); - public static Enchantment rapid_reload; - public static Enchantment powderless; - public static Enchantment high_explosive; - public static Enchantment recoil; + private Enchantments() {} - public static void init(){ - createEnchantments(); - } + public static int level(ResourceKey enchantment, ItemStack stack, RegistryAccess registries) { + return EnchantmentHelper.getItemEnchantmentLevel( + registries.registryOrThrow(Registries.ENCHANTMENT).getHolderOrThrow(enchantment), stack); + } - @SubscribeEvent - public static void registerEnchantments(RegisterEvent event) { - if (!ForgeRegistries.Keys.ENCHANTMENTS.equals(event.getRegistryKey())) return; - init(); - event.register(ForgeRegistries.Keys.ENCHANTMENTS, registry -> { - 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 = 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)); - } + private static ResourceKey key(String path) { + return ResourceKey.create(Registries.ENCHANTMENT, + ResourceLocation.fromNamespaceAndPath(SteamAdvantage.MODID, path)); + } } diff --git a/src/main/java/zone/moddev/mc/basesteam/init/TreasureChests.java b/src/main/java/zone/moddev/mc/basesteam/init/TreasureChests.java index bb25bb1..7e33d2a 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/TreasureChests.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/TreasureChests.java @@ -102,8 +102,7 @@ private static void writeLootFile(Path file, String content){ " \"functions\": [\n" + " {\n" + " \"function\": \"minecraft:enchant_with_levels\",\n" + - " \"levels\": 10,\n" + - " \"treasure\": true\n" + + " \"levels\": 10\n" + " }\n" + " ]\n" + " }\n" + 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 0786e07..638734d 100644 --- a/src/main/java/zone/moddev/mc/basesteam/init/Villages.java +++ b/src/main/java/zone/moddev/mc/basesteam/init/Villages.java @@ -1,6 +1,8 @@ package zone.moddev.mc.basesteam.init; import java.util.List; +import net.minecraft.core.registries.Registries; +import net.minecraft.tags.EnchantmentTags; import net.minecraft.util.RandomSource; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.entity.npc.VillagerProfession; @@ -36,8 +38,10 @@ 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(trader.level().enabledFeatures(), random, - new ItemStack(Items.blackpowder_musket), enchantmentLevel, false); + ItemStack musket = EnchantmentHelper.enchantItem(random, + new ItemStack(Items.blackpowder_musket), enchantmentLevel, + trader.registryAccess().registryOrThrow(Registries.ENCHANTMENT) + .getTag(EnchantmentTags.NON_TREASURE).orElseThrow().stream()); int price = Math.min(randomPrice(random, 15, 25) + enchantmentLevel, 64); return offer(price, musket); }); 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 9f4f866..38ffccc 100644 --- a/src/main/java/zone/moddev/mc/basesteam/items/MusketItem.java +++ b/src/main/java/zone/moddev/mc/basesteam/items/MusketItem.java @@ -15,7 +15,6 @@ 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; @@ -69,8 +68,8 @@ public class MusketItem extends net.minecraft.world.item.Item{ public MusketItem(Item.Properties properties){ super(properties.durability(250).attributes(ItemAttributeModifiers.builder() - .add(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, - "Weapon modifier", getMeleeDamage(), AttributeModifier.Operation.ADD_VALUE), + .add(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_ID, + getMeleeDamage(), AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND) .build())); } @@ -105,7 +104,7 @@ public InteractionResultHolder use(Level world, Player playerEntity, ItemStack srcItemStack = playerEntity.getItemInHand(hand); if(hand != InteractionHand.MAIN_HAND) return InteractionResultHolder.pass(srcItemStack); if(isNotLoaded(srcItemStack) && !hasAmmo(playerEntity, srcItemStack)) return InteractionResultHolder.fail(srcItemStack); - if(isNotLoaded(srcItemStack) && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.rapid_reload, srcItemStack) > 0){ + if(isNotLoaded(srcItemStack) && Enchantments.level(Enchantments.rapid_reload, srcItemStack, world.registryAccess()) > 0){ // instant reload decrementAmmo(playerEntity,srcItemStack); startLoad(srcItemStack); @@ -151,8 +150,8 @@ 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); + int explosive = Enchantments.level(Enchantments.high_explosive, srcItemStack, world.registryAccess()); + int recoil = Enchantments.level(Enchantments.recoil, srcItemStack, world.registryAccess()); unload(srcItemStack); if(isPlayer && !((Player)playerEntity).isCreative()){ srcItemStack.hurtAndBreak(1, playerEntity, EquipmentSlot.MAINHAND); @@ -303,8 +302,8 @@ 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, musket) > 0 - || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.powderless, musket) > 0) return true; + || Enchantments.level(net.minecraft.world.item.enchantment.Enchantments.INFINITY, musket, e.registryAccess()) > 0 + || Enchantments.level(Enchantments.powderless, musket, e.registryAccess()) > 0) return true; for (int i = 0; i < playerEntity.getInventory().items.size(); i++) { ItemStack inventoryStack = playerEntity.getInventory().items.get(i); if (inventoryStack.isEmpty()) continue; @@ -319,8 +318,8 @@ 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, musket) > 0 - || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.powderless, musket) > 0) return; + || Enchantments.level(net.minecraft.world.item.enchantment.Enchantments.INFINITY, musket, e.registryAccess()) > 0 + || Enchantments.level(Enchantments.powderless, musket, e.registryAccess()) > 0) return; for (int i = 0; i < playerEntity.getInventory().items.size(); i++) { ItemStack inventoryStack = playerEntity.getInventory().items.get(i); if (inventoryStack.isEmpty()) continue; @@ -439,7 +438,7 @@ public void appendHoverText(ItemStack stack, TooltipContext context, List recipe.value().assemble(inventory, getLevel().registryAccess())).orElse(ItemStack.EMPTY); } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index df9c59a..b6dd11c 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.2.120061,4.0.0)" +versionRange="[3.1.2.121011,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/advancement/recipes/blackpowder_cartridge.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/blackpowder_cartridge.json rename to src/main/resources/data/basesteam/advancement/recipes/blackpowder_cartridge.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/musket_left_normal.json b/src/main/resources/data/basesteam/advancement/recipes/musket_left_normal.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/musket_left_normal.json rename to src/main/resources/data/basesteam/advancement/recipes/musket_left_normal.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/musket_left_tech.json b/src/main/resources/data/basesteam/advancement/recipes/musket_left_tech.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/musket_left_tech.json rename to src/main/resources/data/basesteam/advancement/recipes/musket_left_tech.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/musket_right_normal.json b/src/main/resources/data/basesteam/advancement/recipes/musket_right_normal.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/musket_right_normal.json rename to src/main/resources/data/basesteam/advancement/recipes/musket_right_normal.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/musket_right_tech.json b/src/main/resources/data/basesteam/advancement/recipes/musket_right_tech.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/musket_right_tech.json rename to src/main/resources/data/basesteam/advancement/recipes/musket_right_tech.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_coal.json b/src/main/resources/data/basesteam/advancement/recipes/steam_boiler_coal.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_boiler_coal.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_boiler_coal.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_electric.json b/src/main/resources/data/basesteam/advancement/recipes/steam_boiler_electric.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_boiler_electric.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_boiler_electric.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_geothermal.json b/src/main/resources/data/basesteam/advancement/recipes/steam_boiler_geothermal.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_boiler_geothermal.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_boiler_geothermal.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_boiler_oil.json b/src/main/resources/data/basesteam/advancement/recipes/steam_boiler_oil.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_boiler_oil.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_boiler_oil.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_crusher.json b/src/main/resources/data/basesteam/advancement/recipes/steam_crusher.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_crusher.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_crusher.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_drill.json b/src/main/resources/data/basesteam/advancement/recipes/steam_drill.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_drill.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_drill.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_drill_bit.json b/src/main/resources/data/basesteam/advancement/recipes/steam_drill_bit.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_drill_bit.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_drill_bit.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_drill_diamond_pickaxe_normal.json b/src/main/resources/data/basesteam/advancement/recipes/steam_drill_diamond_pickaxe_normal.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_drill_diamond_pickaxe_normal.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_drill_diamond_pickaxe_normal.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_elevator.json b/src/main/resources/data/basesteam/advancement/recipes/steam_elevator.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_elevator.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_elevator.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_furnace.json b/src/main/resources/data/basesteam/advancement/recipes/steam_furnace.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_furnace.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_furnace.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_apocalyptic.json b/src/main/resources/data/basesteam/advancement/recipes/steam_governor_apocalyptic.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_governor_apocalyptic.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_governor_apocalyptic.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_normal.json b/src/main/resources/data/basesteam/advancement/recipes/steam_governor_normal.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_governor_normal.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_governor_normal.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_governor_tech.json b/src/main/resources/data/basesteam/advancement/recipes/steam_governor_tech.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_governor_tech.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_governor_tech.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_pipe.json b/src/main/resources/data/basesteam/advancement/recipes/steam_pipe.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_pipe.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_pipe.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_pump.json b/src/main/resources/data/basesteam/advancement/recipes/steam_pump.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_pump.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_pump.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_still.json b/src/main/resources/data/basesteam/advancement/recipes/steam_still.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_still.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_still.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_switch.json b/src/main/resources/data/basesteam/advancement/recipes/steam_switch.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_switch.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_switch.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_tank.json b/src/main/resources/data/basesteam/advancement/recipes/steam_tank.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_tank.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_tank.json diff --git a/src/main/resources/data/basesteam/advancements/recipes/steam_track.json b/src/main/resources/data/basesteam/advancement/recipes/steam_track.json similarity index 100% rename from src/main/resources/data/basesteam/advancements/recipes/steam_track.json rename to src/main/resources/data/basesteam/advancement/recipes/steam_track.json diff --git a/src/main/resources/data/basesteam/enchantment/high_explosive.json b/src/main/resources/data/basesteam/enchantment/high_explosive.json new file mode 100644 index 0000000..bad89d8 --- /dev/null +++ b/src/main/resources/data/basesteam/enchantment/high_explosive.json @@ -0,0 +1,21 @@ +{ + "description": { + "translate": "enchantment.high_explosive" + }, + "supported_items": "#basesteam:muskets", + "weight": 5, + "max_level": 5, + "min_cost": { + "base": 7, + "per_level_above_first": 7 + }, + "max_cost": { + "base": 17, + "per_level_above_first": 7 + }, + "anvil_cost": 2, + "slots": [ + "mainhand" + ], + "effects": {} +} diff --git a/src/main/resources/data/basesteam/enchantment/powderless.json b/src/main/resources/data/basesteam/enchantment/powderless.json new file mode 100644 index 0000000..bd2bfff --- /dev/null +++ b/src/main/resources/data/basesteam/enchantment/powderless.json @@ -0,0 +1,21 @@ +{ + "description": { + "translate": "enchantment.powderless" + }, + "supported_items": "#basesteam:muskets", + "weight": 1, + "max_level": 1, + "min_cost": { + "base": 20, + "per_level_above_first": 0 + }, + "max_cost": { + "base": 50, + "per_level_above_first": 0 + }, + "anvil_cost": 8, + "slots": [ + "mainhand" + ], + "effects": {} +} diff --git a/src/main/resources/data/basesteam/enchantment/rapid_reload.json b/src/main/resources/data/basesteam/enchantment/rapid_reload.json new file mode 100644 index 0000000..2567ca2 --- /dev/null +++ b/src/main/resources/data/basesteam/enchantment/rapid_reload.json @@ -0,0 +1,21 @@ +{ + "description": { + "translate": "enchantment.rapid_reload" + }, + "supported_items": "#basesteam:muskets", + "weight": 2, + "max_level": 1, + "min_cost": { + "base": 15, + "per_level_above_first": 0 + }, + "max_cost": { + "base": 50, + "per_level_above_first": 0 + }, + "anvil_cost": 4, + "slots": [ + "mainhand" + ], + "effects": {} +} diff --git a/src/main/resources/data/basesteam/enchantment/recoil.json b/src/main/resources/data/basesteam/enchantment/recoil.json new file mode 100644 index 0000000..0fa2314 --- /dev/null +++ b/src/main/resources/data/basesteam/enchantment/recoil.json @@ -0,0 +1,21 @@ +{ + "description": { + "translate": "enchantment.recoil" + }, + "supported_items": "#basesteam:muskets", + "weight": 10, + "max_level": 5, + "min_cost": { + "base": 2, + "per_level_above_first": 5 + }, + "max_cost": { + "base": 12, + "per_level_above_first": 5 + }, + "anvil_cost": 1, + "slots": [ + "mainhand" + ], + "effects": {} +} diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_boiler_coal.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_boiler_coal.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_boiler_coal.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_boiler_coal.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_boiler_electric.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_boiler_electric.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_boiler_electric.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_boiler_electric.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_boiler_geothermal.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_boiler_geothermal.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_boiler_geothermal.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_boiler_geothermal.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_boiler_oil.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_boiler_oil.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_boiler_oil.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_boiler_oil.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_crusher.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_crusher.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_crusher.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_crusher.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_drill.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_drill.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_drill.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_drill.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_elevator.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_elevator.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_elevator.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_elevator.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_furnace.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_furnace.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_furnace.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_furnace.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_pipe.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_pipe.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_pipe.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_pipe.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_pump.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_pump.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_pump.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_pump.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_still.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_still.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_still.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_still.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_switch.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_switch.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_switch.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_switch.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_tank.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_tank.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_tank.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_tank.json diff --git a/src/main/resources/data/basesteam/loot_tables/blocks/steam_track.json b/src/main/resources/data/basesteam/loot_table/blocks/steam_track.json similarity index 100% rename from src/main/resources/data/basesteam/loot_tables/blocks/steam_track.json rename to src/main/resources/data/basesteam/loot_table/blocks/steam_track.json diff --git a/src/main/resources/data/basesteam/loot_tables/chests/advantage_parts.json b/src/main/resources/data/basesteam/loot_table/chests/advantage_parts.json similarity index 96% rename from src/main/resources/data/basesteam/loot_tables/chests/advantage_parts.json rename to src/main/resources/data/basesteam/loot_table/chests/advantage_parts.json index 3873eb5..2edfef8 100644 --- a/src/main/resources/data/basesteam/loot_tables/chests/advantage_parts.json +++ b/src/main/resources/data/basesteam/loot_table/chests/advantage_parts.json @@ -62,8 +62,7 @@ "functions": [ { "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true + "levels": 10 } ] } diff --git a/src/main/resources/data/basesteam/recipes/blackpowder_cartridge.json b/src/main/resources/data/basesteam/recipe/blackpowder_cartridge.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/blackpowder_cartridge.json rename to src/main/resources/data/basesteam/recipe/blackpowder_cartridge.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_coal.json b/src/main/resources/data/basesteam/recipe/crushing_steam_boiler_coal.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_boiler_coal.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_boiler_coal.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_electric.json b/src/main/resources/data/basesteam/recipe/crushing_steam_boiler_electric.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_boiler_electric.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_boiler_electric.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_boiler_geothermal.json b/src/main/resources/data/basesteam/recipe/crushing_steam_boiler_geothermal.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_boiler_geothermal.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_boiler_geothermal.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_crusher.json b/src/main/resources/data/basesteam/recipe/crushing_steam_crusher.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_crusher.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_crusher.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_drill.json b/src/main/resources/data/basesteam/recipe/crushing_steam_drill.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_drill.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_drill.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_elevator.json b/src/main/resources/data/basesteam/recipe/crushing_steam_elevator.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_elevator.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_elevator.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_furnace.json b/src/main/resources/data/basesteam/recipe/crushing_steam_furnace.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_furnace.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_furnace.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_governor.json b/src/main/resources/data/basesteam/recipe/crushing_steam_governor.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_governor.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_governor.json diff --git a/src/main/resources/data/basesteam/recipes/crushing_steam_tank.json b/src/main/resources/data/basesteam/recipe/crushing_steam_tank.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/crushing_steam_tank.json rename to src/main/resources/data/basesteam/recipe/crushing_steam_tank.json diff --git a/src/main/resources/data/basesteam/recipes/musket_left_normal.json b/src/main/resources/data/basesteam/recipe/musket_left_normal.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/musket_left_normal.json rename to src/main/resources/data/basesteam/recipe/musket_left_normal.json diff --git a/src/main/resources/data/basesteam/recipes/musket_left_tech.json b/src/main/resources/data/basesteam/recipe/musket_left_tech.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/musket_left_tech.json rename to src/main/resources/data/basesteam/recipe/musket_left_tech.json diff --git a/src/main/resources/data/basesteam/recipes/musket_right_normal.json b/src/main/resources/data/basesteam/recipe/musket_right_normal.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/musket_right_normal.json rename to src/main/resources/data/basesteam/recipe/musket_right_normal.json diff --git a/src/main/resources/data/basesteam/recipes/musket_right_tech.json b/src/main/resources/data/basesteam/recipe/musket_right_tech.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/musket_right_tech.json rename to src/main/resources/data/basesteam/recipe/musket_right_tech.json diff --git a/src/main/resources/data/basesteam/recipes/steam_boiler_coal.json b/src/main/resources/data/basesteam/recipe/steam_boiler_coal.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_boiler_coal.json rename to src/main/resources/data/basesteam/recipe/steam_boiler_coal.json diff --git a/src/main/resources/data/basesteam/recipes/steam_boiler_electric.json b/src/main/resources/data/basesteam/recipe/steam_boiler_electric.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_boiler_electric.json rename to src/main/resources/data/basesteam/recipe/steam_boiler_electric.json diff --git a/src/main/resources/data/basesteam/recipes/steam_boiler_geothermal.json b/src/main/resources/data/basesteam/recipe/steam_boiler_geothermal.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_boiler_geothermal.json rename to src/main/resources/data/basesteam/recipe/steam_boiler_geothermal.json diff --git a/src/main/resources/data/basesteam/recipes/steam_boiler_oil.json b/src/main/resources/data/basesteam/recipe/steam_boiler_oil.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_boiler_oil.json rename to src/main/resources/data/basesteam/recipe/steam_boiler_oil.json diff --git a/src/main/resources/data/basesteam/recipes/steam_crusher.json b/src/main/resources/data/basesteam/recipe/steam_crusher.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_crusher.json rename to src/main/resources/data/basesteam/recipe/steam_crusher.json diff --git a/src/main/resources/data/basesteam/recipes/steam_drill.json b/src/main/resources/data/basesteam/recipe/steam_drill.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_drill.json rename to src/main/resources/data/basesteam/recipe/steam_drill.json diff --git a/src/main/resources/data/basesteam/recipes/steam_drill_bit.json b/src/main/resources/data/basesteam/recipe/steam_drill_bit.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_drill_bit.json rename to src/main/resources/data/basesteam/recipe/steam_drill_bit.json diff --git a/src/main/resources/data/basesteam/recipes/steam_drill_diamond_pickaxe_normal.json b/src/main/resources/data/basesteam/recipe/steam_drill_diamond_pickaxe_normal.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_drill_diamond_pickaxe_normal.json rename to src/main/resources/data/basesteam/recipe/steam_drill_diamond_pickaxe_normal.json diff --git a/src/main/resources/data/basesteam/recipes/steam_elevator.json b/src/main/resources/data/basesteam/recipe/steam_elevator.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_elevator.json rename to src/main/resources/data/basesteam/recipe/steam_elevator.json diff --git a/src/main/resources/data/basesteam/recipes/steam_furnace.json b/src/main/resources/data/basesteam/recipe/steam_furnace.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_furnace.json rename to src/main/resources/data/basesteam/recipe/steam_furnace.json diff --git a/src/main/resources/data/basesteam/recipes/steam_governor_apocalyptic.json b/src/main/resources/data/basesteam/recipe/steam_governor_apocalyptic.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_governor_apocalyptic.json rename to src/main/resources/data/basesteam/recipe/steam_governor_apocalyptic.json diff --git a/src/main/resources/data/basesteam/recipes/steam_governor_normal.json b/src/main/resources/data/basesteam/recipe/steam_governor_normal.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_governor_normal.json rename to src/main/resources/data/basesteam/recipe/steam_governor_normal.json diff --git a/src/main/resources/data/basesteam/recipes/steam_governor_tech.json b/src/main/resources/data/basesteam/recipe/steam_governor_tech.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_governor_tech.json rename to src/main/resources/data/basesteam/recipe/steam_governor_tech.json diff --git a/src/main/resources/data/basesteam/recipes/steam_pipe.json b/src/main/resources/data/basesteam/recipe/steam_pipe.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_pipe.json rename to src/main/resources/data/basesteam/recipe/steam_pipe.json diff --git a/src/main/resources/data/basesteam/recipes/steam_pump.json b/src/main/resources/data/basesteam/recipe/steam_pump.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_pump.json rename to src/main/resources/data/basesteam/recipe/steam_pump.json diff --git a/src/main/resources/data/basesteam/recipes/steam_still.json b/src/main/resources/data/basesteam/recipe/steam_still.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_still.json rename to src/main/resources/data/basesteam/recipe/steam_still.json diff --git a/src/main/resources/data/basesteam/recipes/steam_switch.json b/src/main/resources/data/basesteam/recipe/steam_switch.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_switch.json rename to src/main/resources/data/basesteam/recipe/steam_switch.json diff --git a/src/main/resources/data/basesteam/recipes/steam_tank.json b/src/main/resources/data/basesteam/recipe/steam_tank.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_tank.json rename to src/main/resources/data/basesteam/recipe/steam_tank.json diff --git a/src/main/resources/data/basesteam/recipes/steam_track.json b/src/main/resources/data/basesteam/recipe/steam_track.json similarity index 100% rename from src/main/resources/data/basesteam/recipes/steam_track.json rename to src/main/resources/data/basesteam/recipe/steam_track.json diff --git a/src/main/resources/data/basesteam/tags/blocks/musket_fragile.json b/src/main/resources/data/basesteam/tags/block/musket_fragile.json similarity index 100% rename from src/main/resources/data/basesteam/tags/blocks/musket_fragile.json rename to src/main/resources/data/basesteam/tags/block/musket_fragile.json diff --git a/src/main/resources/data/basesteam/tags/items/muskets.json b/src/main/resources/data/basesteam/tags/item/muskets.json similarity index 100% rename from src/main/resources/data/basesteam/tags/items/muskets.json rename to src/main/resources/data/basesteam/tags/item/muskets.json diff --git a/src/main/resources/data/forge/tags/items/ammo/blackpowder.json b/src/main/resources/data/forge/tags/item/ammo/blackpowder.json similarity index 100% rename from src/main/resources/data/forge/tags/items/ammo/blackpowder.json rename to src/main/resources/data/forge/tags/item/ammo/blackpowder.json diff --git a/src/main/resources/data/forge/tags/items/conduits/steam.json b/src/main/resources/data/forge/tags/item/conduits/steam.json similarity index 100% rename from src/main/resources/data/forge/tags/items/conduits/steam.json rename to src/main/resources/data/forge/tags/item/conduits/steam.json diff --git a/src/main/resources/data/forge/tags/items/governors.json b/src/main/resources/data/forge/tags/item/governors.json similarity index 100% rename from src/main/resources/data/forge/tags/items/governors.json rename to src/main/resources/data/forge/tags/item/governors.json diff --git a/src/main/resources/data/forge/tags/items/governors/brass.json b/src/main/resources/data/forge/tags/item/governors/brass.json similarity index 100% rename from src/main/resources/data/forge/tags/items/governors/brass.json rename to src/main/resources/data/forge/tags/item/governors/brass.json diff --git a/src/main/resources/data/forge/tags/items/guns.json b/src/main/resources/data/forge/tags/item/guns.json similarity index 100% rename from src/main/resources/data/forge/tags/items/guns.json rename to src/main/resources/data/forge/tags/item/guns.json diff --git a/src/main/resources/data/forge/tags/items/wires.json b/src/main/resources/data/forge/tags/item/wires.json similarity index 100% rename from src/main/resources/data/forge/tags/items/wires.json rename to src/main/resources/data/forge/tags/item/wires.json diff --git a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/main/resources/data/minecraft/tags/block/mineable/pickaxe.json similarity index 100% rename from src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json rename to src/main/resources/data/minecraft/tags/block/mineable/pickaxe.json diff --git a/src/main/resources/data/minecraft/tags/enchantment/non_treasure.json b/src/main/resources/data/minecraft/tags/enchantment/non_treasure.json new file mode 100644 index 0000000..407acdd --- /dev/null +++ b/src/main/resources/data/minecraft/tags/enchantment/non_treasure.json @@ -0,0 +1,9 @@ +{ + "replace": false, + "values": [ + "basesteam:high_explosive", + "basesteam:powderless", + "basesteam:rapid_reload", + "basesteam:recoil" + ] +} diff --git a/src/main/resources/data/minecraft/tags/enchantment/tooltip_order.json b/src/main/resources/data/minecraft/tags/enchantment/tooltip_order.json new file mode 100644 index 0000000..407acdd --- /dev/null +++ b/src/main/resources/data/minecraft/tags/enchantment/tooltip_order.json @@ -0,0 +1,9 @@ +{ + "replace": false, + "values": [ + "basesteam:high_explosive", + "basesteam:powderless", + "basesteam:rapid_reload", + "basesteam:recoil" + ] +} diff --git a/src/main/resources/data/minecraft/tags/items/enchantable/durability.json b/src/main/resources/data/minecraft/tags/item/enchantable/durability.json similarity index 100% rename from src/main/resources/data/minecraft/tags/items/enchantable/durability.json rename to src/main/resources/data/minecraft/tags/item/enchantable/durability.json diff --git a/src/main/resources/data/minecraft/tags/items/enchantable/vanishing.json b/src/main/resources/data/minecraft/tags/item/enchantable/vanishing.json similarity index 100% rename from src/main/resources/data/minecraft/tags/items/enchantable/vanishing.json rename to src/main/resources/data/minecraft/tags/item/enchantable/vanishing.json diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index 3486300..25eee2f 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,7 +1,7 @@ { "pack":{ - "pack_format":32, - "supported_formats":{"min_inclusive":32,"max_inclusive":41}, + "pack_format":34, + "supported_formats":{"min_inclusive":34,"max_inclusive":48}, "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 8ab0ee7..33a7102 100644 --- a/src/test/java/zone/moddev/mc/basesteam/blocks/DrillBitPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/blocks/DrillBitPersistenceTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.blocks; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import net.minecraft.nbt.CompoundTag; import net.minecraft.core.Direction; @@ -7,23 +9,24 @@ import static org.junit.Assert.*; public class DrillBitPersistenceTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @org.junit.BeforeClass public static void bootstrapNativeRegistries() { NativeTestBootstrap.start(); } @Test public void allSixDirectionsSurviveNativeSaveAndChunkUpdateTag() { for (Direction direction : Direction.values()) { - DrillBitTileEntity tile = new DrillBitTileEntity(); + DrillBitTileEntity tile = new DrillBitTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("drillbit")); tile.setDirection(direction); var registries = NativeTestBootstrap.registries(); CompoundTag saved = tile.saveWithoutMetadata(registries); assertEquals(direction.get3DDataValue(), saved.getByte("dir")); - DrillBitTileEntity restored = new DrillBitTileEntity(); + DrillBitTileEntity restored = new DrillBitTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("drillbit")); restored.loadWithComponents(saved, registries); assertEquals(direction.get3DDataValue(), restored.getUpdateTag(registries).getByte("dir")); - DrillBitTileEntity client = new DrillBitTileEntity(); + DrillBitTileEntity client = new DrillBitTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("drillbit")); client.handleUpdateTag(tile.getUpdateTag(registries), registries); assertEquals(direction.get3DDataValue(), client.getUpdateTag(registries).getByte("dir")); } @@ -32,7 +35,7 @@ public class DrillBitPersistenceTest { @Test public void oldDirectionKeyRemainsReadableAndCanonicalKeyWins() { CompoundTag tag = new CompoundTag(); tag.putByte("d", (byte) Direction.EAST.get3DDataValue()); - DrillBitTileEntity tile = new DrillBitTileEntity(); + DrillBitTileEntity tile = new DrillBitTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("drillbit")); tile.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(Direction.Axis.X, tile.getDirection()); tag.putByte("dir", (byte) Direction.NORTH.get3DDataValue()); @@ -43,7 +46,7 @@ public class DrillBitPersistenceTest { @Test public void invalidDirectionFallsBackToDown() { CompoundTag tag = new CompoundTag(); tag.putByte("dir", (byte) 127); - DrillBitTileEntity tile = new DrillBitTileEntity(); + DrillBitTileEntity tile = new DrillBitTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("drillbit")); 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/graphics/DrillBitRendererTest.java b/src/test/java/zone/moddev/mc/basesteam/graphics/DrillBitRendererTest.java index 4961fdd..d2959e8 100644 --- a/src/test/java/zone/moddev/mc/basesteam/graphics/DrillBitRendererTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/graphics/DrillBitRendererTest.java @@ -62,7 +62,9 @@ public class DrillBitRendererTest { PoseStack.Pose caller = matrices.last(); try { DrillBitRenderer.renderGeometry(Direction.Axis.X, 37, matrices, new RecordingBuffer() { - @Override public void endVertex() { throw new IllegalStateException("submission failed"); } + @Override public VertexConsumer addVertex(float x, float y, float z) { + throw new IllegalStateException("submission failed"); + } }, LIGHT, OVERLAY); fail("Expected vertex submission failure"); } catch (IllegalStateException expected) { @@ -81,29 +83,24 @@ private static final class Vertex { private static class RecordingBuffer implements VertexConsumer { final List vertices = new ArrayList<>(); - private Vertex vertex = new Vertex(); + private Vertex vertex; - @Override public VertexConsumer vertex(double x, double y, double z) { + @Override public VertexConsumer addVertex(float x, float y, float z) { + vertex = new Vertex(); + vertices.add(vertex); vertex.position[0] = x; vertex.position[1] = y; vertex.position[2] = z; return this; } - @Override public VertexConsumer color(int red, int green, int blue, int alpha) { + @Override public VertexConsumer setColor(int red, int green, int blue, int alpha) { vertex.color[0] = red; vertex.color[1] = green; vertex.color[2] = blue; vertex.color[3] = alpha; return this; } - @Override public VertexConsumer uv(float u, float v) { vertex.u = u; vertex.v = v; return this; } - @Override public VertexConsumer overlayCoords(int u, int v) { vertex.overlay = u | v << 16; return this; } - @Override public VertexConsumer uv2(int u, int v) { vertex.light = u | v << 16; return this; } - @Override public VertexConsumer normal(float x, float y, float z) { + @Override public VertexConsumer setUv(float u, float v) { vertex.u = u; vertex.v = v; return this; } + @Override public VertexConsumer setUv1(int u, int v) { vertex.overlay = u | v << 16; return this; } + @Override public VertexConsumer setUv2(int u, int v) { vertex.light = u | v << 16; return this; } + @Override public VertexConsumer setNormal(float x, float y, float z) { vertex.normal[0] = x; vertex.normal[1] = y; vertex.normal[2] = z; return this; } - @Override public void endVertex() { vertices.add(vertex); vertex = new Vertex(); } - @Override public void defaultColor(int red, int green, int blue, int alpha) { - throw new AssertionError("Drill vertices must retain their explicit colour attributes"); - } - @Override public void unsetDefaultColor() { - throw new AssertionError("Drill rendering must not change the caller's default colour state"); - } } } diff --git a/src/test/java/zone/moddev/mc/basesteam/machines/CoalBoilerFillPersistenceTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/CoalBoilerFillPersistenceTest.java index a9a1957..8109450 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/CoalBoilerFillPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/CoalBoilerFillPersistenceTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.machines; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import static org.junit.Assert.*; @@ -13,10 +15,9 @@ /** Save-notification unit witness; actual disk persistence is checked by the native restart rig. */ public class CoalBoilerFillPersistenceTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @BeforeClass public static void bootstrap() { NativeTestBootstrap.start(); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_COAL == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_COAL = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(CoalBoilerTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); } @Test public void acceptingTheLastFiveMillibucketsRequestsSavingBeforeAnyTick() { @@ -185,6 +186,7 @@ private static void assertUnchangedSave(SaveWitnessBoiler boiler, int amount) { } private static final class SaveWitnessBoiler extends CoalBoilerTileEntity { + SaveWitnessBoiler() { super(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_coal")); } int dirtyCalls; CompoundTag savedTank; SaveWorld saveWorld = world(false); diff --git a/src/test/java/zone/moddev/mc/basesteam/machines/RockCrusherComparatorTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/RockCrusherComparatorTest.java index 3decaf2..3d6b7c6 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/RockCrusherComparatorTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/RockCrusherComparatorTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.machines; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import static org.junit.Assert.assertEquals; import net.minecraft.world.item.ItemStack; @@ -8,10 +10,9 @@ import org.junit.Test; public class RockCrusherComparatorTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @BeforeClass public static void bootstrap() { NativeTestBootstrap.start(); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_CRUSHER == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_CRUSHER = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(RockCrusherTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); } @Test public void emptyInputHasNoComparatorSignal() { assertSignal(0, 0); } @Test public void oneItemGivesSignalOne() { assertSignal(1, 1); } @@ -19,7 +20,7 @@ public class RockCrusherComparatorTest { @Test public void aFullStackGivesSignalFifteen() { assertSignal(64, 15); } private static void assertSignal(int count, int expected) { - RockCrusherTileEntity crusher = new RockCrusherTileEntity(); + RockCrusherTileEntity crusher = new RockCrusherTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_crusher")); crusher.setItem(0, count == 0 ? ItemStack.EMPTY : new ItemStack(Items.COAL, count)); assertEquals("Actual crusher comparator at " + count + " input items", expected, crusher.getComparatorOutput()); } diff --git a/src/test/java/zone/moddev/mc/basesteam/machines/RockCrusherReloadRedstoneTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/RockCrusherReloadRedstoneTest.java index a279aac..35e0e9a 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/RockCrusherReloadRedstoneTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/RockCrusherReloadRedstoneTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.machines; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import static org.junit.Assert.*; import java.lang.reflect.Field; @@ -10,12 +12,9 @@ import org.junit.Test; public class RockCrusherReloadRedstoneTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @BeforeClass public static void bootstrap() { NativeTestBootstrap.start(); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_CRUSHER == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_CRUSHER = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(RockCrusherTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_FURNACE == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_FURNACE = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(BlastFurnaceTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); } @Test public void resumedWorkCannotBeDecrementedBeforeTheFirstLiveControlSample() throws Exception { @@ -72,10 +71,12 @@ private static ControlWorld world() throws Exception { return (ControlWorld) allocator.getMethod("allocateInstance", Class.class).invoke(field.get(null), ControlWorld.class); } private static final class ProbeCrusher extends RockCrusherTileEntity { + ProbeCrusher() { super(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_crusher")); } ControlWorld testWorld; @Override public Level getLevel() { return testWorld; } } private static final class ProbeFurnace extends BlastFurnaceTileEntity { + ProbeFurnace() { super(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_furnace")); } ControlWorld testWorld; @Override public Level getLevel() { return testWorld; } } 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 6a87b4b..474dca7 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/SteamDrillPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/SteamDrillPersistenceTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.machines; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -27,19 +29,20 @@ import static org.junit.Assert.assertTrue; public class SteamDrillPersistenceTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @BeforeClass public static void bootstrapNativeRegistries() { NativeTestBootstrap.start(); } @Test public void retainsLegacyProgressUntilWorldIsAttached() { - SteamDrillTileEntity drill = new SteamDrillTileEntity(); + SteamDrillTileEntity drill = new SteamDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_drill")); drill.loadWithComponents(target(94), NativeTestBootstrap.registries()); drill.prepareDataFieldsForSync(); assertEquals(94, drill.getDataFieldArray()[1]); } @Test public void clearsPreviousProgressOnReadingAnUntargetedTile() { - SteamDrillTileEntity drill = new SteamDrillTileEntity(); + SteamDrillTileEntity drill = new SteamDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_drill")); drill.loadWithComponents(target(94), NativeTestBootstrap.registries()); drill.loadWithComponents(new CompoundTag(), NativeTestBootstrap.registries()); drill.prepareDataFieldsForSync(); @@ -53,7 +56,7 @@ public class SteamDrillPersistenceTest { CompoundTag state = new CompoundTag(); state.putString("Name", "minecraft:stone"); tag.put("TargetState", state); - SteamDrillTileEntity drill = new SteamDrillTileEntity(); + SteamDrillTileEntity drill = new SteamDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_drill")); drill.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(facing, field(drill, "savedFacing")); assertEquals(new BlockPos(2048, 80, 2049), field(drill, "targetBlockCoord")); @@ -65,7 +68,7 @@ public class SteamDrillPersistenceTest { } @Test public void loadingAnotherTileDoesNotKeepPreviousFacing() throws Exception { - SteamDrillTileEntity drill = new SteamDrillTileEntity(); + SteamDrillTileEntity drill = new SteamDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_drill")); CompoundTag tag = target(94); tag.putByte("Facing", (byte) Direction.UP.get3DDataValue()); drill.loadWithComponents(tag, NativeTestBootstrap.registries()); @@ -86,7 +89,7 @@ public class SteamDrillPersistenceTest { stack.putByte("Slot", (byte) 4); items.add(stack); tag.put("Items", items); - SteamDrillTileEntity drill = new SteamDrillTileEntity(); + SteamDrillTileEntity drill = new SteamDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_drill")); drill.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(37.5F, drill.getEnergy(Power.steam_power), 0.0F); ItemStack output = drill.getItem(4); @@ -95,7 +98,7 @@ public class SteamDrillPersistenceTest { } @Test public void drillOutputDoesNotMergeStacksWithDifferentComponents() { - SteamDrillTileEntity drill = new SteamDrillTileEntity(); + SteamDrillTileEntity drill = new SteamDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_drill")); ItemStack first = new ItemStack(net.minecraft.world.item.Items.COBBLESTONE, 8); CustomData.update(DataComponents.CUSTOM_DATA, first, tag -> tag.putString("source", "first")); ItemStack different = new ItemStack(net.minecraft.world.item.Items.COBBLESTONE, 4); @@ -145,7 +148,7 @@ public class SteamDrillPersistenceTest { tag.putInt("targetX", target.getX()); tag.putInt("targetY", target.getY()); tag.putInt("targetZ", target.getZ()); - SteamDrillTileEntity drill = new SteamDrillTileEntity(origin, new SteamDrillBlock().defaultBlockState()); + SteamDrillTileEntity drill = new SteamDrillTileEntity(origin, NativeMachineFixture.state("steam_drill")); 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 d512b8f..ec9f8b4 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/SteamMachinePersistenceTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/SteamMachinePersistenceTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.machines; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import cyano.poweradvantage.api.fluid.FluidStack; import net.minecraft.world.level.block.Blocks; @@ -16,28 +18,23 @@ import static org.junit.Assert.*; public class SteamMachinePersistenceTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @BeforeClass public static void bootstrapNativeTypes() { NativeTestBootstrap.start(); - Entities.STEAM_BOILER_COAL = type("steam_boiler_coal", CoalBoilerTileEntity::new); - Entities.STEAM_BOILER_ELECTRIC = type("steam_boiler_electric", ElectricBoilerTileEntity::new); - Entities.STEAM_BOILER_GEOTHERMAL = type("steam_boiler_geothermal", GeothermalBoilerTileEntity::new); - Entities.STEAM_PUMP = type("steam_pump", SteamPumpTileEntity::new); - Entities.STEAM_STILL = type("steam_still", SteamStillTileEntity::new); - Entities.STEAM_TANK = type("steam_tank", SteamTankTileEntity::new); } @Test public void levelsAndDecayRetainExactBinaryFractions() { - CoalBoilerTileEntity coal = new CoalBoilerTileEntity(); + CoalBoilerTileEntity coal = new CoalBoilerTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_coal")); coal.setEnergy(375.0F, Power.steam_power); coal.getTank().fill(new FluidStack(net.minecraft.world.level.material.Fluids.WATER, 1500), true); assertEquals(0.375F, coal.getSteamLevel(), 0.0F); assertEquals(0.375F, coal.getWaterLevel(), 0.0F); - ElectricBoilerTileEntity electric = new ElectricBoilerTileEntity(); + ElectricBoilerTileEntity electric = new ElectricBoilerTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_electric")); electric.setEnergy(37.5F, Power.steam_power); electric.setEnergy(60.0F, ElectricBoilerTileEntity.ELECTRIC_POWER); assertEquals(0.375F, electric.getSteamLevel(), 0.0F); assertEquals(0.375F, electric.getElectricityLevel(), 0.0F); - SteamTankTileEntity tank = new SteamTankTileEntity(); + SteamTankTileEntity tank = new SteamTankTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_tank")); tank.setEnergy(3750.0F, Power.steam_power); assertEquals(0.375F, tank.getSteamLevel(), 0.0F); tank.tickUpdate(true); @@ -56,20 +53,20 @@ public class SteamMachinePersistenceTest { tag.put("Tank", water(1500)); tag.putInt("BurnTime", 127); tag.putInt("BurnTimeTotal", 1600); - CoalBoilerTileEntity coal = new CoalBoilerTileEntity(); + CoalBoilerTileEntity coal = new CoalBoilerTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_coal")); 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(); + CoalBoilerTileEntity restored = new CoalBoilerTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_coal")); 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(); + ElectricBoilerTileEntity electric = new ElectricBoilerTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_electric")); electric.loadWithComponents(tag, NativeTestBootstrap.registries()); - ElectricBoilerTileEntity electricRestored = new ElectricBoilerTileEntity(); + ElectricBoilerTileEntity electricRestored = new ElectricBoilerTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_electric")); 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); @@ -80,17 +77,17 @@ public class SteamMachinePersistenceTest { CompoundTag tag = state(37.5F); tag.put("TankOut", water(750)); tag.putByte("NextPump", (byte) 11); - SteamPumpTileEntity pump = new SteamPumpTileEntity(); + SteamPumpTileEntity pump = new SteamPumpTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_pump")); 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(); + SteamPumpTileEntity pumpRestored = new SteamPumpTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_pump")); 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(); + GeothermalBoilerTileEntity geothermal = new GeothermalBoilerTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_geothermal")); geothermal.loadWithComponents(tag, NativeTestBootstrap.registries()); assertEquals(412.5F, geothermal.saveWithoutMetadata(NativeTestBootstrap.registries()).getFloat("Temperature"), 0.0F); tag.putFloat("Temperature", 500.0F); @@ -102,9 +99,9 @@ public class SteamMachinePersistenceTest { CompoundTag tag = state(37.5F); tag.put("TankIn", water(625)); tag.put("TankOut", water(375)); - SteamStillTileEntity still = new SteamStillTileEntity(); + SteamStillTileEntity still = new SteamStillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_still")); still.loadWithComponents(tag, NativeTestBootstrap.registries()); - SteamStillTileEntity restored = new SteamStillTileEntity(); + SteamStillTileEntity restored = new SteamStillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_still")); restored.loadWithComponents(still.saveWithoutMetadata(NativeTestBootstrap.registries()), NativeTestBootstrap.registries()); assertEquals(625, restored.getInputTank().getFluidAmount()); assertEquals(375, restored.getOutputTank().getFluidAmount()); @@ -129,17 +126,4 @@ private static CompoundTag water(int amount) { return tag; } - private static BlockEntityType type(String id, BlockEntityType.BlockEntitySupplier factory) { - ForgeRegistry> registry = - (ForgeRegistry>) ForgeRegistries.BLOCK_ENTITY_TYPES; - boolean locked = registry.isLocked(); - registry.unfreeze(); - try { - BlockEntityType type = BlockEntityType.Builder.of(factory, Blocks.STONE).build(null); - 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/SteamOperationalStillCapacityTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/SteamOperationalStillCapacityTest.java index aeb169c..0665b4b 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/SteamOperationalStillCapacityTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/SteamOperationalStillCapacityTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.machines; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import cyano.poweradvantage.api.fluid.FluidStack; import java.lang.reflect.Method; @@ -15,11 +17,9 @@ /** Pure capacity planning; native operating regressions live in SteamOperationalCases. */ public class SteamOperationalStillCapacityTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @BeforeClass public static void bootstrap() { NativeTestBootstrap.start(); - if (Entities.STEAM_STILL == null) { - Entities.STEAM_STILL = BlockEntityType.Builder.of(SteamStillTileEntity::new, Blocks.STONE).build(null); - } } @Test public void fullOutputCannotPlanOrDebitAnyInput() throws Exception { @@ -55,7 +55,7 @@ public class SteamOperationalStillCapacityTest { } @Test public void mismatchedProductIsNotOverwritten() throws Exception { - SteamStillTileEntity still = new SteamStillTileEntity(); + SteamStillTileEntity still = new SteamStillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_still")); still.getOutputTank().setFluid(new FluidStack(Fluids.WATER, 10)); FluidStack input = new FluidStack(Fluids.WATER, 200); assertEquals(0, plan(still, recipe(2, 1), input)); @@ -73,7 +73,7 @@ public class SteamOperationalStillCapacityTest { } private static SteamStillTileEntity still(int output) { - SteamStillTileEntity still = new SteamStillTileEntity(); + SteamStillTileEntity still = new SteamStillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_still")); if (output > 0) still.getOutputTank().setFluid(new FluidStack(Fluids.LAVA, output)); return still; } diff --git a/src/test/java/zone/moddev/mc/basesteam/machines/WaterBoilerFluidBoundaryTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/WaterBoilerFluidBoundaryTest.java index 4a08a86..c22258e 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/WaterBoilerFluidBoundaryTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/WaterBoilerFluidBoundaryTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.machines; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import static org.junit.Assert.*; import java.lang.reflect.Method; @@ -16,6 +18,7 @@ /** Calls each actual boiler method; no stand-in fill/drain implementation or world ticks. */ @RunWith(Parameterized.class) public class WaterBoilerFluidBoundaryTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @Parameterized.Parameters(name = "{0}") public static Collection boilers() { return Arrays.asList(new Object[][]{{CoalBoilerTileEntity.class}, @@ -27,15 +30,9 @@ public static Collection boilers() { public WaterBoilerFluidBoundaryTest(Class type) { this.type = type; } @BeforeClass public static void bootstrap() { NativeTestBootstrap.start(); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_COAL == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_COAL = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(CoalBoilerTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_ELECTRIC == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_ELECTRIC = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(ElectricBoilerTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_GEOTHERMAL == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_GEOTHERMAL = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(GeothermalBoilerTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); } @Before public void createActualBoiler() throws Exception { - boiler = type.getConstructor().newInstance(); + boiler = NativeMachineFixture.create(type.asSubclass(net.minecraft.world.level.block.entity.BlockEntity.class)); tank = (FluidTank) type.getMethod("getTank").invoke(boiler); } diff --git a/src/test/java/zone/moddev/mc/basesteam/machines/WaterBoilerTankNotificationTest.java b/src/test/java/zone/moddev/mc/basesteam/machines/WaterBoilerTankNotificationTest.java index 524409e..c36ae17 100644 --- a/src/test/java/zone/moddev/mc/basesteam/machines/WaterBoilerTankNotificationTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/machines/WaterBoilerTankNotificationTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.machines; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import static org.junit.Assert.*; import cyano.poweradvantage.api.IPowerMachine; @@ -18,6 +20,7 @@ /** Save notifications only; native restart reports remain the disk-persistence evidence. */ @RunWith(Parameterized.class) public class WaterBoilerTankNotificationTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @Parameterized.Parameters(name = "{0}") public static Collection boilers() { return Arrays.asList(new Object[][]{{"electric"}, {"geothermal"}}); } private final String type; @@ -25,10 +28,6 @@ public class WaterBoilerTankNotificationTest { public WaterBoilerTankNotificationTest(String type) { this.type = type; } @BeforeClass public static void bootstrap() { NativeTestBootstrap.start(); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_ELECTRIC == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_ELECTRIC = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(ElectricBoilerTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); - if (zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_GEOTHERMAL == null) - zone.moddev.mc.basesteam.init.Entities.STEAM_BOILER_GEOTHERMAL = net.minecraft.world.level.block.entity.BlockEntityType.Builder.of(GeothermalBoilerTileEntity::new, net.minecraft.world.level.block.Blocks.STONE).build(null); } @Before public void createRealBoiler() { probe = type.equals("electric") ? new ElectricProbe() : new GeothermalProbe(); @@ -129,6 +128,7 @@ private static final class SaveWitness { void changed(FluidTank tank) { dirtyCalls++; savedTank = tank.writeToNBT(new CompoundTag()).copy(); } } private static final class ElectricProbe extends ElectricBoilerTileEntity implements Probe { + ElectricProbe() { super(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_electric")); } private final SaveWitness witness = new SaveWitness(); private Level testWorld = world(false); @Override public Level getLevel() { return testWorld; } @@ -139,6 +139,7 @@ private static final class ElectricProbe extends ElectricBoilerTileEntity implem @Override public void side(boolean client) { testWorld = world(client); } } private static final class GeothermalProbe extends GeothermalBoilerTileEntity implements Probe { + GeothermalProbe() { super(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state("steam_boiler_geothermal")); } private final SaveWitness witness = new SaveWitness(); private Level testWorld = world(false); @Override public Level getLevel() { return testWorld; } 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 b15d7c0..d6d4354 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/BuildWorkflowContractTest.java @@ -12,12 +12,12 @@ public class BuildWorkflowContractTest { 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("1.21.1", pins.getProperty("minecraft_version")); + assertEquals("52.1.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")); + assertEquals("1.21.1", pins.getProperty("mapping_version")); + assertEquals("2.4.14.121011", 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", "poweradvantage_test_registry_source_sha256", @@ -29,7 +29,7 @@ public class BuildWorkflowContractTest { } 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'")); + assertTrue(build.contains("apply from: 'gradle/forge52-mavenizer.gradle'")); assertFalse(build.contains("renamer.classes(")); assertFalse(build.contains("toSrgFile")); assertTrue(build.contains("basePower-${project.poweradvantage_version}.jar")); @@ -40,9 +40,9 @@ public class BuildWorkflowContractTest { String source = Files.readString(Path.of(".github/workflows", name)); 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("branches: [master-1.21.1")); assertTrue(name, source.contains("java-version: '21.0.7+6.0.LTS'")); - assertTrue(name, source.contains("-Pforge50MavenizerJar=$MAVENIZER")); + assertTrue(name, source.contains("-Pforge52MavenizerJar=$MAVENIZER")); assertTrue(name, source.contains("-PpowerAdvantageDeobfJar=$POWER_PLAYER")); assertFalse(name, source.contains("forge47")); } 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 1190564..84131c1 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/MusketFragileTagContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/MusketFragileTagContractTest.java @@ -18,7 +18,7 @@ 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"); + Path path = Path.of("src/main/resources/data/basesteam/tags/block/musket_fragile.json"); try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { var tag = JsonParser.parseReader(reader).getAsJsonObject(); assertFalse("Other packs must be able to extend the fragile block list", tag.get("replace").getAsBoolean()); @@ -30,7 +30,7 @@ public class MusketFragileTagContractTest { 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, + assertTrue("Unregistered Forge 52 block would invalidate the tag: " + id, BuiltInRegistries.BLOCK.containsKey(ResourceLocation.parse(id))); } assertFalse(blocks.contains("minecraft:tnt")); 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 da44be5..055f99c 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/NativeBlockEntityContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeBlockEntityContractTest.java @@ -1,5 +1,7 @@ package zone.moddev.mc.basesteam.resources; +import zone.moddev.mc.basesteam.testing.NativeMachineFixture; + import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -19,14 +21,12 @@ import static org.junit.Assert.*; public class NativeBlockEntityContractTest { + @org.junit.Rule public final NativeMachineFixture machineTypes = new NativeMachineFixture(); @BeforeClass public static void bootstrap() { NativeTestBootstrap.start(); } @Test public void everyProductionFactoryOwnsItsActualNativePositionAndState() { BlockPos pos = new BlockPos(2053, 81, -2049); - for (Block block : new Block[] { new CoalBoilerBlock(), new ElectricBoilerBlock(), - new GeothermalBoilerBlock(), new OilBoilerBlock(), new BlastFurnaceBlock(), - new RockCrusherBlock(), new SteamDrillBlock(), new SteamElevatorBlock(), - new SteamPumpBlock(), new SteamStillBlock(), new SteamTankBlock(), new DrillBitBlock() }) { + for (Block block : NativeMachineFixture.blocks()) { BlockState state = block.defaultBlockState(); BlockEntity tile = ((EntityBlock) block).newBlockEntity(pos, state); assertNotNull(block.getClass().getName(), tile); @@ -38,7 +38,7 @@ public class NativeBlockEntityContractTest { @Test public void drillLoadCannotReplaceDestinationNativePositionOrFacing() { BlockPos destination = new BlockPos(-2050, 83, 2048); for (Direction direction : Direction.values()) { - BlockState state = new SteamDrillBlock().defaultBlockState().setValue(SteamDrillBlock.FACING, direction); + BlockState state = NativeMachineFixture.state("steam_drill").setValue(SteamDrillBlock.FACING, direction); SteamDrillTileEntity drill = new SteamDrillTileEntity(destination, state); CompoundTag saved = new CompoundTag(); saved.putInt("x", 7); saved.putInt("y", 9); saved.putInt("z", 11); @@ -65,4 +65,14 @@ public class NativeBlockEntityContractTest { assertEquals(0, tile.rotation, 0); } finally { Entities.DRILLBIT = previous; } } + + @Test public void nativeConstructorStillRejectsAMismatchedTypeAndBlock() { + BlockEntityType previous = Entities.DRILLBIT; + try { + Entities.DRILLBIT = BlockEntityType.Builder.of(DrillBitTileEntity::new, + net.minecraft.world.level.block.Blocks.STONE).build(null); + assertThrows(IllegalStateException.class, () -> new DrillBitTileEntity( + BlockPos.ZERO, NativeMachineFixture.state("drillbit"))); + } finally { Entities.DRILLBIT = previous; } + } } diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/NativeEnchantmentContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/NativeEnchantmentContractTest.java new file mode 100644 index 0000000..d5ff346 --- /dev/null +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeEnchantmentContractTest.java @@ -0,0 +1,126 @@ +package zone.moddev.mc.basesteam.resources; + +import com.google.gson.JsonParser; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.Lifecycle; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import net.minecraft.core.Holder; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.RegistrationInfo; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +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.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraftforge.registries.ForgeRegistries; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import zone.moddev.mc.basesteam.init.Enchantments; +import zone.moddev.mc.basesteam.init.Items; +import zone.moddev.mc.basesteam.testing.NativeTestBootstrap; +import static org.junit.Assert.*; + +public class NativeEnchantmentContractTest { + private static final List> KEYS = List.of( + Enchantments.high_explosive, Enchantments.powderless, Enchantments.rapid_reload, Enchantments.recoil); + private static RegistryAccess registries; + private static Map, List>> previousTags; + + @BeforeClass public static void decodeActualDataIntoNativeRegistryHolders() throws Exception { + NativeTestBootstrap.start(); + Items.init(); + Items.allItems.forEach((id, item) -> { + ResourceLocation key = ResourceLocation.fromNamespaceAndPath("basesteam", id); + if (!ForgeRegistries.ITEMS.containsKey(key)) ForgeRegistries.ITEMS.register(key, item); + assertSame(item, ForgeRegistries.ITEMS.getValue(key)); + }); + previousTags = new HashMap<>(); + BuiltInRegistries.ITEM.getTags().forEach(pair -> + previousTags.put(pair.getFirst(), pair.getSecond().stream().toList())); + var tags = new HashMap<>(previousTags); + tags.put(ItemTags.create(ResourceLocation.parse("basesteam:muskets")), + List.of(Items.blackpowder_musket.builtInRegistryHolder())); + BuiltInRegistries.ITEM.bindTags(tags); + var enchantments = new MappedRegistry<>(Registries.ENCHANTMENT, Lifecycle.stable()); + registries = new RegistryAccess.ImmutableRegistryAccess(Stream.concat( + NativeTestBootstrap.registries().registries(), + Stream.of(new RegistryAccess.RegistryEntry<>(Registries.ENCHANTMENT, enchantments)))); + var ops = registries.createSerializationContext(JsonOps.INSTANCE); + for (var key : KEYS) { + try (var reader = Files.newBufferedReader(Path.of( + "src/main/resources/data/basesteam/enchantment", key.location().getPath() + ".json"))) { + Enchantment value = Enchantment.DIRECT_CODEC.parse(ops, JsonParser.parseReader(reader)).getOrThrow(); + enchantments.register(key, value, RegistrationInfo.BUILT_IN); + } + } + enchantments.freeze(); + } + + @AfterClass public static void restoreTags() { + if (previousTags != null) BuiltInRegistries.ITEM.bindTags(previousTags); + } + + @Test public void nativeDefinitionsRetainEveryLegacyCostLevelWeightAndSlot() { + int[][] specs = {{5, 5, 7, 7, 17, 7, 2}, {1, 1, 20, 0, 50, 0, 8}, + {2, 1, 15, 0, 50, 0, 4}, {10, 5, 2, 5, 12, 5, 1}}; + for (int index = 0; index < KEYS.size(); index++) { + var key = KEYS.get(index); + Enchantment value = holder(key).value(); + int[] spec = specs[index]; + assertEquals(spec[0], value.getWeight()); + assertEquals(spec[1], value.getMaxLevel()); + assertEquals(spec[6], value.getAnvilCost()); + for (int level = 1; level <= spec[1]; level++) { + assertEquals(spec[2] + spec[3] * (level - 1), value.getMinCost(level)); + assertEquals(spec[4] + spec[5] * (level - 1), value.getMaxCost(level)); + } + assertTrue(value.isPrimaryItem(new ItemStack(Items.blackpowder_musket))); + assertFalse(value.isSupportedItem(new ItemStack(net.minecraft.world.item.Items.STONE))); + for (EquipmentSlot slot : EquipmentSlot.values()) + assertEquals(slot == EquipmentSlot.MAINHAND, value.matchingSlot(slot)); + assertTrue(value.effects().isEmpty()); + for (var other : KEYS) + assertEquals(!key.equals(other), Enchantment.areCompatible(holder(key), holder(other))); + } + } + + @Test public void allFourActualHoldersSurviveNativeSaveAndEveryLoadedStateChange() { + ItemStack stack = new ItemStack(Items.blackpowder_musket); + stack.setDamageValue(123); + for (var key : KEYS) stack.enchant(holder(key), holder(key).value().getMaxLevel()); + var original = stack.get(DataComponents.ENCHANTMENTS); + zone.moddev.mc.basesteam.items.MusketItem.startLoad(stack); + zone.moddev.mc.basesteam.items.MusketItem.finishLoad(stack); + zone.moddev.mc.basesteam.items.MusketItem.unload(stack); + ItemStack restored = ItemStack.parse(registries, stack.save(registries)).orElseThrow(); + assertEquals(original, restored.get(DataComponents.ENCHANTMENTS)); + assertEquals(123, restored.getDamageValue()); + for (var key : KEYS) + assertEquals(holder(key).value().getMaxLevel(), Enchantments.level(key, restored, registries)); + } + + @Test public void absentDataRegistryAndUnknownKeysFailInsteadOfSilentlyDroppingEffects() { + var stack = new ItemStack(Items.blackpowder_musket); + assertThrows(IllegalStateException.class, + () -> Enchantments.level(Enchantments.recoil, stack, RegistryAccess.EMPTY)); + var missing = ResourceKey.create(Registries.ENCHANTMENT, ResourceLocation.parse("basesteam:missing")); + assertThrows(IllegalStateException.class, () -> Enchantments.level(missing, stack, registries)); + } + + private static Holder.Reference holder(ResourceKey key) { + return registries.registryOrThrow(Registries.ENCHANTMENT).getHolderOrThrow(key); + } +} 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 75b2ed0..3bf11b4 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/NativeFuelContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeFuelContractTest.java @@ -36,7 +36,7 @@ public class NativeFuelContractTest { try (MultiPackResourceManager resources = new MultiPackResourceManager( PackType.SERVER_DATA, List.of(ServerPacksSource.createVanillaPackSource()))) { TagLoader> reader = new TagLoader<>( - id -> BuiltInRegistries.ITEM.getHolder(ResourceKey.create(Registries.ITEM, id)), "tags/items"); + id -> BuiltInRegistries.ITEM.getHolder(ResourceKey.create(Registries.ITEM, id)), "tags/item"); Map, List>> loaded = new HashMap<>(); reader.loadAndBuild(resources).forEach((id, tag) -> loaded.put(ItemTags.create(id), List.copyOf(tag))); assertTrue(loaded.containsKey(ItemTags.NON_FLAMMABLE_WOOD)); 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 a8ef27d..a0cbb18 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/NativeLootContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeLootContractTest.java @@ -12,7 +12,7 @@ public class NativeLootContractTest { private static final Path ROOT = Paths.get("src/main/resources"); - private static final Path TABLES = ROOT.resolve("data/basesteam/loot_tables/blocks"); + private static final Path TABLES = ROOT.resolve("data/basesteam/loot_table/blocks"); @Test public void ordinaryBlocksKeepOneSelfDropWithExplosionSurvival() throws Exception { for (String id : new String[] { "steam_pipe", "steam_track", "steam_boiler_coal", @@ -39,12 +39,12 @@ public class NativeLootContractTest { } } - @Test public void packUsesNative1206ResourceAndDataFormats() throws Exception { + @Test public void packUsesNative1211ResourceAndDataFormats() throws Exception { JsonObject pack = read(ROOT.resolve("pack.mcmeta")).getAsJsonObject("pack"); - assertEquals(32, pack.get("pack_format").getAsInt()); + assertEquals(34, 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()); + assertEquals(34, supported.get("min_inclusive").getAsInt()); + assertEquals(48, 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/NativeRegistrationLifecycleTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/NativeRegistrationLifecycleTest.java index 55ed067..4679d0a 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/NativeRegistrationLifecycleTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/NativeRegistrationLifecycleTest.java @@ -20,11 +20,11 @@ public class NativeRegistrationLifecycleTest { assertFalse(calls("SteamAdvantage", "").stream().anyMatch(call -> call.owner.startsWith(INIT))); } - @Test public void owningRegisterEventsInitializeBlocksItemsAndEnchantments() throws Exception { + @Test public void owningRegisterEventsInitializeBlocksAndItemsButEnchantmentsAreDataDriven() throws Exception { assertTrue(calls("init/Blocks", "registerBlocks").stream().anyMatch(call -> initializes(call, "Blocks"))); assertTrue(calls("init/Items", "register").stream().anyMatch(call -> initializes(call, "Items"))); - assertTrue(calls("init/Enchantments", "registerEnchantments").stream() - .anyMatch(call -> initializes(call, "Enchantments"))); + assertFalse(calls("init/Enchantments", "").stream() + .anyMatch(call -> call.owner.startsWith("net/minecraftforge/registries/"))); assertFalse(calls("init/Blocks", "registerBlockItems").stream().anyMatch(call -> initializes(call, "Blocks"))); assertFalse(calls("init/Items", "init").stream().anyMatch(call -> initializes(call, "Blocks"))); assertFalse(calls("init/Recipes", "init").stream() 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 b3d0a39..5a3c988 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/OptionalCrushingRecipeContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/OptionalCrushingRecipeContractTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.*; public class OptionalCrushingRecipeContractTest { - private static final Path RECIPES = Paths.get("src/main/resources/data/basesteam/recipes"); + private static final Path RECIPES = Paths.get("src/main/resources/data/basesteam/recipe"); private static final String[] MACHINES = {"steam_boiler_coal", "steam_boiler_electric", "steam_boiler_geothermal", "steam_crusher", "steam_drill", "steam_elevator", "steam_furnace", "steam_governor", "steam_tank"}; diff --git a/src/test/java/zone/moddev/mc/basesteam/resources/RecipeModeContractTest.java b/src/test/java/zone/moddev/mc/basesteam/resources/RecipeModeContractTest.java new file mode 100644 index 0000000..f0254cb --- /dev/null +++ b/src/test/java/zone/moddev/mc/basesteam/resources/RecipeModeContractTest.java @@ -0,0 +1,59 @@ +package zone.moddev.mc.basesteam.resources; + +import com.google.gson.JsonObject; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.MapCodec; +import net.minecraftforge.common.crafting.conditions.ICondition; +import org.junit.Test; +import zone.moddev.mc.basepower.PowerAdvantage; +import zone.moddev.mc.basepower.RecipeMode; +import zone.moddev.mc.basesteam.SteamAdvantage; +import static org.junit.Assert.*; + +public class RecipeModeContractTest { + @Test public void everyNativeModeConditionSelectsOnlyItsConfiguredMode() throws Exception { + RecipeMode previous = PowerAdvantage.recipeMode; + try { + for (RecipeMode requested : RecipeMode.values()) { + JsonObject input = new JsonObject(); + input.addProperty("mode", requested.name()); + ICondition condition = codec("ModeCondition").codec().parse(JsonOps.INSTANCE, input).getOrThrow(); + for (RecipeMode configured : RecipeMode.values()) { + PowerAdvantage.recipeMode = configured; + assertEquals(requested.name() + " / " + configured.name(), requested == configured, + condition.test(ICondition.IContext.EMPTY, JsonOps.INSTANCE)); + } + } + JsonObject invalid = new JsonObject(); + invalid.addProperty("mode", "not_a_recipe_mode"); + assertTrue(codec("ModeCondition").codec().parse(JsonOps.INSTANCE, invalid).error().isPresent()); + } finally { PowerAdvantage.recipeMode = previous; } + } + + @Test public void nativeMusketConditionHonorsBothConfigValuesWithoutChangingModes() throws Exception { + boolean previous = SteamAdvantage.MUSKET_ENABLE; + RecipeMode previousMode = PowerAdvantage.recipeMode; + try { + ICondition condition = codec("MusketCondition").codec().parse(JsonOps.INSTANCE, new JsonObject()).getOrThrow(); + for (RecipeMode mode : RecipeMode.values()) { + PowerAdvantage.recipeMode = mode; + for (boolean enabled : new boolean[] {false, true}) { + SteamAdvantage.MUSKET_ENABLE = enabled; + assertEquals(enabled, condition.test(ICondition.IContext.EMPTY, JsonOps.INSTANCE)); + assertEquals(mode, PowerAdvantage.recipeMode); + } + } + } finally { + SteamAdvantage.MUSKET_ENABLE = previous; + PowerAdvantage.recipeMode = previousMode; + } + } + + @SuppressWarnings("unchecked") + private static MapCodec codec(String record) throws Exception { + Class type = Class.forName("zone.moddev.mc.basesteam.recipe.RecipeConditions$" + record); + var field = type.getDeclaredField("CODEC"); + field.setAccessible(true); + return (MapCodec) field.get(null); + } +} 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 4a7a056..d098e14 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/RecipeUnlockContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/RecipeUnlockContractTest.java @@ -37,20 +37,20 @@ public class RecipeUnlockContractTest { @Test public void everyCraftingRecipeHasExactlyOneUnlockAndProcessingHasNone() throws IOException { Set expected = new LinkedHashSet<>(); - for (Path file : files(DATA.resolve("recipes"))) { + for (Path file : files(DATA.resolve("recipe"))) { if (crafting(read(file))) expected.add(file.getFileName().toString()); } - Set actual = files(DATA.resolve("advancements/recipes")).stream() + Set actual = files(DATA.resolve("advancement/recipes")).stream() .map(file -> file.getFileName().toString()).collect(Collectors.toSet()); assertFalse("No crafting recipes found", expected.isEmpty()); assertEquals("Missing or orphaned recipe unlocks", expected, actual); } @Test public void discoveriesAreSingleIngredientAlternativesNotAnEntireCraftingGrid() throws IOException { - for (Path file : files(DATA.resolve("recipes"))) { + for (Path file : files(DATA.resolve("recipe"))) { JsonObject recipe = read(file); if (!crafting(recipe)) continue; - JsonObject unlock = read(DATA.resolve("advancements/recipes").resolve(file.getFileName())); + JsonObject unlock = read(DATA.resolve("advancement/recipes").resolve(file.getFileName())); assertEquals("minecraft:recipes/root", unlock.get("parent").getAsString()); assertFalse("Recipe unlocks should not create visible advancement tabs", unlock.has("display")); JsonObject criteria = unlock.getAsJsonObject("criteria"); @@ -83,7 +83,7 @@ public class RecipeUnlockContractTest { } @Test public void rewardAndRecipeCommandCriterionReferToTheExactVariant() throws IOException { - for (Path file : files(DATA.resolve("advancements/recipes"))) { + for (Path file : files(DATA.resolve("advancement/recipes"))) { String id = MOD + ":" + file.getFileName().toString().replace(".json", ""); JsonObject unlock = read(file); JsonArray recipes = unlock.getAsJsonObject("rewards").getAsJsonArray("recipes"); @@ -97,7 +97,7 @@ public class RecipeUnlockContractTest { } @Test public void recipeBookGroupsIdentifyTheOutputNotABroadMachineCategory() throws IOException { - for (Path file : files(DATA.resolve("recipes"))) { + for (Path file : files(DATA.resolve("recipe"))) { JsonObject recipe = read(file); if (!crafting(recipe)) continue; JsonObject result = recipe.getAsJsonObject("result"); @@ -135,7 +135,7 @@ public class RecipeUnlockContractTest { } @Test public void nativeMusketUnlockPredicateRejectsUnrelatedInventory() throws IOException { - JsonObject unlock = read(DATA.resolve("advancements/recipes/musket_right_normal.json")); + JsonObject unlock = read(DATA.resolve("advancement/recipes/musket_right_normal.json")); JsonObject predicate = unlock.getAsJsonObject("criteria").getAsJsonObject("has_ingredient_1") .getAsJsonObject("conditions").getAsJsonArray("items").get(0).getAsJsonObject(); assertEquals("item:minecraft:flint_and_steel", predicateKey(predicate)); diff --git a/src/test/java/zone/moddev/mc/basesteam/testing/NativeMachineFixture.java b/src/test/java/zone/moddev/mc/basesteam/testing/NativeMachineFixture.java new file mode 100644 index 0000000..64843b3 --- /dev/null +++ b/src/test/java/zone/moddev/mc/basesteam/testing/NativeMachineFixture.java @@ -0,0 +1,118 @@ +package zone.moddev.mc.basesteam.testing; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.ForgeRegistry; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import zone.moddev.mc.basesteam.blocks.DrillBitBlock; +import zone.moddev.mc.basesteam.blocks.DrillBitTileEntity; +import zone.moddev.mc.basesteam.init.Entities; +import zone.moddev.mc.basesteam.machines.*; + +/** Actual type/block pairs for detached tests, with every Entities field restored even on failure. */ +public final class NativeMachineFixture implements TestRule { + @Override public Statement apply(Statement test, Description description) { + return new Statement() { + @Override public void evaluate() throws Throwable { + NativeTestBootstrap.start(); + List restore = new ArrayList<>(); + try { + for (Fixture fixture : Fixtures.ALL) restore.add(fixture.install()); + test.evaluate(); + } finally { + for (int index = restore.size() - 1; index >= 0; index--) restore.get(index).run(); + } + } + }; + } + + public static BlockState state(String id) { + return fixture(id).block.defaultBlockState(); + } + + public static List blocks() { + return Fixtures.ALL.stream().map(fixture -> fixture.block).toList(); + } + + public static T create(Class tileClass) { + for (Fixture fixture : Fixtures.ALL) { + BlockEntity tile = fixture.type.create(BlockPos.ZERO, fixture.block.defaultBlockState()); + if (tileClass.isInstance(tile)) return tileClass.cast(tile); + } + throw new IllegalArgumentException("No native Steam fixture for " + tileClass); + } + + private static Fixture fixture(String id) { + return Fixtures.ALL.stream().filter(fixture -> fixture.id.equals(id)).findFirst().orElseThrow(); + } + + private static final class Fixtures { + private static final List> ALL = List.of( + new Fixture<>("steam_boiler_coal", new CoalBoilerBlock(), CoalBoilerTileEntity::new, + () -> Entities.STEAM_BOILER_COAL, type -> Entities.STEAM_BOILER_COAL = type), + new Fixture<>("steam_boiler_electric", new ElectricBoilerBlock(), ElectricBoilerTileEntity::new, + () -> Entities.STEAM_BOILER_ELECTRIC, type -> Entities.STEAM_BOILER_ELECTRIC = type), + new Fixture<>("steam_boiler_geothermal", new GeothermalBoilerBlock(), GeothermalBoilerTileEntity::new, + () -> Entities.STEAM_BOILER_GEOTHERMAL, type -> Entities.STEAM_BOILER_GEOTHERMAL = type), + new Fixture<>("steam_boiler_oil", new OilBoilerBlock(), OilBoilerTileEntity::new, + () -> Entities.STEAM_BOILER_OIL, type -> Entities.STEAM_BOILER_OIL = type), + new Fixture<>("steam_tank", new SteamTankBlock(), SteamTankTileEntity::new, + () -> Entities.STEAM_TANK, type -> Entities.STEAM_TANK = type), + new Fixture<>("steam_furnace", new BlastFurnaceBlock(), BlastFurnaceTileEntity::new, + () -> Entities.STEAM_FURNACE, type -> Entities.STEAM_FURNACE = type), + new Fixture<>("steam_crusher", new RockCrusherBlock(), RockCrusherTileEntity::new, + () -> Entities.STEAM_CRUSHER, type -> Entities.STEAM_CRUSHER = type), + new Fixture<>("steam_drill", new SteamDrillBlock(), SteamDrillTileEntity::new, + () -> Entities.STEAM_DRILL, type -> Entities.STEAM_DRILL = type), + new Fixture<>("steam_elevator", new SteamElevatorBlock(), SteamElevatorTileEntity::new, + () -> Entities.STEAM_ELEVATOR, type -> Entities.STEAM_ELEVATOR = type), + new Fixture<>("drillbit", new DrillBitBlock(), DrillBitTileEntity::new, + () -> Entities.DRILLBIT, type -> Entities.DRILLBIT = type), + new Fixture<>("steam_still", new SteamStillBlock(), SteamStillTileEntity::new, + () -> Entities.STEAM_STILL, type -> Entities.STEAM_STILL = type), + new Fixture<>("steam_pump", new SteamPumpBlock(), SteamPumpTileEntity::new, + () -> Entities.STEAM_PUMP, type -> Entities.STEAM_PUMP = type)); + } + + private static final class Fixture { + private final String id; + private final Block block; + private final BlockEntityType type; + private final Supplier> getter; + private final Consumer> setter; + + private Fixture(String id, Block block, BlockEntityType.BlockEntitySupplier factory, + Supplier> getter, Consumer> setter) { + this.id = id; + this.block = block; + this.getter = getter; + this.setter = setter; + type = BlockEntityType.Builder.of(factory, block).build(null); + ForgeRegistry> registry = (ForgeRegistry>) ForgeRegistries.BLOCK_ENTITY_TYPES; + boolean locked = registry.isLocked(); + registry.unfreeze(); + try { + registry.register(ResourceLocation.fromNamespaceAndPath("basesteam", id), type); + } finally { + if (locked) registry.freeze(); + } + } + + private Runnable install() { + BlockEntityType previous = getter.get(); + setter.accept(type); + return () -> setter.accept(previous); + } + } +} diff --git a/src/test/java/zone/moddev/mc/basesteam/testing/NativeMachineFixtureTest.java b/src/test/java/zone/moddev/mc/basesteam/testing/NativeMachineFixtureTest.java new file mode 100644 index 0000000..e163648 --- /dev/null +++ b/src/test/java/zone/moddev/mc/basesteam/testing/NativeMachineFixtureTest.java @@ -0,0 +1,42 @@ +package zone.moddev.mc.basesteam.testing; + +import java.lang.reflect.Field; +import java.util.LinkedHashMap; +import java.util.Map; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import zone.moddev.mc.basesteam.init.Entities; +import static org.junit.Assert.*; + +public class NativeMachineFixtureTest { + @Test public void fixtureValidatesAllActualBlocksAndRestoresEveryFieldAfterFailure() throws Throwable { + NativeTestBootstrap.start(); + Map previous = new LinkedHashMap<>(); + for (Field field : Entities.class.getFields()) { + if (field.getType() == BlockEntityType.class) previous.put(field, field.get(null)); + } + assertEquals(12, previous.size()); + AssertionError sentinel = new AssertionError("fixture failure witness"); + Statement probe = new Statement() { + @Override public void evaluate() { + for (var block : NativeMachineFixture.blocks()) { + var tile = ((EntityBlock) block).newBlockEntity(BlockPos.ZERO, block.defaultBlockState()); + assertNotNull(tile); + assertTrue(tile.getType().isValid(tile.getBlockState())); + } + throw sentinel; + } + }; + try { + new NativeMachineFixture().apply(probe, Description.EMPTY).evaluate(); + fail("Expected the original fixture failure"); + } catch (AssertionError failure) { + assertSame(sentinel, failure); + } + for (var entry : previous.entrySet()) assertSame(entry.getValue(), entry.getKey().get(null)); + } +} diff --git a/tools/generate-recipe-unlocks.js b/tools/generate-recipe-unlocks.js index 34ed7e9..6053fc6 100644 --- a/tools/generate-recipe-unlocks.js +++ b/tools/generate-recipe-unlocks.js @@ -6,8 +6,8 @@ const root = path.resolve(__dirname, '..'); const properties = fs.readFileSync(path.join(root, 'gradle.properties'), 'utf8'); const mod = /^mod_id=(.+)$/m.exec(properties)[1].trim(); const data = path.join(root, 'src/main/resources/data', mod); -const recipes = path.join(data, 'recipes'); -const output = path.join(data, 'advancements/recipes'); +const recipes = path.join(data, 'recipe'); +const output = path.join(data, 'advancement/recipes'); const check = process.argv.includes('--check'); const ignored = new Set(['item:minecraft:stick', 'item:minecraft:string', 'item:minecraft:feather', 'tag:forge:rods/wooden']); diff --git a/tools/run-packaged-server-smoke.ps1 b/tools/run-packaged-server-smoke.ps1 index 8e2f4ba..67b4e57 100644 --- a/tools/run-packaged-server-smoke.ps1 +++ b/tools/run-packaged-server-smoke.ps1 @@ -13,9 +13,9 @@ $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 +if ($pins.minecraft_version -ne '1.21.1' -or $pins.forge_version -ne '52.1.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.' + throw 'An exact Forge 52.1.0 candidate and committed Power source pin are required.' } $java = (Resolve-Path -LiteralPath $JavaExe).Path $javaVersion = (& $java -version 2>&1 | Out-String).Trim() @@ -34,10 +34,10 @@ if (!$PowerJar) { $PowerJar = Join-Path $project "../../PowerAdvantage/build/libs/basePower-$($pins.poweradvantage_version).jar" } if (!$BaseMetalsJar) { - $BaseMetalsJar = Join-Path $project "../../../../BaseMetals/.verification-basemetals1206/Advantage shared hook/build/libs/BaseMetals-$($pins.basemetals_version).jar" + $BaseMetalsJar = Join-Path $project "../../../../BaseMetals/.verification-basemetals1211/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" + $OreSpawnJar = Join-Path $project "../../../../MinecraftMineralogy/OS1211/OreSpawn/build/libs/OreSpawn-$($pins.orespawn_version).jar" } $mods = [ordered]@{ $steamName = @{ Path = (Join-Path $project "build/libs/$steamName"); Sha256 = $steamSha } @@ -51,11 +51,14 @@ $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' + $shim = $pins.forge_server_shim_sha256 + "$forgeLib/forge-$forgeVersion-server.jar" = $pins.forge_server_sha256 + "$forgeLib/forge-$forgeVersion-universal.jar" = $pins.forge_universal_sha256 } foreach ($file in $forgeJars.Keys) { + if ($forgeJars[$file] -cnotmatch '^[A-F0-9]{64}$') { + throw "Supply the coordinated Forge 52.1.0 runtime hash in gradle.properties: $file" + } if ((Get-FileHash -LiteralPath (Join-Path $forge $file)).Hash -cne $forgeJars[$file]) { throw "Installed Forge runtime hash mismatch: $file" } diff --git a/tools/verify-enchantment-data.js b/tools/verify-enchantment-data.js new file mode 100644 index 0000000..d654ffc --- /dev/null +++ b/tools/verify-enchantment-data.js @@ -0,0 +1,35 @@ +'use strict'; + +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const root = path.resolve(__dirname, '..'); +const read = file => JSON.parse(fs.readFileSync(path.join(root, 'src/main/resources', file), 'utf8')); +const specs = { + high_explosive: [5, 5, 7, 7, 17, 7, 2], + powderless: [1, 1, 20, 0, 50, 0, 8], + rapid_reload: [2, 1, 15, 0, 50, 0, 4], + recoil: [10, 5, 2, 5, 12, 5, 1] +}; +for (const [id, [weight, maxLevel, min, minStep, max, maxStep, anvil]] of Object.entries(specs)) { + assert.deepEqual(read(`data/basesteam/enchantment/${id}.json`), { + description: {translate: `enchantment.${id}`}, + supported_items: '#basesteam:muskets', weight, max_level: maxLevel, + min_cost: {base: min, per_level_above_first: minStep}, + max_cost: {base: max, per_level_above_first: maxStep}, + anvil_cost: anvil, slots: ['mainhand'], effects: {} + }, id); +} +for (const tag of ['non_treasure', 'tooltip_order']) { + const data = read(`data/minecraft/tags/enchantment/${tag}.json`); + assert.equal(data.replace, false); + assert.deepEqual([...data.values].sort(), Object.keys(specs).map(id => `basesteam:${id}`).sort()); +} +assert.deepEqual(read('data/basesteam/tags/item/muskets.json'), {replace: false, values: ['basesteam:musket']}); +const loot = read('data/basesteam/loot_table/chests/advantage_parts.json'); +const enchanted = loot.pools[0].entries.find(entry => entry.functions?.some(f => f.function === 'minecraft:enchant_with_levels')); +assert.equal(enchanted.name, 'basesteam:musket'); +assert.equal(enchanted.weight, 2); +// No options means all registry enchantments, retaining the old treasure=true loot policy. +assert.deepEqual(enchanted.functions, [{function: 'minecraft:enchant_with_levels', levels: 10}]); +console.log('BASESTEAM_ENCHANTMENT_DATA_PASS definitions=4 distributionTags=2'); diff --git a/tools/verify-native-port.js b/tools/verify-native-port.js index 4f5e7b8..ce7637a 100644 --- a/tools/verify-native-port.js +++ b/tools/verify-native-port.js @@ -18,12 +18,14 @@ function files(dir) { } const json = new Map(); for (const name of files(resources).filter(name => /\.(json|mcmeta)$/.test(name))) { + assert(!/\/data\/[^/]+\/(?:recipes|advancements|loot_tables|structures)\//.test(name), name); + assert(!/\/data\/[^/]+\/tags\/(?:items|blocks)\//.test(name), name); const text = read(name); assert(!/steamadvantage|poweradvantage/.test(name + text), name); json.set(name, JSON.parse(text)); } assert.deepEqual(json.get(`${resources}/pack.mcmeta`).pack, { - pack_format: 32, supported_formats: {min_inclusive: 32, max_inclusive: 41}, description: 'baseSteam' + pack_format: 34, supported_formats: {min_inclusive: 34, max_inclusive: 48}, description: 'baseSteam' }); const metadata = read(`${resources}/META-INF/mods.toml`); assert.match(metadata, /modId="basesteam"/); @@ -51,7 +53,7 @@ function verifyModelReferences(value, name) { for (const [name, content] of json) { if (name.startsWith(assets)) verifyModelReferences(content, name); } -for (const sourceRoot of ['src/main/java', 'src/test/java']) { +for (const sourceRoot of ['src/main/java', 'src/test/java', 'src/gametest/java']) { for (const name of files(sourceRoot).filter(name => name.endsWith('.java'))) { const declared = /^package\s+([\w.]+);/m.exec(read(name))?.[1]; const expected = path.posix.dirname(name.slice(sourceRoot.length + 1)).replaceAll('/', '.'); @@ -93,15 +95,16 @@ const entities = read(`${java}/init/Entities.java`); assert(entities.includes('BlockEntityType.BlockEntitySupplier factory')); const ids = [...entities.matchAll(/register\(event, "([^"]+)"/g)].map(match => match[1]); assert.equal(ids.length, 12); -const pickaxe = json.get(`${resources}/data/minecraft/tags/blocks/mineable/pickaxe.json`); +const pickaxe = json.get(`${resources}/data/minecraft/tags/block/mineable/pickaxe.json`); assert.equal(pickaxe.replace, false); assert.equal(new Set(pickaxe.values).size, 17); for (const id of ids) assert(pickaxe.values.includes(`${mod}:${id}`), id); for (const id of pickaxe.values.map(value => value.split(':')[1]).filter(id => !['drillbit', 'platform', 'pump_pipe_steam'].includes(id))) { - const loot = json.get(`${data}/loot_tables/blocks/${id}.json`); + const loot = json.get(`${data}/loot_table/blocks/${id}.json`); assert.equal(loot.pools[0].entries[0].name, `${mod}:${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_NATIVE1206_SOURCE_PASS json=${json.size} java=${source.length} factories=${ids.length} harvest=${pickaxe.values.length} testMethods=${testCount}`); +console.log(`BASESTEAM_NATIVE1211_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.'); +require('./verify-enchantment-data'); From 4c08f6e8dbc4091bef7ec75fbb968de86fd6addc Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 11 Nov 2026 11:02:10 +0000 Subject: [PATCH 2/4] Name the native codec contract for Forge 52 --- .../basesteam/resources/OptionalCrushingRecipeContractTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5a3c988..48dc5fb 100644 --- a/src/test/java/zone/moddev/mc/basesteam/resources/OptionalCrushingRecipeContractTest.java +++ b/src/test/java/zone/moddev/mc/basesteam/resources/OptionalCrushingRecipeContractTest.java @@ -91,7 +91,7 @@ private static boolean baseGuard(JsonElement value) { assertFalse(condition, baseGuard(json(condition))); } - @Test public void nativeForge50CodecRetainsTheExactProviderIdentity() { + @Test public void nativeForge52CodecRetainsTheExactProviderIdentity() { JsonObject guard = json("{\"type\":\"forge:mod_loaded\",\"modid\":\"basemetals\"}"); ModLoadedCondition condition = ModLoadedCondition.CODEC.codec().parse(JsonOps.INSTANCE, guard).getOrThrow(); assertSame(ModLoadedCondition.CODEC, condition.codec()); From 9c5bf9b4610e06d3b5a6d5a0bde38d7516327d96 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 11 Nov 2026 11:47:53 +0000 Subject: [PATCH 3/4] Pin repaired Forge 52 basePower candidate --- docs/PORT1211-STATUS.md | 2 +- gradle.properties | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/PORT1211-STATUS.md b/docs/PORT1211-STATUS.md index cc2a9ef..9d20435 100644 --- a/docs/PORT1211-STATUS.md +++ b/docs/PORT1211-STATUS.md @@ -1,7 +1,7 @@ # Steam on Minecraft 1.21.1 Local candidate 2.2.15.121011 targets Forge 52.1.0 and Java 21. -The build pins the coordinated local basePower commit `72fd326b9a9c` and +The build pins the coordinated local basePower commit `a16e8148871f` and its exact native jar. Public CI still requires merged sources and verified public files. Nothing has been published. diff --git a/gradle.properties b/gradle.properties index 228f56a..db5dda1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -43,11 +43,11 @@ poweradvantage_version=2.4.14.121011 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower # Exact coordinated local candidate. Source and jar checks reject overrides. # Public file IDs await independent public download verification; local approval is not publication. -poweradvantage_source_ref=72fd326b9a9c28e1b2447dfc5ebed99677f09872 +poweradvantage_source_ref=a16e8148871fe7007bf1db5a982dbba5ddf1a1ef poweradvantage_public_file_id= -poweradvantage_deobf_sha256=76CF79E04F36947D25535B982099B31AA88907448959F063BEA617644B7179F7 +poweradvantage_deobf_sha256=F91A613EB5FAA218AAD2DC3C881DEC7B897A5EE874215282A439E34B915C1AE6 # Forge 52 uses the same native jar for development and packaged runtime. -poweradvantage_player_sha256=76CF79E04F36947D25535B982099B31AA88907448959F063BEA617644B7179F7 +poweradvantage_player_sha256=F91A613EB5FAA218AAD2DC3C881DEC7B897A5EE874215282A439E34B915C1AE6 poweradvantage_test_bootstrap_sha256=6AF174EBBBF2501457CE4786A130AFDB6ED92CC47DD105465F9EF8685ECE90E3 poweradvantage_test_bootstrap_source_sha256=CCEB755FDA6D38C492124DC122C993FA7EDA2A945CB603573D4CD9562B6AE280 poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF56CD6203C9CD692CAC1531D0981F From 71677e195929ed0e36006e39255ce7a18985f5d3 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 11 Nov 2026 15:35:36 +0000 Subject: [PATCH 4/4] Prepare baseSteam 1.21.1 with the released basePower dependency --- CHANGELOG.txt | 3 ++- README.md | 10 +++++----- docs/PORT1211-STATUS.md | 14 +++++++------- gradle.properties | 13 ++++++------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index cde438f..58bc847 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,8 +1,9 @@ -baseSteam 2.2.15.121011 (local Minecraft 1.21.1 candidate) +baseSteam 2.2.15.121011 (Minecraft 1.21.1 / Forge) - Target Forge 52.1.0 and Java 21 with basePower 2.4.14.121011. - Keep machine balance, saved state, recipes and the whole fluid gauges unchanged. - Move musket enchantments to native data while retaining all four IDs and effects. +- Pin the released basePower, Base Metals and OreSpawn jars used for the upgrade tests. baseSteam 2.2.14.120061 (Minecraft 1.20.6 / Forge) diff --git a/README.md b/README.md index ba7f0ea..31c1f7c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # baseSteam -**Minecraft 1.21.1 (Forge), local candidate 2.2.15.121011.** +**Minecraft 1.21.1 (Forge), version 2.2.15.121011.** baseSteam adds boilers, steam-powered machines, pumps, storage, elevators and a blackpowder musket to basePower. Items and blocks share the basePower @@ -14,11 +14,11 @@ wrapper use Temurin 21.0.7+6. Mavenizer uses Java 25; the launcher helper also needs Java 8. Minecraft itself runs on Java 21. The default dependency paths use the coordinated 1.21.1 checkouts. This -candidate needs basePower 2.4.14.121011, Base Metals 3.1.2.121011 and +version needs the released basePower 2.4.14.121011, Base Metals 3.1.2.121011 and OreSpawn 4.1.0.121011 as separate native jars, not bundled copies. -Exact local source, jar and test-bootstrap pins are in `gradle.properties`. -They are checked before compilation and tests. Local approval does not -establish public availability. +Exact source, public file, jar and test-bootstrap pins are in `gradle.properties`. +They are checked before compilation and tests. CurseForge, Maven and GitHub +releases use the same checked player jar. The Mavenizer fixture comes from OreSpawn's OS1211 checkout. Another layout can use `-Pforge52MavenizerJar=`. The `*DeobfJar` and `*PlayerJar` diff --git a/docs/PORT1211-STATUS.md b/docs/PORT1211-STATUS.md index 9d20435..f8a76bb 100644 --- a/docs/PORT1211-STATUS.md +++ b/docs/PORT1211-STATUS.md @@ -1,9 +1,8 @@ # Steam on Minecraft 1.21.1 -Local candidate 2.2.15.121011 targets Forge 52.1.0 and Java 21. -The build pins the coordinated local basePower commit `a16e8148871f` and -its exact native jar. Public CI still requires merged sources and verified -public files. Nothing has been published. +Version 2.2.15.121011 targets Forge 52.1.0 and Java 21. +The build pins released basePower 2.4.14.121011 at `8d9937b3c0c9`, with +public file IDs and checked jar hashes for all three dependencies. Steam keeps its mod ID, packages, registry paths, configuration and machine balance. Datapack registry folders use the native singular names, without @@ -19,6 +18,7 @@ plus four native GameTests, archive audits and the Eclipse classpath gate. Fresh packaged dedicated servers also start and stop cleanly with and without Base Metals. -Back up old worlds and use disposable copies with basePower's coordinated -migration rig. These Steam checks do not establish combined world-upgrade, -multiplayer or manual visual acceptance. +The coordinated suite also passed old-world migration, connected machine +jobs, saved-state checks, chunk unloading and two 30-minute endurance runs. +The client visual and recipe-unlock checks were accepted before publication. +Keep a backup and test upgrades on a copy; these checks cannot cover every modpack. diff --git a/gradle.properties b/gradle.properties index db5dda1..a992b2e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -41,10 +41,9 @@ cf_versions=1.21.1 poweradvantage_version=2.4.14.121011 poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower -# Exact coordinated local candidate. Source and jar checks reject overrides. -# Public file IDs await independent public download verification; local approval is not publication. -poweradvantage_source_ref=a16e8148871fe7007bf1db5a982dbba5ddf1a1ef -poweradvantage_public_file_id= +# Exact released dependencies. Source and jar checks reject mismatched overrides. +poweradvantage_source_ref=8d9937b3c0c9ef28a231b90fc2ff6adfea1af733 +poweradvantage_public_file_id=9559143 poweradvantage_deobf_sha256=F91A613EB5FAA218AAD2DC3C881DEC7B897A5EE874215282A439E34B915C1AE6 # Forge 52 uses the same native jar for development and packaged runtime. poweradvantage_player_sha256=F91A613EB5FAA218AAD2DC3C881DEC7B897A5EE874215282A439E34B915C1AE6 @@ -53,13 +52,13 @@ poweradvantage_test_bootstrap_source_sha256=CCEB755FDA6D38C492124DC122C993FA7EDA poweradvantage_test_registry_source_sha256=2E2C52DBAA14B4FA7EF1FF8C3A2BEFF9B1DF56CD6203C9CD692CAC1531D0981F basemetals_version=3.1.2.121011 -basemetals_source_commit=b42b92b0e6f60ac5baf07a6b74042b2fa8427904 -basemetals_public_file_id= +basemetals_source_commit=327c197bcdd0bb5e883d844bb6a6c8791bc580b7 +basemetals_public_file_id=9559006 basemetals_deobf_sha256=7C0B961A8D4991C9B69379518AAD700A71C1E4B2076CF5DEF292C58029408A07 basemetals_player_sha256=7C0B961A8D4991C9B69379518AAD700A71C1E4B2076CF5DEF292C58029408A07 orespawn_version=4.1.0.121011 orespawn_source_commit=62c08169c71f4d4fd8f107289e63fd2a4c7c655c -orespawn_public_file_id= +orespawn_public_file_id=9189594 orespawn_deobf_sha256=EB369B7D7CE6D6C453658347A420C2F0783B7F4D1AC7383C87176AC05192B5A0 orespawn_player_sha256=EB369B7D7CE6D6C453658347A420C2F0783B7F4D1AC7383C87176AC05192B5A0