Skip to content

Commit e90bf21

Browse files
committed
Tidy up the 1.12 build and editor
1 parent e116069 commit e90bf21

21 files changed

Lines changed: 1952 additions & 1713 deletions

‎.editorconfig‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ root = true
44
end_of_line = lf
55
insert_final_newline = true
66

7+
[*.bat]
8+
end_of_line = crlf
9+
10+
[*.cmd]
11+
end_of_line = crlf
12+
713
[*.java]
814
charset = utf-8
915
indent_style = tab

‎.gitattributes‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* text=auto eol=lf
44

55
*.bat text eol=crlf
6-
#*.bat text eol=lf
6+
*.cmd text eol=crlf
77
*.gradle text diff=java
88
mcmod.info text
99
*.java text

‎README.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ from an empty Gradle home followed by an offline replay from that same cache:
151151
.\gradlew.bat genEclipseRuns verifyEclipseProductionClasspath --no-daemon
152152
```
153153

154+
Git stores text with LF endings and checks out source, guides, and `gradlew`
155+
with LF on every platform. Windows `.bat` and `.cmd` files use CRLF. The
156+
`.gitattributes` and `.editorconfig` files agree on this policy; a fresh
157+
checkout applies it without changing any Git or editor-wide settings.
158+
154159
`build` runs the standard `check` lifecycle. In addition to the JUnit suite,
155160
that lifecycle packages a test-only provider mod and verifies 2,304 exposed
156161
surface columns per built-in normal-noise End and Nether dimension, including

‎build.gradle‎

Lines changed: 42 additions & 1673 deletions
Large diffs are not rendered by default.

‎docs/AGENTS.md‎

Lines changed: 0 additions & 16 deletions
This file was deleted.

‎docs/README.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ Choose the guide that matches what you are doing:
1818
- [Migration](MIGRATION.md)
1919
- [Troubleshooting](TROUBLESHOOTING.md)
2020
- [Versioning and release identities](VERSIONS.md)
21-
- [Compact instructions for coding agents](AGENTS.md)
2221

2322
Validated examples are in `examples/`; JSON Schemas are in `schemas/`.
2423
The provider and migration guides include OS3-compatible ranged quantities and

‎gradle.properties‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,15 @@ curseforge_project_id=245586
2525

2626
mod_id=orespawn
2727
mod_name=MMD OreSpawn
28+
mod_artifact=OreSpawn
29+
mod_vendor=Minecraft Mod Development
2830
mod_license=LGPL-2.1
31+
mod_license_name=GNU Lesser General Public License, Version 2.1
32+
mod_license_url=https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
2933
mod_version=4.1.0.112021
3034
mod_group=zone.moddev.mc.orespawn
3135
mod_authors=SkyBlade1978, dshadowwolf, the MMD Team
3236
mod_description=Configurable, provider-driven terrain, ore, and deposit generation.
37+
mod_url=https://github.com/MinecraftModDevelopmentMods/OreSpawn
38+
mod_scm_connection=scm:git:https://github.com/MinecraftModDevelopmentMods/OreSpawn.git
39+
mod_scm_developer_connection=scm:git:ssh://git@github.com/MinecraftModDevelopmentMods/OreSpawn.git

‎gradle/README.md‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Build logic
2+
3+
`build.gradle` defines the Forge 1.12 project, dependencies, Java 8 toolchain,
4+
resource processing, reproducible archives, and the ordinary development runs.
5+
Editable release identity (name, vendor, artifact name, license, and project
6+
links) lives in `gradle.properties`. The release checks still pin compatibility
7+
fields such as the Maven group and artifact name.
8+
The applied scripts keep the larger qualification and release workflows close
9+
to the tasks they configure:
10+
11+
| Script | Responsibility |
12+
| --- | --- |
13+
| `verification/support.gradle` | Sealed fixtures, Java 8 verification, Forge-run delegation, runtime log audits. |
14+
| `verification/legacy-and-migration.gradle` | Surface and migration worlds, Mineralogy lineage, opt-in OS1/OS3 ABI probes. |
15+
| `verification/client-and-benchmark.gradle` | Client integration and opt-in worldgen benchmark. |
16+
| `verification/packaged-forge.gradle` | Fresh/reload test of the reobfuscated jar under installed Forge 14. |
17+
| `release/artifacts.gradle` | API and release jars, release configuration and artifact audits, checksums. |
18+
| `release/publishing.gradle` | Maven publication, coordinates and credential checks. |
19+
| `ide/eclipse.gradle` | Eclipse resources, integration launches, Buildship and production classpath verification. |
20+
21+
The root applies these scripts in dependency order. `oreSpawnVerification` is
22+
the small helper map shared by verification scripts; `oreSpawnBuild` and
23+
`oreSpawnRelease` expose only values needed across the root, release and IDE
24+
scripts. Keep new tasks in their owning script and keep their public task names
25+
stable for CI and documented commands.
26+
27+
The routine offline gate runs `clean check build javadoc verifyReleaseArtifacts writeReleaseChecksums`.
28+
Run `clientIntegrationProcess` separately for rendered client and editor coverage,
29+
and `genEclipseRuns verifyEclipseProductionClasspath` for ordinary production-only
30+
IDE launches.
31+
`legacyAbiIntegrationTest` and `benchmarkIntegrationProcess` remain opt-in
32+
compatibility and performance gates. The benchmark requires `benchmarkRunDir`;
33+
the packaged server gate requires `packagedMinecraftServerJar` and
34+
`packagedForgeLibrariesRoot`, and its server command ends with literal `nogui`.
35+
All gates support the existing `--offline --no-daemon` workflow.

‎gradle/ide/eclipse.gradle‎

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
def buildValues = project.ext.oreSpawnBuild
2+
def trackedDocumentationFiles = buildValues.trackedDocumentationFiles
3+
def documentationRelativePath = buildValues.documentationRelativePath
4+
5+
// These Eclipse shortcuts run the same Gradle world and client checks used on
6+
// the command line, each in its own disposable directory.
7+
task syncForge12EclipseIntegrationLaunches {
8+
group = 'ide'
9+
doLast {
10+
def writeGradleLaunch = { String fileName, String displayName, String arguments ->
11+
File launch = file(fileName)
12+
String escapedArguments = arguments
13+
.replace('&', '&')
14+
.replace('"', '"')
15+
launch.setText("""<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
16+
<launchConfiguration type=\"org.eclipse.ui.externaltools.ProgramLaunchConfigurationType\">
17+
<stringAttribute key=\"org.eclipse.debug.core.ATTR_REFRESH_SCOPE\" value=\"${'$'}{workspace}\"/>
18+
<stringAttribute key=\"org.eclipse.ui.externaltools.ATTR_LOCATION\" value=\"${'$'}{project_loc}\\gradlew.bat\"/>
19+
<stringAttribute key=\"org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS\" value=\"${escapedArguments}\"/>
20+
<stringAttribute key=\"org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY\" value=\"${'$'}{project_loc}\"/>
21+
<stringAttribute key=\"org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE\" value=\"${'$'}{project}\"/>
22+
<stringAttribute key=\"org.eclipse.ui.externaltools.ATTR_NAME\" value=\"${displayName}\"/>
23+
</launchConfiguration>
24+
""", 'UTF-8')
25+
}
26+
27+
writeGradleLaunch('OreSpawn_Surface_FreshReload.launch',
28+
'OreSpawn surface fresh/reload gate',
29+
'surfaceIntegrationTest --offline --no-daemon')
30+
writeGradleLaunch('OreSpawn_Migration_Fresh.launch',
31+
'OreSpawn migration fresh gate',
32+
'migrationIntegrationProcess --offline --no-daemon ' +
33+
'-PmigrationRunDir=build/eclipse-migration-run ' +
34+
'-PmigrationFamily=eclipse-manual -PmigrationPhase=fresh')
35+
writeGradleLaunch('OreSpawn_Migration_Reload.launch',
36+
'OreSpawn migration reload gate',
37+
'migrationIntegrationProcess --offline --no-daemon ' +
38+
'-PmigrationRunDir=build/eclipse-migration-run ' +
39+
'-PmigrationFamily=eclipse-manual -PmigrationPhase=reload')
40+
writeGradleLaunch('OreSpawn_Client_FreshReload.launch',
41+
'OreSpawn client world and editor fresh/reload gate',
42+
'clientIntegrationProcess --offline --no-daemon')
43+
}
44+
}
45+
46+
tasks.named('genEclipseRuns') {
47+
finalizedBy syncForge12EclipseIntegrationLaunches
48+
}
49+
50+
51+
// Eclipse owns bin/main, but it still needs Gradle's expanded mcmod.info and
52+
// bundled guides there before a development launch can see the real mod.
53+
def prepareEclipseResources = tasks.register('prepareEclipseResources') {
54+
group = 'ide'
55+
description = 'Copies Gradle-processed production resources into Eclipse merged output.'
56+
dependsOn tasks.named('processResources')
57+
doLast {
58+
// Do not declare bin/main as a Gradle-owned output. Eclipse owns that
59+
// directory and ForgeGradle inspects it while generating launches.
60+
project.copy {
61+
from(layout.buildDirectory.dir('resources/main'))
62+
into(layout.projectDirectory.dir('bin/main'))
63+
}
64+
}
65+
}
66+
67+
68+
// Older ForgeGradle workspaces can retain GradleStart launchers alongside the
69+
// ForgeGradle 7 Buildship launches. Remove only those exact obsolete launch
70+
// types; leave independently maintained launch files untouched.
71+
def obsoleteForgeGradleEclipseLaunches = [
72+
'OreSpawn_Client.launch': 'GradleStart',
73+
'OreSpawn_Server.launch': 'GradleStartServer'
74+
]
75+
76+
eclipse {
77+
classpath {
78+
downloadSources = true
79+
downloadJavadoc = true
80+
}
81+
synchronizationTasks 'isolateEclipseProductionRuns'
82+
}
83+
84+
// Point Buildship at this project's wrapper and the cache used by Gradle runs.
85+
tasks.register('configureEclipseBuildship') {
86+
group = 'ide'
87+
description = 'Creates the Buildship project preferences used by ForgeGradle 7 imports.'
88+
doLast {
89+
File preferencesFile = file('.settings/org.eclipse.buildship.core.prefs')
90+
Properties preferences = new Properties()
91+
Map<String, String> requiredPreferences = [
92+
'eclipse.preferences.version' : '1',
93+
'connection.gradle.distribution': 'GRADLE_DISTRIBUTION(WRAPPER)',
94+
'connection.gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath,
95+
'connection.project.dir' : '',
96+
'gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath,
97+
'override.workspace.settings' : 'true'
98+
]
99+
requiredPreferences.each { key, value -> preferences.setProperty(key, value) }
100+
preferencesFile.parentFile.mkdirs()
101+
preferencesFile.withOutputStream {
102+
preferences.store(it,
103+
'Generated by configureEclipseBuildship; keep Eclipse and command-line caches aligned.')
104+
}
105+
}
106+
}
107+
108+
// ForgeGradle 7 generates a few launch values that Forge 1.12 cannot use as-is.
109+
// Fix those generated files and keep test code out of ordinary client/server runs.
110+
tasks.register('isolateEclipseProductionRuns') {
111+
group = 'ide'
112+
description = 'Normalizes ForgeGradle 7 Eclipse launches and marks ordinary launches as production-only.'
113+
dependsOn tasks.named('genEclipseRuns')
114+
dependsOn tasks.named('configureEclipseBuildship')
115+
dependsOn prepareEclipseResources
116+
117+
doLast {
118+
obsoleteForgeGradleEclipseLaunches.each { String name, String mainClass ->
119+
File launch = file(name)
120+
if (launch.isFile()) {
121+
String contents = launch.getText('UTF-8')
122+
String obsoleteMainType =
123+
"org.eclipse.jdt.launching.MAIN_TYPE\" value=\"${mainClass}\""
124+
if (contents.contains(obsoleteMainType) && !launch.delete()) {
125+
throw new GradleException("Could not remove obsolete ForgeGradle launch ${name}")
126+
}
127+
}
128+
}
129+
130+
// ForgeGradle 7's legacy 1.12 run generator does not know its own
131+
// MC_VERSION token. It emits ${MC_VERSION} as an Eclipse variable,
132+
// which prevents every generated launch from starting. Store the
133+
// target version as a literal environment value instead.
134+
fileTree(project.projectDir) {
135+
include 'run*.launch'
136+
}.files.each { File launch ->
137+
String contents = launch.getText('UTF-8')
138+
contents = contents.replace(
139+
'key="MC_VERSION" value="${MC_VERSION}"',
140+
"key=\"MC_VERSION\" value=\"${minecraft_version}\"")
141+
contents = contents.replace(
142+
'key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="--nogui"',
143+
'key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="nogui"')
144+
launch.setText(contents.replace('\r\n', '\n'), 'UTF-8')
145+
}
146+
147+
['runClient.launch', 'runServer.launch'].each { name ->
148+
File launch = file(name)
149+
if (!launch.isFile()) {
150+
throw new GradleException("ForgeGradle did not generate ${name}")
151+
}
152+
String contents = launch.getText('UTF-8')
153+
if (!contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) {
154+
String marker = '</launchConfiguration>'
155+
String attribute =
156+
' <booleanAttribute key="org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE" value="true"/>'
157+
contents = contents.replace(marker, attribute + '\n' + marker)
158+
}
159+
launch.setText(contents.replace('\r\n', '\n'), 'UTF-8')
160+
}
161+
}
162+
}
163+
164+
// Check the resulting Eclipse files themselves; a successful Gradle build does
165+
// not prove that an IDE launch has the right resources or classpath.
166+
tasks.register('verifyEclipseProductionClasspath') {
167+
group = 'verification'
168+
description = 'Verifies that ordinary generated Eclipse launches exclude tests, fixtures, and probe mods.'
169+
dependsOn tasks.named('isolateEclipseProductionRuns')
170+
dependsOn tasks.named('verifyLegacyOracleIsolation')
171+
172+
doLast {
173+
File buildshipPreferences = file('.settings/org.eclipse.buildship.core.prefs')
174+
if (!buildshipPreferences.isFile()) {
175+
throw new GradleException('Missing Eclipse Buildship project preferences')
176+
}
177+
File eclipseResources = file('bin/main')
178+
List<File> trackedDocs = trackedDocumentationFiles()
179+
if (trackedDocs.size() != 20) {
180+
throw new GradleException("Expected 20 tracked documentation files, found ${trackedDocs.size()}")
181+
}
182+
trackedDocs.each { File source ->
183+
String relative = documentationRelativePath(source)
184+
File eclipseCopy = new File(eclipseResources, "META-INF/orespawn/docs/${relative}")
185+
if (!eclipseCopy.isFile()
186+
|| !java.util.Arrays.equals(source.bytes, eclipseCopy.bytes)) {
187+
throw new GradleException("Eclipse documentation differs for ${relative}")
188+
}
189+
}
190+
[
191+
'mcmod.info',
192+
'META-INF/orespawn/docs/README.md',
193+
'META-INF/orespawn/docs/VERSIONS.md'
194+
].each { relative ->
195+
File required = new File(eclipseResources, relative)
196+
if (!required.isFile()) {
197+
throw new GradleException(
198+
"Eclipse production output is missing processed resource ${relative}")
199+
}
200+
}
201+
String eclipseMetadata = new File(eclipseResources, 'mcmod.info').getText('UTF-8')
202+
if (!eclipseMetadata.contains("\"version\": \"${project.version}\"")
203+
|| !eclipseMetadata.contains(
204+
"\"mcversion\": \"${minecraft_version}\"")) {
205+
throw new GradleException('Eclipse mcmod.info retains unexpanded build placeholders')
206+
}
207+
List<File> launchFiles = fileTree(project.projectDir) {
208+
include 'runClient.launch'
209+
include 'runServer.launch'
210+
include '.eclipse/runClient.launch'
211+
include '.eclipse/runServer.launch'
212+
}.files as List<File>
213+
if (launchFiles.size() < 2) {
214+
throw new GradleException('ForgeGradle did not generate ordinary client/server Eclipse launches')
215+
}
216+
List<File> allGeneratedLaunches = fileTree(project.projectDir) {
217+
include 'run*.launch'
218+
}.files as List<File>
219+
allGeneratedLaunches.each { launch ->
220+
String contents = launch.getText('UTF-8')
221+
if (contents.contains('--nogui')) {
222+
throw new GradleException(
223+
"${launch.name} uses invalid legacy server argument --nogui; expected bare nogui")
224+
}
225+
if (contents.contains('${MC_VERSION}')) {
226+
throw new GradleException(
227+
"${launch.name} retains ForgeGradle's unresolved MC_VERSION token")
228+
}
229+
if (!contents.contains(
230+
"key=\"MC_VERSION\" value=\"${minecraft_version}\"")) {
231+
throw new GradleException(
232+
"${launch.name} does not define literal MC_VERSION=${minecraft_version}")
233+
}
234+
}
235+
obsoleteForgeGradleEclipseLaunches.each { String name, String mainClass ->
236+
File launch = file(name)
237+
if (launch.isFile() && launch.getText('UTF-8').contains(
238+
"org.eclipse.jdt.launching.MAIN_TYPE\" value=\"${mainClass}\"")) {
239+
throw new GradleException(
240+
"Obsolete ForgeGradle ${mainClass} launch remains at ${name}")
241+
}
242+
}
243+
List<String> forbidden = [
244+
'src/test', 'bin/test', 'build/classes/java/test',
245+
'biomeIntegrationTest', 'migrationIntegrationTest', 'clientIntegrationTest',
246+
'os1AbiFixture', 'os3AbiFixture', 'surfaceprobe', 'migrationprobe', 'clientprobe',
247+
'OreSourceEditorProbeBridge', 'junit-', 'opentest4j-', 'junit-platform-',
248+
'Mineralogy-1.10.2-3.3.8.26.jar', 'Mineralogy-1.12.2-3.8.0.53.jar'
249+
]
250+
launchFiles.each { launch ->
251+
String contents = launch.getText('UTF-8').replace('\\', '/')
252+
List<String> present = forbidden.findAll { contents.contains(it) }
253+
if (!present.isEmpty()) {
254+
throw new GradleException("${launch.name} exposes test code/dependencies: ${present}")
255+
}
256+
if (!contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')
257+
|| !contents.contains('value="true"')) {
258+
throw new GradleException("${launch.name} does not exclude test code")
259+
}
260+
if (!contents.contains('PROJECT_ATTR" value="OreSpawn"')) {
261+
throw new GradleException("${launch.name} targets the wrong Eclipse project")
262+
}
263+
}
264+
}
265+
}

0 commit comments

Comments
 (0)