Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
* text=auto
# Store and check out repository text as LF on every platform. Windows command
# files are the sole exception below.
* text=auto eol=lf

*.bat text eol=crlf
#*.bat text eol=lf
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
Version 4.0.5

* Complete native translations for every shipped non-English locale
* Add automatic fresh-and-reload validation for provider-owned custom biomes
* Correct NeoForge biome terminology while retaining the Minecraft 1.21.1 ResourceLocation API
* Preserve public API major 1 and provider/global/world schemas 4/6/5

Version 3.3.1

* Fix several bugs
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,19 @@ exported to `config/orespawn-guide/` without overwriting existing files.
Use Java 21 from the repository root:

```powershell
.\gradlew.bat test processResources build javadoc --no-daemon
.\gradlew.bat clean build javadoc --no-daemon
.\gradlew.bat eclipse --no-daemon
```

`build` runs the standard `check` lifecycle. In addition to the JUnit suite,
that lifecycle packages a test-only provider mod, loads its custom biome in
normal noise terrain, and verifies both fresh generation and reopening the
same saved world. The fixture is not included in OreSpawn's published jars.

Import or refresh the project with Eclipse Buildship. NeoGradle supplies the
Eclipse model and run configurations through the `eclipse` task; this branch
does not use ForgeGradle's `genEclipseRuns` task.

Machine-specific `AGENTS.md` and `agent-notes/` files are intentionally ignored.
Public developer and AI integration guidance lives in `docs/` and is included
in the built jar.
Expand Down
93 changes: 93 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ runs {
file('src/generated/resources/').absolutePath, '--existing',
file('src/main/resources/').absolutePath
}

['Fresh', 'Reload'].each { String phase ->
register("biomeIntegration${phase}") {
runType 'server'
workingDirectory layout.buildDirectory.dir('biome-integration-run')
systemProperty 'forge.logging.console.level', 'info'
systemProperty 'cakeworld.biomeIntegrationPhase', phase.toLowerCase(Locale.ROOT)
argument '--nogui'
modSource project.sourceSets.main
}
}
}

configurations {
Expand Down Expand Up @@ -189,6 +200,88 @@ tasks.named('test', Test).configure {
useJUnitPlatform()
}

def biomeIntegrationClasses = layout.buildDirectory.dir('biome-integration-fixture/classes')
def compileBiomeIntegrationTestMod = tasks.register('compileBiomeIntegrationTestMod', JavaCompile) {
dependsOn tasks.named('classes')
source fileTree('src/biomeIntegrationTest/java')
classpath = files(sourceSets.main.output, sourceSets.main.compileClasspath)
destinationDirectory.set(biomeIntegrationClasses)
javaCompiler.set(javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(21)
})
options.release = 21
options.encoding = 'UTF-8'
}

def biomeIntegrationTestModJar = tasks.register('biomeIntegrationTestModJar', Jar) {
dependsOn compileBiomeIntegrationTestMod
archiveFileName = 'cakeworldprobe.jar'
destinationDirectory = layout.buildDirectory.dir('biome-integration-fixture')
from biomeIntegrationClasses
from 'src/biomeIntegrationTest/resources'
}

def biomeIntegrationRunDirectory = layout.buildDirectory.dir('biome-integration-run')
def prepareBiomeIntegrationTest = tasks.register('prepareBiomeIntegrationTest') {
dependsOn biomeIntegrationTestModJar
doLast {
File runDirectory = biomeIntegrationRunDirectory.get().asFile
delete runDirectory
runDirectory.mkdirs()
copy {
from biomeIntegrationTestModJar.flatMap { it.archiveFile }
into biomeIntegrationRunDirectory.map { it.dir('mods') }
}
new File(runDirectory, 'server.properties').setText('''\
level-name=biome-integration-world
level-seed=-4965128775892001975
level-type=minecraft:normal
online-mode=false
allow-nether=true
generate-structures=false
spawn-protection=0
max-tick-time=-1
''', 'UTF-8')
}
}

tasks.configureEach {
if (name == 'runBiomeIntegrationFresh') {
dependsOn prepareBiomeIntegrationTest
} else if (name == 'runBiomeIntegrationReload') {
dependsOn 'runBiomeIntegrationFresh'
}
}

def biomeIntegrationTest = tasks.register('biomeIntegrationTest') {
group = 'verification'
description = 'Verifies a provider-owned custom biome in fresh and reloaded normal terrain.'
dependsOn 'runBiomeIntegrationReload'
doLast {
File marker = biomeIntegrationRunDirectory.get().file(
'biome-integration-world/cakeworld-biome-integration.properties').asFile
if (!marker.isFile()) {
throw new GradleException("Biome integration completion marker is missing: ${marker}")
}
Properties result = new Properties()
marker.withInputStream { result.load(it) }
if (result.getProperty('reload_verified') != 'true') {
throw new GradleException("Biome integration reload was not verified: ${marker}")
}
File eulaFile = biomeIntegrationRunDirectory.get().file('eula.txt').asFile
if (eulaFile.exists()) {
throw new GradleException("Biome integration test unexpectedly created an EULA file: ${eulaFile}")
}
logger.lifecycle('Custom-biome integration verified: {} chunks, {} top blocks, {} filler blocks, fresh + reload',
result.getProperty('matching_chunks'), result.getProperty('pink_surface'),
result.getProperty('white_filler'))
}
}

tasks.named('check') {
dependsOn biomeIntegrationTest
}

idea {
module {
downloadSources = true
Expand Down
85 changes: 12 additions & 73 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,15 @@
# OreSpawn Integration Notes For Coding Agents
# OreSpawn Documentation Map

OreSpawn 4.0 is a required NeoForge mod and declarative world-generation engine.
Public API major version 1 consists only of `zone.moddev.mc.orespawn.api`. Treat
every other Java package as internal and unstable.
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).

Integration entry points:
Use the focused guides for implementation details:

- Java declarations: `OreSpawnApi.enqueue(WorldgenProvider)` during
`InterModEnqueueEvent`.
- Packaged declarations: `data/<modid>/orespawn/provider.json`.
- Pack overrides: `config/<modid>-orespawn.json`.
- Active queries: `getActiveProfile(MinecraftServer)` and
`createSampler(ServerLevel)`.
- Native-ore takeover: disable only when `isOreTakeoverActive(modid)` is true.

Configuration contracts:

- Global `config/orespawn-worldgen.json`: schema 6.
- World `serverconfig/orespawn-worldgen.json`: schema 5.
- Provider files: schema 4; legacy schemas 1-3 remain accepted.
- Ore placement accepts fixed `quantity` or paired inclusive
`min_quantity`/`max_quantity` values in the range 1-64. A complete range is
authoritative when both forms exist.
- `dimension_selectors.orespawn:all_except_nether_end` applies to ordinary
dimensions but never Nether or End. Explicit dimension entries override it
per ore and must also drive vanilla-feature suppression.
- JSON Schemas and examples are under `META-INF/orespawn/docs/` in the jar.
- Schema 4 providers may declare `biome_palettes` and `dimension_materials`.
Palettes wrap the native dimension biome source. Region presets are 128,
256, 512, 1024, and 2048 blocks.

Lifecycle and ownership:

- NeoForge setup is parallel. Never mutate OreSpawn internals directly.
- A pack override file is authoritative over packaged and API definitions for
the same provider. A malformed override fails closed.
- Provider rule IDs use the provider namespace. A rule's `block` or weighted
output may reference any installed block.
- Definitions freeze at load completion and change only after restart or an
operator `/orespawn reload`.
- Auto-selected templates apply only to fresh worlds with no explicit
`default_template`. Highest priority wins, then lexical ID. Existing world
profiles never auto-switch.

Performance constraints:

- Do not request callbacks in block-generation loops.
- Registry IDs remain `ResourceLocation` values until setup-time baking.
- Dimension, tag, alias, biome, geome, family, pattern, and block-state
resolution occurs before generation.
- Biome palettes bake holders, climate bounds, namespace filters, weights,
surfaces, and dimension materials. Provider callbacks never run in selection.
- Ore rules support `uniform`, `triangle`, `bottom_triangle`, and
`uniform_bottom_triangle` height distributions plus a 0-1
`discard_chance_on_air_exposure` value for buried deposits.
- The chunk hot path must contain no config reads, registry access, strings,
logging, reflection, or per-block allocation.
- Cache biome filters as registry keys, never `Biome` object identities;
dynamic-registry biome instances are not identity-stable.
- Ore and flat-bedrock retrogen are bounded and marker-based. Terrain strata
are never retrogened.

Compatibility defaults:

- Standalone OreSpawn is passive: no rocks, terrain dimensions, fluid deposits, ore
suppression, retrogen, or flat bedrock are enabled by default.
- The Overworld is the conventional geology target, but a provider must opt it
in. Nether and End terrain remain untouched unless explicitly configured.
- Mineralogy 6 is a provider, not a public-API compatibility facade. Do not use
removed `zone.moddev.mc.mineralogy.api` classes.

Common tasks are documented in `API.md`, `PROVIDERS.md`, `FEATURES.md`,
`TEMPLATES.md`, `BIOMES.md`, and `DIMENSIONS.md`. Start with
`DEVELOPER_GUIDE.md` when the task is broader than one isolated schema or API
question.
- [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;
- [README.md](README.md) for schemas, examples, and the complete documentation index.
8 changes: 8 additions & 0 deletions docs/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,11 @@ bounded ore or bedrock retrogen is enabled.
and without compatibility mods.
6. Confirm the provider appears in `/orespawn status`.
7. Test a new world; profile edits do not rewrite already generated terrain.

OreSpawn's own standard `check` lifecycle includes a consumer-style biome
integration test. It loads a separate test provider and datapack biome, proves
the provider is active, verifies biome selection, tags, climate and configured
surface blocks in non-flat terrain, then reopens and rechecks the same saved
world. Run `gradlew check` (or `gradlew build`, which includes it) before
publishing any change to biome registration, palettes, surfaces or profile
persistence.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ mod_name=MMD OreSpawn
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=LGPL-2.1
# The mod version. See https://semver.org/
mod_version=4.0.4
mod_version=4.0.5
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
Expand Down
Loading
Loading