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