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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ jobs:
if-no-files-found: error
retention-days: 30
path: |
build/libs/OreSpawn-4.0.10.119041.jar
build/libs/OreSpawn-4.0.10.119041-sources.jar
build/libs/OreSpawn-4.0.10.119041-javadoc.jar
build/libs/OreSpawn-4.0.11.119041.jar
build/libs/OreSpawn-4.0.11.119041-sources.jar
build/libs/OreSpawn-4.0.11.119041-javadoc.jar
build/release/SHA256SUMS
CHANGELOG.txt

Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
Version 4.0.11.119041

* Preserve biome-dictionary geome weights when a data-driven biome is reached
through its stable registry key rather than the object baked at startup.
* Apply ore biome include and exclude filters by stable registry key so
dynamic-registry biome instances with the same ID are treated consistently.
* Existing chunks and profile formats are unchanged; the corrections apply to
generation in affected provider biomes.

Version 4.0.10.119041

* Evaluate Stable Layers rock min_y and max_y bounds against actual world Y
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ End" policy used by mods such as Base Metals.
This is not the unrelated mod that adds mobs and dimensions under the same
name.

This branch builds target-qualified version `4.0.10.119041`: the OreSpawn 4.0.10
This branch builds target-qualified version `4.0.11.119041`: the OreSpawn 4.0.11
feature set for Minecraft 1.19.4 and Forge. See the
[versioning policy](docs/VERSIONS.md) for the encoding and release convention.

Expand Down
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ def preparedReleaseDir = providers.gradleProperty('preparedReleaseDir')
tasks.register('verifyReleaseConfiguration') {
group = 'verification'
doLast {
if (project.mod_version != '4.0.10.119041'
if (project.mod_version != '4.0.11.119041'
|| project.mod_group != expectedMavenGroup
|| project.minecraft_version != '1.19.4'
|| project.forge_version != '45.4.0'
Expand All @@ -859,9 +859,9 @@ tasks.register('verifyReleaseConfiguration') {
throw new GradleException('Unexpected dispatcher or Java target metadata')
}
List<String> expectedPublicArtifacts = [
'OreSpawn-4.0.10.119041.jar',
'OreSpawn-4.0.10.119041-sources.jar',
'OreSpawn-4.0.10.119041-javadoc.jar'
'OreSpawn-4.0.11.119041.jar',
'OreSpawn-4.0.11.119041-sources.jar',
'OreSpawn-4.0.11.119041-javadoc.jar'
]
if (base.archivesName.get() != expectedMavenArtifact
|| expectedReleaseFiles.get().collect { it.toString() } != expectedPublicArtifacts) {
Expand All @@ -878,7 +878,7 @@ tasks.register('verifyReleaseConfiguration') {
'src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java',
'README.md', 'CHANGELOG.txt'
].each { path ->
if (!file(path).getText('UTF-8').contains('4.0.10.119041')) {
if (!file(path).getText('UTF-8').contains('4.0.11.119041')) {
throw new GradleException("Release identity missing from ${path}")
}
}
Expand Down
6 changes: 5 additions & 1 deletion docs/VERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Examples:
| 1.16.5 | Forge | `116051` | `4.0.9.116051` |
| 1.17.1 | Forge | `117011` | `4.0.9.117011` |
| 1.18.2 | Forge | `118021` | `4.0.10.118021` |
| 1.19.4 | Forge | `119041` | `4.0.10.119041` |
| 1.19.4 | Forge | `119041` | `4.0.11.119041` |
| 1.20.6 | Forge | `120061` | `4.0.6.120061` |
| 1.21.11 | Forge | `121111` | `4.0.6.121111` |
| 26.1.2 | Forge | `2601021` | `4.0.6.2601021` |
Expand Down Expand Up @@ -155,6 +155,10 @@ Forge 1.18.2 and 1.19.4 then advanced to their target-qualified 4.0.10 releases
for the distinct Stable Layers actual-height eligibility repair. A branch may
therefore legitimately skip functional version numbers.

Forge 1.19.4 then advanced to `4.0.11.119041` to retain biome-dictionary
weights and ore biome filters when a data-driven biome is represented by a
different runtime object with the same stable registry key.

This provides three useful guarantees:

1. A functional version is not used to describe two unrelated change sets.
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ mcp_version=20230314.122934
mod_id=orespawn
mod_name=MMD OreSpawn
mod_license=LGPL-2.1
mod_version=4.0.10.119041
mod_version=4.0.11.119041
mod_group=zone.moddev.mc.orespawn
mod_authors=SkyBlade1978, dshadowwolf, the MMD Team
mod_description=Configurable, provider-driven terrain, ore, and deposit generation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public final class SurfaceProbeTestMod {
private static final ResourceLocation BIOME_A = new ResourceLocation(MODID + ":surface_a");
private static final ResourceLocation BIOME_B = new ResourceLocation(MODID + ":surface_b");
private static final ResourceLocation PROBE_GEOME = new ResourceLocation(MODID + ":dynamic_biome_geome");
private static final ResourceLocation PROBE_GEOME_ALTERNATIVE =
new ResourceLocation(MODID + ":dynamic_biome_geome_alternative");
private static final ResourceLocation DYNAMIC_FLUID = new ResourceLocation(MODID + ":fluid/dynamic_water");
private static final Block[] NATURAL_SOURCES = {
Blocks.DIRT, Blocks.GRASS_BLOCK, Blocks.COARSE_DIRT, Blocks.PODZOL,
Expand Down Expand Up @@ -144,19 +146,34 @@ private static void addDynamicBiomeGeology(WorldgenProvider.Builder provider) {
provider.geome(PROBE_GEOME, geome -> geome
.baseWeight(0.0D)
.familyWeight(GeologyFamily.SEDIMENTARY, 1.0D));
provider.geome(PROBE_GEOME_ALTERNATIVE, geome -> geome
.baseWeight(0.0D)
.familyWeight(GeologyFamily.SEDIMENTARY, 1.0D));
provider.rock(new ResourceLocation(MODID + ":rock/dynamic_biome"), blockId(Blocks.CALCITE),
GeologyFamily.SEDIMENTARY, rock -> {
rock.dimensions(java.util.Collections.singleton(OPEN_ID));
rock.geomeWeight(PROBE_GEOME, 1.0D);
rock.geomeWeight(PROBE_GEOME_ALTERNATIVE, 0.0D);
for (ResourceLocation geome : BUILT_IN_GEOMES) rock.geomeWeight(geome, 0.0D);
});
provider.rock(new ResourceLocation(MODID + ":rock/dynamic_biome_alternative"), blockId(Blocks.BASALT),
GeologyFamily.SEDIMENTARY, rock -> {
rock.dimensions(java.util.Collections.singleton(OPEN_ID));
rock.geomeWeight(PROBE_GEOME, 0.0D);
rock.geomeWeight(PROBE_GEOME_ALTERNATIVE, 1.0D);
for (ResourceLocation geome : BUILT_IN_GEOMES) rock.geomeWeight(geome, 0.0D);
});
provider.rock(new ResourceLocation(MODID + ":rock/fallback"), blockId(Blocks.BASALT),
provider.rock(new ResourceLocation(MODID + ":rock/fallback"), blockId(Blocks.DEEPSLATE),
GeologyFamily.SEDIMENTARY, rock -> {
rock.dimensions(java.util.Collections.singleton(OPEN_ID));
rock.geomeWeight(PROBE_GEOME, 0.0D);
rock.geomeWeight(PROBE_GEOME_ALTERNATIVE, 0.0D);
for (ResourceLocation geome : BUILT_IN_GEOMES) rock.geomeWeight(geome, 1.0D);
});
provider.biome(BIOME_A, java.util.Collections.singletonMap(PROBE_GEOME, 100.0D));
Map<ResourceLocation, Double> biomeAWeights = new LinkedHashMap<>();
biomeAWeights.put(PROBE_GEOME, 6.0D);
biomeAWeights.put(PROBE_GEOME_ALTERNATIVE, 14.0D);
provider.biome(BIOME_A, biomeAWeights);
provider.biome(BIOME_B, java.util.Collections.singletonMap(PROBE_GEOME, 100.0D));
}

Expand All @@ -171,6 +188,19 @@ private void enableGeologyProbe(ServerAboutToStartEvent event) {
}
try {
root.addProperty("place_fluid_deposits", true);
root.addProperty("place_ores", true);
JsonObject dictionary = root.getAsJsonObject("biome_dictionary");
if (dictionary == null) {
dictionary = new JsonObject();
root.add("biome_dictionary", dictionary);
}
JsonObject cold = dictionary.getAsJsonObject("COLD");
if (cold == null) {
cold = new JsonObject();
dictionary.add("COLD", cold);
}
cold.addProperty(PROBE_GEOME.toString(), 8.0D);
addDynamicBiomeOre(root);
JsonObject terrain = root.getAsJsonObject("terrain_dimensions");
if (terrain == null) {
terrain = new JsonObject();
Expand Down Expand Up @@ -200,6 +230,49 @@ private void enableGeologyProbe(ServerAboutToStartEvent event) {
}
}

private static void addDynamicBiomeOre(JsonObject root) {
JsonObject ores = root.getAsJsonObject("ores");
if (ores == null) {
ores = new JsonObject();
root.add("ores", ores);
}
JsonObject ore = new JsonObject();
ore.addProperty("block", blockId(Blocks.DIAMOND_BLOCK).toString());
ore.addProperty("enabled", true);
ore.addProperty("native_generation", false);
ore.addProperty("suppress_vanilla", false);
ore.addProperty("retrogen", false);
JsonObject dimensions = new JsonObject();
JsonObject end = new JsonObject();
end.addProperty("enabled", true);
end.addProperty("min_y", 16);
end.addProperty("max_y", 48);
end.addProperty("frequency", 16.0D);
end.addProperty("quantity", 8);
end.addProperty("pattern", "cluster");
end.addProperty("height_distribution", "uniform");
end.addProperty("discard_chance_on_air_exposure", 0.0D);
end.addProperty("spread", 4);
end.addProperty("vertical_spread", 3);
end.addProperty("node_size", 3);
end.add("host_families", new JsonArray());
JsonArray hosts = new JsonArray();
hosts.add(blockId(Blocks.CALCITE).toString());
hosts.add(blockId(Blocks.BASALT).toString());
end.add("host_blocks", hosts);
end.add("host_tags", new JsonArray());
end.add("geomes", new JsonObject());
JsonArray biomes = new JsonArray();
biomes.add(BIOME_A.toString());
end.add("biome_ids", biomes);
end.add("excluded_biome_ids", new JsonArray());
end.add("biome_dictionary", new JsonArray());
end.add("excluded_biome_dictionary", new JsonArray());
dimensions.add(OPEN_ID.toString(), end);
ore.add("dimensions", dimensions);
ores.add(MODID + ":ore/dynamic_biome_filter", ore);
}

private static void addPalette(WorldgenProvider.Builder provider, String name,
ResourceLocation dimension, boolean ceiling) {
BiomeSurfaceDefinition surfaceA = surface(DyeColor.PINK, DyeColor.WHITE,
Expand Down Expand Up @@ -308,6 +381,8 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
long underwaterPockets = 0L;
long rawBedrock = 0L;
long rawBlockEntities = 0L;
long dictionaryPrimary = 0L;
long dictionaryAlternative = 0L;
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();

for (int chunkZ = MINIMUM_CHUNK; chunkZ <= MAXIMUM_CHUNK; chunkZ++) {
Expand All @@ -317,6 +392,10 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
LevelChunk chunk = level.getChunk(chunkX, chunkZ);
int chunkMinX = chunkX << 4;
int chunkMinZ = chunkZ << 4;
int centerGroundY = findMarkedGround(chunk, pos, chunkMinX + 8, chunkMinZ + 8,
level.getMinBuildHeight(), level.getMaxBuildHeight());
ResourceLocation generationBiomeId = biomeId(level.getBiome(
pos.set(chunkMinX + 8, centerGroundY, chunkMinZ + 8)));
for (int localZ = 0; localZ < 16; localZ++) {
for (int localX = 0; localX < 16; localX++) {
int x = chunkMinX + localX;
Expand Down Expand Up @@ -346,8 +425,15 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
}
if (!roofed) {
for (int depth = 6; depth <= 8; depth++) {
assertBlock(chunk, pos, x, groundY - depth, z,
Blocks.CALCITE.defaultBlockState(), "dynamic-biome geome rock");
BlockState geologyState = chunk.getBlockState(pos.set(x, groundY - depth, z));
if (geologyState.is(Blocks.BASALT)) {
dictionaryAlternative++;
} else if (geologyState.is(Blocks.CALCITE)) {
dictionaryPrimary++;
} else {
throw new IllegalStateException("Unexpected dynamic-biome geome rock at "
+ pos + " in " + biomeId + ": " + geologyState);
}
geology++;
}
}
Expand All @@ -364,11 +450,8 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
}
}
}
ResourceLocation centerBiome = biomeId(level.getBiome(pos.set(chunkMinX + 8,
findMarkedGround(chunk, pos, chunkMinX + 8, chunkMinZ + 8,
level.getMinBuildHeight(), level.getMaxBuildHeight()), chunkMinZ + 8)));
if (previousChunkBiome != null && !previousChunkBiome.equals(centerBiome)) edgeChanges++;
previousChunkBiome = centerBiome;
if (previousChunkBiome != null && !previousChunkBiome.equals(generationBiomeId)) edgeChanges++;
previousChunkBiome = generationBiomeId;
sentinels += auditSentinels(level, chunk, pos, chunkMinX, chunkMinZ);
if (!roofed) {
NaturalSourceAudit natural = auditNaturalSources(level, chunk, pos,
Expand All @@ -384,6 +467,7 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
}
}

long dynamicBiomeOre = roofed ? 0L : auditDynamicBiomeOre(level);
if (top != EXPECTED_COLUMNS - 9 || underwater != 9 || filler != EXPECTED_FILLER
|| biomeA == 0 || biomeB == 0 || edgeChanges == 0 || sentinels != 9 * 4
|| geology != (roofed ? 0 : EXPECTED_FILLER)
Expand All @@ -392,7 +476,9 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
|| structureNaturalSources != EXPECTED_NATURAL_SOURCES
|| vegetationNaturalSources != EXPECTED_NATURAL_SOURCES
|| cavePockets != 54 || underwaterPockets != 63
|| rawBedrock != 9 || rawBlockEntities != 9))) {
|| rawBedrock != 9 || rawBlockEntities != 9
|| dictionaryPrimary != EXPECTED_FILLER || dictionaryAlternative != 0
|| dynamicBiomeOre == 0))) {
throw new IllegalStateException("Incomplete surface audit for " + level.dimension().location()
+ ": top=" + top + ", underwater=" + underwater + ", filler=" + filler
+ ", biomeA=" + biomeA + ", biomeB=" + biomeB + ", edges=" + edgeChanges
Expand All @@ -404,13 +490,38 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
+ ", cavePockets=" + cavePockets
+ ", underwaterPockets=" + underwaterPockets
+ ", rawBedrock=" + rawBedrock
+ ", rawBlockEntities=" + rawBlockEntities);
+ ", rawBlockEntities=" + rawBlockEntities
+ ", dictionaryPrimary=" + dictionaryPrimary
+ ", dictionaryAlternative=" + dictionaryAlternative
+ ", dynamicBiomeOre=" + dynamicBiomeOre);
}
long aquiferFluid = roofed ? 0L : auditDynamicFluid(level);
return new AuditResult(top, underwater, filler, geology, ceiling, roofTop,
biomeA, biomeB, edgeChanges, sentinels, aquiferFluid,
rawNaturalSources, structureNaturalSources, vegetationNaturalSources,
cavePockets, underwaterPockets, rawBedrock, rawBlockEntities);
cavePockets, underwaterPockets, rawBedrock, rawBlockEntities,
dictionaryPrimary, dictionaryAlternative, dynamicBiomeOre);
}

private static long auditDynamicBiomeOre(ServerLevel level) {
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
long count = 0L;
for (int chunkZ = MINIMUM_CHUNK; chunkZ <= MAXIMUM_CHUNK; chunkZ++) {
for (int chunkX = MINIMUM_CHUNK; chunkX <= MAXIMUM_CHUNK; chunkX++) {
LevelChunk chunk = level.getChunk(chunkX, chunkZ);
for (int x = chunk.getPos().getMinBlockX(); x <= chunk.getPos().getMaxBlockX(); x++) {
for (int z = chunk.getPos().getMinBlockZ(); z <= chunk.getPos().getMaxBlockZ(); z++) {
for (int y = 16; y <= 48; y++) {
if (chunk.getBlockState(pos.set(x, y, z)).is(Blocks.DIAMOND_BLOCK)) count++;
}
}
}
}
}
if (count == 0L) {
throw new IllegalStateException("Dynamic-registry biome filter produced no managed ore");
}
return count;
}

private static NaturalSourceAudit auditNaturalSources(ServerLevel level, LevelChunk chunk,
Expand All @@ -427,7 +538,8 @@ private static NaturalSourceAudit auditNaturalSources(ServerLevel level, LevelCh
int z = naturalZ(minZ, index);
int groundY = findMarkedGround(chunk, pos, x, z,
level.getMinBuildHeight(), level.getMaxBuildHeight());
if (chunk.getBlockState(pos.set(x, groundY - 12, z)).is(Blocks.CALCITE)) rawConverted++;
BlockState converted = chunk.getBlockState(pos.set(x, groundY - 12, z));
if (converted.is(Blocks.CALCITE) || converted.is(Blocks.BASALT)) rawConverted++;
Block pocket = chunk.getBlockState(pos.set(x, groundY - 11, z)).getBlock();
if (index < NATURAL_SOURCES.length / 2) {
if (pocket == Blocks.AIR) cavePreserved++;
Expand Down Expand Up @@ -601,6 +713,9 @@ private static Properties properties(long seed, Map<String, AuditResult> results
values.setProperty(prefix + "underwater_pockets", Long.toString(result.underwaterPockets()));
values.setProperty(prefix + "raw_bedrock", Long.toString(result.rawBedrock()));
values.setProperty(prefix + "raw_block_entities", Long.toString(result.rawBlockEntities()));
values.setProperty(prefix + "dictionary_primary", Long.toString(result.dictionaryPrimary()));
values.setProperty(prefix + "dictionary_alternative", Long.toString(result.dictionaryAlternative()));
values.setProperty(prefix + "dynamic_biome_ore", Long.toString(result.dynamicBiomeOre()));
}
return values;
}
Expand Down Expand Up @@ -805,5 +920,6 @@ private record AuditResult(long top, long underwater, long filler, long geology,
int edgeChanges, int sentinels, long aquiferFluid,
long rawNaturalSources, long structureNaturalSources,
long vegetationNaturalSources, long cavePockets, long underwaterPockets,
long rawBedrock, long rawBlockEntities) { }
long rawBedrock, long rawBlockEntities,
long dictionaryPrimary, long dictionaryAlternative, long dynamicBiomeOre) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"surfaceprobe:surface_a"
]
}
Loading
Loading