diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ce6057e2..6fa868247 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,19 +1,19 @@ -name: Base Metals 26.1.2 CI +name: Base Metals 26.2 CI on: push: branches: - - master-26.1.2 + - master-26.2 - 'feature/**' pull_request: branches: - - master-26.1.2 + - master-26.2 permissions: contents: read concurrency: - group: basemetals-26.1.2-${{ github.workflow }}-${{ github.ref }} + group: basemetals-26.2-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -49,7 +49,7 @@ jobs: "$RUNNER_TEMP/nbt-tests/bin/python" -m unittest discover -s tools/validation -p 'test_*.py' - name: Test upgrade log boundaries - run: node --test tools/validation/test_painting_registry.js + run: node --test tools/validation/test_painting_registry.js tools/validation/test_runtime_log.js - name: Build, test, and audit first candidate run: | @@ -59,9 +59,9 @@ jobs: --no-daemon --stacktrace first="$RUNNER_TEMP/basemetals-first" mkdir -p "$first" - cp build/libs/BaseMetals-3.1.1.2601021.jar "$first/" - cp build/libs/BaseMetals-3.1.1.2601021-sources.jar "$first/" - cp build/libs/BaseMetals-3.1.1.2601021-javadoc.jar "$first/" + cp build/libs/BaseMetals-3.1.1.2602001.jar "$first/" + cp build/libs/BaseMetals-3.1.1.2602001-sources.jar "$first/" + cp build/libs/BaseMetals-3.1.1.2602001-javadoc.jar "$first/" cp build/release/SHA256SUMS "$first/" - name: Rebuild and prove byte-identical archives @@ -69,9 +69,9 @@ jobs: ./gradlew clean assemble verifyReleaseArtifacts writeReleaseChecksums \ -PorespawnVerificationRepository="${{ steps.orespawn.outputs.repository }}" \ --no-daemon --stacktrace - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.1.2601021.jar" build/libs/BaseMetals-3.1.1.2601021.jar - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.1.2601021-sources.jar" build/libs/BaseMetals-3.1.1.2601021-sources.jar - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.1.2601021-javadoc.jar" build/libs/BaseMetals-3.1.1.2601021-javadoc.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.1.2602001.jar" build/libs/BaseMetals-3.1.1.2602001.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.1.2602001-sources.jar" build/libs/BaseMetals-3.1.1.2602001-sources.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.1.2602001-javadoc.jar" build/libs/BaseMetals-3.1.1.2602001-javadoc.jar cmp "$RUNNER_TEMP/basemetals-first/SHA256SUMS" build/release/SHA256SUMS - name: Run all required GameTests @@ -83,14 +83,14 @@ jobs: - name: Install official Forge packaged runtimes id: forge-runtimes run: | - server_runtime="$RUNNER_TEMP/forge-26.1.2-64.0.9-server" - client_runtime="$RUNNER_TEMP/forge-26.1.2-64.0.9-client" - installer="$RUNNER_TEMP/forge-26.1.2-64.0.9-installer.jar" + server_runtime="$RUNNER_TEMP/forge-26.2-65.1.0-server" + client_runtime="$RUNNER_TEMP/forge-26.2-65.1.0-client" + installer="$RUNNER_TEMP/forge-26.2-65.1.0-installer.jar" mkdir -p "$server_runtime" "$client_runtime" curl --fail --location --retry 3 \ --output "$installer" \ - https://maven.minecraftforge.net/net/minecraftforge/forge/26.1.2-64.0.9/forge-26.1.2-64.0.9-installer.jar - echo "608BC9F028A0EF8DCD1A49C6EB85DDFCFA3B3BCD8AE27FC1B2AE02888ED8CB0A $installer" | sha256sum --check --strict + https://maven.minecraftforge.net/net/minecraftforge/forge/26.2-65.1.0/forge-26.2-65.1.0-installer.jar + echo "813FBBFECC3086A492783B9F5023AE15007737B42E17AAB75F48BA77403314DF $installer" | sha256sum --check --strict ( cd "$server_runtime" java -jar "$installer" --installServer @@ -135,13 +135,13 @@ jobs: - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: BaseMetals-26.1.2-${{ github.sha }} + name: BaseMetals-26.2-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/BaseMetals-3.1.1.2601021.jar - build/libs/BaseMetals-3.1.1.2601021-sources.jar - build/libs/BaseMetals-3.1.1.2601021-javadoc.jar + build/libs/BaseMetals-3.1.1.2602001.jar + build/libs/BaseMetals-3.1.1.2602001-sources.jar + build/libs/BaseMetals-3.1.1.2602001-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt @@ -149,7 +149,7 @@ jobs: if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: BaseMetals-26.1.2-diagnostics-${{ github.sha }} + name: BaseMetals-26.2-diagnostics-${{ github.sha }} if-no-files-found: ignore retention-days: 14 path: | diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 51315cef4..7bb158a99 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,11 +3,11 @@ name: CodeQL on: push: branches: - - master-26.1.2 + - master-26.2 - 'feature/**' pull_request: branches: - - master-26.1.2 + - master-26.2 permissions: actions: read diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index 531f53fed..d8bacce9a 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-26.1.2 + - master-26.2 - 'feature/**' pull_request: branches: - - master-26.1.2 + - master-26.2 permissions: contents: read diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 3c097cafe..d7289ae53 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,11 @@ +Base Metals 3.1.1.2602001 + +- Port the released 26.1.2 version to Minecraft 26.2 and Forge 65, keeping Java 25. +- Keep raw metals, ore overlays, filled buckets, High/Low Fantasy and the existing gameplay fixes. +- Use published OreSpawn 4.1.0.2602001 with the same eleven rules and copper defaults. +- Keep existing world profiles, saved items and legacy-upgrade protections. +- Keep generated Javadoc icons consistent between Windows and Linux builds. + Base Metals 3.1.1.2601021 - Port the released 1.21.11 version to Minecraft 26.1.2, Forge 64 and Java 25. diff --git a/README.md b/README.md index d3c06cd46..18a85fcab 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Discord](https://img.shields.io/badge/Discord-MMD-green.svg?style=flat&logo=Discord)](https://discord.moddev.zone) [![CurseForge downloads](https://cf.way2muchnoise.eu/full_base-metals_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/base-metals) [![Supported Minecraft versions](https://cf.way2muchnoise.eu/versions/Minecraft_base-metals_all.svg)](https://www.curseforge.com/minecraft/mc-mods/base-metals) -[![Build, test, and audit](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml/badge.svg?branch=master-26.1.2)](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml?query=branch%3Amaster-26.1.2) +[![Build, test, and audit](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml/badge.svg?branch=master-26.2)](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml?query=branch%3Amaster-26.2) # Base Metals @@ -12,23 +12,23 @@ shields, bows, crossbows, arrows, and bolts. The mod also includes Crack Hammers, scythes, metal anvils, the human detector, villager trades, advancements, and structure loot. -This is the Minecraft 26.1.2 Forge version, `3.1.1.2601021`. It keeps the -fixes and features from the released 1.21.11 version, including raw metals, ore +This is the Minecraft 26.2 Forge version, `3.1.1.2602001`. It keeps the +fixes and features from the released 26.1.2 version, including raw metals, ore texture overlays and High/Low Fantasy modes. Existing Base Metals items and blocks keep their registry IDs. OreSpawn handles ore generation; MMDLib and Additional Loot Tables are no longer needed. ## Requirements -- Minecraft `26.1.2` -- Forge `64.0.9` or newer in the Minecraft 26.1.2 Forge 64 line +- Minecraft `26.2` +- Forge `65.1.0` or newer in the Minecraft 26.2 Forge 65 line - A current Java 25 runtime -- OreSpawn `[4.1.0.2601021,5.0.0)` on both client and server +- OreSpawn `[4.1.0.2602001,5.0.0)` on both client and server -The build uses Forge `64.0.9` and is also tested on `64.1.5`. +The build uses Forge `65.1.0` and is also tested on `65.1.5`. -This version uses OreSpawn `4.1.0.2601021`. Put -`BaseMetals-3.1.1.2601021.jar` and a compatible OreSpawn JAR in the `mods` +This version uses OreSpawn `4.1.0.2602001`. Put +`BaseMetals-3.1.1.2602001.jar` and a compatible OreSpawn JAR in the `mods` directory. MMDLib and Additional Loot Tables must not be carried forward from an older installation. Mineralogy is optional. @@ -150,7 +150,7 @@ Forge item, block, and fluid tags are Base Metals' public compatibility API. Compatible tags and the existing recipe data for Mekanism, Thermal, Tinkers' Construct and Ender IO are retained, but their Java integrations are not enabled -in this Forge 26.1.2 port. Do not add jars made for older Minecraft versions or +in this Forge 26.2 port. Do not add jars made for older Minecraft versions or NeoForge to this instance. No optional integration API is required to compile or launch Base Metals. @@ -201,7 +201,7 @@ early splash window. Minecraft still opens its game window and runs the full world check. Ordinary client launches keep the normal splash screen. Release artifacts use Maven coordinate -`zone.moddev.mc.basemetals:BaseMetals:3.1.1.2601021`. +`zone.moddev.mc.basemetals:BaseMetals:3.1.1.2602001`. Report defects and compatibility problems through the [Base Metals issue tracker](https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues). diff --git a/build.gradle b/build.gradle index 9e5e6f300..bf2e3ceb7 100644 --- a/build.gradle +++ b/build.gradle @@ -9,14 +9,14 @@ plugins { ext.mavenizerCompatibilityJar = layout.projectDirectory.file( 'ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar') ext.mavenizerCompatibilitySha256 = - 'BB0DACB3DEB2A711CA67DD402D5FDAB5A9847C37C7B9B596DEC7CF37378FA085' + '5ABAB52A3F1BE115381C3CE80D5FD38DBE6C9F4C0B9ECF70A957700EC90FB88B' ext.mavenizerFixtureChecksums = [ 'minecraft-mavenizer-0.5.21-orespawn-compat.jar': mavenizerCompatibilitySha256, - 'minecraft-source-compatibility.json': '21D1F5984E735BCEA1B1EFB9F965655796B39538FC91AAED1C3474004710423D', - 'minecraft-mavenizer-0.5.21-orespawn-compat.patch': '7C8EC895E79DF31AFD2CA3B505B43573C7052718A24050832189AAA2D3CC6137', + 'minecraft-source-compatibility.json': '9437E03FC5E1CB5D605D72F0538C4DF4417B64DB0A57D0AABDC5184781517AC1', + 'minecraft-mavenizer-0.5.21-orespawn-compat.patch': '2DA8DD0FD5F112F5B7591113AED06D9A58C584A25F8705E26445A6D2E9D5C78E', 'LICENSE-MAVENIZER.txt': '20C17D8B8C48A600800DFD14F95D5CB9FF47066A9641DDEAB48DC54AEC96E331', - 'README.md': '7686880D2B0F6BD6ACAFA4F0AB7585189767813174BC36DB675FEC0142440A77' + 'README.md': 'EAD1477F393897C491A10FB86178213A99C360571A8063D551DA0579DF65BA6F' ] // Mavenizer runs during configuration, so verify its inputs before configuring Forge. mavenizerFixtureChecksums.each { name, expected -> @@ -27,7 +27,7 @@ mavenizerFixtureChecksums.each { name, expected -> } } -// Forge 64 needs no source repairs. The sealed fixture records that result +// Forge 65 needs no source repairs. The sealed fixture records that result // and stays separate from the mod and its runtime dependencies. fgtools.configure('mavenizer') { classpath.from(mavenizerCompatibilityJar) diff --git a/ci-fixtures/tools/README.md b/ci-fixtures/tools/README.md index 4258c43c7..1365b4203 100644 --- a/ci-fixtures/tools/README.md +++ b/ci-fixtures/tools/README.md @@ -2,7 +2,7 @@ This directory contains a build-only derivative of MinecraftForge's MinecraftMavenizer `0.5.21`. It is used only while ForgeGradle prepares the -exact Forge `26.1.2-64.0.9` development dependency and is excluded from every +exact Forge `26.2-65.1.0` development dependency and is excluded from every OreSpawn publication artifact. ## Provenance and licence @@ -21,13 +21,13 @@ declaration and one accessor in that record. Missing, partial, duplicate or ambiguous states fail preparation. Targets without an explicit rule set are left unchanged. -Forge `26.1.2-64.0.9` compiles without source compatibility edits. Its explicit +Forge `26.2-65.1.0` compiles without source compatibility edits. Its explicit zero-rule entry proves that result is intentional and target-qualified rather than an accidental fall-through. A marker beside Mavenizer's output records the target and manifest SHA-256. Reprocessing the same source is idempotent. The derivative also propagates Gradle offline mode when the build sets -`ORESPAWN_MAVENIZER_OFFLINE=true`. Mavenizer, OreSpawn and Minecraft 26.1.2 all +`ORESPAWN_MAVENIZER_OFFLINE=true`. Mavenizer, OreSpawn and Minecraft 26.2 all run and compile with Java 25. ## Rebuild diff --git a/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar b/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar index 37a70e0cc..b5f7fb50b 100644 Binary files a/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar and b/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar differ diff --git a/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.patch b/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.patch index f8c2c8acb..b0c92c519 100644 --- a/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.patch +++ b/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.patch @@ -371,7 +371,7 @@ index 0000000..702d759 +{ + "schema": 1, + "targets": { -+ "net.minecraftforge:forge:26.1.2-64.0.9": { ++ "net.minecraftforge:forge:26.2-65.1.0": { + "expectedApplications": 0, + "rules": [] + } diff --git a/ci-fixtures/tools/minecraft-source-compatibility.json b/ci-fixtures/tools/minecraft-source-compatibility.json index 0901331f0..f6c049d6b 100644 --- a/ci-fixtures/tools/minecraft-source-compatibility.json +++ b/ci-fixtures/tools/minecraft-source-compatibility.json @@ -1,7 +1,7 @@ { "schema": 1, "targets": { - "net.minecraftforge:forge:26.1.2-64.0.9": { + "net.minecraftforge:forge:26.2-65.1.0": { "expectedApplications": 0, "rules": [] } diff --git a/docs/COMPATIBILITY.md b/docs/COMPATIBILITY.md index 50fa1e123..cfcdf4f58 100644 --- a/docs/COMPATIBILITY.md +++ b/docs/COMPATIBILITY.md @@ -23,7 +23,7 @@ recycling recipes also accept the appropriate vanilla equivalent. The tags and existing integration data for Mekanism, Thermal, Tinkers' Construct and Ender IO remain available for future compatibility work. Their Java API hooks -and runtime jars are not included in this Forge 26.1.2 port. Do not substitute +and runtime jars are not included in this Forge 26.2 port. Do not substitute jars made for older Minecraft versions or NeoForge. Other processors can use the shared Forge tags without a direct Java integration. diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 09d110c5a..9b3dcdfbf 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -2,7 +2,7 @@ Always upgrade a copy and retain the original legacy world. Install Base Metals 3.1.1 and OreSpawn 4.1.0, but do not carry MMDLib, Additional Loot Tables, the -OreSpawn 3 plugin, or the old native fallback generator into the 26.1.2 instance. +OreSpawn 3 plugin, or the old native fallback generator into the 26.2 instance. Minecraft's data fixer cannot identify third-party numeric block IDs from before the 1.13 flattening. Base Metals snapshots those positions, runs @@ -148,6 +148,11 @@ when the current world metadata confirms an upgrade from the previous storage format. The source files are kept for recovery. A modern world with leftover old files does not activate this step. +Minecraft 26.2 also moves world-generation settings, game rules and world clocks +out of `level.dat` into separate saved-data files. Minecraft handles that move +during the upgrade. Keep the whole world folder together rather than copying +an older `level.dat` over the upgraded save. + If an older single-player save has its player only in `level.dat`, Base Metals preserves a separate player file before Minecraft converts the folders. An existing player file always wins; a stale backup cannot restore an older player. diff --git a/docs/VERSIONS.md b/docs/VERSIONS.md index 15887a0e4..54b930f1b 100644 --- a/docs/VERSIONS.md +++ b/docs/VERSIONS.md @@ -1,22 +1,22 @@ # Supported versions -Base Metals `3.1.1.2601021` targets Minecraft 26.1.2, Forge 64.0.9 and Java 25. -Forge 64.1.5 is the additional compatibility target. -OreSpawn `4.1.0.2601021` is the exact build and test dependency. Clients and -servers need OreSpawn `[4.1.0.2601021,5.0.0)`. +Base Metals `3.1.1.2602001` targets Minecraft 26.2, Forge 65.1.0 and Java 25. +Forge 65.1.5 is the additional compatibility target. +OreSpawn `4.1.0.2602001` is the exact build and test dependency. Clients and +servers need OreSpawn `[4.1.0.2602001,5.0.0)`. -The pinned CurseForge artifact is project 245586, file 9299079: -`curse.maven:mmd-orespawn-245586:9299079`. +The pinned CurseForge artifact is project 245586, file 9332183: +`curse.maven:mmd-orespawn-245586:9332183`. Its SHA-256 is -`6D5CE2017C3314968083D140309E2F1A54BC239AC65C48944C995E9ECF937948`. +`F74785025898DF059E0F00F6ADA53364E07ECBBC306807ED7CD55350609E2547`. Release artifacts use Maven coordinate -`zone.moddev.mc.basemetals:BaseMetals:3.1.1.2601021`. +`zone.moddev.mc.basemetals:BaseMetals:3.1.1.2602001`. The provider remains schema 3, revision 1. OreSpawn 4.1 is needed for the configuration-screen API; the provider's eleven rule IDs and 1.18 distributions have not changed. -The data pack uses format `101.1`. Forge wraps client mod resources with the -native resource-pack format `84.0`. The resource metadata retains the minor -version rather than rounding the data format down to `101`. +The data pack uses format `107.1`. Forge wraps client mod resources with the +native resource-pack format `88.0`. The resource metadata retains the minor +version rather than rounding the data format down to `107`. diff --git a/docs/WORLDGEN.md b/docs/WORLDGEN.md index a6804c651..bd2909986 100644 --- a/docs/WORLDGEN.md +++ b/docs/WORLDGEN.md @@ -1,8 +1,8 @@ # OreSpawn world generation -Base Metals requires OreSpawn `[4.1.0.2601021,5.0.0)` and packages provider schema 3, +Base Metals requires OreSpawn `[4.1.0.2602001,5.0.0)` and packages provider schema 3, revision 1 at `data/basemetals/orespawn/provider.json`. Builds and tests use the -published OreSpawn `4.1.0.2601021` release. The provider is checked against the +published OreSpawn `4.1.0.2602001` release. The provider is checked against the included 4.1.0 schema. The provider declares ores only: it has no rocks, geomes, biome rules, terrain diff --git a/docs/schemas/orespawn-4.1.0/README.md b/docs/schemas/orespawn-4.1.0/README.md index a724e48f9..c7e20bdf1 100644 --- a/docs/schemas/orespawn-4.1.0/README.md +++ b/docs/schemas/orespawn-4.1.0/README.md @@ -1,9 +1,9 @@ # OreSpawn 4.1.0 schemas -These public schemas match OreSpawn 4.1.0.2601021. The Base Metals provider +These public schemas match OreSpawn 4.1.0.2602001. The Base Metals provider still uses schema 3 and revision 1; its ore rules have not changed. The build validates the provider against this snapshot. OreSpawn 4.1 is also needed for the Base Metals configuration button in its world-creation screen. -Source: [OreSpawn 4.1.0.2601021](https://github.com/MinecraftModDevelopmentMods/OreSpawn/releases/tag/4.1.0.2601021). +Source: [OreSpawn 4.1.0.2602001](https://github.com/MinecraftModDevelopmentMods/OreSpawn/releases/tag/4.1.0.2602001). diff --git a/gradle.properties b/gradle.properties index e905e3fba..06a4ea1b0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,14 +11,14 @@ net.minecraftforge.gradle.merge-source-sets=true ## Environment Properties # The Minecraft version must agree with the Forge version to get a valid artifact -minecraft_version=26.1.2 +minecraft_version=26.2 # The Minecraft version range can use any release version of Minecraft as bounds. # Snapshots, pre-releases, and release candidates are not guaranteed to sort properly # as they do not follow standard versioning conventions. -minecraft_version_range=[26.1.2,26.2) +minecraft_version_range=[26.2,26.3) # The Forge version must agree with the Minecraft version to get a valid artifact -forge_version=64.0.9 -forge_installer_sha256=608BC9F028A0EF8DCD1A49C6EB85DDFCFA3B3BCD8AE27FC1B2AE02888ED8CB0A +forge_version=65.1.0 +forge_installer_sha256=813FBBFECC3086A492783B9F5023AE15007737B42E17AAB75F48BA77403314DF # Release metadata consumed by the generic dispatcher. loader_name=forge loader_code=1 @@ -29,14 +29,14 @@ curseforge_project_id=240967 # Exact released OreSpawn used for development and qualification. Runtime # metadata intentionally remains compatible with supported OreSpawn 4 builds. -orespawn_version=4.1.0.2601021 +orespawn_version=4.1.0.2602001 orespawn_curse_project_id=245586 -orespawn_curse_file_id=9299079 -orespawn_sha256=6D5CE2017C3314968083D140309E2F1A54BC239AC65C48944C995E9ECF937948 +orespawn_curse_file_id=9332183 +orespawn_sha256=F74785025898DF059E0F00F6ADA53364E07ECBBC306807ED7CD55350609E2547 # The Forge version range can use any version of Forge as bounds or match the loader version range -forge_version_range=[64.0.9,65) +forge_version_range=[65.1.0,66) # The loader version range can only use the major version of Forge/FML as bounds -loader_version_range=[64,65) +loader_version_range=[65,66) # The mapping channel to use for mappings. # The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"]. # Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin. @@ -54,7 +54,7 @@ loader_version_range=[64,65) mapping_channel=official # The mapping version to query from the mapping channel. # This must match the format required by the mapping channel. -mapping_version=26.1.2 +mapping_version=26.2 ## Mod Properties @@ -67,7 +67,7 @@ mod_name=Base Metals # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-2.1 # The mod version. See https://semver.org/ -mod_version=3.1.1.2601021 +mod_version=3.1.1.2602001 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html @@ -77,7 +77,7 @@ mod_authors=Cyanobacterium, jriwanek, dshadowwolf, GetDizzy611, SkyBlade1978, th # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. mod_description=Adds historically common metals, fantasy metals, alloys, tools, armour, and OreSpawn-powered deposits. -# Forge 64 uses official runtime names. +# Forge 65 uses official runtime names. reobf=false -mcp_version=20260409.101008 +mcp_version=20260616.103818 java_setup_version=25.0.3+9.0.LTS diff --git a/gradle/README.md b/gradle/README.md index 5de5afe6a..c4ada76fd 100644 --- a/gradle/README.md +++ b/gradle/README.md @@ -32,7 +32,7 @@ flower, sapling and leaf tags include suitable new plants. Normal client and server launches load only Base Metals and OreSpawn. The optional-mod profile has its own run folder, but no optional integration mods -are pinned for Forge 26.1.2. The Mekanism, Tinkers, Thermal and Ender IO Java +are pinned for Forge 26.2. The Mekanism, Tinkers, Thermal and Ender IO Java integrations are not enabled here; their dormant data remains available for future integration work. diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 4da004036..1c8af9ad8 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -54,12 +54,12 @@ dependencies { implementation minecraft.dependency("net.minecraftforge:forge:${minecraft_version}-${forge_version}") // OreSpawn remains an ordinary hard mod dependency in metadata and is - // never shaded into Base Metals. Use the published 26.1.2 release in + // never shaded into Base Metals. Use the published 26.2 release in // development so clean checkouts exercise the same artifact as players. implementation "curse.maven:mmd-orespawn-${orespawn_curse_project_id}:${orespawn_curse_file_id}" orespawnRelease "curse.maven:mmd-orespawn-${orespawn_curse_project_id}:${orespawn_curse_file_id}" - // Optional Java integrations are not enabled in this Forge 26.1.2 port. + // Optional Java integrations are not enabled in this Forge 26.2 port. testImplementation platform('org.junit:junit-bom:5.10.2') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.10.2' diff --git a/gradle/ide/eclipse.gradle b/gradle/ide/eclipse.gradle index fe1025132..bb25ef855 100644 --- a/gradle/ide/eclipse.gradle +++ b/gradle/ide/eclipse.gradle @@ -91,7 +91,7 @@ def verifyDevelopmentRunProfiles = tasks.register('verifyDevelopmentRunProfiles' || optionalDevelopmentArtifacts.any { expected -> !optionalClient.classpath.files.any { it.name.contains("${expected.module}-${expected.file}") } }) { - throw new GradleException('The optional client must load the pinned 26.1.2 dependencies') + throw new GradleException('The optional client must load the pinned 26.2 dependencies') } } } @@ -334,7 +334,7 @@ def verifyEclipseProductionClasspath = tasks.register('verifyEclipseProductionCl } } String metadata = new File(projectDir, 'bin/main/META-INF/mods.toml').getText('UTF-8') - if (metadata.contains('${') || !metadata.contains('version="3.1.1.2601021"')) { + if (metadata.contains('${') || !metadata.contains('version="3.1.1.2602001"')) { throw new GradleException('Eclipse output contains unresolved or invalid Base Metals version metadata') } } diff --git a/gradle/release/artifacts.gradle b/gradle/release/artifacts.gradle index 7911fecab..11de2a215 100644 --- a/gradle/release/artifacts.gradle +++ b/gradle/release/artifacts.gradle @@ -9,7 +9,7 @@ tasks.withType(Jar).configureEach { filteringCharset = 'UTF-8' filesMatching(['**/*.java', '**/*.json', '**/*.lang', '**/*.mcmeta', '**/*.md', '**/*.txt', '**/*.cfg', '**/*.properties', '**/*.xml', '**/*.html', - '**/*.css', '**/*.js', '**/element-list', '**/package-list']) { + '**/*.css', '**/*.js', '**/*.svg', '**/element-list', '**/package-list']) { filter(FixCrLfFilter, eol: FixCrLfFilter.CrLf.newInstance('lf'), eof: FixCrLfFilter.AddAsisRemove.newInstance('asis')) } @@ -184,7 +184,7 @@ tasks.register('verifyMavenCoordinates') { tasks.register('verifyMavenizerCompatibilityFixture') { group = 'verification' - description = 'Verifies the checksum-sealed Forge 26.1.2 Mavenizer compatibility fixture.' + description = 'Verifies the checksum-sealed Forge 26.2 Mavenizer compatibility fixture.' inputs.file project.ext.mavenizerCompatibilityJar doLast { File fixture = project.ext.mavenizerCompatibilityJar.asFile @@ -198,23 +198,23 @@ tasks.register('verifyMavenizerCompatibilityFixture') { tasks.register('verifyReleaseConfiguration') { group = 'verification' - description = 'Verifies the exact Base Metals 26.1.2 release identity.' + description = 'Verifies the exact Base Metals 26.2 release identity.' dependsOn tasks.named('verifyMavenizerCompatibilityFixture') dependsOn tasks.named('verifyJava25Toolchain') doLast { - if (configuredReleaseIdentity.modVersion != '3.1.1.2601021' + if (configuredReleaseIdentity.modVersion != '3.1.1.2602001' || configuredReleaseIdentity.modGroup != expectedMavenGroup - || configuredReleaseIdentity.minecraftVersion != '26.1.2' - || configuredReleaseIdentity.forgeVersion != '64.0.9' - || configuredReleaseIdentity.forgeInstallerSha256 != '608BC9F028A0EF8DCD1A49C6EB85DDFCFA3B3BCD8AE27FC1B2AE02888ED8CB0A' + || configuredReleaseIdentity.minecraftVersion != '26.2' + || configuredReleaseIdentity.forgeVersion != '65.1.0' + || configuredReleaseIdentity.forgeInstallerSha256 != '813FBBFECC3086A492783B9F5023AE15007737B42E17AAB75F48BA77403314DF' || configuredReleaseIdentity.mappingChannel != 'official' - || configuredReleaseIdentity.mappingVersion != '26.1.2' + || configuredReleaseIdentity.mappingVersion != '26.2' || configuredReleaseIdentity.loaderName != 'forge' || configuredReleaseIdentity.loaderCode != '1' || configuredReleaseIdentity.javaVersion != '25' || configuredReleaseIdentity.gradleJavaVersion != '25' || configuredReleaseIdentity.curseForgeProjectId != '240967') { - throw new GradleException('Unexpected Base Metals 26.1.2 release identity') + throw new GradleException('Unexpected Base Metals 26.2 release identity') } } } @@ -223,10 +223,10 @@ tasks.register('verifyReleaseDependencies') { group = 'verification' description = 'Resolves and verifies the exact released OreSpawn qualification dependency.' doLast { - if (configuredOreSpawnIdentity.version != '4.1.0.2601021' + if (configuredOreSpawnIdentity.version != '4.1.0.2602001' || configuredOreSpawnIdentity.curseProjectId != '245586' - || configuredOreSpawnIdentity.curseFileId != '9299079' - || configuredOreSpawnIdentity.sha256 != '6D5CE2017C3314968083D140309E2F1A54BC239AC65C48944C995E9ECF937948') { + || configuredOreSpawnIdentity.curseFileId != '9332183' + || configuredOreSpawnIdentity.sha256 != 'F74785025898DF059E0F00F6ADA53364E07ECBBC306807ED7CD55350609E2547') { throw new GradleException('Unexpected OreSpawn release coordinates') } File artifact = configurations.orespawnRelease.resolvedConfiguration.resolvedArtifacts @@ -285,6 +285,12 @@ tasks.register('verifyReleaseArtifacts') { if (leaked != null) { throw new GradleException("${artifactName} contains validation, fixture, legacy, or agent-only path ${leaked.name}") } + + zip.entries().toList().findAll { it.name.endsWith('.svg') }.each { entry -> + if (zip.getInputStream(entry).getText('UTF-8').contains('\r')) { + throw new GradleException("${artifactName} contains non-LF SVG text: ${entry.name}") + } + } } } @@ -320,14 +326,14 @@ tasks.register('verifyReleaseArtifacts') { if (manifest.mainAttributes.getValue('Maven-Artifact') != expectedMavenCoordinate) { throw new GradleException('Release manifest contains the wrong Maven coordinate') } - String expectedBuildTarget = 'minecraft-26.1.2-forge-64.0.9-java-25' + String expectedBuildTarget = 'minecraft-26.2-forge-65.1.0-java-25' if (manifest.mainAttributes.getValue('Build-Target') != expectedBuildTarget) { throw new GradleException('Release manifest contains the wrong stable build target') } String modsToml = zip.getInputStream(zip.getEntry('META-INF/mods.toml')).getText('UTF-8') if (modsToml.contains('${') - || !modsToml.contains('version="3.1.1.2601021"') - || !modsToml.contains('versionRange="[4.1.0.2601021,5.0.0)"')) { + || !modsToml.contains('version="3.1.1.2602001"') + || !modsToml.contains('versionRange="[4.1.0.2602001,5.0.0)"')) { throw new GradleException('Release mods.toml contains unresolved or incompatible metadata') } def provider = new JsonSlurper().parse(zip.getInputStream( diff --git a/gradle/verification/packaged-runtime.gradle b/gradle/verification/packaged-runtime.gradle index 5e353283f..bce75d64b 100644 --- a/gradle/verification/packaged-runtime.gradle +++ b/gradle/verification/packaged-runtime.gradle @@ -134,8 +134,8 @@ def packagedServerStartupSmoke = tasks.register('packagedServerStartupSmoke', Ex doFirst { File runtime = requireRuntimeDirectory(packagedForgeServerRuntime, 'packagedForgeServerRuntime') File libraries = new File(runtime, 'libraries') - File forgeDirectory = new File(libraries, 'net/minecraftforge/forge/26.1.2-64.0.9') - File launcher = new File(forgeDirectory, 'forge-26.1.2-64.0.9-server.jar') + File forgeDirectory = new File(libraries, 'net/minecraftforge/forge/26.2-65.1.0') + File launcher = new File(forgeDirectory, 'forge-26.2-65.1.0-server.jar') File sourceArguments = new File(forgeDirectory, System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows') ? 'win_args.txt' : 'unix_args.txt') @@ -174,9 +174,9 @@ def packagedServerStartupSmoke = tasks.register('packagedServerStartupSmoke', Ex if (!marker.isFile()) throw new GradleException('Packaged dedicated-server completion marker is missing') Properties values = new Properties() marker.withInputStream { values.load(it) } - if (values.getProperty('basemetals') != '3.1.1.2601021' - || values.getProperty('orespawn') != '4.1.0.2601021' - || values.getProperty('forge') != '64.0.9') { + if (values.getProperty('basemetals') != '3.1.1.2602001' + || values.getProperty('orespawn') != '4.1.0.2602001' + || values.getProperty('forge') != '65.1.0') { throw new GradleException("Packaged dedicated-server versions are wrong: ${values}") } verifyPackagedLog(runDirectory, 'BASEMETALS_PACKAGED_SERVER_SMOKE PASS', @@ -219,11 +219,11 @@ def preparePackagedClientSmoke = tasks.register('preparePackagedClientSmoke') { File hostPack = new File(runDirectory, 'resourcepacks/basemetals-host-test') File texture = new File(hostPack, 'assets/minecraft/textures/block/stone.png') texture.parentFile.mkdirs() - new java.util.zip.ZipFile(new File(runtime, 'versions/26.1.2/26.1.2.jar')).withCloseable { zip -> + new java.util.zip.ZipFile(new File(runtime, 'versions/26.2/26.2.jar')).withCloseable { zip -> texture.bytes = zip.getInputStream(zip.getEntry('assets/minecraft/textures/block/dirt.png')).bytes } new File(hostPack, 'pack.mcmeta').setText( - '{"pack":{"min_format":[75,0],"max_format":[75,0],"description":"Ore host replacement test"}}\n', 'UTF-8') + '{"pack":{"min_format":[88,0],"max_format":[88,0],"description":"Ore host replacement test"}}\n', 'UTF-8') new File(runDirectory, 'options.txt').append( 'resourcePacks:["vanilla","mod_resources","file/basemetals-host-test"]\n', 'UTF-8') } @@ -243,13 +243,13 @@ def packagedClientStartupSmoke = tasks.register('packagedClientStartupSmoke', Ex dependsOn preparePackagedClientSmoke doFirst { File runtime = requireRuntimeDirectory(packagedForgeClientRuntime, 'packagedForgeClientRuntime') - String forgeVersionId = ['26.1.2-forge-64.0.9', 'forge-64.0.9'].find { candidate -> + String forgeVersionId = ['26.2-forge-65.1.0', 'forge-65.1.0'].find { candidate -> new File(runtime, "versions/${candidate}/${candidate}.json").isFile() } - if (forgeVersionId == null) throw new GradleException('Official client runtime has no Forge 64.0.9 profile') + if (forgeVersionId == null) throw new GradleException('Official client runtime has no Forge 65.1.0 profile') File forgeJsonFile = new File(runtime, "versions/${forgeVersionId}/${forgeVersionId}.json") - File baseJsonFile = new File(runtime, 'versions/26.1.2/26.1.2.json') - File baseJar = new File(runtime, 'versions/26.1.2/26.1.2.jar') + File baseJsonFile = new File(runtime, 'versions/26.2/26.2.json') + File baseJar = new File(runtime, 'versions/26.2/26.2.jar') File nativesDirectory = new File(runtime, "natives/${forgeVersionId}") [forgeJsonFile, baseJsonFile, baseJar, new File(runtime, 'libraries'), new File(runtime, 'assets'), nativesDirectory].each { diff --git a/src/dataGenerator/java/zone/moddev/mc/basemetals/data/GeneratedData.java b/src/dataGenerator/java/zone/moddev/mc/basemetals/data/GeneratedData.java index 7d1169432..c2a34ed48 100644 --- a/src/dataGenerator/java/zone/moddev/mc/basemetals/data/GeneratedData.java +++ b/src/dataGenerator/java/zone/moddev/mc/basemetals/data/GeneratedData.java @@ -1621,7 +1621,7 @@ private void writeManifest(CachedOutput cache) throws IOException { JsonObject root = new JsonObject(); root.addProperty("format", 1); - root.addProperty("source", "Base Metals 26.1.2 catalogue"); + root.addProperty("source", "Base Metals 26.2 catalogue"); root.add("blocks", array(blocks)); root.add("items", array(items)); root.add("fluids", array(ModContent.fluids().keySet().stream().flatMap(id -> diff --git a/src/gametest/java/zone/moddev/mc/basemetals/content/BaseMetalsGameTests.java b/src/gametest/java/zone/moddev/mc/basemetals/content/BaseMetalsGameTests.java index b2be9fd83..85c6df11f 100644 --- a/src/gametest/java/zone/moddev/mc/basemetals/content/BaseMetalsGameTests.java +++ b/src/gametest/java/zone/moddev/mc/basemetals/content/BaseMetalsGameTests.java @@ -38,7 +38,7 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; @@ -137,7 +137,7 @@ Direction.WEST, new AABB(15.0D / 16.0D, 0, 0, 1, 1, 1), public static void humanDetectorIgnoresNonPlayers(GameTestHelper helper) { HumanDetectorBlock detector = (HumanDetectorBlock) ModContent.HUMAN_DETECTOR.get(); BlockPos position = helper.absolutePos(new BlockPos(1, 1, 1)); - helper.spawnWithNoFreeWill(EntityType.COW, 1.5F, 1.0F, 1.5F); + helper.spawnWithNoFreeWill(EntityTypes.COW, 1.5F, 1.0F, 1.5F); require(helper, detector.getSignalStrength(helper.getLevel(), position) == 0, "Human detector responded to a non-player entity"); @@ -593,7 +593,7 @@ public static void customAnvilsWearWithoutChangingTheirSavedIdentity(GameTestHel @GameTest(structure = EMPTY) public static void smithsRetainTheLegacyMercuryIngotSale(GameTestHelper helper) { - var trader = EntityType.VILLAGER.create(helper.getLevel(), net.minecraft.world.entity.EntitySpawnReason.COMMAND); + var trader = EntityTypes.VILLAGER.create(helper.getLevel(), net.minecraft.world.entity.EntitySpawnReason.COMMAND); var parameters = new net.minecraft.world.level.storage.loot.LootParams.Builder(helper.getLevel()) .withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.ORIGIN, trader.position()) .withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.THIS_ENTITY, trader) @@ -808,7 +808,7 @@ public static void armorToolEffectsAndStarsteelRegenerationAreServerAuthoritativ require(helper, armor.getDamageValue() == 5, "Starsteel armor regenerated despite the armor exclusion"); - LivingEntity target = helper.spawnWithNoFreeWill(EntityType.IRON_GOLEM, 2.0F, 1.0F, 2.0F); + LivingEntity target = helper.spawnWithNoFreeWill(EntityTypes.IRON_GOLEM, 2.0F, 1.0F, 2.0F); player.setItemInHand(InteractionHand.MAIN_HAND, ModContent.item("adamantine_sword").get().getDefaultInstance()); LivingHurtEvent hurt = new LivingHurtEvent(target, player.damageSources().playerAttack(player), 3.0F); @@ -863,7 +863,7 @@ public static void remainingLegacyMeleeEffectsUseTargetIdentity(GameTestHelper h BaseMetalsEvents events = new BaseMetalsEvents(); ServerPlayer player = survivalPlayer(helper); - LivingEntity aquatic = helper.spawnWithNoFreeWill(EntityType.COD, 2.0F, 1.0F, 2.0F); + LivingEntity aquatic = helper.spawnWithNoFreeWill(EntityTypes.COD, 2.0F, 1.0F, 2.0F); player.setItemInHand(InteractionHand.MAIN_HAND, ModContent.item("aquarium_sword").get().getDefaultInstance()); LivingHurtEvent aquariumHit = new LivingHurtEvent(aquatic, player.damageSources().playerAttack(player), 3.0F); @@ -871,7 +871,7 @@ public static void remainingLegacyMeleeEffectsUseTargetIdentity(GameTestHelper h require(helper, aquariumHit.getAmount() == 7.0F, "Aquarium melee bonus did not use the target's water-breathing identity"); - LivingEntity blaze = helper.spawnWithNoFreeWill(EntityType.BLAZE, 3.0F, 1.0F, 2.0F); + LivingEntity blaze = helper.spawnWithNoFreeWill(EntityTypes.BLAZE, 3.0F, 1.0F, 2.0F); player.setItemInHand(InteractionHand.MAIN_HAND, ModContent.item("coldiron_sword").get().getDefaultInstance()); LivingHurtEvent coldIronHit = new LivingHurtEvent(blaze, player.damageSources().playerAttack(player), 3.0F); @@ -879,7 +879,7 @@ public static void remainingLegacyMeleeEffectsUseTargetIdentity(GameTestHelper h require(helper, coldIronHit.getAmount() == 6.0F, "Cold Iron melee bonus did not use the target's fire immunity"); - LivingEntity undead = helper.spawnWithNoFreeWill(EntityType.ZOMBIE, 4.0F, 1.0F, 2.0F); + LivingEntity undead = helper.spawnWithNoFreeWill(EntityTypes.ZOMBIE, 4.0F, 1.0F, 2.0F); player.setItemInHand(InteractionHand.MAIN_HAND, ModContent.item("mithril_sword").get().getDefaultInstance()); LivingHurtEvent mithrilHit = new LivingHurtEvent(undead, player.damageSources().playerAttack(player), 3.0F); @@ -1122,7 +1122,7 @@ public static void fullyDrawnWeaponsApplyMaterialDamageBeforePower(GameTestHelpe MaterialProjectile projectile = projectiles.getFirst(); require(helper, projectile.isOnFire() == (power > 0), launcher + " did not apply Flame at launch"); - var target = EntityType.ZOMBIE.create(helper.getLevel(), net.minecraft.world.entity.EntitySpawnReason.COMMAND); + var target = EntityTypes.ZOMBIE.create(helper.getLevel(), net.minecraft.world.entity.EntitySpawnReason.COMMAND); double damage = EnchantmentHelper.modifyDamage(helper.getLevel(), projectile.getWeaponItem(), target, helper.getLevel().damageSources().arrow(projectile, player), (float) baseDamage); var vanilla = ((net.minecraft.world.item.ArrowItem) Items.ARROW) diff --git a/src/gametest/java/zone/moddev/mc/basemetals/content/ForwardPortGameTests.java b/src/gametest/java/zone/moddev/mc/basemetals/content/ForwardPortGameTests.java index c1f0ff169..46a95d018 100644 --- a/src/gametest/java/zone/moddev/mc/basemetals/content/ForwardPortGameTests.java +++ b/src/gametest/java/zone/moddev/mc/basemetals/content/ForwardPortGameTests.java @@ -136,7 +136,7 @@ public static void vanillaCopperKeepsExistingRecipeChainsUsable(GameTestHelper h "Copper plate crafting rejected a supported ingot"); } - for (var entry : java.util.Map.of(Items.COPPER_TRAPDOOR, 3, + for (var entry : java.util.Map.of(Items.COPPER_TRAPDOOR.weathering().unaffected(), 3, ModContent.item("copper_trapdoor").get(), 4).entrySet()) { var input = new SingleRecipeInput(entry.getKey().getDefaultInstance()); ItemStack recycled = level.getServer().getRecipeManager().getRecipeFor(RecipeType.SMELTING, diff --git a/src/gametest/java/zone/moddev/mc/basemetals/content/NativeComponentGameTests.java b/src/gametest/java/zone/moddev/mc/basemetals/content/NativeComponentGameTests.java index 520d72eee..3193a88bf 100644 --- a/src/gametest/java/zone/moddev/mc/basemetals/content/NativeComponentGameTests.java +++ b/src/gametest/java/zone/moddev/mc/basemetals/content/NativeComponentGameTests.java @@ -9,7 +9,7 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.StringTag; import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.crafting.Recipe; @@ -197,8 +197,8 @@ public static void oldEmbeddedBoltsKeepTheirCustomItemData(GameTestHelper helper public static void projectilesKeepWeaponEnchantmentsAfterReload(GameTestHelper helper) { var level = helper.getLevel(); var enchantments = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); - var shooter = EntityType.ZOMBIE.create(level, net.minecraft.world.entity.EntitySpawnReason.COMMAND); - var target = EntityType.ZOMBIE.create(level, net.minecraft.world.entity.EntitySpawnReason.COMMAND); + var shooter = EntityTypes.ZOMBIE.create(level, net.minecraft.world.entity.EntitySpawnReason.COMMAND); + var target = EntityTypes.ZOMBIE.create(level, net.minecraft.world.entity.EntitySpawnReason.COMMAND); for (boolean bolt : new boolean[] {false, true}) { ItemStack weapon = ModContent.item("steel_" + (bolt ? "crossbow" : "bow")).get().getDefaultInstance(); diff --git a/src/generated/resources/data/basemetals/registry_manifest.json b/src/generated/resources/data/basemetals/registry_manifest.json index 525ccb8da..618609d91 100644 --- a/src/generated/resources/data/basemetals/registry_manifest.json +++ b/src/generated/resources/data/basemetals/registry_manifest.json @@ -1735,5 +1735,5 @@ "basemetals:wood", "basemetals:stone" ], - "source": "Base Metals 26.1.2 catalogue" + "source": "Base Metals 26.2 catalogue" } \ No newline at end of file diff --git a/src/integratedSmoke/java/zone/moddev/mc/basemetals/smoke/ConfigScreenSmoke.java b/src/integratedSmoke/java/zone/moddev/mc/basemetals/smoke/ConfigScreenSmoke.java index d30e35aa0..9f2b0e20a 100644 --- a/src/integratedSmoke/java/zone/moddev/mc/basemetals/smoke/ConfigScreenSmoke.java +++ b/src/integratedSmoke/java/zone/moddev/mc/basemetals/smoke/ConfigScreenSmoke.java @@ -38,7 +38,7 @@ private static void verifyOnce(Minecraft minecraft, Screen parent) { String originalMode = BaseMetalsConfig.CONTENT_MODE.get(); boolean originalEffects = BaseMetalsConfig.SPECIAL_EFFECTS.get(); ContentMode activeMode = BaseMetalsConfig.activeMode(); - minecraft.setScreen(screen); + minecraft.gui.setScreen(screen); require(buttons(screen).size() == 9, "Expected the mode, four switches and four action buttons"); String initialLabel = buttons(screen).get(0).getMessage().getString(); buttons(screen).get(0).onPress(new net.minecraft.client.input.KeyEvent(257, 0, 0)); @@ -49,23 +49,23 @@ private static void verifyOnce(Minecraft minecraft, Screen parent) { require(buttons(screen).get(0).getMessage().getString().contains(I18n.get(ContentMode.HIGH_FANTASY.translationKey())), "Defaults must select High Fantasy"); screen.onClose(); - require(minecraft.screen == parent, "Cancel did not return to the parent screen"); + require(minecraft.gui.screen() == parent, "Cancel did not return to the parent screen"); require(originalMode.equals(BaseMetalsConfig.CONTENT_MODE.get()), "Cancel saved pending edits"); screen = extensions.get(0).createScreen(parent); - minecraft.setScreen(screen); + minecraft.gui.setScreen(screen); buttons(screen).get(1).onPress(new net.minecraft.client.input.KeyEvent(257, 0, 0)); button(screen, "gui.done").onPress(new net.minecraft.client.input.KeyEvent(257, 0, 0)); - require(minecraft.screen == parent, "Done did not return to the parent screen"); + require(minecraft.gui.screen() == parent, "Done did not return to the parent screen"); require(BaseMetalsConfig.SPECIAL_EFFECTS.get() != originalEffects, "Done did not save a boolean edit"); screen = extensions.get(0).createScreen(parent); - minecraft.setScreen(screen); + minecraft.gui.setScreen(screen); buttons(screen).get(0).onPress(new net.minecraft.client.input.KeyEvent(257, 0, 0)); button(screen, "gui.done").onPress(new net.minecraft.client.input.KeyEvent(257, 0, 0)); - require(minecraft.screen instanceof ConfirmScreen, "A mode change needs restart confirmation"); - button(minecraft.screen, "gui.yes").onPress(new net.minecraft.client.input.KeyEvent(257, 0, 0)); - require(minecraft.screen == parent, "Confirmation did not return to the parent screen"); + require(minecraft.gui.screen() instanceof ConfirmScreen, "A mode change needs restart confirmation"); + button(minecraft.gui.screen(), "gui.yes").onPress(new net.minecraft.client.input.KeyEvent(257, 0, 0)); + require(minecraft.gui.screen() == parent, "Confirmation did not return to the parent screen"); require(!originalMode.equals(BaseMetalsConfig.CONTENT_MODE.get()), "Done did not save the mode edit"); require(BaseMetalsConfig.activeMode() == activeMode, "A GUI edit changed the running content mode"); diff --git a/src/integratedSmoke/java/zone/moddev/mc/basemetals/smoke/IntegratedWorldSmoke.java b/src/integratedSmoke/java/zone/moddev/mc/basemetals/smoke/IntegratedWorldSmoke.java index a5f767f4f..71c1e82e6 100644 --- a/src/integratedSmoke/java/zone/moddev/mc/basemetals/smoke/IntegratedWorldSmoke.java +++ b/src/integratedSmoke/java/zone/moddev/mc/basemetals/smoke/IntegratedWorldSmoke.java @@ -77,8 +77,8 @@ public static void onClientTick(TickEvent.ClientTickEvent.Post event) { Minecraft minecraft = Minecraft.getInstance(); minecraft.options.pauseOnLostFocus = false; - if (minecraft.screen instanceof net.minecraft.client.gui.screens.AccessibilityOnboardingScreen) { - minecraft.screen.onClose(); + if (minecraft.gui.screen() instanceof net.minecraft.client.gui.screens.AccessibilityOnboardingScreen) { + minecraft.gui.screen().onClose(); return; } elapsedTicks++; @@ -95,17 +95,17 @@ public static void onClientTick(TickEvent.ClientTickEvent.Post event) { BaseMetals.LOGGER.info("BASEMETALS_CLIENT_PROFILE PASS mods={}", actual); } } - if (!renderLayersChecked && minecraft.screen instanceof TitleScreen) { + if (!renderLayersChecked && minecraft.gui.screen() instanceof TitleScreen) { verifyBlockRenderLayers(minecraft); renderLayersChecked = true; } if (!creationStarted && elapsedTicks % 200 == 0) { BaseMetals.LOGGER.info("BASEMETALS_INTEGRATED_SMOKE waiting for title screen current={} overlay={}", - minecraft.screen == null ? "none" : minecraft.screen.getClass().getName(), - minecraft.getOverlay() == null ? "none" : minecraft.getOverlay().getClass().getName()); + minecraft.gui.screen() == null ? "none" : minecraft.gui.screen().getClass().getName(), + minecraft.gui.overlay() == null ? "none" : minecraft.gui.overlay().getClass().getName()); } - if (!creationStarted && minecraft.screen instanceof TitleScreen && minecraft.getOverlay() == null) { - ConfigScreenSmoke.verify(minecraft, minecraft.screen); + if (!creationStarted && minecraft.gui.screen() instanceof TitleScreen && minecraft.gui.overlay() == null) { + ConfigScreenSmoke.verify(minecraft, minecraft.gui.screen()); verifyOreOverlayModels(minecraft); verifyBarsModels(minecraft); creationStarted = true; @@ -126,23 +126,23 @@ public static void onClientTick(TickEvent.ClientTickEvent.Post event) { BaseMetals.LOGGER.info("BASEMETALS_INTEGRATED_SMOKE creating world={}", worldName); minecraft.createWorldOpenFlows().createFreshLevel(worldName, levelSettings, new net.minecraft.world.level.levelgen.WorldOptions(0L, true, false), - net.minecraft.world.level.levelgen.presets.WorldPresets::createNormalWorldDimensions, minecraft.screen); + net.minecraft.world.level.levelgen.presets.WorldPresets::createNormalWorldDimensions, minecraft.gui.screen()); } - if (creationStarted && minecraft.screen instanceof net.minecraft.client.gui.screens.ConfirmScreen) { - String title = minecraft.screen.getTitle().getString(); + if (creationStarted && minecraft.gui.screen() instanceof net.minecraft.client.gui.screens.ConfirmScreen) { + String title = minecraft.gui.screen().getTitle().getString(); boolean finishedUpgrade = Boolean.getBoolean("basemetals.integratedExistingWorldSmoke") && title.equals(net.minecraft.client.resources.language.I18n.get("upgradeWorld.done")); if (!finishedUpgrade && !title.toLowerCase(java.util.Locale.ROOT).contains("experimental")) { throw new IllegalStateException("Unexpected confirmation in the disposable world: " + title); } // Forge marks modded registries experimental. This applies only to the new smoke-test world. - minecraft.screen.children().stream().filter(net.minecraft.client.gui.components.Button.class::isInstance) + minecraft.gui.screen().children().stream().filter(net.minecraft.client.gui.components.Button.class::isInstance) .map(net.minecraft.client.gui.components.Button.class::cast).findFirst().orElseThrow().onPress(new net.minecraft.client.input.KeyEvent(257, 0, 0)); } if (creationStarted && Boolean.getBoolean("basemetals.integratedExistingWorldSmoke") - && minecraft.screen instanceof net.minecraft.client.gui.screens.BackupConfirmScreen backup) { + && minecraft.gui.screen() instanceof net.minecraft.client.gui.screens.BackupConfirmScreen backup) { backup.children().stream().filter(net.minecraft.client.gui.components.Button.class::isInstance) .map(net.minecraft.client.gui.components.Button.class::cast) .filter(button -> button.getMessage().getString().equals( diff --git a/src/main/java/zone/moddev/mc/basemetals/BaseMetalsAdvancements.java b/src/main/java/zone/moddev/mc/basemetals/BaseMetalsAdvancements.java index 9f739e64f..ce4fd588e 100644 --- a/src/main/java/zone/moddev/mc/basemetals/BaseMetalsAdvancements.java +++ b/src/main/java/zone/moddev/mc/basemetals/BaseMetalsAdvancements.java @@ -70,7 +70,8 @@ static void onSmelted(ServerPlayer player, ItemStack result) { static void onPlaced(ServerPlayer player, BlockState state) { Identifier id = ForgeRegistries.BLOCKS.getKey(state.getBlock()); if (id != null && (id.getNamespace().equals(BaseMetals.MOD_ID) - || state.is(net.minecraft.world.level.block.Blocks.COPPER_BLOCK)) && state.is(STORAGE_BLOCKS)) { + || state.is(net.minecraft.world.level.block.Blocks.COPPER_BLOCK.weathering().unaffected())) + && state.is(STORAGE_BLOCKS)) { award(player, "blocktastic"); } } diff --git a/src/main/java/zone/moddev/mc/basemetals/client/BaseMetalsConfigScreen.java b/src/main/java/zone/moddev/mc/basemetals/client/BaseMetalsConfigScreen.java index b831d5826..1bcf1adc4 100644 --- a/src/main/java/zone/moddev/mc/basemetals/client/BaseMetalsConfigScreen.java +++ b/src/main/java/zone/moddev/mc/basemetals/client/BaseMetalsConfigScreen.java @@ -91,7 +91,7 @@ private void initLabels() { private void done() { if (edits.modeChanged()) { - minecraft.setScreen(new ConfirmScreen(this::confirmResult, + minecraft.gui.setScreen(new ConfirmScreen(this::confirmResult, Component.translatable(PREFIX + "confirm.title"), Component.translatable(PREFIX + "confirm.message"))); } else { @@ -103,7 +103,7 @@ private void confirmResult(boolean accepted) { if (accepted) { saveAndClose(); } else { - minecraft.setScreen(this); + minecraft.gui.setScreen(this); } } @@ -117,7 +117,7 @@ private void saveAndClose() { @Override public void onClose() { - minecraft.setScreen(parent); + minecraft.gui.setScreen(parent); } @Override diff --git a/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalBucketItem.java b/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalBucketItem.java index de1586253..427693940 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalBucketItem.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalBucketItem.java @@ -5,7 +5,7 @@ import javax.annotation.Nullable; -import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.advancements.triggers.CriteriaTriggers; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerPlayer; diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 9f63f5a3f..1b932ddd2 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -14,7 +14,7 @@ description='''${mod_description}''' [[dependencies.${mod_id}]] modId="orespawn" mandatory=true -versionRange="[4.1.0.2601021,5.0.0)" +versionRange="[4.1.0.2602001,5.0.0)" ordering="AFTER" side="BOTH" diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index ac441d481..9ea2b4f5f 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,7 +1,7 @@ { "pack": { "description": "${mod_id} resources", - "min_format": [101, 1], - "max_format": [101, 1] + "min_format": [107, 1], + "max_format": [107, 1] } } diff --git a/src/packagedClientSmoke/java/zone/moddev/mc/basemetals/smoke/RemoteLoginSmoke.java b/src/packagedClientSmoke/java/zone/moddev/mc/basemetals/smoke/RemoteLoginSmoke.java index f7d52008b..ca4c4cd5d 100644 --- a/src/packagedClientSmoke/java/zone/moddev/mc/basemetals/smoke/RemoteLoginSmoke.java +++ b/src/packagedClientSmoke/java/zone/moddev/mc/basemetals/smoke/RemoteLoginSmoke.java @@ -28,15 +28,15 @@ public static void tick(TickEvent.ClientTickEvent.Post event) { if (completed || !Boolean.getBoolean("basemetals.remoteLoginSmoke")) return; Minecraft minecraft = Minecraft.getInstance(); if (++ticks > 3600) throw new IllegalStateException("MODE_LOGIN_SMOKE FAIL: timed out at " - + (minecraft.screen == null ? "gameplay" : minecraft.screen.getClass().getName())); + + (minecraft.gui.screen() == null ? "gameplay" : minecraft.gui.screen().getClass().getName())); boolean reject = Boolean.getBoolean("basemetals.expectModeReject"); - if (!connecting && minecraft.screen instanceof TitleScreen) { + if (!connecting && minecraft.gui.screen() instanceof TitleScreen) { // Wait until the loading overlay is gone, as a player would have to. - if (minecraft.getOverlay() != null || ++titleTicks < 20) return; + if (minecraft.gui.overlay() != null || ++titleTicks < 20) return; connecting = true; String address = System.getProperty("basemetals.remoteAddress"); - ConnectScreen.startConnecting(minecraft.screen, minecraft, ServerAddress.parseString(address), + ConnectScreen.startConnecting(minecraft.gui.screen(), minecraft, ServerAddress.parseString(address), new net.minecraft.client.multiplayer.ServerData("Base Metals smoke", address, net.minecraft.client.multiplayer.ServerData.Type.OTHER), false, null); } @@ -57,7 +57,7 @@ public static void tick(TickEvent.ClientTickEvent.Post event) { } else { finish(minecraft, "connected"); } - } else if (minecraft.screen instanceof DisconnectedScreen disconnected) { + } else if (minecraft.gui.screen() instanceof DisconnectedScreen disconnected) { String reason = disconnected.getNarrationMessage().getString(); if (!reject || !reason.contains("Base Metals") diff --git a/src/packagedClientSmoke/packaged-resources/META-INF/mods.toml b/src/packagedClientSmoke/packaged-resources/META-INF/mods.toml index 53cfb688c..6ad3ab50d 100644 --- a/src/packagedClientSmoke/packaged-resources/META-INF/mods.toml +++ b/src/packagedClientSmoke/packaged-resources/META-INF/mods.toml @@ -10,13 +10,13 @@ displayName="Base Metals packaged client smoke" [[dependencies.basemetals_client_smoke]] modId="basemetals" mandatory=true -versionRange="[3.1.1.2601021]" +versionRange="[3.1.1.2602001]" ordering="AFTER" side="CLIENT" [[dependencies.basemetals_client_smoke]] modId="orespawn" mandatory=true -versionRange="[4.1.0.2601021]" +versionRange="[4.1.0.2602001]" ordering="AFTER" side="CLIENT" diff --git a/src/packagedServerSmoke/java/zone/moddev/mc/basemetals/smoke/PackagedServerSmoke.java b/src/packagedServerSmoke/java/zone/moddev/mc/basemetals/smoke/PackagedServerSmoke.java index 4da0534b4..cb5cdfff3 100644 --- a/src/packagedServerSmoke/java/zone/moddev/mc/basemetals/smoke/PackagedServerSmoke.java +++ b/src/packagedServerSmoke/java/zone/moddev/mc/basemetals/smoke/PackagedServerSmoke.java @@ -40,7 +40,7 @@ public PackagedServerSmoke() { public void onServerStarted(ServerStartedEvent event) { String baseMetals = version("basemetals"); String oreSpawn = version("orespawn"); - if (!"3.1.1.2601021".equals(baseMetals) || !"4.1.0.2601021".equals(oreSpawn)) { + if (!"3.1.1.2602001".equals(baseMetals) || !"4.1.0.2602001".equals(oreSpawn)) { throw new IllegalStateException("PACKAGED_SERVER_SMOKE FAIL versions basemetals=" + baseMetals + " orespawn=" + oreSpawn); } @@ -176,7 +176,7 @@ private static void verifyOreSample(net.minecraft.server.MinecraftServer server) } private static void verifyTinkers() { - throw new IllegalStateException("Tinkers integration is not enabled in this Forge 26.1.2 build"); + throw new IllegalStateException("Tinkers integration is not enabled in this Forge 26.2 build"); } private static void verifyModernFlatTerrain(net.minecraft.server.MinecraftServer server) { diff --git a/src/packagedServerSmoke/packaged-resources/META-INF/mods.toml b/src/packagedServerSmoke/packaged-resources/META-INF/mods.toml index 15f050e2b..898db2c93 100644 --- a/src/packagedServerSmoke/packaged-resources/META-INF/mods.toml +++ b/src/packagedServerSmoke/packaged-resources/META-INF/mods.toml @@ -10,13 +10,13 @@ displayName="Base Metals packaged server smoke" [[dependencies.basemetals_server_smoke]] modId="basemetals" mandatory=true -versionRange="[3.1.1.2601021]" +versionRange="[3.1.1.2602001]" ordering="AFTER" side="SERVER" [[dependencies.basemetals_server_smoke]] modId="orespawn" mandatory=true -versionRange="[4.1.0.2601021]" +versionRange="[4.1.0.2602001]" ordering="AFTER" side="SERVER" diff --git a/src/smoke/datapack/pack.mcmeta b/src/smoke/datapack/pack.mcmeta index ddd71fd27..0b61bc891 100644 --- a/src/smoke/datapack/pack.mcmeta +++ b/src/smoke/datapack/pack.mcmeta @@ -1,7 +1,7 @@ { "pack": { - "min_format": [101, 1], - "max_format": [101, 1], + "min_format": [107, 1], + "max_format": [107, 1], "description": "Base Metals custom ordinary dimension smoke fixture" } } diff --git a/src/test/java/zone/moddev/mc/basemetals/data/Minecraft1211ResourceTest.java b/src/test/java/zone/moddev/mc/basemetals/data/Minecraft1211ResourceTest.java index 52c3bc462..95c17fc82 100644 --- a/src/test/java/zone/moddev/mc/basemetals/data/Minecraft1211ResourceTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/data/Minecraft1211ResourceTest.java @@ -14,14 +14,14 @@ class Minecraft1211ResourceTest { @Test - void resourceAndDataPacksUseThe2612Formats() throws Exception { + void resourceAndDataPacksUseThe262Formats() throws Exception { var pack = read("src/main/resources/pack.mcmeta").getAsJsonObject("pack"); - assertEquals("[101,1]", pack.get("min_format").toString()); - assertEquals("[101,1]", pack.get("max_format").toString()); + assertEquals("[107,1]", pack.get("min_format").toString()); + assertEquals("[107,1]", pack.get("max_format").toString()); net.minecraft.SharedConstants.tryDetectVersion(); var resources = net.minecraft.SharedConstants.getCurrentVersion() .packVersion(net.minecraft.server.packs.PackType.CLIENT_RESOURCES); - assertEquals(84, resources.major()); + assertEquals(88, resources.major()); assertEquals(0, resources.minor()); } diff --git a/src/test/java/zone/moddev/mc/basemetals/migration/LegacyMigrationSafetyTest.java b/src/test/java/zone/moddev/mc/basemetals/migration/LegacyMigrationSafetyTest.java index b9cf34baf..402af8953 100644 --- a/src/test/java/zone/moddev/mc/basemetals/migration/LegacyMigrationSafetyTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/migration/LegacyMigrationSafetyTest.java @@ -100,7 +100,7 @@ void modernExternalChunk() throws Exception { @Test void modernLz4Chunk() throws Exception { - assumeTrue(VERSION.equals("1.20.6") || VERSION.equals("1.21.11") || VERSION.equals("26.1.2"), "Native LZ4 is not available on older targets"); + assumeTrue(VERSION.equals("1.20.6") || VERSION.equals("1.21.11") || VERSION.equals("26.2"), "Native LZ4 is not available on older targets"); Path world = world("lz4", false); Path file = region(world, false, true); assertTrue(nativeAccepts(file, false)); @@ -177,7 +177,7 @@ void savedRegistryCanBeScannedWithAnEmptyRegion() throws Exception { @Test void savedRegistryCanBeScannedWithLz4Chunks() throws Exception { - assumeTrue(VERSION.equals("1.20.6") || VERSION.equals("1.21.11") || VERSION.equals("26.1.2")); + assumeTrue(VERSION.equals("1.20.6") || VERSION.equals("1.21.11") || VERSION.equals("26.2")); Path world = world("saved-registry-lz4", false); writeRegistry(world.resolve("basemetals-legacy-registry.dat")); Path file = region(world, false, true); diff --git a/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldStorageTest.java b/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldStorageTest.java index da6540b23..dbda7d46d 100644 --- a/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldStorageTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldStorageTest.java @@ -53,6 +53,21 @@ void modernWorldNeverImportsALeftoverLegacyCapabilityFile() throws Exception { assertFalse(Files.exists(world.resolve("basemetals-legacy-registry.dat"))); } + @Test + void firstNativeStorageVersionDoesNotImportStaleFiles() throws Exception { + embeddedPlayer(42); + CompoundTag root = LegacyNbt.readCompressed(world.resolve("level.dat").toFile()); + root.getCompoundOrEmpty("Data").putInt("DataVersion", 4772); + LegacyNbt.writeCompressed(root, world.resolve("level.dat").toFile()); + capability("data/capabilities.dat", 1); + + prepare(); + + assertFalse(Files.exists(world.resolve("playerdata"))); + assertFalse(Files.exists(world.resolve("dimensions/minecraft/overworld/data/forge/capabilities.dat"))); + assertFalse(Files.exists(world.resolve("basemetals-legacy-registry.dat"))); + } + @Test void metadataWithoutAPositiveVersionDoesNotActivateStorageMigration() throws Exception { try (var output = Files.newOutputStream(world.resolve("level.dat"))) { diff --git a/tools/validation/README.md b/tools/validation/README.md index 08ac0de0b..749f15b7e 100644 --- a/tools/validation/README.md +++ b/tools/validation/README.md @@ -1,11 +1,11 @@ # World upgrade checks -`test_legacy_worlds.js` starts the packaged Forge 26.1.2 server against a fresh +`test_legacy_worlds.js` starts the packaged Forge 26.2 server against a fresh copy of each supplied world, then starts it again to check the saved result. It refuses to overwrite an existing test directory and fingerprints every source world before and after the test. -An optional `forgeVersion` selects another installed Forge 26.1.2 build for -compatibility checks; the default is the compilation target, `64.0.9`. +An optional `forgeVersion` selects another installed Forge 26.2 build for +compatibility checks; the default is the compilation target, `65.1.0`. Pass a local JSON specification containing `java` (the Java 25 executable), `serverRuntime`, `output`, `modJar`, `probeJar`, `oreSpawn` (a `path` and `sha256`), and a `profiles` list. @@ -25,6 +25,11 @@ The log check accepts known vanilla registry changes, including paintings moved to data files. Unknown or modded entries still fail the test. Check that boundary with `node --test tools/validation/test_painting_registry.js`. +On Windows, the exact missing-Perflib-counter diagnostic from Minecraft's system +probe is reported separately. It is not accepted on Linux, from another logger +or as a fatal error. Run `node --test tools/validation/test_runtime_log.js` to +check those limits; other runtime errors still fail the suite. + `compare_world_terrain.py` checks fixed vanilla terrain before and after conversion. It accepts Minecraft's new underground floor and accounts for normal falling sand and gravel, but rejects ore replacing existing rock. diff --git a/tools/validation/runtime_log.js b/tools/validation/runtime_log.js new file mode 100644 index 000000000..ef905e64f --- /dev/null +++ b/tools/validation/runtime_log.js @@ -0,0 +1,9 @@ +'use strict'; + +// Minecraft's system probe may report missing Windows performance-counter names. +function isWindowsCounterDiagnostic(line, platform = process.platform) { + return platform === 'win32' + && /\/ERROR\] \[(?:oshi\.driver\.windows\.registry\.HkeyPerformanceDataUtil|os\.dr\.wi\.re\.HkeyPerformanceDataUtil)\/\]: Unable to locate English counter names in registry Perflib 009\. Counters may need to be rebuilt: $/.test(line); +} + +module.exports = { isWindowsCounterDiagnostic }; diff --git a/tools/validation/test_content_modes.js b/tools/validation/test_content_modes.js index de7a83816..b9b4de559 100644 --- a/tools/validation/test_content_modes.js +++ b/tools/validation/test_content_modes.js @@ -94,7 +94,7 @@ function verifyConfig(directory, initial) { (async () => { const results = []; - const client = clientLaunch(spec.clientRuntime, '26.1.2', '64.0.9'); + const client = clientLaunch(spec.clientRuntime, '26.2', '65.1.0'); const selected = spec.cases ? cases.filter(([name]) => spec.cases.includes(name)) : cases; if (!selected.length || (spec.cases && selected.length !== spec.cases.length)) { throw new Error('The requested mode-test case is unknown or duplicated.'); @@ -114,14 +114,14 @@ function verifyConfig(directory, initial) { + 'generator-settings={"layers":[{"block":"minecraft:bedrock","height":1},{"block":"minecraft:dirt","height":2},{"block":"minecraft:grass_block","height":1}],"biome":"minecraft:plains"}\n' + 'generate-structures=false\nmax-tick-time=-1\n'); const server = launch(serverDir, ['-Xms256m', '-Xmx2g', '-Dbasemetals.awaitLoginSmoke=true', - ...serverArguments(spec.serverRuntime, serverDir, '26.1.2', '64.0.9')], 'server.log'); + ...serverArguments(spec.serverRuntime, serverDir, '26.2', '65.1.0')], 'server.log'); let player; try { await waitFor(server, 'BASEMETALS_PACKAGED_SERVER_SMOKE PASS', 240000); player = launch(clientDir, ['-Xms512m', '-Xmx2g', '-Dbasemetals.remoteLoginSmoke=true', `-Dbasemetals.remoteAddress=127.0.0.1:${port}`, `-Dbasemetals.loginSmokeConnections=${reject ? 1 : 3}`, `-Dbasemetals.expectModeReject=${!!reject}`, ...client.args, ...client.metadata.arguments.game, - '--username', 'BMValidation', '--version', '26.1.2', '--gameDir', clientDir, + '--username', 'BMValidation', '--version', '26.2', '--gameDir', clientDir, '--assetsDir', path.join(spec.clientRuntime, 'assets'), '--assetIndex', client.vanilla.assetIndex.id, '--uuid', '00000000000000000000000000000118', '--accessToken', '0', '--userType', 'legacy'], 'client.log'); await waitFor(player, 'BASEMETALS_MODE_LOGIN_CLIENT PASS result=' + (reject ? 'rejected' : 'connected'), 240000); diff --git a/tools/validation/test_legacy_worlds.js b/tools/validation/test_legacy_worlds.js index 865dbb581..fea11afc0 100644 --- a/tools/validation/test_legacy_worlds.js +++ b/tools/validation/test_legacy_worlds.js @@ -5,6 +5,7 @@ const crypto = require('crypto'); const { spawn } = require('child_process'); const { serverArguments } = require('./forge_launcher'); const { isVanillaPaintingSnapshot } = require('./painting_registry'); +const { isWindowsCounterDiagnostic } = require('./runtime_log'); const spec = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')); const phase = process.argv[3] || 'upgrade'; @@ -109,6 +110,11 @@ function checkUpgradeLog(log) { const line = lines[index]; if (!/\/(?:ERROR|FATAL)\]/.test(line)) continue; + if (isWindowsCounterDiagnostic(line)) { + console.warn('Known Windows host diagnostic: ' + line); + continue; + } + if (phase === 'upgrade' && line.includes('Unidentified mapping from registry minecraft:')) { const entries = []; for (let next = index + 1; next < lines.length && lines[next].trim(); next++) { @@ -148,7 +154,7 @@ async function run(directory, launcher, label, marker, properties = []) { const output = fs.createWriteStream(path.join(directory, label + '.log')); const executable = phase === 'capture' ? spec.java8 : (spec.java || spec.java17); const launchArguments = phase === 'capture' ? ['-jar', launcher, 'nogui'] - : serverArguments(spec.serverRuntime, directory, '26.1.2', spec.forgeVersion || '64.0.9'); + : serverArguments(spec.serverRuntime, directory, '26.2', spec.forgeVersion || '65.1.0'); const child = spawn(executable, ['-Xms256m', '-Xmx2g', ...properties, ...launchArguments], { cwd: directory, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] }); child.stdout.pipe(output, { end: false }); diff --git a/tools/validation/test_runtime_log.js b/tools/validation/test_runtime_log.js new file mode 100644 index 000000000..b3240409e --- /dev/null +++ b/tools/validation/test_runtime_log.js @@ -0,0 +1,26 @@ +'use strict'; + +const test = require('node:test'); +const assert = require('node:assert/strict'); +const { isWindowsCounterDiagnostic } = require('./runtime_log'); + +const detail = 'Unable to locate English counter names in registry Perflib 009. Counters may need to be rebuilt: '; +const line = '[15:03:33] [main/ERROR] [oshi.driver.windows.registry.HkeyPerformanceDataUtil/]: ' + detail; + +test('recognises the exact Windows counter diagnostic in both logger formats', () => { + assert.equal(isWindowsCounterDiagnostic(line, 'win32'), true); + assert.equal(isWindowsCounterDiagnostic(line.replace('oshi.driver.windows.registry', 'os.dr.wi.re'), 'win32'), true); +}); + +test('does not allow it on another operating system', () => { + assert.equal(isWindowsCounterDiagnostic(line, 'linux'), false); +}); + +test('does not hide a fatal message or another logger', () => { + assert.equal(isWindowsCounterDiagnostic(line.replace('/ERROR]', '/FATAL]'), 'win32'), false); + assert.equal(isWindowsCounterDiagnostic(line.replace('HkeyPerformanceDataUtil', 'BaseMetals'), 'win32'), false); +}); + +test('does not hide a different counter failure', () => { + assert.equal(isWindowsCounterDiagnostic(line.replace(detail, 'Could not read system counters'), 'win32'), false); +});