Skip to content

Commit e8e45a6

Browse files
committed
Backport OreSpawn 4.0.5 to NeoForge 1.21.11
1 parent 54669f6 commit e8e45a6

32 files changed

Lines changed: 1876 additions & 1252 deletions

‎CHANGELOG.txt‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
Version 4.0.5
2+
3+
* Complete native translations for every shipped non-English locale
4+
* Add automatic fresh-and-reload validation for provider-owned custom biomes
5+
* Correct NeoForge biome terminology and Minecraft 1.21.11 Identifier documentation
6+
* Preserve public API major 1 and provider/global/world schemas 4/6/5
7+
18
Version 3.3.1
29

310
* Fix several bugs

‎README.md‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# MMD OreSpawn
22

3-
OreSpawn 4 is a provider-driven world-generation engine for Minecraft 1.21.1.
3+
OreSpawn 4 is a provider-driven world-generation engine for Minecraft 1.21.11.
44
It gives mods and modpacks one place to configure ores, deposit shapes, optional
55
rock strata and geomes, provider-owned underground fluid deposits, biome
66
palettes and world materials, flat bedrock, and bounded ore retrogen.
@@ -79,10 +79,19 @@ exported to `config/orespawn-guide/` without overwriting existing files.
7979
Use Java 21 from the repository root:
8080

8181
```powershell
82-
.\gradlew.bat test processResources build javadoc --no-daemon
82+
.\gradlew.bat clean build javadoc --no-daemon
8383
.\gradlew.bat eclipse --no-daemon
8484
```
8585

86+
`build` runs the standard `check` lifecycle. In addition to the JUnit suite,
87+
that lifecycle packages a test-only provider mod, loads its custom biome in
88+
normal noise terrain, and verifies both fresh generation and reopening the
89+
same saved world. The fixture is not included in OreSpawn's published jars.
90+
91+
Import or refresh the project with Eclipse Buildship. NeoGradle supplies the
92+
Eclipse model and run configurations through the `eclipse` task; this branch
93+
does not use ForgeGradle's `genEclipseRuns` task.
94+
8695
Machine-specific `AGENTS.md` and `agent-notes/` files are intentionally ignored.
8796
Public developer and AI integration guidance lives in `docs/` and is included
8897
in the built jar.

‎build.gradle‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,17 @@ runs {
9898
file('src/generated/resources/').absolutePath, '--existing',
9999
file('src/main/resources/').absolutePath
100100
}
101+
102+
['Fresh', 'Reload'].each { String phase ->
103+
register("biomeIntegration${phase}") {
104+
runType 'gameTestServer'
105+
workingDirectory layout.buildDirectory.dir('biome-integration-run')
106+
systemProperty 'neoforge.enabledGameTestNamespaces', 'cakeworldprobe'
107+
systemProperty 'forge.logging.console.level', 'info'
108+
systemProperty 'cakeworld.biomeIntegrationPhase', phase.toLowerCase(Locale.ROOT)
109+
modSource project.sourceSets.main
110+
}
111+
}
101112
}
102113

103114
configurations {
@@ -188,6 +199,75 @@ tasks.named('test', Test).configure {
188199
useJUnitPlatform()
189200
}
190201

202+
def biomeIntegrationClasses = layout.buildDirectory.dir('biome-integration-fixture/classes')
203+
def compileBiomeIntegrationTestMod = tasks.register('compileBiomeIntegrationTestMod', JavaCompile) {
204+
dependsOn tasks.named('classes')
205+
source fileTree('src/biomeIntegrationTest/java')
206+
classpath = files(sourceSets.main.output, sourceSets.main.compileClasspath)
207+
destinationDirectory.set(biomeIntegrationClasses)
208+
javaCompiler.set(javaToolchains.compilerFor {
209+
languageVersion = JavaLanguageVersion.of(21)
210+
})
211+
options.release = 16
212+
options.encoding = 'UTF-8'
213+
}
214+
215+
def biomeIntegrationTestModJar = tasks.register('biomeIntegrationTestModJar', Jar) {
216+
dependsOn compileBiomeIntegrationTestMod
217+
archiveFileName = 'cakeworldprobe.jar'
218+
destinationDirectory = layout.buildDirectory.dir('biome-integration-fixture')
219+
manifest {
220+
attributes 'MixinConfigs': 'cakeworldprobe.mixins.json'
221+
}
222+
from biomeIntegrationClasses
223+
from 'src/biomeIntegrationTest/resources'
224+
}
225+
226+
def biomeIntegrationRunDirectory = layout.buildDirectory.dir('biome-integration-run')
227+
def prepareBiomeIntegrationTest = tasks.register('prepareBiomeIntegrationTest') {
228+
dependsOn biomeIntegrationTestModJar
229+
doLast {
230+
delete biomeIntegrationRunDirectory
231+
copy {
232+
from biomeIntegrationTestModJar.flatMap { it.archiveFile }
233+
into biomeIntegrationRunDirectory.map { it.dir('mods') }
234+
}
235+
}
236+
}
237+
238+
tasks.configureEach {
239+
if (name == 'runBiomeIntegrationFresh') {
240+
dependsOn prepareBiomeIntegrationTest
241+
} else if (name == 'runBiomeIntegrationReload') {
242+
dependsOn 'runBiomeIntegrationFresh'
243+
}
244+
}
245+
246+
def biomeIntegrationTest = tasks.register('biomeIntegrationTest') {
247+
group = 'verification'
248+
description = 'Verifies a provider-owned custom biome in fresh and reloaded normal terrain.'
249+
dependsOn 'runBiomeIntegrationReload'
250+
doLast {
251+
File marker = biomeIntegrationRunDirectory.get().file(
252+
'gametestserver/gametestworld/cakeworld-biome-integration.properties').asFile
253+
if (!marker.isFile()) {
254+
throw new GradleException("Biome integration completion marker is missing: ${marker}")
255+
}
256+
Properties result = new Properties()
257+
marker.withInputStream { result.load(it) }
258+
if (result.getProperty('reload_verified') != 'true') {
259+
throw new GradleException("Biome integration reload was not verified: ${marker}")
260+
}
261+
logger.lifecycle('Custom-biome integration verified: {} chunks, {} top blocks, {} filler blocks, fresh + reload',
262+
result.getProperty('matching_chunks'), result.getProperty('pink_surface'),
263+
result.getProperty('white_filler'))
264+
}
265+
}
266+
267+
tasks.named('check') {
268+
dependsOn biomeIntegrationTest
269+
}
270+
191271
idea {
192272
module {
193273
downloadSources = true

‎docs/AGENTS.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
# OreSpawn Documentation For Coding Agents
1+
# OreSpawn Documentation Map
22

3-
This index is for coding agents working on other mods or modpacks that integrate
4-
with OreSpawn. Start with [DEVELOPER_GUIDE.md](DEVELOPER_GUIDE.md).
3+
This index is for navigating the documentation to learn how to integrate with
4+
and use OreSpawn with a mod or modpack.
5+
Start with [DEVELOPER_GUIDE.md](DEVELOPER_GUIDE.md).
56

67
Use the focused guides for implementation details:
78

‎docs/API.md‎

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Submit declarations during `InterModEnqueueEvent`:
2121

2222
```java
2323
WorldgenProvider provider = WorldgenProvider.builder("examplemod", 1)
24-
.rock(ResourceLocation.fromNamespaceAndPath("examplemod", "slate"), GeologyFamily.METAMORPHIC, rock -> rock
24+
.rock(Identifier.fromNamespaceAndPath("examplemod", "slate"), GeologyFamily.METAMORPHIC, rock -> rock
2525
.depth(12, 36)
2626
.weight(1.2)
2727
.oreReplaceable(true))
@@ -33,7 +33,7 @@ For a complete ore-only Java example, including dimensions, height curves,
3333
patterns, and host tags, see `DEVELOPER_GUIDE.md`.
3434

3535
Definitions are immutable after `build()`. Registry references remain
36-
`ResourceLocation` values until OreSpawn validates and bakes them. Provider
36+
`Identifier` values until OreSpawn validates and bakes them. Provider
3737
messages are processed through NeoForge IMC and frozen at load completion; direct
3838
cross-mod mutation during parallel setup is unsupported.
3939

@@ -56,17 +56,17 @@ FormationDefinition formations = FormationDefinition.builder()
5656
.waviness(FormationPreset.LARGE)
5757
.build();
5858
FluidDepositDefinition brine = FluidDepositDefinition.builder(
59-
ResourceLocation.fromNamespaceAndPath("examplemod", "fluid_deposit/brine"),
60-
ResourceLocation.fromNamespaceAndPath("examplemod", "brine"))
61-
.dimension(ResourceLocation.fromNamespaceAndPath("minecraft", "overworld"), placement -> placement
59+
Identifier.fromNamespaceAndPath("examplemod", "fluid_deposit/brine"),
60+
Identifier.fromNamespaceAndPath("examplemod", "brine"))
61+
.dimension(Identifier.fromNamespaceAndPath("minecraft", "overworld"), placement -> placement
6262
.yRange(-48, 32)
6363
.attempts(0.05)
6464
.radius(4, 10)
6565
.verticalRadius(2, 4)
6666
.maxLobes(3)
6767
.minSolidCover(2)
6868
.minSolidShell(1)
69-
.hostTag(ResourceLocation.fromNamespaceAndPath("minecraft", "stone_ore_replaceables")))
69+
.hostTag(Identifier.fromNamespaceAndPath("minecraft", "stone_ore_replaceables")))
7070
.build();
7171

7272
WorldgenProvider provider = WorldgenProvider.builder("examplemod", 1)
@@ -77,14 +77,14 @@ WorldgenProvider provider = WorldgenProvider.builder("examplemod", 1)
7777
`OilDefinition` and template `.oil(...)` remain deprecated migration adapters
7878
for one legacy oil rule. New integrations should use `FluidDepositDefinition`.
7979

80-
NeoForge 21.1 biomes are data-driven registry entries. Package biome JSON under
80+
Minecraft 1.21.11 biomes are data-driven registry entries. Package biome JSON under
8181
`data/<modid>/worldgen/biome/`, or generate it with a
8282
`DatapackBuiltinEntriesProvider`. `OreSpawnBiomes.copyAndRegister` is an
8383
optional bootstrap/datagen convenience for cloning a known biome:
8484

8585
```java
8686
public static final ResourceKey<Biome> CANDY_PLAINS = ResourceKey.create(
87-
Registries.BIOME, ResourceLocation.fromNamespaceAndPath("examplemod", "candy_plains"));
87+
Registries.BIOME, Identifier.fromNamespaceAndPath("examplemod", "candy_plains"));
8888

8989
public static final RegistrySetBuilder BIOME_BUILDER = new RegistrySetBuilder()
9090
.add(Registries.BIOME, context -> {
@@ -99,21 +99,21 @@ materials through the same OreSpawn provider:
9999

100100
```java
101101
WorldgenProvider provider = WorldgenProvider.builder("examplemod", 1)
102-
.biomePalette(ResourceLocation.fromNamespaceAndPath("examplemod", "overworld"),
103-
ResourceLocation.fromNamespaceAndPath("minecraft", "overworld"), palette -> palette
102+
.biomePalette(Identifier.fromNamespaceAndPath("examplemod", "overworld"),
103+
Identifier.fromNamespaceAndPath("minecraft", "overworld"), palette -> palette
104104
.mode(BiomePlacementMode.REPLACE)
105105
.scope(BiomeReplacementScope.MINECRAFT_ONLY)
106106
.regionSize(BiomeRegionSize.LARGE)
107107
.coverage(1.0)
108108
.fallbackWeight(0.0)
109-
.biome(ResourceLocation.fromNamespaceAndPath("examplemod", "candy_plains"), biome -> biome
109+
.biome(Identifier.fromNamespaceAndPath("examplemod", "candy_plains"), biome -> biome
110110
.weight(3.0)
111-
.similarBiome(ResourceLocation.fromNamespaceAndPath("minecraft", "plains"))))
112-
.dimensionMaterials(ResourceLocation.fromNamespaceAndPath("examplemod", "overworld_materials"),
113-
ResourceLocation.fromNamespaceAndPath("minecraft", "overworld"), materials -> materials
114-
.defaultFluid(ResourceLocation.fromNamespaceAndPath("examplemod", "lemonade"))
115-
.snowBlock(ResourceLocation.fromNamespaceAndPath("examplemod", "icing"))
116-
.iceBlock(ResourceLocation.fromNamespaceAndPath("examplemod", "frozen_lemonade")))
111+
.similarBiome(Identifier.fromNamespaceAndPath("minecraft", "plains"))))
112+
.dimensionMaterials(Identifier.fromNamespaceAndPath("examplemod", "overworld_materials"),
113+
Identifier.fromNamespaceAndPath("minecraft", "overworld"), materials -> materials
114+
.defaultFluid(Identifier.fromNamespaceAndPath("examplemod", "lemonade"))
115+
.snowBlock(Identifier.fromNamespaceAndPath("examplemod", "icing"))
116+
.iceBlock(Identifier.fromNamespaceAndPath("examplemod", "frozen_lemonade")))
117117
.build();
118118
```
119119

‎docs/BIOMES.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ known biome's complete builder inside a `RegistrySetBuilder` bootstrap:
100100

101101
```java
102102
public static final ResourceKey<Biome> CANDY_PLAINS = ResourceKey.create(
103-
Registries.BIOME, ResourceLocation.fromNamespaceAndPath("examplemod", "candy_plains"));
103+
Registries.BIOME, Identifier.fromNamespaceAndPath("examplemod", "candy_plains"));
104104

105105
public static final RegistrySetBuilder BIOME_BUILDER = new RegistrySetBuilder()
106106
.add(Registries.BIOME, context -> {
@@ -114,7 +114,7 @@ public static final RegistrySetBuilder BIOME_BUILDER = new RegistrySetBuilder()
114114
datagen that deliberately supplies every required climate, effects, spawn, and
115115
generation field. Both helpers create datapack content; live placement belongs
116116
in the provider declaration. Do not use a static `DeferredRegister<Biome>`:
117-
NeoForge 21.1 biomes belong to the dynamic world registry.
117+
Minecraft 1.21.11 biomes belong to the dynamic world registry.
118118

119119
## Surfaces And Materials
120120

‎docs/DEVELOPER_GUIDE.md‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ import zone.moddev.mc.orespawn.api.OreDimensionSelector;
8585
import zone.moddev.mc.orespawn.api.OrePattern;
8686
import zone.moddev.mc.orespawn.api.OreSpawnApi;
8787
import zone.moddev.mc.orespawn.api.WorldgenProvider;
88-
import net.minecraft.resources.ResourceLocation;
88+
import net.minecraft.resources.Identifier;
8989
import net.neoforged.fml.event.lifecycle.InterModEnqueueEvent;
9090

9191
private void enqueueWorldgen(InterModEnqueueEvent event) {
92-
ResourceLocation tin = ResourceLocation.fromNamespaceAndPath("examplemod", "tin_ore");
92+
Identifier tin = Identifier.fromNamespaceAndPath("examplemod", "tin_ore");
9393
WorldgenProvider provider = WorldgenProvider.builder("examplemod", 1)
9494
.ore(tin, ore -> ore
9595
.retrogen(false)
@@ -100,7 +100,7 @@ private void enqueueWorldgen(InterModEnqueueEvent event) {
100100
.quantityRange(4, 11)
101101
.pattern(OrePattern.VEIN)
102102
.heightDistribution(OreHeightDistribution.TRIANGLE)
103-
.hostTag(ResourceLocation.fromNamespaceAndPath("minecraft", "stone_ore_replaceables"))))
103+
.hostTag(Identifier.fromNamespaceAndPath("minecraft", "stone_ore_replaceables"))))
104104
.build();
105105

106106
OreSpawnApi.enqueue(provider);
@@ -197,3 +197,11 @@ bounded ore or bedrock retrogen is enabled.
197197
and without compatibility mods.
198198
6. Confirm the provider appears in `/orespawn status`.
199199
7. Test a new world; profile edits do not rewrite already generated terrain.
200+
201+
OreSpawn's own standard `check` lifecycle includes a consumer-style biome
202+
integration test. It loads a separate test provider and datapack biome, proves
203+
the provider is active, verifies biome selection, climate and configured
204+
surface blocks in non-flat terrain, then reopens and rechecks the same saved
205+
world. Run `gradlew check` (or `gradlew build`, which includes it) before
206+
publishing any change to biome registration, palettes, surfaces or profile
207+
persistence.

‎gradle.properties‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mod_name=MMD OreSpawn
3030
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
3131
mod_license=LGPL-2.1
3232
# The mod version. See https://semver.org/
33-
mod_version=4.0.4
33+
mod_version=4.0.5
3434
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
3535
# This should match the base package used for the mod sources.
3636
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html

0 commit comments

Comments
 (0)