diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 361dcb9d9..c14a1fcb6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,19 +1,19 @@ -name: Base Metals 1.14.4 CI +name: Base Metals 1.15.2 CI on: push: branches: - - master-1.14.4 + - master-1.15.2 - 'feature/**' pull_request: branches: - - master-1.14.4 + - master-1.15.2 permissions: contents: read concurrency: - group: basemetals-1.14-${{ github.workflow }}-${{ github.ref }} + group: basemetals-1.15-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -141,9 +141,9 @@ jobs: ./gradlew "${gradle_args[@]}" first="$RUNNER_TEMP/basemetals-first" mkdir -p "$first" - cp build/libs/BaseMetals-3.0.1.114041.jar "$first/" - cp build/libs/BaseMetals-3.0.1.114041-sources.jar "$first/" - cp build/libs/BaseMetals-3.0.1.114041-javadoc.jar "$first/" + cp build/libs/BaseMetals-3.0.1.115021.jar "$first/" + cp build/libs/BaseMetals-3.0.1.115021-sources.jar "$first/" + cp build/libs/BaseMetals-3.0.1.115021-javadoc.jar "$first/" cp build/release/SHA256SUMS "$first/" - name: Rebuild and prove byte-identical archives @@ -159,9 +159,9 @@ jobs: -Dorg.gradle.java.installations.auto-download=false ) ./gradlew "${gradle_args[@]}" - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.0.1.114041.jar" build/libs/BaseMetals-3.0.1.114041.jar - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.0.1.114041-sources.jar" build/libs/BaseMetals-3.0.1.114041-sources.jar - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.0.1.114041-javadoc.jar" build/libs/BaseMetals-3.0.1.114041-javadoc.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.0.1.115021.jar" build/libs/BaseMetals-3.0.1.115021.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.0.1.115021-sources.jar" build/libs/BaseMetals-3.0.1.115021-sources.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.0.1.115021-javadoc.jar" build/libs/BaseMetals-3.0.1.115021-javadoc.jar cmp "$RUNNER_TEMP/basemetals-first/SHA256SUMS" build/release/SHA256SUMS - name: Run exact-OreSpawn dedicated-server probe @@ -181,13 +181,13 @@ jobs: - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: BaseMetals-1.14.4-${{ github.sha }} + name: BaseMetals-1.15.2-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/BaseMetals-3.0.1.114041.jar - build/libs/BaseMetals-3.0.1.114041-sources.jar - build/libs/BaseMetals-3.0.1.114041-javadoc.jar + build/libs/BaseMetals-3.0.1.115021.jar + build/libs/BaseMetals-3.0.1.115021-sources.jar + build/libs/BaseMetals-3.0.1.115021-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt @@ -195,7 +195,7 @@ jobs: if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: BaseMetals-1.14.4-diagnostics-${{ github.sha }} + name: BaseMetals-1.15.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 c65022fe2..c3fa8e69f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,11 +3,11 @@ name: CodeQL on: push: branches: - - master-1.14.4 + - master-1.15.2 - 'feature/**' pull_request: branches: - - master-1.14.4 + - master-1.15.2 schedule: - cron: '37 7 * * 4' diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index c471b0988..7d4748476 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.14.4 + - master-1.15.2 - 'feature/**' pull_request: branches: - - master-1.14.4 + - master-1.15.2 permissions: contents: read diff --git a/.gitignore b/.gitignore index 3e3fab992..72067f686 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ out # gradle build .gradle +.local-gradle.properties # other eclipse diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4e40f28d4..491f2d76d 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,20 @@ +Base Metals 3.0.1.115021 + +- Bring Base Metals to Minecraft 1.15.2 and Forge 31.2.57. +- Update ore overlays, metal bars, doors, trapdoors and molten fluids for + Minecraft 1.15's rendering changes. +- Keep bows firing arrows and crossbows firing bolts, including the free iron + bolt used when firing without ammunition in Creative mode. +- Keep material arrows and bolts visible in flight and when stuck in a target. +- Keep the 1.14 recipes, equipment effects, configuration screens, smith trades and village loot. +- Preserve Kiri's ore overlays and their resource-pack-aware vanilla backgrounds. +- Support upgrades from Cyano and MMD 1.10, MMD 1.12, and the 1.13 and 1.14 + ports, keeping existing blocks, items, equipment and saved data. +- Keep ForgeGradle 7 and Java 8 game compatibility. Builds and IDE launches + keep test code separate from the mod. +- Use the published OreSpawn 4.1.0.115021 release for ore placement. The eleven + ore rules and their defaults are unchanged. + Base Metals 3.0.1.114041 - Bring the finished 1.13.2 port to Minecraft 1.14.4 and Forge 28.2.26. diff --git a/README.md b/README.md index eb9a2ae6e..44e6053af 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,36 @@ [![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-1.14.4)](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml?query=branch%3Amaster-1.14.4) +[![Build, test, and audit](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml/badge.svg?branch=master-1.15.2)](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml?query=branch%3Amaster-1.15.2) # Base Metals -Base Metals adds historically common metals, useful alloys, and fantasy metals -to Minecraft. Depending on the material, these are available as ores, storage +Base Metals adds real and fantasy metals, along with useful alloys, to +Minecraft. Depending on the material, these are available as ores, storage and decorative blocks, molten fluids, crafting components, tools, armour, shields, bows, crossbows, arrows, and bolts. The mod also includes Crack Hammers, scythes, metal anvils, the human detector, villager trades, advancements, and extra loot to find in chests. -This is the Minecraft 1.14.4 version, `3.0.1.114041`, continued from the finished -1.13.2 port. It keeps the historical `basemetals` block and item IDs, but no longer -needs MMDLib or Additional Loot Tables. OreSpawn places the ores, and Base -Metals supplies the metals and their recipes. +This is Base Metals `3.0.1.115021` for Minecraft 1.15.2. It brings the 1.14.4 +release forward while keeping the same blocks, items and recipes. MMDLib and +Additional Loot Tables are no longer needed. OreSpawn places the ores, and +Base Metals supplies the metals and their recipes. Ores use vanilla stone, netherrack and end-stone textures beneath Kiri's ore overlays, so resource packs can change their surroundings without making the -ores look out of place. Smith trades and village chest loot use the new +ores look out of place. Smith trades and village chest loot use the Armorer, Weaponsmith and Toolsmith professions introduced in Minecraft 1.14. ## Requirements -- Minecraft `1.14.4` -- Forge `28.2.26` +- Minecraft `1.15.2` +- Forge `31.2.57` - Java 8 -- OreSpawn `[4.1.0.114041,5.0.0)` on both client and server +- OreSpawn `[4.1.0.115021,5.0.0)` on both client and server -Put `BaseMetals-3.0.1.114041.jar` and OreSpawn `4.1.0.114041` (or a later -compatible OreSpawn 4 build for 1.14.4) in the `mods` directory. MMDLib and +Put `BaseMetals-3.0.1.115021.jar` and OreSpawn `4.1.0.115021` (or a later +compatible OreSpawn 4 build for 1.15.2) in the `mods` directory. MMDLib and Additional Loot Tables are not dependencies. Mineralogy is optional. ## Materials and gameplay @@ -122,13 +122,14 @@ items in containers are protected too. Always perform the first upgrade on a copy of the world and keep the untouched original. Read [Migration](docs/MIGRATION.md) before opening an old save. A -world already upgraded to Minecraft 1.15 or later must not be opened in this -older version. Worlds from the Base Metals 1.13.2 port can be upgraded normally. +world already upgraded to Minecraft 1.16 or later must not be opened in this +older version. Worlds from the Base Metals 1.13.2 and 1.14.4 ports can be +upgraded normally. ## Compatibility Forge item, block, and fluid tags are Base Metals' public compatibility API. -The 1.14.4 line deliberately contains no version-specific Mekanism, Thermal, +The 1.15.2 line deliberately contains no version-specific Mekanism, Thermal, Tinkers' Construct, Ender IO, IC2, or Thaumcraft plugin code. Compatible mods can consume the common tags without linking to Base Metals internals. See [Compatibility](docs/COMPATIBILITY.md) and [Supported versions](docs/VERSIONS.md). @@ -174,7 +175,7 @@ Generate and verify Eclipse launches with: ``` Release candidates can also be exercised as packaged mods in prepared official -Forge 28 client and server runtimes with `packagedRuntimeIntegrationTest`; pass +Forge 31 client and server runtimes with `packagedRuntimeIntegrationTest`; pass their directories through the `packagedForgeClientRuntime` and `packagedForgeServerRuntime` Gradle properties. These probes load the exact release JAR and OreSpawn dependency, create real worlds, validate client models @@ -184,18 +185,26 @@ and colours, and remain outside the published artifact. content modes, old configuration files, client/server matching and mismatch messages in disposable multiplayer profiles. +`packagedMineralogyIntegrationTest` checks ore placement alongside Mineralogy. +It uses the server runtime above and a `mineralogyTestJar` property pointing to +the qualified Mineralogy 1.15.2 JAR. Mineralogy remains optional for players. + CI checks a fresh Forge setup, unit tests, generated files, a dedicated server with the pinned OreSpawn release, release-JAR contents, checksums, reproducible builds, CodeQL, wrapper validation, and Eclipse classpath isolation. Test probes and historical fixtures are excluded from the published JAR. -Development and CI use the published -[OreSpawn 4.1.0.114041 release](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9041431) -from CurseMaven. The build checks its exact file ID and SHA-256 before release -auditing and packaged tests; no local OreSpawn build is needed. +Builds use the published [OreSpawn `4.1.0.115021` release](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9073591) +through Curse Maven. No sibling checkout or local candidate repository is +needed. The build verifies the download's checksum, Minecraft version and +configuration-screen API. + +CI stages that same download with `gradle/stage-orespawn-release.sh` and passes +the temporary repository through `orespawnVerificationRepository`. Local +candidate builds remain guarded against publication. Release artifacts use Maven coordinate -`zone.moddev.mc.basemetals:BaseMetals:3.0.1.114041`. +`zone.moddev.mc.basemetals:BaseMetals:3.0.1.115021`. Report defects through the [Base Metals issue tracker](https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues). diff --git a/build.gradle b/build.gradle index 310b25765..d5f146f3f 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,16 @@ group = project.mod_group version = project.mod_version base.archivesName = 'BaseMetals' +// Keep local candidate paths out of version control and Eclipse's public setup. +File localPropertiesFile = file('.local-gradle.properties') +if (localPropertiesFile.isFile()) { + Properties localProperties = new Properties() + localPropertiesFile.withInputStream { localProperties.load(it) } + localProperties.each { key, value -> + if (!project.hasProperty(key.toString())) project.ext.set(key.toString(), value) + } +} + def eclipseWorkspaceProjectName = projectDir.name def expectedMavenGroup = 'zone.moddev.mc.basemetals' def expectedMavenArtifact = 'BaseMetals' @@ -113,7 +123,7 @@ def mainModClasses = "${mod_id}%%${forgeMainOutputPath}${File.pathSeparator}${mo def forgeProbeOutputPath = integrationTestModClassesDirectory.get().asFile.absolutePath def probeModClasses = mainModClasses + "${File.pathSeparator}basemetalsprobe%%${forgeProbeOutputPath}" + "${File.pathSeparator}basemetalsprobe%%${forgeProbeOutputPath}" -def forge28RunTargets = [client: 'fmluserdevclient', server: 'fmluserdevserver', +def forge31RunTargets = [client: 'fmluserdevclient', server: 'fmluserdevserver', data: 'fmluserdevdata', runtimeProbeServer: 'fmluserdevserver', legacyUpgradeServer: 'fmluserdevserver'] minecraft { @@ -126,7 +136,7 @@ minecraft { systemProperty 'forge.logging.markers', 'REGISTRIES' systemProperty 'forge.logging.console.level', 'info' mods { basemetals { source sourceSets.main } } - environment 'target', forge28RunTargets[name] + environment 'target', forge31RunTargets[name] environment 'MCP_MAPPINGS', "${mapping_channel}_${mapping_version}" environment 'MCP_VERSION', mcp_version environment 'FORGE_VERSION', forge_version @@ -172,7 +182,7 @@ def prepareIntegrationTestModClasses = tasks.register('prepareIntegrationTestMod } tasks.withType(JavaExec).configureEach { JavaExec runTask -> - def runName = forge28RunTargets.keySet().find { runTask.name == 'run' + it.capitalize() } + def runName = forge31RunTargets.keySet().find { runTask.name == 'run' + it.capitalize() } if (runName != null) { runTask.dependsOn prepareForgeRunModClasses if (runTask.name in ['runRuntimeProbeServer', 'runLegacyUpgradeServer']) { @@ -190,7 +200,15 @@ tasks.withType(JavaExec).configureEach { JavaExec runTask -> def orespawnModule = "mmd-orespawn-${project.orespawn_curse_project_id}" def orespawnVerificationRepository = project.findProperty('orespawnVerificationRepository') -def orespawnCoordinate = "curse.maven:${orespawnModule}:${orespawn_curse_file_id}" +def orespawnCandidate = project.orespawn_dependency_mode == 'candidate' +def orespawnCandidateRepository = project.findProperty('orespawnCandidateRepository') +if (orespawnCandidate && orespawnCandidateRepository == null) { + throw new GradleException('Local qualification needs -PorespawnCandidateRepository=. ' + + 'You may also set it in the ignored .local-gradle.properties file.') +} +def orespawnCoordinate = orespawnCandidate + ? "zone.moddev.mc.orespawn:OreSpawn:${orespawn_version}" + : "curse.maven:${orespawnModule}:${orespawn_curse_file_id}" repositories { minecraft.mavenizer(it) maven fg.forgeMaven @@ -204,13 +222,17 @@ repositories { exclusiveContent { forRepository { maven { - name = orespawnVerificationRepository == null ? 'CurseMaven' : 'OreSpawnReleaseVerificationMirror' - url = orespawnVerificationRepository == null + name = orespawnCandidate ? 'OreSpawnLocalCandidate' : 'OreSpawnReleaseVerificationMirror' + url = orespawnCandidate ? uri(orespawnCandidateRepository) + : orespawnVerificationRepository == null ? uri('https://www.cursemaven.com') : uri(orespawnVerificationRepository) metadataSources { artifact() } } } - filter { includeModule('curse.maven', orespawnModule) } + filter { + if (orespawnCandidate) includeModule('zone.moddev.mc.orespawn', 'OreSpawn') + else includeModule('curse.maven', orespawnModule) + } } } @@ -225,6 +247,7 @@ dependencies { renamer.mappings.from minecraft.dependency.toSrgFile configurations.named('testRuntimeClasspath') { exclude group: 'curse.maven', module: orespawnModule + exclude group: 'zone.moddev.mc.orespawn', module: 'OreSpawn' } tasks.named('processResources', ProcessResources) { @@ -253,6 +276,7 @@ tasks.named('jar', Jar) { 'Specification-Version': '1', 'Implementation-Title': 'Base Metals', 'Implementation-Version': project.version, 'Implementation-Vendor': project.mod_authors, 'Built-On-Java': '8', 'Built-On': "${project.minecraft_version}-${project.forge_version}", + 'OreSpawn-Dependency-Mode': project.orespawn_dependency_mode, 'Build-Target': "minecraft-${project.minecraft_version}-${project.loader_name}-" + "${project.forge_version}-java-${project.java_version}"]) } @@ -279,6 +303,7 @@ ext.baseMetalsBuild = [ expectedMavenArtifact: expectedMavenArtifact, expectedMavenCoordinate: expectedMavenCoordinate, eclipseWorkspaceProjectName: eclipseWorkspaceProjectName, + orespawnCandidate: orespawnCandidate, prepareIntegrationTestModClasses: prepareIntegrationTestModClasses, releaseJar: releaseJar ] diff --git a/docs/COMPATIBILITY.md b/docs/COMPATIBILITY.md index 071371286..bd7b8a154 100644 --- a/docs/COMPATIBILITY.md +++ b/docs/COMPATIBILITY.md @@ -8,14 +8,14 @@ ores, crystals, shards, clumps, dirty dusts, and molten fluids. Adamantite, Adamantium, Adamant, Quicksilver, and steel-sprocket names are forwarding tags. Copper-consuming recipes accept `forge:ingots/copper`, except Base Metals' own compacting and decompacting recipes, whose output must remain -the Base Metals item. On Minecraft 1.14.4 the copper ore, ingot, and storage +the Base Metals item. On Minecraft 1.15.2 the copper ore, ingot, and storage tags contain Base Metals entries; other mods can add their equivalents through normal tag merging. This version has no mod-specific plugins for Mekanism, Thermal Expansion, Tinkers' Construct, Ender IO, IC2, Thaumcraft, Dense Ores, VeinMiner, or Constructs Armory. Their version-specific 1.18 data and APIs are not valid on Forge -28. Generic processors and tools can interoperate through Forge tags. +31. Generic processors and tools can interoperate through Forge tags. Mineralogy is optional. When installed, OreSpawn can place the same ores in Mineralogy's rocks. Base Metals does not need Mineralogy to run. diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index cd2f155e7..ff9d2e212 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -6,7 +6,7 @@ blocks cannot be reconstructed by Mojang's vanilla fixer alone, so Base Metals installs a narrowly scoped migration hook before Forge reads an old world. Always upgrade a copy and retain the original 1.10/1.12 world. Install Base -Metals `3.0.1.114041`, OreSpawn `4.1.0.114041`, and any other 1.14.4 mods needed +Metals `3.0.1.115021`, OreSpawn `4.1.0.115021`, and any other 1.15.2 mods needed by that world. Do not carry MMDLib, Additional Loot Tables, the OreSpawn 3 plugin, or Base Metals' old fallback generator into the new instance. @@ -37,8 +37,8 @@ nugget, and the MMDLib Vanilla Bits block/item/fluid names. The migration supports the original Cyano Base Metals 2.4 line and the later MMD Base Metals releases for Minecraft 1.10.2 and 1.12.2. It is not a downgrade -path: do not open a world already saved by Minecraft 1.15 or newer, including -the Base Metals 1.18.2 port, in Minecraft 1.14.4. +path: do not open a world already saved by Minecraft 1.16 or newer, including +the Base Metals 1.18.2 port, in Minecraft 1.15.2. ## Mod settings @@ -54,22 +54,22 @@ limit what you can make instead. See [Content modes and configuration](CONTENT_M ## OreSpawn configuration -The Base Metals provider uses the historical 1.14.4 defaults documented in +The Base Metals provider keeps the historical defaults documented in [WORLDGEN.md](WORLDGEN.md), including enabled copper. OreSpawn configuration migration remains OreSpawn's responsibility. Keep a copy of the old OreSpawn configuration alongside the untouched source world when validating an upgrade. The generated manifests at `data/basemetals/registry_manifest_1_12.json` and `data/basemetals/registry_manifest.json` document the historical registry -baseline and its 1.14.4 projection. +baseline and its 1.15.2 projection. -## Moving from Minecraft 1.13.2 +## Moving from Minecraft 1.13.2 or 1.14.4 -Use a copy of your 1.13.2 world, with the 1.14.4 releases of Base Metals and +Use a copy of your 1.13.2 or 1.14.4 world, with the 1.15.2 builds of Base Metals and OreSpawn. Keep `basemetals-common.toml` and your OreSpawn settings: this port uses the same configuration keys, registered names and ore-rule IDs. Existing items, recipe-book progress and terrain should remain unchanged. Once Minecraft -has saved the copy in 1.14.4, do not reopen it in the older game. +has saved the copy in 1.15.2, do not reopen it in the older game. Forge 1.13 saved a profession registry that no longer exists in 1.14. Base Metals removes that obsolete index when it contains only vanilla professions; diff --git a/docs/VERSIONS.md b/docs/VERSIONS.md index b58de7368..03a7f0bb8 100644 --- a/docs/VERSIONS.md +++ b/docs/VERSIONS.md @@ -1,19 +1,19 @@ # Supported versions -Base Metals `3.0.1.114041` targets Minecraft `1.14.4`, Forge `28.2.26`, and +Base Metals `3.0.1.115021` targets Minecraft `1.15.2`, Forge `31.2.57`, and Java 8. The Gradle build itself runs on Java `17.0.1+12` and uses ForgeGradle `7.0.34` with Gradle `9.6.1`; those build-time runtimes do not change the Java 8 requirement of the released mod. -Builds and tests use the published OreSpawn -`4.1.0.114041` release (CurseForge project `245586`, file `9041431`, SHA-256 -`7691C1AE7C6AC890A2CC785F3EEF54A1255D61E4CFCF5661D67CB1609CFC41C6`). -At runtime, Base Metals requires OreSpawn `[4.1.0.114041,5.0.0)` for Minecraft 1.14.4. +Builds and tests use the published [OreSpawn `4.1.0.115021` release](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9073591), +CurseForge project `245586`, file `9073591`, with +SHA-256 `F7C9A110E834EC3F73D55C20E8F52EEA1CF48C4E3ACCFBE8FCEFB60E78ABE387`. +At runtime, Base Metals requires OreSpawn `[4.1.0.115021,5.0.0)` for Minecraft 1.15.2. The configuration cog uses OreSpawn's public 4.1 client API. -Builds download this file through CurseMaven. CI verifies the download and -stages it in a temporary Maven repository. The schema-3 provider supports the -OreSpawn versions in the runtime range above. +The exact build dependency is `curse.maven:mmd-orespawn-245586:9073591`. +CI stages the same checksum-verified file in a temporary Maven repository. +The schema-3 provider supports the OreSpawn versions in the runtime range above. Release artifacts use Maven coordinate -`zone.moddev.mc.basemetals:BaseMetals:3.0.1.114041`. +`zone.moddev.mc.basemetals:BaseMetals:3.0.1.115021`. diff --git a/docs/WORLDGEN.md b/docs/WORLDGEN.md index 74b0c6b86..3e3575190 100644 --- a/docs/WORLDGEN.md +++ b/docs/WORLDGEN.md @@ -1,8 +1,8 @@ # OreSpawn world generation -Base Metals requires OreSpawn `[4.1.0.114041,5.0.0)` and packages provider +Base Metals requires OreSpawn `[4.1.0.115021,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.114041` release. +tests use the published OreSpawn `4.1.0.115021` release. The provider declares ores only: it has no rocks, geomes, biome rules, terrain dimensions, formations, fluid deposits, vanilla suppression, or strata @@ -24,7 +24,7 @@ and `retrogen:false`. | Nickel | all except Nether/End | 32..95 | uniform | 1 | same | | Platinum | all except Nether/End | 1..31 | uniform | 0.125 | same | -Minecraft 1.14.4 has no vanilla copper ore, so Base Metals copper generates +Minecraft 1.15.2 has no vanilla copper ore, so Base Metals copper generates by default. Antimony and Bismuth ores are available in creative mode and old saves, but do not generate unless you add rules for them in OreSpawn. diff --git a/gradle.properties b/gradle.properties index f3fff463a..9e2dfec32 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,10 +7,10 @@ org.gradle.parallel=false net.minecraftforge.gradle.merge-source-sets=false # Minecraft, Forge and mappings must describe the same game version. -minecraft_version=1.14.4 -minecraft_version_range=[1.14.4] -forge_version=28.2.26 -forge_installer_sha256=E68A0E2D589B2954C5D109A04B80747AC8C061ACABE074DB1607F9C2FD7D2CE1 +minecraft_version=1.15.2 +minecraft_version_range=[1.15.2] +forge_version=31.2.57 +forge_installer_sha256=84FD49A743978421B26F62AC78222289FE892A46F996CF11CB5E05B7441A7773 # Target and Java versions used by release checks and publishing. loader_name=forge @@ -20,26 +20,27 @@ java_toolchain_version=8.0.502+7 gradle_java_version=17 curseforge_project_id=240967 -# Pin the OreSpawn release we build and test against. -orespawn_version=4.1.0.114041 +# Exact OreSpawn release used by development, CI and release checks. +orespawn_dependency_mode=release +orespawn_version=4.1.0.115021 orespawn_curse_project_id=245586 -orespawn_curse_file_id=9041431 -orespawn_sha256=7691C1AE7C6AC890A2CC785F3EEF54A1255D61E4CFCF5661D67CB1609CFC41C6 +orespawn_curse_file_id=9073591 +orespawn_sha256=F7C9A110E834EC3F73D55C20E8F52EEA1CF48C4E3ACCFBE8FCEFB60E78ABE387 # Versions accepted when players load the mod. -forge_version_range=[28,) -loader_version_range=[28,) +forge_version_range=[31,) +loader_version_range=[31,) -# MCP mappings for Forge 28. +# MCP mappings for Forge 31. mapping_channel=snapshot -mapping_version=20190719-1.14.3 -mcp_version=20190829.143755 +mapping_version=20200514-1.15.1 +mcp_version=20200515.085601 # Mod identity. Keep mod_id unchanged so existing saves still load. mod_id=basemetals mod_name=Base Metals mod_license=LGPL-2.1 -mod_version=3.0.1.114041 +mod_version=3.0.1.115021 # Maven coordinates and credits. mod_group=zone.moddev.mc.basemetals diff --git a/gradle/README.md b/gradle/README.md index 3c23c090b..fbeada3d3 100644 --- a/gradle/README.md +++ b/gradle/README.md @@ -17,6 +17,15 @@ Use Java 17 to run Gradle. ForgeGradle uses Java 25 for its Mavenizer; Minecraft and the mod run on Java 8. Development accepts newer Java 8 updates, while release auditing requires the pinned compiler in `gradle.properties`. +Development resolves OreSpawn `4.1.0.115021` from Curse Maven, using file +`9073591`. `verifyReleaseDependencies` checks its checksum, mod metadata and +configuration-screen API. No local candidate setup is needed. + +CI runs `stage-orespawn-release.sh ` to download and checksum that +same file, then passes `-PorespawnVerificationRepository=` to +Gradle. The mirror does not change the dependency's coordinates or checksum. +The optional local-candidate path still blocks publication. + Run `check build` for the normal build, then `verifyReleaseArtifacts` and `writeReleaseChecksums` when preparing a release candidate. Packaged checks also need `packagedForgeServerRuntime` and `packagedForgeClientRuntime`, pointing diff --git a/gradle/ide/eclipse.gradle b/gradle/ide/eclipse.gradle index 6c386c513..452337b00 100644 --- a/gradle/ide/eclipse.gradle +++ b/gradle/ide/eclipse.gradle @@ -75,7 +75,7 @@ def quoteEclipseLaunchPathArguments = { String contents -> contents } -def syncForge28EclipseLaunches = tasks.register('syncForge28EclipseLaunches') { +def syncForge31EclipseLaunches = tasks.register('syncForge31EclipseLaunches') { group = 'ide' dependsOn tasks.named('processResources') doLast { @@ -126,13 +126,13 @@ def syncForge28EclipseLaunches = tasks.register('syncForge28EclipseLaunches') { } } } -tasks.matching { it.name == 'genEclipseRuns' }.configureEach { finalizedBy syncForge28EclipseLaunches } -tasks.matching { it.name == 'eclipse' }.configureEach { finalizedBy syncForge28EclipseLaunches } +tasks.matching { it.name == 'genEclipseRuns' }.configureEach { finalizedBy syncForge31EclipseLaunches } +tasks.matching { it.name == 'eclipse' }.configureEach { finalizedBy syncForge31EclipseLaunches } tasks.register('isolateEclipseProductionRuns') { group = 'ide' dependsOn tasks.named('genEclipseRuns') - dependsOn syncForge28EclipseLaunches + dependsOn syncForge31EclipseLaunches dependsOn configureEclipseBuildship } @@ -198,7 +198,7 @@ tasks.register('verifyEclipseProductionClasspath') { || !contents.contains("MOD_CLASSES\" value=\"${expectedModClasses}\"") || !contents.contains('MAIN_TYPE" value="net.minecraftforge.launcher.Main"') || !contents.contains('--main net.minecraftforge.userdev.LaunchTesting')) { - throw new GradleException("${name} is not an isolated Forge 28 launch: ${leaked}") + throw new GradleException("${name} is not an isolated Forge 31 launch: ${leaked}") } } List allLaunches = fileTree(projectDir) { include '*.launch' }.files.sort { it.name } diff --git a/gradle/release/artifacts.gradle b/gradle/release/artifacts.gradle index be1a161a0..66b5f06d6 100644 --- a/gradle/release/artifacts.gradle +++ b/gradle/release/artifacts.gradle @@ -69,7 +69,7 @@ tasks.register('verifyJava8Toolchain') { doLast { def metadata = tasks.named('compileJava', JavaCompile).get().javaCompiler.get().metadata if (metadata.languageVersion.asInt() != 8) { - throw new GradleException("Minecraft 1.14.4 requires a Java 8 JDK, found " + + throw new GradleException("Minecraft 1.15.2 requires a Java 8 JDK, found " + "${metadata.vendor} ${metadata.javaRuntimeVersion} at ${metadata.installationPath}") } logger.lifecycle("Java 8 development toolchain: ${metadata.vendor} ${metadata.javaRuntimeVersion}") @@ -131,21 +131,21 @@ tasks.register('verifyReleaseConfiguration') { loaderCode: project.loader_code.toString(), javaVersion: project.java_version.toString(), gradleJavaVersion: project.gradle_java_version.toString(), curseForgeProjectId: project.curseforge_project_id.toString()] - def expected = [modVersion: '3.0.1.114041', modGroup: expectedMavenGroup, - minecraftVersion: '1.14.4', forgeVersion: '28.2.26', - forgeInstallerSha256: 'E68A0E2D589B2954C5D109A04B80747AC8C061ACABE074DB1607F9C2FD7D2CE1', - mappingChannel: 'snapshot', mappingVersion: '20190719-1.14.3', - mcpVersion: '20190829.143755', loaderName: 'forge', loaderCode: '1', + def expected = [modVersion: '3.0.1.115021', modGroup: expectedMavenGroup, + minecraftVersion: '1.15.2', forgeVersion: '31.2.57', + forgeInstallerSha256: '84FD49A743978421B26F62AC78222289FE892A46F996CF11CB5E05B7441A7773', + mappingChannel: 'snapshot', mappingVersion: '20200514-1.15.1', + mcpVersion: '20200515.085601', loaderName: 'forge', loaderCode: '1', javaVersion: '8', gradleJavaVersion: '17', curseForgeProjectId: '240967'] - if (actual != expected) throw new GradleException("Unexpected Base Metals 1.14.4 identity: ${actual}") + if (actual != expected) throw new GradleException("Unexpected Base Metals 1.15.2 identity: ${actual}") } } tasks.register('verifyReleaseDependencies') { group = 'verification' doLast { - def expected = [version: '4.1.0.114041', curseProjectId: '245586', curseFileId: '9041431', - sha256: '7691C1AE7C6AC890A2CC785F3EEF54A1255D61E4CFCF5661D67CB1609CFC41C6'] + def expected = [version: '4.1.0.115021', curseProjectId: '245586', curseFileId: '9073591', + sha256: 'F7C9A110E834EC3F73D55C20E8F52EEA1CF48C4E3ACCFBE8FCEFB60E78ABE387'] if (configuredOreSpawnIdentity != expected) { throw new GradleException("Unexpected OreSpawn identity: ${configuredOreSpawnIdentity}") } @@ -160,10 +160,11 @@ tasks.register('verifyReleaseDependencies') { if (metadataEntry == null) throw new GradleException('OreSpawn mod metadata is missing') String metadata = zip.getInputStream(metadataEntry).getText('UTF-8') if (!metadata.contains('modId="orespawn"') - || !metadata.contains('version="4.1.0.114041"') - || !metadata.contains('versionRange="[1.14.4]"') - || zip.getEntry('zone/moddev/mc/orespawn/api/OreSpawnApi.class') == null) { - throw new GradleException('Expected the published Minecraft 1.14.4 OreSpawn 4.1 release and public API') + || !metadata.contains('version="4.1.0.115021"') + || !metadata.contains('versionRange="[1.15.2]"') + || zip.getEntry('zone/moddev/mc/orespawn/api/OreSpawnApi.class') == null + || zip.getEntry('zone/moddev/mc/orespawn/api/client/WorldSettingsExtensionRegistry.class') == null) { + throw new GradleException('Expected Minecraft 1.15.2 OreSpawn 4.1 and its configuration-screen API') } } } @@ -242,7 +243,7 @@ tasks.register('verifyReleaseArtifacts') { new ZipFile(main).withCloseable { zip -> Set names = zip.entries().toList().collect { it.name } as Set ['META-INF/mods.toml', 'META-INF/MANIFEST.MF', 'META-INF/coremods.json', - 'coremods/basemetals_114_compatibility.js', 'pack.mcmeta', + 'coremods/basemetals_115_compatibility.js', 'pack.mcmeta', 'data/basemetals/orespawn/provider.json', 'data/basemetals/recipes/stone_crackhammer.json', 'data/minecraft/tags/blocks/anvil.json', 'assets/basemetals/lang/en_us.json', 'META-INF/basemetals/docs/VERSIONS.md'].each { required -> @@ -251,12 +252,12 @@ tasks.register('verifyReleaseArtifacts') { Manifest manifest = new Manifest(zip.getInputStream(zip.getEntry('META-INF/MANIFEST.MF'))) if (manifest.mainAttributes.getValue('Maven-Artifact') != expectedMavenCoordinate || manifest.mainAttributes.getValue('Build-Target') != - 'minecraft-1.14.4-forge-28.2.26-java-8') { + 'minecraft-1.15.2-forge-31.2.57-java-8') { throw new GradleException('Release manifest contains the wrong identity') } String modsToml = zip.getInputStream(zip.getEntry('META-INF/mods.toml')).getText('UTF-8') - if (modsToml.contains('${') || !modsToml.contains('version="3.0.1.114041"') - || !modsToml.contains('versionRange="[4.1.0.114041,5.0.0)"')) { + if (modsToml.contains('${') || !modsToml.contains('version="3.0.1.115021"') + || !modsToml.contains('versionRange="[4.1.0.115021,5.0.0)"')) { throw new GradleException('Release mods.toml contains unresolved or incompatible metadata') } def provider = new JsonSlurper().parse(zip.getInputStream( @@ -327,6 +328,9 @@ tasks.register('verifyPreparedReleaseArtifacts') { tasks.register('validateMavenReleaseCredentials') { group = 'publishing' doLast { + if (project.ext.baseMetalsBuild.orespawnCandidate) { + throw new GradleException('Publication is blocked until the public OreSpawn release is pinned.') + } if (!System.getenv('MAVEN_UPLOAD_URL') || !System.getenv('MAVEN_UPLOAD_USERNAME') || !System.getenv('MAVEN_UPLOAD_PASSWORD')) { throw new GradleException('MAVEN_UPLOAD_URL, MAVEN_UPLOAD_USERNAME, and MAVEN_UPLOAD_PASSWORD are required') @@ -343,6 +347,14 @@ tasks.withType(PublishToMavenRepository).configureEach { ? tasks.named('verifyReleaseArtifacts') : tasks.named('verifyPreparedReleaseArtifacts')) } +tasks.withType(PublishToMavenLocal).configureEach { + doFirst { + if (project.ext.baseMetalsBuild.orespawnCandidate) { + throw new GradleException('Do not publish a Base Metals build using the local OreSpawn candidate.') + } + } +} + project.ext.baseMetalsBuild.putAll([ sha256: sha256, configuredOreSpawnIdentity: configuredOreSpawnIdentity diff --git a/gradle/stage-orespawn-candidate.ps1 b/gradle/stage-orespawn-candidate.ps1 new file mode 100644 index 000000000..15b8eca38 --- /dev/null +++ b/gradle/stage-orespawn-candidate.ps1 @@ -0,0 +1,40 @@ +param( + [Parameter(Mandatory = $true)][string]$CandidateJar, + [Parameter(Mandatory = $true)][string]$Repository +) + +$ErrorActionPreference = 'Stop' +$candidateVersion = '4.1.0.115021' +$candidateSha256 = 'F7C9A110E834EC3F73D55C20E8F52EEA1CF48C4E3ACCFBE8FCEFB60E78ABE387' + +if ((Get-FileHash -LiteralPath $CandidateJar -Algorithm SHA256).Hash -ne $candidateSha256) { + throw 'The OreSpawn candidate differs from the qualified build.' +} + +Add-Type -AssemblyName System.IO.Compression.FileSystem +$archive = [IO.Compression.ZipFile]::OpenRead((Resolve-Path -LiteralPath $CandidateJar).Path) +try { + $metadata = $archive.GetEntry('META-INF/mods.toml') + if ($null -eq $metadata) { throw 'OreSpawn mod metadata is missing.' } + $reader = [IO.StreamReader]::new($metadata.Open()) + try { $text = $reader.ReadToEnd() } finally { $reader.Dispose() } + if (!$text.Contains('version="4.1.0.115021"') -or !$text.Contains('versionRange="[1.15.2]"') -or + $null -eq $archive.GetEntry('zone/moddev/mc/orespawn/api/client/WorldSettingsExtensionRegistry.class')) { + throw 'Expected the OreSpawn 1.15.2 candidate with its configuration-screen API.' + } +} finally { $archive.Dispose() } + +$artifactDirectory = Join-Path $Repository "zone/moddev/mc/orespawn/OreSpawn/$candidateVersion" +New-Item -ItemType Directory -Path $artifactDirectory -Force | Out-Null +Copy-Item -LiteralPath $CandidateJar -Destination (Join-Path $artifactDirectory "OreSpawn-$candidateVersion.jar") +$pom = @" + + 4.0.0 + zone.moddev.mc.orespawn + OreSpawn + $candidateVersion + +"@ +[IO.File]::WriteAllText((Join-Path $artifactDirectory "OreSpawn-$candidateVersion.pom"), + $pom.Replace("`r`n", "`n") + "`n", [Text.UTF8Encoding]::new($false)) +Write-Output "Staged verified OreSpawn $candidateVersion in $Repository" diff --git a/gradle/stage-orespawn-release.sh b/gradle/stage-orespawn-release.sh index c17c4a37e..5395ab2a9 100644 --- a/gradle/stage-orespawn-release.sh +++ b/gradle/stage-orespawn-release.sh @@ -4,6 +4,11 @@ set -euo pipefail repository="${1:?Usage: stage-orespawn-release.sh }" value() { sed -n "s/^$1=//p" gradle.properties; } +if [[ "$(value orespawn_dependency_mode)" == "candidate" ]]; then + echo 'Publication is blocked: pin the public OreSpawn 1.15.2 release first.' >&2 + exit 1 +fi + project_id="$(value orespawn_curse_project_id)" file_id="$(value orespawn_curse_file_id)" expected_sha="$(value orespawn_sha256)" diff --git a/gradle/verification/development.gradle b/gradle/verification/development.gradle index 51097cdfb..e963c2a8a 100644 --- a/gradle/verification/development.gradle +++ b/gradle/verification/development.gradle @@ -132,8 +132,8 @@ def verifyLegacyUpgradeRun = tasks.register('verifyLegacyUpgradeRun') { if (fixtureManifest.isFile()) { boolean from110 = new File(runDirectory, 'world/BASEMETALS_1_10_FIXTURE_COMPLETE.txt').isFile() - String marker = from110 ? 'BASEMETALS_1_10_TO_1_14_UPGRADE PASS' - : 'BASEMETALS_1_12_TO_1_14_UPGRADE PASS' + String marker = from110 ? 'BASEMETALS_1_10_TO_1_15_UPGRADE PASS' + : 'BASEMETALS_1_12_TO_1_15_UPGRADE PASS' if (!text.contains(marker)) { throw new GradleException("Complete ${from110 ? '1.10' : '1.12'} fixture verification did not report PASS") } diff --git a/gradle/verification/generated-data.gradle b/gradle/verification/generated-data.gradle index 4d37279fd..51cfdcf1d 100644 --- a/gradle/verification/generated-data.gradle +++ b/gradle/verification/generated-data.gradle @@ -8,8 +8,8 @@ def sha256 = project.ext.baseMetalsBuild.sha256 def verifyGeneratedData = tasks.register('verifyGeneratedData', Exec) { group = 'verification' - description = 'Regenerates and proves that the committed Minecraft 1.14.4 resource projection is current.' - commandLine 'node', 'tools/generate_114_resources.js' + description = 'Regenerates and proves that the committed Minecraft 1.15.2 resource projection is current.' + commandLine 'node', 'tools/generate_115_resources.js' def snapshot = { Map result = new TreeMap<>() [file('src/generated/resources'), diff --git a/gradle/verification/packaged-forge.gradle b/gradle/verification/packaged-forge.gradle index d7871f950..3c9f9f510 100644 --- a/gradle/verification/packaged-forge.gradle +++ b/gradle/verification/packaged-forge.gradle @@ -52,7 +52,7 @@ def packagedForgeServerRuntime = providers.gradleProperty('packagedForgeServerRu def packagedForgeClientRuntime = providers.gradleProperty('packagedForgeClientRuntime') def requireRuntimeDirectory = { Provider configuredPath, String propertyName -> if (!configuredPath.isPresent()) { - throw new GradleException("Pass -P${propertyName}=") + throw new GradleException("Pass -P${propertyName}=") } File runtime = file(configuredPath.get()).canonicalFile if (!runtime.isDirectory()) { @@ -109,6 +109,7 @@ def preparePackagedServerIntegration = tasks.register('preparePackagedServerInte } new File(runDirectory, 'server.properties').setText('''\ level-name=basemetals-packaged-server-smoke +level-seed=0 online-mode=false spawn-protection=0 server-port=0 @@ -140,7 +141,7 @@ def packagedServerProcess = tasks.register('packagedServerProcess', Exec) { } tasks.register('packagedServerIntegrationTest') { group = 'verification' - description = 'Runs the exact release jars in an official Forge 28 dedicated-server runtime.' + description = 'Runs the exact release jars in an official Forge 31 dedicated-server runtime.' dependsOn packagedServerProcess doLast { assertPackagedRuntimePassed(packagedServerRunDirectory.get().asFile, @@ -186,7 +187,7 @@ def preparePackagedClientIntegration = tasks.register('preparePackagedClientInte File overlayPack = new File(runDirectory, 'resourcepacks/basemetals-ore-overlay-fixture') copy { from oreOverlayClientFixtures; into overlayPack } new File(overlayPack, 'pack.mcmeta').setText( - '{"pack":{"pack_format":4,"description":"Base Metals ore overlay test fixture"}}\n', 'UTF-8') + '{"pack":{"pack_format":5,"description":"Base Metals ore overlay test fixture"}}\n', 'UTF-8') new File(runDirectory, 'options.txt').setText( 'fullscreen:false\nlang:en_us\nresourcePacks:["file/basemetals-ore-overlay-fixture"]\n', 'UTF-8') } @@ -205,7 +206,8 @@ def packagedClientProcess = tasks.register('packagedClientProcess', Exec) { File assets = new File(runtime, 'assets-local') if (!assets.isDirectory()) assets = new File(runtime, 'assets') File natives = new File(runtime, 'natives') - File versionNatives = new File(natives, "forge-${forge_version}") + File versionNatives = new File(natives, "${minecraft_version}-forge-${forge_version}") + if (!versionNatives.isDirectory()) versionNatives = new File(natives, "forge-${forge_version}") if (versionNatives.isDirectory()) natives = versionNatives [forgeJsonFile, baseJsonFile, baseJar, libraries, assets, natives].each { if (!it.exists()) throw new GradleException("Incomplete official client runtime: ${it}") @@ -268,7 +270,7 @@ def packagedClientProcess = tasks.register('packagedClientProcess', Exec) { } tasks.register('packagedClientIntegrationTest') { group = 'verification' - description = 'Loads and renders the exact release jars in an official Forge 28 client runtime.' + description = 'Loads and renders the exact release jars in an official Forge 31 client runtime.' dependsOn packagedClientProcess doLast { File runDirectory = packagedClientRunDirectory.get().asFile @@ -286,11 +288,50 @@ tasks.register('packagedClientIntegrationTest') { tasks.register('packagedRuntimeIntegrationTest') { group = 'verification' - description = 'Runs the exact Base Metals and OreSpawn jars in official Forge 28 server and client runtimes.' + description = 'Runs the exact Base Metals and OreSpawn jars in official Forge 31 server and client runtimes.' dependsOn tasks.named('packagedServerReloadTest') dependsOn tasks.named('packagedClientIntegrationTest') } +tasks.register('packagedMineralogyIntegrationTest', Exec) { + group = 'verification' + description = 'Checks the same ore rules inside real Mineralogy strata, without adding a second provider.' + dependsOn releaseJar, packagedServerProbeJar, tasks.named('verifyReleaseDependencies') + timeout = java.time.Duration.ofMinutes(5) + doFirst { + String configuredJar = providers.gradleProperty('mineralogyTestJar').orNull + if (configuredJar == null) throw new GradleException('Pass -PmineralogyTestJar=') + File mineralogy = file(configuredJar) + if (!mineralogy.isFile() || sha256(mineralogy) != + 'ADACF365CCAFF7091980AA92ED1FCC14892AA6CD4B10E82336C8512525341DFA') { + throw new GradleException('Expected the qualified Mineralogy 6.0.1.115021 artifact') + } + + File runDirectory = prepareBuildOwnedRunDirectory( + file("${buildDir}/packaged-mineralogy-run"), 'packaged-mineralogy-run') + copy { + from releaseJar, packagedServerProbeJar, releasedOreSpawnJar(), mineralogy + into new File(runDirectory, 'mods') + } + new File(runDirectory, 'server.properties').setText( + 'level-name=world\nlevel-seed=0\nonline-mode=false\nserver-port=0\nview-distance=4\nmax-tick-time=-1\n', 'UTF-8') + new File(runDirectory, 'eula.txt').setText('eula=true\n', 'UTF-8') + File runtime = requireRuntimeDirectory(packagedForgeServerRuntime, 'packagedForgeServerRuntime') + workingDir runDirectory + commandLine javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(8) + vendor = JvmVendorSpec.ADOPTIUM + }.get().executablePath.asFile.absolutePath, + '-Xms512m', '-Xmx2g', '-Dbasemetalsprobe.sampleOres=true', '-jar', + new File(runtime, "forge-${minecraft_version}-${forge_version}.jar").absolutePath, 'nogui' + } + doLast { + File runDirectory = file("${buildDir}/packaged-mineralogy-run") + assertPackagedRuntimePassed(runDirectory, 'BASEMETALS_RUNTIME_PROBE PASS', 'Mineralogy coexistence') + assertPackagedRuntimePassed(runDirectory, 'BASEMETALS_MINERALOGY_COEXISTENCE PASS', 'Mineralogy strata') + } +} + tasks.register('contentModeIntegrationTest', Exec) { group = 'verification' description = 'Tests packaged content policies and client/server mode matching with disposable profiles.' diff --git a/src/clientIntegrationTest/java/net/minecraftforge/fml/client/gui/ModSelection.java b/src/clientIntegrationTest/java/net/minecraftforge/fml/client/gui/ModSelection.java deleted file mode 100644 index 76b606dd3..000000000 --- a/src/clientIntegrationTest/java/net/minecraftforge/fml/client/gui/ModSelection.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minecraftforge.fml.client.gui; - -/** Test access to Forge's package-private Mods-list entries. */ -public final class ModSelection { - private ModSelection() {} - - public static void select(GuiModList screen, String modId) { - GuiSlotModList list = (GuiSlotModList) screen.children().stream() - .filter(child -> child instanceof GuiSlotModList).findFirst().get(); - - for (GuiSlotModList.ModEntry entry : list.children()) { - if (entry.getInfo().getModId().equals(modId)) { - screen.setSelected(entry); - return; - } - } - - throw new IllegalStateException("Missing mod " + modId); - } -} diff --git a/src/clientIntegrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsClientProbe.java b/src/clientIntegrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsClientProbe.java index ae613ee32..a0c434903 100644 --- a/src/clientIntegrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsClientProbe.java +++ b/src/clientIntegrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsClientProbe.java @@ -26,7 +26,8 @@ import net.minecraft.item.BowItem; import net.minecraft.item.Items; import net.minecraft.resources.IResource; -import net.minecraft.util.BlockRenderLayer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.RenderTypeLookup; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; @@ -41,7 +42,8 @@ import net.minecraftforge.fml.ExtensionPoint; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.event.TickEvent; -import net.minecraftforge.fml.client.gui.GuiModList; +import net.minecraftforge.fml.client.gui.screen.ModListScreen; +import net.minecraftforge.fml.client.gui.widget.ModListWidget; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; @@ -67,6 +69,7 @@ public final class BaseMetalsClientProbe { private int state; private int stateTicks; private int renderedFrames; + private final java.util.Set renderedProjectiles = new java.util.HashSet<>(); public BaseMetalsClientProbe() { instance = this; @@ -76,11 +79,21 @@ public BaseMetalsClientProbe() { @SubscribeEvent public static void onWorldRendered(RenderWorldLastEvent event) { BaseMetalsClientProbe probe = instance; - if (probe != null && Boolean.getBoolean("basemetalsclientprobe.enabled") && probe.state == 1) { + if (probe != null && Boolean.getBoolean("basemetalsclientprobe.enabled") + && (probe.state == 1 || probe.state == 4)) { probe.renderedFrames++; } } + @SubscribeEvent + public static void onProjectileRendered(net.minecraftforge.client.event.RenderNameplateEvent event) { + BaseMetalsClientProbe probe = instance; + if (probe != null && probe.state == 4 + && event.getEntity() instanceof zone.moddev.mc.basemetals.entity.MaterialProjectile) { + probe.renderedProjectiles.add(event.getEntity().getEntityId()); + } + } + @SubscribeEvent public static void onClientTick(TickEvent.ClientTickEvent event) { BaseMetalsClientProbe probe = instance; @@ -112,6 +125,10 @@ private void tick() { } else if (state == 1 && minecraft.world != null && minecraft.player != null && renderedFrames >= 8 && stateTicks >= 100) { validateCreativeCrossbows(minecraft); + spawnProjectileRenderChecks(minecraft); + nextState(4); + } else if (state == 4 && renderedProjectiles.size() == 6 && stateTicks >= 40) { + LOGGER.info("BASEMETALS_PROJECTILE_RENDER_PROBE PASS rendered={}", renderedProjectiles.size()); writeMarker(); LOGGER.info("BASEMETALS_CLIENT_PROBE PASS frames={}", Integer.valueOf(renderedFrames)); minecraft.shutdown(); @@ -124,6 +141,33 @@ private void tick() { } } + private static void spawnProjectileRenderChecks(Minecraft minecraft) { + java.util.UUID playerId = minecraft.player.getUniqueID(); + minecraft.getIntegratedServer().execute(() -> { + net.minecraft.entity.player.ServerPlayerEntity player = minecraft.getIntegratedServer() + .getPlayerList().getPlayerByUUID(playerId); + net.minecraft.world.server.ServerWorld world = player.getServerWorld(); + net.minecraft.util.math.Vec3d look = player.getLookVec(); + int index = 0; + + for (String material : new String[] {"gold", "steel", "adamantine"}) { + for (boolean bolt : new boolean[] {false, true}) { + String name = material + (bolt ? "_bolt" : "_arrow"); + zone.moddev.mc.basemetals.entity.MaterialProjectile projectile = + new zone.moddev.mc.basemetals.entity.MaterialProjectile( + bolt ? zone.moddev.mc.basemetals.entity.ModEntities.CUSTOM_BOLT.get() + : zone.moddev.mc.basemetals.entity.ModEntities.CUSTOM_ARROW.get(), + world, player, new ItemStack(ModContent.item(name).get())); + net.minecraft.entity.Entity entity = projectile; + entity.setPosition(player.getPosX() + look.x * 3 + (index++ - 2.5) * 0.25, + player.getPosY() + player.getEyeHeight(), player.getPosZ() + look.z * 3); + entity.setNoGravity(true); + world.addEntity(projectile); + } + } + }); + } + private static void validateCreativeCrossbows(Minecraft minecraft) { require(minecraft.world.isRemote, "crossbow probe must run on the client"); require(minecraft.player.abilities.isCreativeMode, "crossbow probe needs a Creative player"); @@ -236,9 +280,23 @@ private static void validateClientContent(Minecraft minecraft) throws IOExceptio "mercury bucket registration"); for (FluidContent fluid : ModContent.fluids().values()) { require(fluid.bucket().get().getGroup() == ModTabs.ITEMS, "bucket creative group"); + require(RenderTypeLookup.canRenderInLayer(fluid.block().get().getDefaultState(), + RenderType.getTranslucent()), "molten block render layer"); + require(RenderTypeLookup.canRenderInLayer(fluid.source().get().getDefaultState(), + RenderType.getTranslucent()), "molten source render layer"); + require(RenderTypeLookup.canRenderInLayer(fluid.flowing().get().getDefaultState(), + RenderType.getTranslucent()), "molten flowing render layer"); + validateBucketModel(minecraft, fluid.bucket().get().getRegistryName().getPath()); + } + for (net.minecraft.block.Block block : ForgeRegistries.BLOCKS) { + if (!"basemetals".equals(block.getRegistryName().getNamespace())) continue; + if (block instanceof net.minecraft.block.DoorBlock + || block instanceof net.minecraft.block.TrapDoorBlock + || block instanceof net.minecraft.block.PaneBlock) { + require(RenderTypeLookup.canRenderInLayer(block.getDefaultState(), + RenderType.getCutoutMipped()), "transparent block render layer: " + block); + } } - validateBucketModel(minecraft, "mercury_bucket"); - validateBucketModel(minecraft, "tin_bucket"); validateOreModels(minecraft); minecraft.getResourceManager().getResource( new ResourceLocation("basemetals", "textures/item/adamantine_sword.png")); @@ -252,7 +310,7 @@ private static void validateConfigScreen(Minecraft minecraft) { String originalMode = BaseMetalsConfig.CONTENT_MODE.get(); ContentMode activeMode = BaseMetalsConfig.activeMode(); - GuiModList modsScreen = new GuiModList(parent); + ModListScreen modsScreen = new ModListScreen(parent); minecraft.displayGuiScreen(modsScreen); int baseMetalsIndex = -1; for (int index = 0; index < ModList.get().getMods().size(); index++) { @@ -324,8 +382,18 @@ private static void validateConfigScreen(Minecraft minecraft) { LOGGER.info("BASEMETALS_CONFIG_GUI_PROBE PASS entries=5 factories=2 mods_button=true cancel=true undo=true defaults=true save=true"); } - private static void selectMod(GuiModList screen, String modId) { - net.minecraftforge.fml.client.gui.ModSelection.select(screen, modId); + private static void selectMod(ModListScreen screen, String modId) { + ModListWidget list = (ModListWidget) screen.children().stream() + .filter(child -> child instanceof ModListWidget).findFirst().get(); + + for (ModListWidget.ModEntry entry : list.children()) { + if (entry.getInfo().getModId().equals(modId)) { + entry.mouseClicked(0, 0, 0); + return; + } + } + + throw new IllegalStateException("Missing mod " + modId); } private static void confirmation(Minecraft minecraft, boolean accepted) { @@ -369,7 +437,8 @@ private static void validateOreModels(Minecraft minecraft) throws IOException { } Block block = ModContent.blocksById().get(name).get(); - require(block.getRenderLayer() == BlockRenderLayer.CUTOUT_MIPPED, name + " is not cutout-mipped"); + require(RenderTypeLookup.canRenderInLayer(block.getDefaultState(), RenderType.getCutoutMipped()), + name + " is not cutout-mipped"); String overlay = "basemetals:block/ore_overlays/" + name; IBakedModel blockModel = minecraft.getBlockRendererDispatcher().getModelForState(block.getDefaultState()); @@ -398,18 +467,18 @@ private static void validateOreModel(IBakedModel model, Block block, String name boolean hasBase = false; boolean hasOverlay = false; for (BakedQuad quad : quads) { - String texture = quad.getSprite().getName().toString(); + String texture = quad.func_187508_a().getName().toString(); hasBase |= host.equals(texture); hasOverlay |= overlay.equals(texture); - require(!"missingno".equals(quad.getSprite().getName().getPath()), name + " missing texture"); + require(!"missingno".equals(quad.func_187508_a().getName().getPath()), name + " missing texture"); validateOreVertices(quad, overlay.equals(texture), name); if (overlay.equals(texture)) { boolean transparent = false; boolean visible = false; - for (int y = 0; y < quad.getSprite().getHeight(); y++) { - for (int x = 0; x < quad.getSprite().getWidth(); x++) { - if (quad.getSprite().isPixelTransparent(0, x, y)) transparent = true; + for (int y = 0; y < quad.func_187508_a().getHeight(); y++) { + for (int x = 0; x < quad.func_187508_a().getWidth(); x++) { + if (quad.func_187508_a().isPixelTransparent(0, x, y)) transparent = true; else visible = true; } } @@ -466,7 +535,7 @@ private static void validateBucketModel(Minecraft minecraft, String name) { require(!quads.isEmpty(), name + " has no rendered quads"); boolean hasTintedFluidLayer = false; for (BakedQuad quad : quads) { - require(!"missingno".equals(quad.getSprite().getName().getPath()), + require(!"missingno".equals(quad.func_187508_a().getName().getPath()), name + " uses the missing-texture sprite"); if (quad.hasTintIndex() && quad.getTintIndex() == 1) hasTintedFluidLayer = true; } @@ -488,7 +557,7 @@ private void writeMarker() throws IOException { values.setProperty("integrated_world_rendered", Boolean.toString(renderedFrames >= 8)); values.setProperty("rendered_frames", Integer.toString(renderedFrames)); try (FileOutputStream output = new FileOutputStream(new File("client-smoke-pass.properties"))) { - values.store(output, "Base Metals Forge 1.14.4 packaged-client gate"); + values.store(output, "Base Metals Forge 1.15.2 packaged-client gate"); } } diff --git a/src/clientIntegrationTest/resources/META-INF/mods.toml b/src/clientIntegrationTest/resources/META-INF/mods.toml index a45d89585..2322fc845 100644 --- a/src/clientIntegrationTest/resources/META-INF/mods.toml +++ b/src/clientIntegrationTest/resources/META-INF/mods.toml @@ -1,30 +1,30 @@ modLoader="javafml" -loaderVersion="[28,)" +loaderVersion="[31,)" license="LGPL-2.1" [[mods]] modId="basemetalsclientprobe" version="1" displayName="Base Metals Client Probe" -description='''Build-only packaged-client checks for Base Metals 1.14.4.''' +description='''Build-only packaged-client checks for Base Metals 1.15.2.''' [[dependencies.basemetalsclientprobe]] modId="basemetals" mandatory=true -versionRange="[3.0.1.114041]" +versionRange="[3.0.1.115021]" ordering="AFTER" side="CLIENT" [[dependencies.basemetalsclientprobe]] modId="orespawn" mandatory=true -versionRange="[4.1.0.114041,5.0.0)" +versionRange="[4.1.0.115021,5.0.0)" ordering="AFTER" side="CLIENT" [[dependencies.basemetalsclientprobe]] modId="minecraft" mandatory=true -versionRange="[1.14.4]" +versionRange="[1.15.2]" ordering="NONE" side="CLIENT" diff --git a/src/clientIntegrationTest/resources/pack.mcmeta b/src/clientIntegrationTest/resources/pack.mcmeta index 95952d0e1..464cfce05 100644 --- a/src/clientIntegrationTest/resources/pack.mcmeta +++ b/src/clientIntegrationTest/resources/pack.mcmeta @@ -1,8 +1,8 @@ { "pack": { "description": "Base Metals packaged-client qualification fixture", - "forge:resource_pack_format": 4, - "forge:data_pack_format": 4, - "pack_format": 4 + "forge:resource_pack_format": 5, + "forge:data_pack_format": 5, + "pack_format": 5 } } diff --git a/src/generated/resources/data/basemetals/registry_manifest.json b/src/generated/resources/data/basemetals/registry_manifest.json index 82e0cd332..1c10643e2 100644 --- a/src/generated/resources/data/basemetals/registry_manifest.json +++ b/src/generated/resources/data/basemetals/registry_manifest.json @@ -1,6 +1,6 @@ { "format": 1, - "source": "Base Metals 1.14.4 catalogue", + "source": "Base Metals 1.15.2 catalogue", "blocks": [ "basemetals:adamantine_block", "basemetals:adamantine_plate", diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsRuntimeProbe.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsRuntimeProbe.java index bea91c78b..d02d92a17 100644 --- a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsRuntimeProbe.java +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsRuntimeProbe.java @@ -133,7 +133,7 @@ private void serverStarted(FMLServerStartedEvent event) { MinecraftServer server = event.getServer(); if ("login".equals(System.getProperty("basemetalsprobe.mode"))) { try { - int count = ContentModeChecks.run(server) + Native114Checks.run(server); + int count = ContentModeChecks.run(server) + Native115Checks.run(server); LOGGER.info("BASEMETALS_CONTENT_MODE_PROBE PASS mode={} checks={}", zone.moddev.mc.basemetals.config.BaseMetalsConfig.activeMode().serializedName(), count); } catch (Exception failure) { @@ -214,7 +214,7 @@ private void verifyLegacyFixture(MinecraftServer server, Path root) throws IOExc int checkedPlayerItems = 0; boolean source110 = Files.isRegularFile(root.resolve("BASEMETALS_1_10_FIXTURE_COMPLETE.txt")); - String upgradeMarker = source110 ? "BASEMETALS_1_10_TO_1_14_UPGRADE" : "BASEMETALS_1_12_TO_1_14_UPGRADE"; + String upgradeMarker = source110 ? "BASEMETALS_1_10_TO_1_15_UPGRADE" : "BASEMETALS_1_12_TO_1_15_UPGRADE"; if (!source110 && !Files.isRegularFile(root.resolve("BASEMETALS_1_12_FIXTURE_COMPLETE.txt"))) { failures.add("missing legacy fixture completion marker"); } @@ -503,7 +503,7 @@ private static String currentItemId(String legacy) { private static void writeFixtureResult(Path root, String result) { try { - Files.write(root.resolve("BASEMETALS_LEGACY_TO_1_14_UPGRADE_RESULT.txt"), + Files.write(root.resolve("BASEMETALS_LEGACY_TO_1_15_UPGRADE_RESULT.txt"), (result + System.lineSeparator()).getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } catch (IOException exception) { @@ -617,6 +617,20 @@ private void runChecks(MinecraftServer server) throws Exception { Object providerStatus = Class.forName("zone.moddev.mc.orespawn.api.OreSpawnApi") .getMethod("getProviderStatus", String.class).invoke(null, BaseMetals.MOD_ID); check("ACTIVE".equals(String.valueOf(providerStatus)), "OreSpawn provider active"); + Class oreSpawnApi = Class.forName("zone.moddev.mc.orespawn.api.OreSpawnApi"); + check(Boolean.TRUE.equals(oreSpawnApi.getMethod("isOreTakeoverActive", String.class) + .invoke(null, BaseMetals.MOD_ID)), "OreSpawn owns Base Metals ore placement"); + java.util.Optional activeProfile = (java.util.Optional) oreSpawnApi + .getMethod("getActiveProfile", MinecraftServer.class).invoke(null, server); + check(activeProfile.isPresent(), "OreSpawn active profile is available"); + java.util.Set oreIds = (java.util.Set) activeProfile.get().getClass() + .getMethod("oreIds").invoke(activeProfile.get()); + check(oreIds.stream().filter(value -> value.toString().startsWith("basemetals:")) + .count() == 11, "exactly eleven Base Metals rules, including with Mineralogy"); + if (net.minecraftforge.fml.ModList.get().isLoaded("mineralogy")) { + check("ACTIVE".equals(String.valueOf(oreSpawnApi.getMethod("getProviderStatus", String.class) + .invoke(null, "mineralogy"))), "Mineralogy provider active"); + } check(classMissing("zone.moddev.mc.basemetals.worldgen.BaseMetalsOreGenerator"), "native world generator absent"); @@ -642,7 +656,7 @@ private void runChecks(MinecraftServer server) throws Exception { testCrossbowContract(); checks += GameplayRegressionChecks.run(server); checks += ContentModeChecks.run(server); - checks += Native114Checks.run(server); + checks += Native115Checks.run(server); } private void testProjectilePersistence(ServerWorld world) { diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native114Checks.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native115Checks.java similarity index 91% rename from src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native114Checks.java rename to src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native115Checks.java index d9e1d89a4..139e16b05 100644 --- a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native114Checks.java +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native115Checks.java @@ -28,9 +28,9 @@ import zone.moddev.mc.basemetals.content.ModContent; import zone.moddev.mc.basemetals.content.RegistryHandle; -/** Covers the game systems that changed between Minecraft 1.13 and 1.14. */ -final class Native114Checks { - private Native114Checks() {} +/** Checks native loot, molten-fluid attributes and village smith trades. */ +final class Native115Checks { + private Native115Checks() {} static int run(MinecraftServer server) { ServerWorld world = server.getWorld(DimensionType.OVERWORLD); @@ -78,17 +78,17 @@ static int run(MinecraftServer server) { for (VillagerProfession profession : new VillagerProfession[] { VillagerProfession.ARMORER, VillagerProfession.TOOLSMITH, VillagerProfession.WEAPONSMITH}) { int baseMetalsOffers = 0; - for (Map.Entry level : VillagerTrades.field_221239_a.get(profession).entrySet()) { + for (Map.Entry level : VillagerTrades.VILLAGER_DEFAULT_TRADES.get(profession).entrySet()) { for (VillagerTrades.ITrade factory : level.getValue()) { if (!factory.getClass().getName().startsWith("zone.moddev.mc.basemetals.")) continue; MerchantOffer offer = factory.getOffer(null, new Random(1)); if (offer == null) continue; baseMetalsOffers++; - require(offer.func_222218_a().getItem() == Items.EMERALD - || offer.func_222206_f().getItem() == Items.EMERALD, "smith price currency"); - require(ContentPolicy.active().allows(offer.func_222206_f().getItem().getRegistryName().toString()), + require(offer.getBuyingStackFirst().getItem() == Items.EMERALD + || offer.getSellingStack().getItem() == Items.EMERALD, "smith price currency"); + require(ContentPolicy.active().allows(offer.getSellingStack().getItem().getRegistryName().toString()), "smith bypasses content policy"); - require(offer.func_222214_i() == 12 && offer.func_222210_n() > 0, "smith restocking/experience"); + require(offer.func_222214_i() == 12 && offer.getGivenExp() > 0, "smith restocking/experience"); checks += 3; } } @@ -119,6 +119,6 @@ private static void assertDrop(ServerWorld world, BlockState state, String item, } private static void require(boolean condition, String message) { - if (!condition) throw new IllegalStateException("Native 1.14 check failed: " + message); + if (!condition) throw new IllegalStateException("Native 1.15 check failed: " + message); } } diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/OrePlacementChecks.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/OrePlacementChecks.java index 3a1857b8c..3ccb29f5f 100644 --- a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/OrePlacementChecks.java +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/OrePlacementChecks.java @@ -40,6 +40,7 @@ static int run(MinecraftServer server) throws Exception { ServerWorld world = server.getWorld(dimension); String dimensionId = DimensionType.getKey(dimension).toString(); Map counts = new LinkedHashMap<>(); + int rockCount = 0; int centerX = dimension == DimensionType.OVERWORLD ? world.getSpawnPoint().getX() >> 4 : 0; int centerZ = dimension == DimensionType.OVERWORLD ? world.getSpawnPoint().getZ() >> 4 : 0; @@ -50,6 +51,8 @@ static int run(MinecraftServer server) throws Exception { if (section == null || section.isEmpty()) continue; for (int x = 0; x < 16; x++) for (int y = 0; y < 16; y++) for (int z = 0; z < 16; z++) { Block block = section.getBlockState(x, y, z).getBlock(); + if ("mineralogy".equals(block.getRegistryName().getNamespace()) + && !block.getRegistryName().getPath().endsWith("_ore")) rockCount++; if (!rules.containsKey(block)) { if (block == ModContent.blocksById().get("antimony_ore").get() || block == ModContent.blocksById().get("bismuth_ore").get()) { @@ -77,6 +80,10 @@ static int run(MinecraftServer server) throws Exception { } if (counts.isEmpty()) throw new IllegalStateException("No Base Metals ore in " + dimensionId + " sample"); + if (dimension == DimensionType.OVERWORLD && net.minecraftforge.fml.ModList.get().isLoaded("mineralogy")) { + if (rockCount == 0) throw new IllegalStateException("Mineralogy strata are absent from the ore sample"); + LogManager.getLogger("basemetalsprobe").info("BASEMETALS_MINERALOGY_COEXISTENCE PASS rocks={}", rockCount); + } LogManager.getLogger("basemetalsprobe").info("BASEMETALS_ORE_SAMPLE PASS dimension={} chunks=25 counts={}", dimensionId, counts); } diff --git a/src/integrationTest/resources/META-INF/mods.toml b/src/integrationTest/resources/META-INF/mods.toml index 3c79f44f5..acf8edc78 100644 --- a/src/integrationTest/resources/META-INF/mods.toml +++ b/src/integrationTest/resources/META-INF/mods.toml @@ -1,30 +1,30 @@ modLoader="javafml" -loaderVersion="[28,)" +loaderVersion="[31,)" license="LGPL-2.1" [[mods]] modId="basemetalsprobe" version="1" displayName="Base Metals Runtime Probe" -description='''Build-only lifecycle checks for Base Metals 1.14.4.''' +description='''Build-only lifecycle checks for Base Metals 1.15.2.''' [[dependencies.basemetalsprobe]] modId="basemetals" mandatory=true -versionRange="[3.0.1.114041]" +versionRange="[3.0.1.115021]" ordering="AFTER" side="BOTH" [[dependencies.basemetalsprobe]] modId="orespawn" mandatory=true -versionRange="[4.1.0.114041,5.0.0)" +versionRange="[4.1.0.115021,5.0.0)" ordering="AFTER" side="BOTH" [[dependencies.basemetalsprobe]] modId="minecraft" mandatory=true -versionRange="[1.14.4]" +versionRange="[1.15.2]" ordering="NONE" side="BOTH" diff --git a/src/integrationTest/resources/pack.mcmeta b/src/integrationTest/resources/pack.mcmeta index aec965e53..af21bb926 100644 --- a/src/integrationTest/resources/pack.mcmeta +++ b/src/integrationTest/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "description": "Base Metals 1.14.4 build-only runtime probe", - "pack_format": 4 + "description": "Base Metals 1.15.2 build-only runtime probe", + "pack_format": 5 } } diff --git a/src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java b/src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java index 4e7611d7f..f1da29550 100644 --- a/src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java +++ b/src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java @@ -2,13 +2,20 @@ import zone.moddev.mc.basemetals.content.FluidContent; import zone.moddev.mc.basemetals.content.ModContent; -import zone.moddev.mc.basemetals.entity.MaterialProjectile; +import zone.moddev.mc.basemetals.entity.ModEntities; import net.minecraftforge.client.event.ColorHandlerEvent; -import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.DeferredWorkQueue; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.ExtensionPoint; import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.RenderTypeLookup; +import net.minecraft.block.Block; +import net.minecraft.block.DoorBlock; +import net.minecraft.block.PaneBlock; +import net.minecraft.block.TrapDoorBlock; import zone.moddev.mc.orespawn.api.client.WorldSettingsExtensionRegistry; public final class ClientSetup { @@ -20,8 +27,31 @@ public static void register() { WorldSettingsExtensionRegistry.registerConfigScreen("basemetals", BaseMetalsConfigScreen::new); net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext.get().getModEventBus() .addListener(ClientSetup::registerBucketColours); - RenderingRegistry.registerEntityRenderingHandler(MaterialProjectile.class, - manager -> new MaterialProjectileRenderer(manager)); + net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext.get().getModEventBus() + .addListener(ClientSetup::setupRendering); + } + + private static void setupRendering(FMLClientSetupEvent event) { + RenderingRegistry.registerEntityRenderingHandler(ModEntities.CUSTOM_ARROW.get(), MaterialProjectileRenderer::new); + RenderingRegistry.registerEntityRenderingHandler(ModEntities.CUSTOM_BOLT.get(), MaterialProjectileRenderer::new); + + DeferredWorkQueue.runLater(ClientSetup::registerRenderLayers); + } + + private static void registerRenderLayers() { + ModContent.blocksById().forEach((name, handle) -> { + Block block = handle.get(); + if (name.endsWith("_ore") || block instanceof DoorBlock + || block instanceof TrapDoorBlock || block instanceof PaneBlock) { + RenderTypeLookup.setRenderLayer(block, RenderType.getCutoutMipped()); + } + }); + + for (FluidContent fluid : ModContent.fluids().values()) { + RenderTypeLookup.setRenderLayer(fluid.source().get(), RenderType.getTranslucent()); + RenderTypeLookup.setRenderLayer(fluid.flowing().get(), RenderType.getTranslucent()); + RenderTypeLookup.setRenderLayer(fluid.block().get(), RenderType.getTranslucent()); + } } private static void registerBucketColours(ColorHandlerEvent.Item event) { diff --git a/src/main/java/zone/moddev/mc/basemetals/client/MaterialProjectileRenderer.java b/src/main/java/zone/moddev/mc/basemetals/client/MaterialProjectileRenderer.java index d9aa3a7e2..bd42c3ff1 100644 --- a/src/main/java/zone/moddev/mc/basemetals/client/MaterialProjectileRenderer.java +++ b/src/main/java/zone/moddev/mc/basemetals/client/MaterialProjectileRenderer.java @@ -15,7 +15,7 @@ public MaterialProjectileRenderer(EntityRendererManager manager) { } @Override - protected ResourceLocation getEntityTexture(MaterialProjectile projectile) { + public ResourceLocation getEntityTexture(MaterialProjectile projectile) { return ARROW_TEXTURE; } } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/CrackhammerItem.java b/src/main/java/zone/moddev/mc/basemetals/content/CrackhammerItem.java index b78e66545..ca792914d 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/CrackhammerItem.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/CrackhammerItem.java @@ -113,7 +113,7 @@ private static void spawnOutputs(World world, ItemEntity source, ItemStack resul ItemStack output = result.copy(); output.setCount(Math.min(output.getMaxStackSize(), remaining)); remaining -= output.getCount(); - ItemEntity crushed = new ItemEntity(world, source.posX, source.posY, source.posZ, output); + ItemEntity crushed = new ItemEntity(world, source.getPosX(), source.getPosY(), source.getPosZ(), output); crushed.setDefaultPickupDelay(); world.addEntity(crushed); } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MaterialItems.java b/src/main/java/zone/moddev/mc/basemetals/content/MaterialItems.java index fc50d5b61..e7db5b708 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MaterialItems.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MaterialItems.java @@ -252,7 +252,7 @@ public void onPlayerStoppedUsing(ItemStack bow, World world, LivingEntity user, if (infiniteShot) projectile.pickupStatus = AbstractArrowEntity.PickupStatus.CREATIVE_ONLY; world.addEntity(projectile); } - world.playSound(null, player.posX, player.posY, player.posZ, + world.playSound(null, player.getPosX(), player.getPosY(), player.getPosZ(), SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.PLAYERS, 1.0F, 1.0F / (random.nextFloat() * 0.4F + 1.2F) + power * 0.5F); if (!infiniteShot && !player.abilities.isCreativeMode) { diff --git a/src/main/java/zone/moddev/mc/basemetals/content/ModContent.java b/src/main/java/zone/moddev/mc/basemetals/content/ModContent.java index fd881cc06..63c694baf 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/ModContent.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/ModContent.java @@ -36,7 +36,6 @@ import net.minecraft.item.Item; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemGroup; -import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.registry.Registry; import net.minecraftforge.common.ToolType; @@ -531,8 +530,6 @@ private static class HarvestBlock extends Block { private static class HarvestOre extends HarvestBlock { HarvestOre(Properties properties, int level) { super(properties, level); } - // Cutout rendering leaves the transparent parts of the ore overlay clear. - @Override public BlockRenderLayer getRenderLayer() { return BlockRenderLayer.CUTOUT_MIPPED; } } private static class HarvestPane extends PaneBlock { private final int level; diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java b/src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java index 5fc2d888b..f59aaf751 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java @@ -7,13 +7,10 @@ import net.minecraft.fluid.IFluidState; import net.minecraft.item.Item; import net.minecraft.state.StateContainer; -import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IWorld; import net.minecraft.world.IWorldReader; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fluids.FluidAttributes; import net.minecraft.util.ResourceLocation; @@ -37,8 +34,6 @@ protected FluidAttributes createAttributes() { @Override public Fluid getStillFluid() { return content().source().get(); } @Override public Item getFilledBucket() { return content().bucket().get(); } - @Override @OnlyIn(Dist.CLIENT) - public BlockRenderLayer getRenderLayer() { return BlockRenderLayer.TRANSLUCENT; } @Override protected boolean canSourcesMultiply() { return false; } @Override protected void beforeReplacingBlock(IWorld world, BlockPos pos, BlockState state) { net.minecraft.block.Block.spawnDrops(state, world.getWorld(), pos); @@ -50,7 +45,7 @@ protected FluidAttributes createAttributes() { @Override public boolean isEquivalentTo(Fluid fluid) { return fluid == content().source().get() || fluid == content().flowing().get(); } - @Override protected boolean func_215665_a(IFluidState state, net.minecraft.world.IBlockReader world, + @Override protected boolean canDisplace(IFluidState state, net.minecraft.world.IBlockReader world, BlockPos pos, Fluid fluid, Direction direction) { return direction == Direction.DOWN && !fluid.isEquivalentTo(this); } diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json index adb448d57..94cc3aafb 100644 --- a/src/main/resources/META-INF/coremods.json +++ b/src/main/resources/META-INF/coremods.json @@ -1,3 +1,3 @@ { - "basemetals_114_compatibility": "coremods/basemetals_114_compatibility.js" + "basemetals_115_compatibility": "coremods/basemetals_115_compatibility.js" } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 72fb3fa98..57b8054ca 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,11 +1,11 @@ modLoader="javafml" -loaderVersion="[28,)" +loaderVersion="[31,)" license="LGPL-2.1" issueTrackerURL="https://github.com/SkyBlade1978/BaseMetals/issues" [[mods]] modId="basemetals" -version="3.0.1.114041" +version="3.0.1.115021" displayName="Base Metals" displayURL="https://www.curseforge.com/minecraft/mc-mods/base-metals" authors="Cyanobacterium, jriwanek, dshadowwolf, GetDizzy611, SkyBlade1978, the MMD Team" @@ -14,20 +14,20 @@ description='''Adds real and fantasy metals, alloys, tools and armour. Crush ore [[dependencies.basemetals]] modId="orespawn" mandatory=true -versionRange="[4.1.0.114041,5.0.0)" +versionRange="[4.1.0.115021,5.0.0)" ordering="AFTER" side="BOTH" [[dependencies.basemetals]] modId="forge" mandatory=true -versionRange="[28,)" +versionRange="[31,)" ordering="NONE" side="BOTH" [[dependencies.basemetals]] modId="minecraft" mandatory=true -versionRange="[1.14.4]" +versionRange="[1.15.2]" ordering="NONE" side="BOTH" diff --git a/src/main/resources/coremods/basemetals_114_compatibility.js b/src/main/resources/coremods/basemetals_115_compatibility.js similarity index 100% rename from src/main/resources/coremods/basemetals_114_compatibility.js rename to src/main/resources/coremods/basemetals_115_compatibility.js diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index bd4b82fe4..0289f865d 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { "description": "Base Metals resources", - "pack_format": 4 + "pack_format": 5 } } diff --git a/src/test/java/zone/moddev/mc/basemetals/Native115ContractTest.java b/src/test/java/zone/moddev/mc/basemetals/Native115ContractTest.java new file mode 100644 index 000000000..21d0a3d05 --- /dev/null +++ b/src/test/java/zone/moddev/mc/basemetals/Native115ContractTest.java @@ -0,0 +1,59 @@ +package zone.moddev.mc.basemetals; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Properties; +import org.junit.jupiter.api.Test; + +class Native115ContractTest { + @Test + void registersBothProjectileTypesAndNativeRenderLayers() throws Exception { + String setup = source("src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java"); + assertTrue(setup.contains("ModEntities.CUSTOM_ARROW.get()")); + assertTrue(setup.contains("ModEntities.CUSTOM_BOLT.get()")); + assertTrue(setup.contains("RenderTypeLookup.setRenderLayer")); + assertTrue(setup.contains("RenderType.getCutoutMipped()")); + assertTrue(setup.contains("RenderType.getTranslucent()")); + assertFalse(setup.contains("registerEntityRenderingHandler(MaterialProjectile.class")); + assertFalse(source("src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java") + .contains("BlockRenderLayer")); + assertFalse(source("src/main/java/zone/moddev/mc/basemetals/content/ModContent.java") + .contains("BlockRenderLayer")); + } + + @Test + void pinsThePublishedOreSpawnRelease() throws Exception { + Properties properties = new Properties(); + + try (InputStream input = Files.newInputStream(Paths.get("gradle.properties"))) { + properties.load(input); + } + + assertEquals("release", properties.getProperty("orespawn_dependency_mode")); + assertEquals("4.1.0.115021", properties.getProperty("orespawn_version")); + assertEquals("245586", properties.getProperty("orespawn_curse_project_id")); + assertEquals("9073591", properties.getProperty("orespawn_curse_file_id")); + assertEquals("F7C9A110E834EC3F73D55C20E8F52EEA1CF48C4E3ACCFBE8FCEFB60E78ABE387", + properties.getProperty("orespawn_sha256")); + assertTrue(source("build.gradle").contains("curse.maven:${orespawnModule}:${orespawn_curse_file_id}")); + } + + @Test + void keepsTheLocalCandidatePublicationGuard() throws Exception { + assertTrue(source("gradle/stage-orespawn-release.sh") + .contains("Publication is blocked")); + String artifacts = source("gradle/release/artifacts.gradle"); + assertTrue(artifacts.contains("PublishToMavenLocal")); + assertTrue(artifacts.contains("Publication is blocked until the public OreSpawn release is pinned")); + } + + private static String source(String path) throws Exception { + return new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); + } +} diff --git a/src/test/java/zone/moddev/mc/basemetals/data/ResourceIntegrityTest.java b/src/test/java/zone/moddev/mc/basemetals/data/ResourceIntegrityTest.java index c7f01a56f..d77529b94 100644 --- a/src/test/java/zone/moddev/mc/basemetals/data/ResourceIntegrityTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/data/ResourceIntegrityTest.java @@ -34,7 +34,7 @@ import com.google.gson.JsonParser; import org.junit.jupiter.api.Test; -/** Resource contract for the flattened Minecraft 1.14.4 data pack. */ +/** Resource contract for the flattened Minecraft 1.15.2 data pack. */ class ResourceIntegrityTest { private static final Path MAIN = Paths.get("src", "main", "resources"); private static final Path GENERATED = Paths.get("src", "generated", "resources"); @@ -60,7 +60,7 @@ void manifestHasModelsAndTranslationsForEveryRegisteredId() throws Exception { Set blocks = strings(manifest.getAsJsonArray("blocks")); Set items = strings(manifest.getAsJsonArray("items")); Set fluids = strings(manifest.getAsJsonArray("fluids")); - assertEquals("Base Metals 1.14.4 catalogue", manifest.get("source").getAsString()); + assertEquals("Base Metals 1.15.2 catalogue", manifest.get("source").getAsString()); assertEquals(360, blocks.size()); assertEquals(1115, items.size()); assertEquals(72, fluids.size()); diff --git a/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldSourceTest.java b/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldSourceTest.java index 265a35917..65a87aeb3 100644 --- a/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldSourceTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldSourceTest.java @@ -48,7 +48,7 @@ void removesOnlyTheRetiredVanillaProfessionIndex() { CompoundNBT aliased = professionSnapshot("minecraft:smith"); ListNBT aliases = new ListNBT(); - aliases.add(new StringNBT("anothermod:smith")); + aliases.add(StringNBT.valueOf("anothermod:smith")); aliased.getCompound("fml").getCompound("Registries") .getCompound("minecraft:villagerprofessions").put("aliases", aliases); assertTrue(!LegacyWorldDataHook.removeRetiredVanillaProfessionRegistry(aliased)); @@ -97,7 +97,7 @@ void normalizesRegistryPathsThatWereLegalInMinecraft110() { @Test void targetsNative114ChunkLoadingWithoutTheOldLeavesPatch() throws IOException { String coremod = new String(Files.readAllBytes(Paths.get( - "src/main/resources/coremods/basemetals_114_compatibility.js")), "UTF-8"); + "src/main/resources/coremods/basemetals_115_compatibility.js")), "UTF-8"); assertTrue(coremod.contains("net.minecraft.world.chunk.storage.ChunkLoader")); assertTrue(coremod.contains("Ljava/util/function/Supplier;")); assertTrue(!coremod.contains("leaves_fixer")); diff --git a/tools/generate_114_resources.js b/tools/generate_115_resources.js similarity index 97% rename from tools/generate_114_resources.js rename to tools/generate_115_resources.js index 5e1383748..800994a07 100644 --- a/tools/generate_114_resources.js +++ b/tools/generate_115_resources.js @@ -1,7 +1,7 @@ /* - * Converts the catalogue-generated resources to Minecraft 1.14 formats. + * Converts the catalogue-generated resources to Minecraft 1.15 formats. * Removes unsupported recipes and integrations, and converts block states, - * item models and tags to the names and formats used by Forge 28. + * item models and tags to the names and formats used by Forge 31. */ 'use strict'; @@ -85,7 +85,7 @@ for (const file of filesUnder(path.join(generated, 'data', 'basemetals', 'recipe const manifestFile = path.join(generated, 'data', 'basemetals', 'registry_manifest.json'); const manifest = JSON.parse(fs.readFileSync(manifestFile, 'utf8')); -manifest.source = 'Base Metals 1.14.4 catalogue'; +manifest.source = 'Base Metals 1.15.2 catalogue'; manifest.loot_modifier_serializers = []; manifest.new_loot_modifier_serializers = []; for (const key of ['recipe_serializers', 'new_recipe_serializers']) { @@ -144,7 +144,7 @@ writeBase64(path.join(generated, 'assets', 'basemetals', 'textures', 'item', 'bu 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAA4SURBVDhPY2AYnuA/DoCuDgOga8AF0PWhAHTF6ABdPU5AtkZcgGSD0BWj80kGFBtAMRh4FwxeAAB9Pod56G8eMAAAAABJRU5ErkJggg=='); // Vanilla copper and the modern Nether/Caves & Cliffs plants do not exist in -// 1.14.4. Keep Base Metals copper in the common tags and retain only plants +// 1.15.2. Keep Base Metals copper in the common tags and retain only plants // present in the target registry. for (const relative of [ 'data/forge/tags/blocks/ores/copper.json', @@ -200,7 +200,7 @@ if (!crushable.values.includes('minecraft:gravel')) { } writeJson(crushableFile, crushable); -// Forge 28 did not provide a forge:gravel item tag. Keep the historical +// Forge 31 did not provide a forge:gravel item tag. Keep the historical // gravel-to-sand crushing recipe, but name the vanilla item directly. const gravelCrushingFile = path.join(generated, 'data', 'basemetals', 'recipes', 'gravel_crushing.json'); @@ -218,7 +218,7 @@ for (const file of filesUnder(legacyChests, '.json')) { const target = path.join(targetChests, path.basename(file)); const table = JSON.parse(fs.readFileSync(file, 'utf8')); const tableName = path.basename(file, '.json'); - // Forge 28 requires every loot pool to have a stable, unique name. + // Forge 31 requires every loot pool to have a stable, unique name. table.pools.forEach((pool, index) => { pool.name = `basemetals_${tableName}_${index}`; for (const entry of pool.entries) { @@ -430,4 +430,4 @@ for (const file of filesUnder(path.join(generated, 'assets', 'basemetals', 'lang writeJson(file, language); } -console.log('Generated Minecraft 1.14.4-compatible Base Metals resources.'); +console.log('Generated Minecraft 1.15.2-compatible Base Metals resources.'); diff --git a/tools/test_content_modes.js b/tools/test_content_modes.js index fa5b26371..c91f9939f 100644 --- a/tools/test_content_modes.js +++ b/tools/test_content_modes.js @@ -11,8 +11,8 @@ if (path.dirname(root) !== build || path.basename(root) !== 'content-mode-tests' throw new Error(`Content-mode profiles must be inside the build directory: ${root}`); } -const version = '1.14.4'; -const forge = '28.2.26'; +const version = '1.15.2'; +const forge = '31.2.57'; const forgeMetadata = JSON.parse(fs.readFileSync(path.join(clientRuntime, 'versions', `${version}-forge-${forge}`, `${version}-forge-${forge}.json`))); const vanillaMetadata = JSON.parse(fs.readFileSync(path.join(clientRuntime, 'versions', version, `${version}.json`))); const libraries = new Map(); @@ -29,8 +29,9 @@ for (const metadata of [vanillaMetadata, forgeMetadata]) { } } const classpath = [...libraries.values(), path.join(clientRuntime, 'versions', version, `${version}.jar`)].join(path.delimiter); -const versionNatives = path.join(clientRuntime, 'natives', `forge-${forge}`); -const natives = fs.existsSync(versionNatives) ? versionNatives : path.join(clientRuntime, 'natives'); +const versionNatives = [path.join(clientRuntime, 'natives', `${version}-forge-${forge}`), + path.join(clientRuntime, 'natives', `forge-${forge}`)].find(directory => fs.existsSync(directory)); +const natives = versionNatives || path.join(clientRuntime, 'natives'); const sleep = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds)); function profile(directory, client, mode, oldConfig) { diff --git a/tools/validation/legacy-capture/README.md b/tools/validation/legacy-capture/README.md index 0ae51efa0..515c7085d 100644 --- a/tools/validation/legacy-capture/README.md +++ b/tools/validation/legacy-capture/README.md @@ -12,7 +12,7 @@ equipment and playerdata checks. The first run saves a registry manifest and stops the server. A second run checks that the original Minecraft version can reload the fixture. Only then -should a copy be opened in Minecraft 1.14.4. +should a copy be opened in Minecraft 1.15.2. ## Build @@ -41,7 +41,7 @@ Keep that specification under ignored build output. It supplies these paths: - `output`: a new, empty directory for disposable test servers and results; - `java8`: the Java 8 executable; -- `runtime110` and `runtime114`: installed Forge server directories, including +- `runtime110` and `runtime115`: installed Forge server directories, including their launcher, Minecraft server JAR and `libraries` directory; - `captureJar`, `modJar` and `probeJar`: the fixture generator, packaged Base Metals candidate and packaged runtime probe; @@ -68,7 +68,7 @@ Minecraft's player-advancement manager before checking it again on reload. `src/integrationTest/resources/upgrade/advancement_progress_113.json` covers an armour achievement and both ingot- and rod-based recipe discovery. -The 1.14 probe checks block identities and saved orientation/state, item +The 1.15 probe checks block identities and saved orientation/state, item identity and count, durability, names, enchantments, proof NBT, worn armour, playerdata and converted fluid buckets. Connected faces, powered states and flowing-fluid levels can change normally when Minecraft ticks the world; diff --git a/tools/validation/test_legacy_worlds.js b/tools/validation/test_legacy_worlds.js index 6b048a580..93775ce7d 100644 --- a/tools/validation/test_legacy_worlds.js +++ b/tools/validation/test_legacy_worlds.js @@ -37,7 +37,7 @@ function treeDigest(directory) { function prepare(directory, runtime, launcher, mods) { if (fs.existsSync(directory)) throw new Error('Refusing to overwrite ' + directory); fs.mkdirSync(path.join(directory, 'mods'), { recursive: true }); - for (const file of [launcher, 'minecraft_server.' + (phase === 'capture' ? captureVersion : '1.14.4') + '.jar']) { + for (const file of [launcher, 'minecraft_server.' + (phase === 'capture' ? captureVersion : '1.15.2') + '.jar']) { fs.copyFileSync(path.join(runtime, file), path.join(directory, file)); } fs.cpSync(path.join(runtime, 'libraries'), path.join(directory, 'libraries'), { recursive: true }); @@ -99,8 +99,8 @@ async function run(directory, launcher, label, marker, properties = []) { } else { const source = profile.world || path.join(root, 'capture', profile.id, 'world'); const before = treeDigest(source); - const launcher = 'forge-1.14.4-28.2.26.jar'; - prepare(directory, spec.runtime114, launcher, [spec.modJar, spec.probeJar, spec.oreSpawn]); + const launcher = 'forge-1.15.2-31.2.57.jar'; + prepare(directory, spec.runtime115, launcher, [spec.modJar, spec.probeJar, spec.oreSpawn]); fs.cpSync(source, path.join(directory, 'world'), { recursive: true }); if (profile.advancementFixture) { const fixture = JSON.parse(fs.readFileSync(profile.advancementFixture, 'utf8'));