From 4940e309aa66c9786a81c3193e8bd385636e327b Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Mon, 24 Aug 2026 15:52:31 +0100 Subject: [PATCH 1/2] Fix ForgeGradle Eclipse path quoting --- .project | 37 +++-- CHANGELOG.txt | 1 + build.gradle | 141 ++++++++++++++++-- docs/DEVELOPER_GUIDE.md | 15 +- .../mc/mineralogy/VersionContractTest.java | 14 ++ .../DocumentationContractTest.java | 7 +- 6 files changed, 184 insertions(+), 31 deletions(-) diff --git a/.project b/.project index b597f7a84..53346fb71 100644 --- a/.project +++ b/.project @@ -1,16 +1,21 @@ - - - MinecraftMineralogy - Mineralogy - - - org.eclipse.jdt.core.javanature - - - - org.eclipse.jdt.core.javabuilder - - - - - + + + MinecraftMineralogy + Mineralogy + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + + + org.eclipse.jdt.core.javabuilder + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 8a7418757..4342fb4b6 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -19,4 +19,5 @@ Mineralogy 6.0.1.110021 for Minecraft 1.10.2 Forge - Documents OreSpawn's custom terrain dimensions and per-rock dimension membership as the resolution for issue #30, including Minecraft 1.10 numeric-ID mapping, dimension-specific rock sets and altitudes, and new-chunks-only behavior. - Repairs saved rock-furnace loading so Minecraft can reconstruct the tile entity, restore its inventory and progress, and recover the rock-specific burn rate without changing historical NBT or tile IDs. - Aligns novaculite with Mineralogy 6 hardness/resistance and makes double slabs drop two matching slabs normally or one matching full block with Silk Touch. +- Repairs generated ForgeGradle 7 Eclipse launches by restoring their Buildship project/cache configuration, retiring obsolete ForgeGradle 2 launches, quoting Slime Launcher paths that contain spaces, and verifying the result before handoff. - Advances the functional bug version to 6.0.1 because this release includes fixes and compatibility improvements not present in Mineralogy 6.0.0. diff --git a/build.gradle b/build.gradle index 20b118e75..abd4d7a22 100644 --- a/build.gradle +++ b/build.gradle @@ -594,27 +594,93 @@ eclipse { synchronizationTasks 'genEclipseRuns' } +def configureEclipseBuildship = tasks.register('configureEclipseBuildship') { + group = 'ide' + description = 'Creates the Buildship project configuration required by ForgeGradle Eclipse launches.' + + doLast { + File preferencesFile = file('.settings/org.eclipse.buildship.core.prefs') + Properties preferences = new Properties() + if (preferencesFile.isFile()) { + preferencesFile.withInputStream { preferences.load(it) } + } + + Map requiredPreferences = [ + 'eclipse.preferences.version' : '1', + 'connection.gradle.distribution' : 'GRADLE_DISTRIBUTION(WRAPPER)', + 'connection.gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath, + 'connection.project.dir' : '', + 'gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath, + 'override.workspace.settings' : 'true' + ] + if (!preferencesFile.isFile() || requiredPreferences.any { key, value -> + preferences.getProperty(key) != value + }) { + requiredPreferences.each { key, value -> preferences.setProperty(key, value) } + preferencesFile.parentFile.mkdirs() + preferencesFile.withOutputStream { + preferences.store(it, + 'Generated by configureEclipseBuildship; keep Eclipse and command-line caches aligned.') + } + } + } +} + +tasks.named('genEclipseRuns') { + finalizedBy configureEclipseBuildship, 'isolateEclipseProductionRuns' +} + tasks.register('verifyEclipseProductionClasspath') { group = 'verification' description = 'Verifies that ordinary generated Eclipse launches exclude test code and dependencies.' - dependsOn 'isolateEclipseProductionRuns' + dependsOn tasks.named('genEclipseRuns') doLast { + File buildshipPreferences = file('.settings/org.eclipse.buildship.core.prefs') + if (!buildshipPreferences.isFile()) { + throw new GradleException("Missing Eclipse Buildship project configuration: ${buildshipPreferences}") + } + Properties buildship = new Properties() + buildshipPreferences.withInputStream { buildship.load(it) } + if (buildship.getProperty('eclipse.preferences.version') != '1' + || buildship.getProperty('connection.gradle.distribution') != 'GRADLE_DISTRIBUTION(WRAPPER)') { + throw new GradleException('Eclipse Buildship project configuration does not use the Gradle wrapper') + } + String configuredGradleHome = buildship.getProperty('connection.gradle.user.home', '').trim() + if (!configuredGradleHome + || file(configuredGradleHome).canonicalFile != gradle.gradleUserHomeDir.canonicalFile) { + throw new GradleException("Eclipse Buildship Gradle home is not ${gradle.gradleUserHomeDir.canonicalPath}") + } + String projectMetadata = file('.project').getText('UTF-8') + if (!projectMetadata.contains('org.eclipse.buildship.core.gradleprojectnature') + || !projectMetadata.contains('org.eclipse.buildship.core.gradleprojectbuilder')) { + throw new GradleException('Eclipse project metadata is missing its Buildship nature or builder') + } + + ['MinecraftMineralogy_Client.launch', 'MinecraftMineralogy_Server.launch'].each { name -> + if (file(name).exists()) { + throw new GradleException("Obsolete ForgeGradle 2 Eclipse launch still exists: ${name}") + } + } + List launchFiles = fileTree(project.projectDir) { include '*.launch' include '.eclipse/*.launch' }.files.findAll { file -> - ['runClient', 'runServer', 'runGameTestServer', 'runData'].any { file.name.contains(it) } + ['runClient.launch', 'runServer.launch', + 'runTestClient.launch', 'runTestServer.launch'].contains(file.name) } as List - if (launchFiles.isEmpty()) { - throw new GradleException('ForgeGradle did not generate ordinary Eclipse launch files') + if (launchFiles.size() != 4) { + throw new GradleException("ForgeGradle generated ${launchFiles.size()} of 4 expected Eclipse launch files") } List forbidden = [ 'src/test', 'bin/test', 'build/classes/java/test', 'junit-', 'mockito-', 'byte-buddy', 'objenesis', 'OilRuntimeProbe' ] - launchFiles.each { launch -> + launchFiles.findAll { launch -> + ['runClient.launch', 'runServer.launch'].contains(launch.name) + }.each { launch -> String contents = launch.getText('UTF-8').replace('\\', '/') List present = forbidden.findAll { contents.contains(it) } if (!present.isEmpty()) { @@ -628,25 +694,80 @@ tasks.register('verifyEclipseProductionClasspath') { throw new GradleException("${launch.name} targets the wrong Eclipse project") } } + launchFiles.each { launch -> + String contents = launch.getText('UTF-8') + ['--cache', '--metadata', '--to-srg', '--to-obf'].each { option -> + String prefix = option + ' ' + int valueStart = contents.indexOf(prefix) + if (valueStart < 0) { + throw new GradleException("${launch.name} is missing Slime Launcher argument ${option}") + } + valueStart += prefix.length() + int valueEnd = contents.indexOf(' --', valueStart) + if (valueEnd < 0) { + throw new GradleException("${launch.name} has a malformed Slime Launcher argument ${option}") + } + String value = contents.substring(valueStart, valueEnd) + boolean quoted = value.startsWith('"') && value.endsWith('"') + if (value.find(/\s/) != null && !quoted) { + throw new GradleException("${launch.name} leaves whitespace unquoted in ${option}: ${value}") + } + } + } } } tasks.register('isolateEclipseProductionRuns') { group = 'ide' - description = 'Marks ordinary Eclipse launches as production-only after ForgeGradle generation.' - dependsOn tasks.named('genEclipseRuns') - + description = 'Normalizes ordinary ForgeGradle Eclipse launches for production-only execution.' doLast { - ['runClient.launch', 'runServer.launch'].each { name -> + [ + 'MinecraftMineralogy_Client.launch': 'MAIN_TYPE" value="GradleStart"', + 'MinecraftMineralogy_Server.launch': 'MAIN_TYPE" value="GradleStartServer"' + ].each { name, legacyMarker -> + File legacy = file(name) + if (legacy.isFile() && legacy.getText('UTF-8').contains(legacyMarker)) { + if (!legacy.delete()) { + throw new GradleException("Could not retire obsolete ForgeGradle 2 launch ${name}") + } + } + } + + ['runClient.launch', 'runServer.launch', + 'runTestClient.launch', 'runTestServer.launch'].each { name -> File launch = file(name) if (!launch.isFile()) { throw new GradleException("ForgeGradle did not generate ${name}") } String contents = launch.getText('UTF-8') - if (!contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) { + boolean changed = false + boolean production = ['runClient.launch', 'runServer.launch'].contains(name) + if (production && !contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) { String marker = '' String attribute = ' ' contents = contents.replace(marker, attribute + System.lineSeparator() + marker) + changed = true + } + ['--cache', '--metadata', '--to-srg', '--to-obf'].each { option -> + String prefix = option + ' ' + int valueStart = contents.indexOf(prefix) + if (valueStart < 0) { + throw new GradleException("${name} is missing Slime Launcher argument ${option}") + } + valueStart += prefix.length() + int valueEnd = contents.indexOf(' --', valueStart) + if (valueEnd < 0) { + throw new GradleException("${name} has a malformed Slime Launcher argument ${option}") + } + String value = contents.substring(valueStart, valueEnd) + if (value.find(/\s/) != null && !value.startsWith('"')) { + contents = (contents.substring(0, valueStart) + + '"' + value + '"' + + contents.substring(valueEnd)) + changed = true + } + } + if (changed) { launch.setText(contents, 'UTF-8') } } diff --git a/docs/DEVELOPER_GUIDE.md b/docs/DEVELOPER_GUIDE.md index 389b68907..129d0fb49 100644 --- a/docs/DEVELOPER_GUIDE.md +++ b/docs/DEVELOPER_GUIDE.md @@ -55,18 +55,25 @@ recipes, so existing content remains loadable. ## Building -Use JDK 8, Gradle 4.9, and ForgeGradle `2.2-SNAPSHOT` from the nested 1.10 -checkout: +Use a JDK 21 Gradle runtime with the checked-in Gradle 9.6.1 wrapper and +ForgeGradle `7.0.34`. The project itself still compiles and packages Java 8 +bytecode through its Java 8 toolchain: ```powershell -$env:JAVA_HOME='C:\Program Files\Java\jdk1.8.0_202' +$env:JAVA_HOME='C:\path\to\jdk-21' $env:GRADLE_USER_HOME='D:\MinecraftMineralogy\.gradle-verify-cache' .\gradlew.bat test compileJava processResources --no-daemon .\gradlew.bat clean build javadoc --no-daemon -.\gradlew.bat setupDecompWorkspace eclipse verifyEclipseProductionClasspath --no-daemon +.\gradlew.bat genEclipseRuns isolateEclipseProductionRuns verifyEclipseProductionClasspath --no-daemon .\gradlew.bat assemble --no-daemon ``` +Import the nested checkout into Eclipse as an existing Gradle project. Do not +run the legacy `setupDecompWorkspace` task. Regenerate the Forge run +configurations after changing the checkout path or Gradle cache; Mineralogy's +normalization task keeps the ordinary client/server launches production-only +and safely quotes Slime Launcher paths containing spaces. + Inspect complete client/server logs and test the reobfuscated jar with released OreSpawn in a launcher-like Forge installation. The normal jar packages this guide under `META-INF/mineralogy/docs/`. diff --git a/src/test/java/zone/moddev/mc/mineralogy/VersionContractTest.java b/src/test/java/zone/moddev/mc/mineralogy/VersionContractTest.java index e6c98ff42..a7e2ebf8b 100644 --- a/src/test/java/zone/moddev/mc/mineralogy/VersionContractTest.java +++ b/src/test/java/zone/moddev/mc/mineralogy/VersionContractTest.java @@ -69,6 +69,20 @@ public void modernBuildAndReleaseMetadataKeepTheRequiredOreSpawnContract() throw assertFalse(properties.containsKey("create_deobf_jar")); } + @Test + public void eclipseLaunchNormalizationQuotesWhitespacePathsAndVerifiesThem() throws Exception { + String build = read(new File("build.gradle")); + String project = read(new File(".project")); + assertTrue(build.contains("tasks.register('configureEclipseBuildship')")); + assertTrue(build.contains("tasks.register('isolateEclipseProductionRuns')")); + assertTrue(build.contains("['--cache', '--metadata', '--to-srg', '--to-obf']")); + assertTrue(build.contains("+ '"' + value + '"'")); + assertTrue(build.contains("leaves whitespace unquoted")); + assertTrue(build.contains("finalizedBy configureEclipseBuildship, 'isolateEclipseProductionRuns'")); + assertTrue(project.contains("org.eclipse.buildship.core.gradleprojectnature")); + assertTrue(project.contains("org.eclipse.buildship.core.gradleprojectbuilder")); + } + @Test public void productionMetadataDoesNotRetainTheLegacyFingerprintToken() throws Exception { String source = read(new File("src/main/java/zone/moddev/mc/mineralogy/Mineralogy.java")); diff --git a/src/test/java/zone/moddev/mc/mineralogy/documentation/DocumentationContractTest.java b/src/test/java/zone/moddev/mc/mineralogy/documentation/DocumentationContractTest.java index 5d49e8aa7..0319ee777 100644 --- a/src/test/java/zone/moddev/mc/mineralogy/documentation/DocumentationContractTest.java +++ b/src/test/java/zone/moddev/mc/mineralogy/documentation/DocumentationContractTest.java @@ -45,6 +45,10 @@ public void guidesDescribeTheTargetNative110Contract() throws Exception { assertTrue(all.contains("Minecraft 1.10.2")); assertTrue(all.contains("Forge 12.18.3.2511")); assertTrue(all.contains("OreSpawn 4.0.6")); + assertTrue(all.contains("JDK 21")); + assertTrue(all.contains("Gradle 9.6.1")); + assertTrue(all.contains("ForgeGradle `7.0.34`")); + assertTrue(all.contains("Java 8 toolchain")); assertTrue(all.contains("schema 4")); assertTrue(all.contains("provider revision 3")); assertTrue(all.contains("assets/mineralogy/orespawn/provider.json")); @@ -73,7 +77,8 @@ public void guidesDescribeTheTargetNative110Contract() throws Exception { assertFalse(targetNativeGuides.contains("mineralogy-common.toml")); assertFalse(targetNativeGuides.contains("data/mineralogy/orespawn/provider.json")); assertFalse(targetNativeGuides.contains("Minecraft 1.18.2")); - assertFalse(targetNativeGuides.contains("Java 17")); + assertFalse(targetNativeGuides.contains(".\\gradlew.bat setupDecompWorkspace")); + assertFalse(targetNativeGuides.contains("Gradle 4.9")); assertFalse(targetNativeGuides.toLowerCase().contains("deepslate")); assertFalse(targetNativeGuides.contains("Y -48")); } From 87456ead5547ed6954f3925846e71d4ff51c123d Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Mon, 24 Aug 2026 16:13:52 +0100 Subject: [PATCH 2/2] Fix OreSpawn access in legacy development runs --- CHANGELOG.txt | 1 + build.gradle | 65 ++++++++++++++++++- docs/DEVELOPER_GUIDE.md | 15 ++++- ...respawn-development-access-transformer.cfg | 2 + .../mc/mineralogy/VersionContractTest.java | 14 ++++ 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 gradle/orespawn-development-access-transformer.cfg diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4342fb4b6..13f7be11f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -20,4 +20,5 @@ Mineralogy 6.0.1.110021 for Minecraft 1.10.2 Forge - Repairs saved rock-furnace loading so Minecraft can reconstruct the tile entity, restore its inventory and progress, and recover the rock-specific burn rate without changing historical NBT or tile IDs. - Aligns novaculite with Mineralogy 6 hardness/resistance and makes double slabs drop two matching slabs normally or one matching full block with Silk Touch. - Repairs generated ForgeGradle 7 Eclipse launches by restoring their Buildship project/cache configuration, retiring obsolete ForgeGradle 2 launches, quoting Slime Launcher paths that contain spaces, and verifying the result before handoff. +- Applies OreSpawn's released access-transformer contract to ForgeGradle's mapped development runtime and synchronizes processed metadata and bundled guides into Eclipse output without changing the production jar. - Advances the functional bug version to 6.0.1 because this release includes fixes and compatibility improvements not present in Mineralogy 6.0.0. diff --git a/build.gradle b/build.gradle index abd4d7a22..923306cf3 100644 --- a/build.gradle +++ b/build.gradle @@ -86,10 +86,17 @@ def normalizeArchiveLineEndings = { details -> minecraft { mappings channel: project.mappings_channel, version: project.mappings_version + // Forge applies OreSpawn's SRG FMLAT in an ordinary packaged installation, + // but ForgeGradle 7 does not remap a dependency transform for mapped + // development Minecraft. Mirror the exact two released rules for + // Gradle/Eclipse only. This file is outside main resources and is never + // packaged by Mineralogy. + accessTransformer.from(file('gradle/orespawn-development-access-transformer.cfg')) + String configuredRunDirectory = providers.gradleProperty('mineralogyRunDirectory').getOrElse('run') runs { configureEach { - workingDir.convention layout.projectDirectory.dir('run') + workingDir.convention layout.projectDirectory.dir(configuredRunDirectory) systemProperty 'forge.logging.console.level', 'debug' } @@ -174,6 +181,18 @@ tasks.named('processResources', ProcessResources) { filesMatching(archiveTextPatterns, normalizeArchiveLineEndings) } +def prepareEclipseResources = tasks.register('prepareEclipseResources') { + group = 'ide' + description = 'Copies Gradle-processed production resources into Eclipse merged output.' + dependsOn tasks.named('processResources') + doLast { + project.copy { + from(layout.buildDirectory.dir('resources/main')) + into(layout.projectDirectory.dir('bin/main')) + } + } +} + tasks.named('jar', Jar) { archiveClassifier = 'deobf' destinationDirectory = layout.buildDirectory.dir('libs-dev') @@ -325,6 +344,29 @@ tasks.register('verifyReleaseDependencies') { throw new GradleException('Resolved OreSpawn file does not contain version ' + project.orespawn_version) } + + def transformerEntry = oreSpawn.getEntry('META-INF/accesstransformer.cfg') + if (transformerEntry == null) { + throw new GradleException('Resolved OreSpawn file is missing its access transformer') + } + List releasedTransformer = oreSpawn.getInputStream(transformerEntry) + .getText(StandardCharsets.UTF_8.name()).readLines() + .findAll { !it.trim().isEmpty() } + List expectedReleasedTransformer = [ + 'public-f net.minecraft.world.WorldProvider field_76578_c # biomeProvider', + 'public-f net.minecraft.world.gen.ChunkProviderOverworld field_186001_t # oceanBlock' + ] + List developmentTransformer = file( + 'gradle/orespawn-development-access-transformer.cfg').readLines('UTF-8') + .findAll { !it.trim().isEmpty() } + List expectedDevelopmentTransformer = [ + 'public-f net.minecraft.world.WorldProvider biomeProvider', + 'public-f net.minecraft.world.gen.ChunkProviderOverworld oceanBlock' + ] + if (releasedTransformer != expectedReleasedTransformer + || developmentTransformer != expectedDevelopmentTransformer) { + throw new GradleException('Development access transformer no longer matches released OreSpawn semantics') + } } finally { oreSpawn.close() } @@ -385,7 +427,9 @@ tasks.register('verifyReleaseArtifacts') { } } ['agent-notes/', 'src/test/', 'OilRuntimeProbe', 'org/junit/', - 'org/mockito/', 'net/bytebuddy/'].each { forbidden -> + 'org/mockito/', 'net/bytebuddy/', + 'orespawn-development-access-transformer.cfg', + 'META-INF/accesstransformer.cfg'].each { forbidden -> if (names.any { it.contains(forbidden) }) { throw new GradleException("Release jar contains forbidden entry matching ${forbidden}") } @@ -657,6 +701,22 @@ tasks.register('verifyEclipseProductionClasspath') { throw new GradleException('Eclipse project metadata is missing its Buildship nature or builder') } + File eclipseModMetadata = file('bin/main/mcmod.info') + if (!eclipseModMetadata.isFile()) { + throw new GradleException('Eclipse output is missing processed mcmod.info') + } + def eclipseMetadata = new JsonSlurper().parseText(eclipseModMetadata.getText('UTF-8')) + def eclipseMod = eclipseMetadata instanceof List ? eclipseMetadata.first() : eclipseMetadata + if (eclipseMod.version != project.mod_version || eclipseMod.mcversion != project.mc_version) { + throw new GradleException('Eclipse output contains unexpanded or incorrect mod metadata') + } + ['README.md', 'PLAYER_GUIDE.md', 'DEVELOPER_GUIDE.md', + 'CONTENT_CONFIG.md', 'PROVIDER.md', 'VERSIONS.md'].each { guide -> + if (!file("bin/main/META-INF/mineralogy/docs/${guide}").isFile()) { + throw new GradleException("Eclipse output is missing bundled guide ${guide}") + } + } + ['MinecraftMineralogy_Client.launch', 'MinecraftMineralogy_Server.launch'].each { name -> if (file(name).exists()) { throw new GradleException("Obsolete ForgeGradle 2 Eclipse launch still exists: ${name}") @@ -720,6 +780,7 @@ tasks.register('verifyEclipseProductionClasspath') { tasks.register('isolateEclipseProductionRuns') { group = 'ide' description = 'Normalizes ordinary ForgeGradle Eclipse launches for production-only execution.' + dependsOn prepareEclipseResources doLast { [ 'MinecraftMineralogy_Client.launch': 'MAIN_TYPE" value="GradleStart"', diff --git a/docs/DEVELOPER_GUIDE.md b/docs/DEVELOPER_GUIDE.md index 129d0fb49..7644cb12e 100644 --- a/docs/DEVELOPER_GUIDE.md +++ b/docs/DEVELOPER_GUIDE.md @@ -72,7 +72,20 @@ Import the nested checkout into Eclipse as an existing Gradle project. Do not run the legacy `setupDecompWorkspace` task. Regenerate the Forge run configurations after changing the checkout path or Gradle cache; Mineralogy's normalization task keeps the ordinary client/server launches production-only -and safely quotes Slime Launcher paths containing spaces. +and safely quotes Slime Launcher paths containing spaces. It also copies the +Gradle-processed resources into Eclipse's merged `bin/main`, so expanded +metadata and the bundled guide are identical to a Gradle development run. + +OreSpawn's released jar owns the production access transformer. ForgeGradle 7 +does not remap a dependency transform for Minecraft's mapped development +classes, so this project mirrors OreSpawn's two rules with mapped field names +in `gradle/orespawn-development-access-transformer.cfg`. The dependency audit +keeps those rules aligned with the released jar, and the development-only file +must never be packaged by Mineralogy. + +For a disposable Gradle runtime, pass +`-PmineralogyRunDirectory=build/`; Eclipse continues to use the +normal `run` directory unless that Gradle property is deliberately supplied. Inspect complete client/server logs and test the reobfuscated jar with released OreSpawn in a launcher-like Forge installation. The normal jar packages this diff --git a/gradle/orespawn-development-access-transformer.cfg b/gradle/orespawn-development-access-transformer.cfg new file mode 100644 index 000000000..f6e960f5f --- /dev/null +++ b/gradle/orespawn-development-access-transformer.cfg @@ -0,0 +1,2 @@ +public-f net.minecraft.world.WorldProvider biomeProvider +public-f net.minecraft.world.gen.ChunkProviderOverworld oceanBlock diff --git a/src/test/java/zone/moddev/mc/mineralogy/VersionContractTest.java b/src/test/java/zone/moddev/mc/mineralogy/VersionContractTest.java index a7e2ebf8b..285db8dd0 100644 --- a/src/test/java/zone/moddev/mc/mineralogy/VersionContractTest.java +++ b/src/test/java/zone/moddev/mc/mineralogy/VersionContractTest.java @@ -8,6 +8,7 @@ import java.io.FileInputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.util.Arrays; import java.util.Properties; import org.junit.Test; @@ -57,6 +58,9 @@ public void modernBuildAndReleaseMetadataKeepTheRequiredOreSpawnContract() throw assertTrue(build.contains("id 'net.minecraftforge.renamer' version '1.1.5'")); assertTrue(build.contains("JavaLanguageVersion.of(8)")); assertTrue(build.contains("tasks.register('verifyReleaseDependencies')")); + assertTrue(build.contains("accessTransformer.from(file('gradle/orespawn-development-access-transformer.cfg'))")); + assertTrue(build.contains("Development access transformer no longer matches released OreSpawn semantics")); + assertTrue(build.contains("providers.gradleProperty('mineralogyRunDirectory').getOrElse('run')")); assertTrue(build.contains("tasks.register('verifyPreparedReleaseArtifacts')")); assertTrue(build.contains("providers.gradleProperty('preparedReleaseDir')")); assertTrue(wrapper.contains("gradle-9.6.1-bin.zip")); @@ -67,6 +71,12 @@ public void modernBuildAndReleaseMetadataKeepTheRequiredOreSpawnContract() throw assertEquals("4.0.6.110021", properties.getProperty("orespawn_version")); assertFalse(properties.containsKey("create_api_jar")); assertFalse(properties.containsKey("create_deobf_jar")); + + assertEquals(Arrays.asList( + "public-f net.minecraft.world.WorldProvider biomeProvider", + "public-f net.minecraft.world.gen.ChunkProviderOverworld oceanBlock"), + Files.readAllLines(new File("gradle/orespawn-development-access-transformer.cfg").toPath(), + StandardCharsets.UTF_8)); } @Test @@ -75,6 +85,10 @@ public void eclipseLaunchNormalizationQuotesWhitespacePathsAndVerifiesThem() thr String project = read(new File(".project")); assertTrue(build.contains("tasks.register('configureEclipseBuildship')")); assertTrue(build.contains("tasks.register('isolateEclipseProductionRuns')")); + assertTrue(build.contains("tasks.register('prepareEclipseResources')")); + assertTrue(build.contains("dependsOn prepareEclipseResources")); + assertTrue(build.contains("Eclipse output contains unexpanded or incorrect mod metadata")); + assertTrue(build.contains("Eclipse output is missing bundled guide")); assertTrue(build.contains("['--cache', '--metadata', '--to-srg', '--to-obf']")); assertTrue(build.contains("+ '"' + value + '"'")); assertTrue(build.contains("leaves whitespace unquoted"));