From 0e6ca87b8d3bfb540923e5e554b10df11450d8d3 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 20 Oct 2026 13:21:03 +0100 Subject: [PATCH 1/2] Keep existing provider settings --- .github/workflows/ci.yml | 6 +- CHANGELOG.txt | 9 ++ README.md | 2 +- build.gradle | 8 +- docs/AGENTS.md | 16 ---- docs/MIGRATION.md | 6 ++ docs/README.md | 4 +- docs/VERSIONS.md | 2 +- gradle.properties | 2 +- gradle/ide/eclipse.gradle | 4 +- gradle/release/artifacts.gradle | 15 ++- .../orespawn/compat/LegacyOs3Bridge.java | 19 +++- src/main/java/cyano/orespawn/OreSpawn.java | 2 +- .../zone/moddev/mc/orespawn/OreSpawn.java | 2 +- .../documentation/DocumentationExporter.java | 1 - .../LegacyMineralogyProfileMigration.java | 2 +- .../worldgen/LegacyOs3ProfileMigration.java | 2 +- .../orespawn/compat/LegacyOs3BridgeTest.java | 94 +++++++++++++++++++ .../client/OreSpawnModDirectoryModelTest.java | 2 +- .../DocumentationExporterTest.java | 4 +- 20 files changed, 152 insertions(+), 50 deletions(-) delete mode 100644 docs/AGENTS.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b541302..4eed68e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,9 +126,9 @@ jobs: if-no-files-found: error retention-days: 30 path: | - build/libs/OreSpawn-4.1.0.110021.jar - build/libs/OreSpawn-4.1.0.110021-sources.jar - build/libs/OreSpawn-4.1.0.110021-javadoc.jar + build/libs/OreSpawn-4.1.1.110021.jar + build/libs/OreSpawn-4.1.1.110021-sources.jar + build/libs/OreSpawn-4.1.1.110021-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 981ddf3f..cd32a97f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,12 @@ +Version 4.1.1.110021 + +* Keep existing provider settings when importing older OS1 or OS3 files for + the first time, instead of replacing them with the older settings. +* Describe preserved settings as retained rather than verified in the upgrade + report. Invalid files are still checked by the normal provider loader. +* Keep the documentation index in docs/README.md and stop bundling the old + duplicate guide. + Version 4.1.0.110021 * Clarify dimension-wide material controls and replace light-equivalent custom diff --git a/README.md b/README.md index f8ee7f3d..4b35e455 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ It gives mods and modpacks one place to configure ores, deposit shapes, optional rock strata and geomes, provider-owned underground fluid deposits, biome palettes and world materials, flat bedrock, and bounded ore retrogen. -This branch builds target-qualified version `4.1.0.110021`: the OreSpawn 4.1.0 +This branch builds target-qualified version `4.1.1.110021`: the OreSpawn 4.1.1 feature set for Minecraft 1.10.2 and Forge. It adds stable generation identity, non-loading geology sampling, per-resource background control, existing-world provider merge policy, an Ore Sources arbiter for equivalent provider ores and diff --git a/build.gradle b/build.gradle index 7721fde1..2e3c6606 100644 --- a/build.gradle +++ b/build.gradle @@ -189,8 +189,8 @@ tasks.register('verifyDocumentationParity') { dependsOn tasks.named('processResources') doLast { List tracked = trackedDocumentationFiles() - if (tracked.size() != 21) { - throw new GradleException("Expected 21 tracked documentation files, found ${tracked.size()}") + if (tracked.size() != 20) { + throw new GradleException("Expected 20 tracked documentation files, found ${tracked.size()}") } tracked.each { File source -> String relative = documentationRelativePath(source) @@ -213,10 +213,6 @@ tasks.named('processResources', ProcessResources) { filesMatching('mcmod.info') { expand version: project.version, mcversion: project.minecraft_version } - from('docs/AGENTS.md') { - into '' - rename { 'AGENTS.md' } - } from('docs') { into 'META-INF/orespawn/docs' } diff --git a/docs/AGENTS.md b/docs/AGENTS.md deleted file mode 100644 index 04e7b789..00000000 --- a/docs/AGENTS.md +++ /dev/null @@ -1,16 +0,0 @@ -# OreSpawn Documentation Map - -This index is for navigating the documentation to learn how to integrate with -and use OreSpawn with a mod or modpack. Start with -[DEVELOPER_GUIDE.md](DEVELOPER_GUIDE.md). - -Use the focused guides for implementation details: - -- [API.md](API.md) for the supported Java API; -- [PROVIDERS.md](PROVIDERS.md) for packaged and configurable providers; -- [FEATURES.md](FEATURES.md) for rocks, ores, deposits, and geology; -- [BIOMES.md](BIOMES.md) and [DIMENSIONS.md](DIMENSIONS.md) for world integration; -- [TEMPLATES.md](TEMPLATES.md) for selectable world styles; -- [CONFIGURATION.md](CONFIGURATION.md) for configuration behavior; -- [VERSIONS.md](VERSIONS.md) for the shared four-component target-qualified versioning and branch-release convention; -- [README.md](README.md) for schemas, examples, and the complete documentation index. diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index c2ee05c7..5cc591bc 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -89,6 +89,12 @@ legacy-ID behaviour. Migration is non-destructive. OreSpawn writes `config/orespawn-worldgen.json` only when that target does not already exist and retains every source file. +An existing `config/-orespawn.json` override is also kept unchanged, +even when legacy files are imported for the first time. The upgrade report +records that the existing provider settings were retained. An unfinished or +invalid override is left for the normal provider validator; migration does not +replace it with defaults or older settings. + When `config/mineralogy-geomes.json` exists, OreSpawn imports the Mineralogy 6 profile directly, updates its schema marker, and records `migrated_from`. diff --git a/docs/README.md b/docs/README.md index e0e46029..aafc1673 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,6 +6,9 @@ shaded or embeddable engine artifact. Choose the guide that matches what you are doing: +For mod or modpack integration, start with the developer guide, then use the +API and provider references for the details. + - [Player and server guide](PLAYER_GUIDE.md) - [Developer quick start and complete integration map](DEVELOPER_GUIDE.md) - [Configuration field reference](CONFIGURATION.md) @@ -18,7 +21,6 @@ Choose the guide that matches what you are doing: - [Migration](MIGRATION.md) - [Troubleshooting](TROUBLESHOOTING.md) - [Versioning and release identities](VERSIONS.md) -- [Compact instructions for coding agents](AGENTS.md) Validated examples are in `examples/`; JSON Schemas are in `schemas/`. The provider and migration guides include OS3-compatible ranged quantities and diff --git a/docs/VERSIONS.md b/docs/VERSIONS.md index 2069a178..6cb33c22 100644 --- a/docs/VERSIONS.md +++ b/docs/VERSIONS.md @@ -51,7 +51,7 @@ Examples: | Minecraft | Loader | Target | Example full version | | --- | --- | ---: | --- | -| 1.10.2 | Forge | `110021` | `4.1.0.110021` | +| 1.10.2 | Forge | `110021` | `4.1.1.110021` | | 1.12.2 | Forge | `112021` | `4.0.6.112021` | | 1.13.2 | Forge | `113021` | `4.0.6.113021` | | 1.20.6 | Forge | `120061` | `4.0.6.120061` | diff --git a/gradle.properties b/gradle.properties index f16c8ae7..df156223 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,7 +30,7 @@ mod_vendor=Minecraft Mod Development mod_license=LGPL-2.1 mod_license_name=GNU Lesser General Public License, Version 2.1 mod_license_url=https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt -mod_version=4.1.0.110021 +mod_version=4.1.1.110021 mod_group=zone.moddev.mc.orespawn mod_authors=SkyBlade1978, dshadowwolf, the MMD Team mod_description=Configurable, provider-driven terrain, ore, and deposit generation. diff --git a/gradle/ide/eclipse.gradle b/gradle/ide/eclipse.gradle index 2b24379d..51f50f01 100644 --- a/gradle/ide/eclipse.gradle +++ b/gradle/ide/eclipse.gradle @@ -157,8 +157,8 @@ tasks.register('verifyEclipseProductionClasspath') { } File eclipseResources = file('bin/main') List trackedDocs = trackedDocumentationFiles() - if (trackedDocs.size() != 21) { - throw new GradleException("Expected 21 tracked documentation files, found ${trackedDocs.size()}") + if (trackedDocs.size() != 20) { + throw new GradleException("Expected 20 tracked documentation files, found ${trackedDocs.size()}") } trackedDocs.each { File source -> String relative = documentationRelativePath(source) diff --git a/gradle/release/artifacts.gradle b/gradle/release/artifacts.gradle index 092780cd..11f7c36b 100644 --- a/gradle/release/artifacts.gradle +++ b/gradle/release/artifacts.gradle @@ -77,7 +77,7 @@ tasks.register('verifyReleaseConfiguration') { description = 'Validates the target-qualified release, API, schemas, reports, and publishing identity.' doLast { - if (project.mod_version != '4.1.0.110021' + if (project.mod_version != '4.1.1.110021' || project.mod_group != expectedMavenGroup) { throw new GradleException("Unexpected OreSpawn release version: ${project.mod_version}") } @@ -106,8 +106,8 @@ tasks.register('verifyReleaseConfiguration') { 'src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java', 'README.md', 'CHANGELOG.txt' ].each { path -> - if (!file(path).getText('UTF-8').contains('4.1.0.110021')) { - throw new GradleException("Authoritative release location does not contain 4.1.0.110021: ${path}") + if (!file(path).getText('UTF-8').contains('4.1.1.110021')) { + throw new GradleException("Authoritative release location does not contain 4.1.1.110021: ${path}") } } if (!file('docs/API.md').getText('UTF-8').contains('orespawn@[4.0.6,5.0.0)')) { @@ -171,7 +171,7 @@ tasks.register('verifyReleaseArtifacts') { } ['src/test/', 'src/biomeIntegrationTest/', 'src/migrationIntegrationTest/', 'src/clientIntegrationTest/', 'src/os1AbiFixture/', 'src/os3AbiFixture/', - 'agent-notes/', 'surfaceprobe', 'migrationprobe', 'clientprobe', + 'agent-notes/', 'AGENTS.md', 'AGENT.md', 'surfaceprobe', 'migrationprobe', 'clientprobe', 'OreSourceEditorProbeBridge', 'org/junit/', 'org/mockito/', 'net/bytebuddy/'].each { forbidden -> if (candidateZip.entries().any { it.name.contains(forbidden) }) { @@ -197,16 +197,15 @@ tasks.register('verifyReleaseArtifacts') { 'META-INF/orespawn/docs/VERSIONS.md', 'META-INF/orespawn/docs/schemas/orespawn-provider.schema.json', 'META-INF/orespawn/docs/schemas/orespawn-global.schema.json', - 'META-INF/orespawn/docs/schemas/orespawn-world.schema.json', - 'AGENTS.md' + 'META-INF/orespawn/docs/schemas/orespawn-world.schema.json' ].each { required -> if (!names.contains(required)) { throw new GradleException("Release jar is missing ${required}") } } List trackedDocs = trackedDocumentationFiles() - if (trackedDocs.size() != 21) { - throw new GradleException("Expected 21 tracked documentation files, found ${trackedDocs.size()}") + if (trackedDocs.size() != 20) { + throw new GradleException("Expected 20 tracked documentation files, found ${trackedDocs.size()}") } trackedDocs.each { File source -> String relative = documentationRelativePath(source) diff --git a/src/main/java/com/mcmoddev/orespawn/compat/LegacyOs3Bridge.java b/src/main/java/com/mcmoddev/orespawn/compat/LegacyOs3Bridge.java index b5a60e59..24b503d1 100644 --- a/src/main/java/com/mcmoddev/orespawn/compat/LegacyOs3Bridge.java +++ b/src/main/java/com/mcmoddev/orespawn/compat/LegacyOs3Bridge.java @@ -391,7 +391,7 @@ private static void migrateConfigDirectory(Path configDirectory) { } for (Map.Entry provider : providers.entrySet()) { try { - writeAtomicIfChanged(configDirectory.resolve(provider.getKey() + "-orespawn.json"), provider.getValue()); + writeProviderIfAbsent(configDirectory.resolve(provider.getKey() + "-orespawn.json"), provider.getValue()); } catch (IOException failure) { REPORT.add("provider_write_failed=" + provider.getKey() + ":" + failure.getClass().getSimpleName()); LOGGER.error("Could not write migrated OS3 provider {}", provider.getKey(), failure); @@ -964,6 +964,16 @@ private static int metadata(String block, String state) { return 0; } + static void writeProviderIfAbsent(Path destination, JsonObject value) throws IOException { + // An existing OS4 file is a pack's choice, even on its first legacy import. + if (Files.isRegularFile(destination)) { + REPORT.add("provider_preserved=" + destination.getFileName()); + return; + } + + writeAtomicIfChanged(destination, value); + } + private static void writeAtomicIfChanged(Path destination, JsonObject value) throws IOException { byte[] data = (GSON.toJson(value) + System.lineSeparator()).getBytes(StandardCharsets.UTF_8); if (Files.isRegularFile(destination) && Arrays.equals(Files.readAllBytes(destination), data)) { @@ -1007,7 +1017,8 @@ private static void writeHumanUpgradeReport(Path destination) throws IOException || lower.startsWith("resource_loaded=") || lower.startsWith("os1_config_registered=")) { sources.add(row); } - if ((lower.startsWith("provider_written=") || lower.startsWith("provider_unchanged=")) + if ((lower.startsWith("provider_written=") || lower.startsWith("provider_unchanged=") + || lower.startsWith("provider_preserved=")) && !lower.contains("migration-report")) providers.add(row); if (lower.contains("_failed=") || lower.contains("_rejected=") || lower.contains("_ignored=") || lower.contains("_unresolved=") @@ -1016,12 +1027,12 @@ private static void writeHumanUpgradeReport(Path destination) throws IOException } } List lines = new ArrayList<>(); - lines.add("OreSpawn 4.1.0.110021 Upgrade Report"); + lines.add("OreSpawn 4.1.1.110021 Upgrade Report"); lines.add("================================"); lines.add(""); lines.add("RESULT: Legacy OreSpawn configuration was consumed and translated for OS4."); lines.add("- Legacy sources read: " + sources.size()); - lines.add("- OS4 provider files written or verified: " + providers.size()); + lines.add("- OS4 provider files written or retained: " + providers.size()); lines.add("- Unique items requiring review: " + warnings.size()); lines.add(""); lines.add(warnings.isEmpty() diff --git a/src/main/java/cyano/orespawn/OreSpawn.java b/src/main/java/cyano/orespawn/OreSpawn.java index 18d9485d..54304afe 100644 --- a/src/main/java/cyano/orespawn/OreSpawn.java +++ b/src/main/java/cyano/orespawn/OreSpawn.java @@ -19,7 +19,7 @@ public class OreSpawn { public static OreSpawn INSTANCE; public static final String MODID = "orespawn"; public static final String NAME = "OreSpawn"; - public static final String VERSION = "4.1.0.110021"; + public static final String VERSION = "4.1.1.110021"; public static final List oreSpawnConfigFiles = new ArrayList<>(); public static final List additionalStoneBlocks = new ArrayList<>(); public static boolean disableVanillaOreGen; diff --git a/src/main/java/zone/moddev/mc/orespawn/OreSpawn.java b/src/main/java/zone/moddev/mc/orespawn/OreSpawn.java index 1c91df6f..470a7567 100644 --- a/src/main/java/zone/moddev/mc/orespawn/OreSpawn.java +++ b/src/main/java/zone/moddev/mc/orespawn/OreSpawn.java @@ -52,7 +52,7 @@ public class OreSpawn { public static final String MODID = "orespawn"; public static final String NAME = "OreSpawn"; - public static final String VERSION = "4.1.0.110021"; + public static final String VERSION = "4.1.1.110021"; private static final Logger LOGGER = LogManager.getLogger(); diff --git a/src/main/java/zone/moddev/mc/orespawn/documentation/DocumentationExporter.java b/src/main/java/zone/moddev/mc/orespawn/documentation/DocumentationExporter.java index 2b2c7269..2d4ea7a3 100644 --- a/src/main/java/zone/moddev/mc/orespawn/documentation/DocumentationExporter.java +++ b/src/main/java/zone/moddev/mc/orespawn/documentation/DocumentationExporter.java @@ -30,7 +30,6 @@ public final class DocumentationExporter { "BIOMES.md", "MIGRATION.md", "TROUBLESHOOTING.md", - "AGENTS.md", "examples/examplemod-orespawn.json", "examples/orespawn-global.json", "examples/orespawn-world.json", diff --git a/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java b/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java index 145648cd..ed77fb71 100644 --- a/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java +++ b/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java @@ -125,7 +125,7 @@ private static void writeUpgradeReport(Path worldRoot, Path configDirectory, } List lines = new ArrayList<>(); - lines.add("OreSpawn 4.1.0.110021 Upgrade Report"); + lines.add("OreSpawn 4.1.1.110021 Upgrade Report"); lines.add("================================"); lines.add(""); lines.add("RESULT: Existing Mineralogy " + mineralogyVersion diff --git a/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java b/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java index f1113d92..e7e3feb2 100644 --- a/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java +++ b/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java @@ -65,7 +65,7 @@ private static void writeInitialUpgradeReport(Path configDirectory, boolean forceRetrogen, boolean flatBedrock, boolean retrogenBedrock, int bedrockLayers) throws IOException { String newline = System.lineSeparator(); - String text = "OreSpawn 4.1.0.110021 Upgrade Report" + newline + String text = "OreSpawn 4.1.1.110021 Upgrade Report" + newline + "================================" + newline + newline + "RESULT: Legacy OreSpawn settings were imported into the OS4 profile." + newline + "- Manage vanilla ores: " + manageVanilla + newline diff --git a/src/test/java/com/mcmoddev/orespawn/compat/LegacyOs3BridgeTest.java b/src/test/java/com/mcmoddev/orespawn/compat/LegacyOs3BridgeTest.java index 318bb8b9..841d4222 100644 --- a/src/test/java/com/mcmoddev/orespawn/compat/LegacyOs3BridgeTest.java +++ b/src/test/java/com/mcmoddev/orespawn/compat/LegacyOs3BridgeTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -44,6 +45,99 @@ static void bootstrapMinecraft() { Forge12TestBootstrap.registerVanilla(); } + @Test + void keepsAnExistingProviderDuringTheFirstImportAndReload() throws Exception { + LegacyOs3Bridge.resetProgrammaticForTests("overridefixture"); + Path legacy = temporary.resolve("orespawn3"); + Files.createDirectories(legacy); + Files.write(legacy.resolve("overridefixture.json"), + "{\"spawns\":{}}".getBytes(StandardCharsets.UTF_8)); + Path destination = temporary.resolve("orespawn-orespawn.json"); + String existing = "{ \"schema_version\": 5, \"provider_modid\": \"orespawn\", \"provider_revision\": 9 }\n"; + Files.write(destination, existing.getBytes(StandardCharsets.UTF_8)); + + migrateLegacyDirectory(temporary); + + assertEquals(existing, new String(Files.readAllBytes(destination), StandardCharsets.UTF_8)); + assertFalse(Files.exists(temporary.resolve("orespawn-orespawn.json.os3-backup"))); + Path report = temporary.resolve("orespawn-upgrade-report.txt"); + String firstReport = new String(Files.readAllBytes(report), StandardCharsets.UTF_8); + assertTrue(firstReport.contains("provider_preserved=orespawn-orespawn.json")); + + migrateLegacyDirectory(temporary); + + assertEquals(existing, new String(Files.readAllBytes(destination), StandardCharsets.UTF_8)); + assertEquals(firstReport, new String(Files.readAllBytes(report), StandardCharsets.UTF_8)); + } + + @Test + void describesAnUnvalidatedOverrideAsRetainedRatherThanVerified() throws Exception { + LegacyOs3Bridge.resetProgrammaticForTests("reportfixture"); + Path legacy = temporary.resolve("orespawn3"); + Files.createDirectories(legacy); + Files.write(legacy.resolve("reportfixture.json"), + "{\"spawns\":{}}".getBytes(StandardCharsets.UTF_8)); + Path destination = temporary.resolve("orespawn-orespawn.json"); + String existing = "{ unfinished user edit"; + Files.write(destination, existing.getBytes(StandardCharsets.UTF_8)); + + migrateLegacyDirectory(temporary); + + assertEquals(existing, new String(Files.readAllBytes(destination), StandardCharsets.UTF_8)); + String report = new String(Files.readAllBytes( + temporary.resolve("orespawn-upgrade-report.txt")), StandardCharsets.UTF_8); + assertTrue(report.contains("OS4 provider files written or retained: 1")); + assertFalse(report.contains("written or verified")); + assertTrue(report.contains("provider_preserved=orespawn-orespawn.json")); + } + + private static void migrateLegacyDirectory(Path directory) throws Exception { + Method migration = LegacyOs3Bridge.class.getDeclaredMethod("migrateConfigDirectory", Path.class); + migration.setAccessible(true); + migration.invoke(null, directory); + } + + + @Test + void keepsAnExistingProviderOverrideDuringLegacyImport() throws Exception { + Path destination = temporary.resolve("basemetals-orespawn.json"); + String existing = "{ \"schema_version\": 5, \"provider_modid\": \"basemetals\", \"provider_revision\": 1 }\n"; + Files.write(destination, existing.getBytes(StandardCharsets.UTF_8)); + + LegacyOs3Bridge.writeProviderIfAbsent(destination, new JsonObject()); + + assertEquals(existing, new String(Files.readAllBytes(destination), StandardCharsets.UTF_8)); + assertFalse(Files.exists(temporary.resolve("basemetals-orespawn.json.os3-backup"))); + assertTrue(LegacyOs3Bridge.reportForTests().contains("provider_preserved=basemetals-orespawn.json")); + } + + @Test + void leavesAMalformedOverrideForTheNormalProviderValidator() throws Exception { + Path destination = temporary.resolve("basemetals-orespawn.json"); + String existing = "{ unfinished user edit"; + Files.write(destination, existing.getBytes(StandardCharsets.UTF_8)); + + LegacyOs3Bridge.writeProviderIfAbsent(destination, new JsonObject()); + + assertEquals(existing, new String(Files.readAllBytes(destination), StandardCharsets.UTF_8)); + } + + @Test + void writesAnImportedProviderOnlyWhenNoOverrideExists() throws Exception { + Path destination = temporary.resolve("basemetals-orespawn.json"); + JsonObject imported = new JsonObject(); + imported.addProperty("provider_modid", "basemetals"); + imported.addProperty("provider_revision", 1); + + LegacyOs3Bridge.writeProviderIfAbsent(destination, imported); + String first = new String(Files.readAllBytes(destination), StandardCharsets.UTF_8); + assertEquals(imported, new JsonParser().parse(first)); + + imported.addProperty("provider_revision", 9); + LegacyOs3Bridge.writeProviderIfAbsent(destination, imported); + assertEquals(first, new String(Files.readAllBytes(destination), StandardCharsets.UTF_8)); + } + @Test void translatesOs1MetadataFractionalFrequencyExclusiveHeightAndPlusDimensions() throws Exception { JsonObject source = new JsonParser().parse("{\"dimensions\":[" diff --git a/src/test/java/zone/moddev/mc/orespawn/client/OreSpawnModDirectoryModelTest.java b/src/test/java/zone/moddev/mc/orespawn/client/OreSpawnModDirectoryModelTest.java index 06f080cc..f466c0c9 100644 --- a/src/test/java/zone/moddev/mc/orespawn/client/OreSpawnModDirectoryModelTest.java +++ b/src/test/java/zone/moddev/mc/orespawn/client/OreSpawnModDirectoryModelTest.java @@ -30,7 +30,7 @@ void discoversLoadedNativeLegacyUiOnlyInactiveAndRejectedIntegrations() { "directory_ui_only", parent -> new GuiScreen() { }); List loaded = Arrays.asList( - new LoadedMod("orespawn", "MMD OreSpawn", "4.1.0.110021"), + new LoadedMod("orespawn", "MMD OreSpawn", "4.1.1.110021"), new LoadedMod("directory_realistic", "Realistic Deposits", "0.1.0.110021"), new LoadedMod("directory_base", "Base Metals", "2.5.0-beta5"), new LoadedMod("directory_mineralogy", "Mineralogy", "6.0.2.110021"), diff --git a/src/test/java/zone/moddev/mc/orespawn/documentation/DocumentationExporterTest.java b/src/test/java/zone/moddev/mc/orespawn/documentation/DocumentationExporterTest.java index 237cd6ca..659de75f 100644 --- a/src/test/java/zone/moddev/mc/orespawn/documentation/DocumentationExporterTest.java +++ b/src/test/java/zone/moddev/mc/orespawn/documentation/DocumentationExporterTest.java @@ -1,6 +1,7 @@ package zone.moddev.mc.orespawn.documentation; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.nio.charset.StandardCharsets; @@ -27,7 +28,7 @@ void exportsCompleteGuideAndDoesNotOverwriteExistingFiles() throws Exception { .sorted() .collect(Collectors.toList()); } - assertEquals(21, tracked.size()); + assertEquals(20, tracked.size()); assertEquals(tracked.size(), firstExport); for (Path source : tracked) { Path relative = Paths.get("docs").relativize(source); @@ -38,6 +39,7 @@ void exportsCompleteGuideAndDoesNotOverwriteExistingFiles() throws Exception { "runtime export differs for " + relative); } assertTrue(Files.isRegularFile(temporaryDirectory.resolve("README.md"))); + assertFalse(Files.exists(temporaryDirectory.resolve("AGENTS.md"))); assertTrue(Files.isRegularFile(temporaryDirectory.resolve("DEVELOPER_GUIDE.md"))); assertTrue(Files.isRegularFile(temporaryDirectory.resolve("BIOMES.md"))); assertTrue(Files.isRegularFile(temporaryDirectory.resolve("examples/examplemod-orespawn.json"))); From 424c4345d4a62fb8b30813a276421a65f37e4d7b Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 20 Oct 2026 13:25:00 +0100 Subject: [PATCH 2/2] Let the client test shut down cleanly --- .../zone/moddev/mc/orespawn/client/ClientProbeTestMod.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clientIntegrationTest/java/zone/moddev/mc/orespawn/client/ClientProbeTestMod.java b/src/clientIntegrationTest/java/zone/moddev/mc/orespawn/client/ClientProbeTestMod.java index 4ba8a455..9b2e1f98 100644 --- a/src/clientIntegrationTest/java/zone/moddev/mc/orespawn/client/ClientProbeTestMod.java +++ b/src/clientIntegrationTest/java/zone/moddev/mc/orespawn/client/ClientProbeTestMod.java @@ -769,9 +769,9 @@ private static void pressDone(OreSpawnScreen screen) { } private static void stopIntegratedServer(Minecraft minecraft) { - // Ask the integrated server to stop while retaining the client world until - // the server and its queued play packets have drained. Clearing the world in - // this tick races Forge 1.10 packet tasks against a null client world. + // Stop the server before closing the channel. Otherwise its automatic + // disconnect can finish first and leave loadWorld waiting on a stopped thread. + if (minecraft.getIntegratedServer() != null) minecraft.getIntegratedServer().initiateShutdown(); if (minecraft.world != null) minecraft.world.sendQuittingDisconnectingPacket(); minecraft.displayGuiScreen(new GuiMainMenu()); }