Skip to content

Commit c408a79

Browse files
committed
Fix dynamic registry biome rule matching
1 parent e5bd549 commit c408a79

16 files changed

Lines changed: 322 additions & 48 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,9 @@ jobs:
132132
if-no-files-found: error
133133
retention-days: 30
134134
path: |
135-
build/libs/OreSpawn-4.0.10.120011.jar
136-
build/libs/OreSpawn-4.0.10.120011-sources.jar
137-
build/libs/OreSpawn-4.0.10.120011-javadoc.jar
135+
build/libs/OreSpawn-4.0.11.120011.jar
136+
build/libs/OreSpawn-4.0.11.120011-sources.jar
137+
build/libs/OreSpawn-4.0.11.120011-javadoc.jar
138138
build/release/SHA256SUMS
139139
CHANGELOG.txt
140140

‎CHANGELOG.txt‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
Version 4.0.11.120011
2+
3+
* Preserve biome-dictionary geome weights when a data-driven biome is reached
4+
through its stable registry key rather than the object baked at startup.
5+
* Apply ore biome include and exclude filters by stable registry key so
6+
dynamic-registry biome instances with the same ID are treated consistently.
7+
* Existing chunks and profile formats are unchanged; the corrections apply to
8+
generation in affected provider biomes.
9+
110
Version 4.0.10.120011
211

312
* Evaluate Stable Layers rock min_y and max_y bounds against actual world Y

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ End" policy used by mods such as Base Metals.
1717
This is not the unrelated mod that adds mobs and dimensions under the same
1818
name.
1919

20-
This branch builds target-qualified version `4.0.10.120011`: the OreSpawn 4.0.10
20+
This branch builds target-qualified version `4.0.11.120011`: the OreSpawn 4.0.11
2121
feature set for Minecraft 1.20.1 and Forge. See the
2222
[versioning policy](docs/VERSIONS.md) for the encoding and release convention.
2323

‎build.gradle‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ def preparedReleaseDir = providers.gradleProperty('preparedReleaseDir')
847847
tasks.register('verifyReleaseConfiguration') {
848848
group = 'verification'
849849
doLast {
850-
if (project.mod_version != '4.0.10.120011'
850+
if (project.mod_version != '4.0.11.120011'
851851
|| project.mod_group != expectedMavenGroup
852852
|| project.minecraft_version != '1.20.1'
853853
|| project.forge_version != '47.4.10'
@@ -861,9 +861,9 @@ tasks.register('verifyReleaseConfiguration') {
861861
throw new GradleException('Unexpected dispatcher or Java target metadata')
862862
}
863863
List<String> expectedPublicArtifacts = [
864-
'OreSpawn-4.0.10.120011.jar',
865-
'OreSpawn-4.0.10.120011-sources.jar',
866-
'OreSpawn-4.0.10.120011-javadoc.jar'
864+
'OreSpawn-4.0.11.120011.jar',
865+
'OreSpawn-4.0.11.120011-sources.jar',
866+
'OreSpawn-4.0.11.120011-javadoc.jar'
867867
]
868868
if (base.archivesName.get() != expectedMavenArtifact
869869
|| expectedReleaseFiles.get().collect { it.toString() } != expectedPublicArtifacts) {
@@ -880,7 +880,7 @@ tasks.register('verifyReleaseConfiguration') {
880880
'src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java',
881881
'README.md', 'CHANGELOG.txt'
882882
].each { path ->
883-
if (!file(path).getText('UTF-8').contains('4.0.10.120011')) {
883+
if (!file(path).getText('UTF-8').contains('4.0.11.120011')) {
884884
throw new GradleException("Release identity missing from ${path}")
885885
}
886886
}

‎docs/VERSIONS.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Examples:
5858
| 1.17.1 | Forge | `117011` | `4.0.9.117011` |
5959
| 1.18.2 | Forge | `118021` | `4.0.10.118021` |
6060
| 1.19.4 | Forge | `119041` | `4.0.10.119041` |
61-
| 1.20.1 | Forge | `120011` | `4.0.10.120011` |
61+
| 1.20.1 | Forge | `120011` | `4.0.11.120011` |
6262
| 1.20.6 | Forge | `120061` | `4.0.6.120061` |
6363
| 1.21.11 | Forge | `121111` | `4.0.6.121111` |
6464
| 26.1.2 | Forge | `2601021` | `4.0.6.2601021` |
@@ -156,6 +156,10 @@ Forge 1.18.2 through 1.20.1 then advanced to their target-qualified 4.0.10
156156
releases for the distinct Stable Layers actual-height eligibility repair. A
157157
branch may therefore legitimately skip functional version numbers.
158158

159+
Forge 1.20.1 then advanced to `4.0.11.120011` to retain biome-dictionary
160+
weights and ore biome filters when a data-driven biome is represented by a
161+
different runtime object with the same stable registry key.
162+
159163
This provides three useful guarantees:
160164

161165
1. A functional version is not used to describe two unrelated change sets.

‎gradle.properties‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ mcp_version=20230612.114412
1919
mod_id=orespawn
2020
mod_name=MMD OreSpawn
2121
mod_license=LGPL-2.1
22-
mod_version=4.0.10.120011
22+
mod_version=4.0.11.120011
2323
mod_group=zone.moddev.mc.orespawn
2424
mod_authors=SkyBlade1978, dshadowwolf, the MMD Team
2525
mod_description=Configurable, provider-driven terrain, ore, and deposit generation.

‎src/biomeIntegrationTest/java/zone/moddev/mc/orespawn/testmod/SurfaceProbeTestMod.java‎

Lines changed: 130 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ public final class SurfaceProbeTestMod {
7777
private static final ResourceLocation BIOME_A = ResourceLocation.parse(MODID + ":surface_a");
7878
private static final ResourceLocation BIOME_B = ResourceLocation.parse(MODID + ":surface_b");
7979
private static final ResourceLocation PROBE_GEOME = ResourceLocation.parse(MODID + ":dynamic_biome_geome");
80+
private static final ResourceLocation PROBE_GEOME_ALTERNATIVE =
81+
ResourceLocation.parse(MODID + ":dynamic_biome_geome_alternative");
8082
private static final ResourceLocation DYNAMIC_FLUID = ResourceLocation.parse(MODID + ":fluid/dynamic_water");
8183
private static final Block[] NATURAL_SOURCES = {
8284
Blocks.DIRT, Blocks.GRASS_BLOCK, Blocks.COARSE_DIRT, Blocks.PODZOL,
@@ -143,19 +145,34 @@ private static void addDynamicBiomeGeology(WorldgenProvider.Builder provider) {
143145
provider.geome(PROBE_GEOME, geome -> geome
144146
.baseWeight(0.0D)
145147
.familyWeight(GeologyFamily.SEDIMENTARY, 1.0D));
148+
provider.geome(PROBE_GEOME_ALTERNATIVE, geome -> geome
149+
.baseWeight(0.0D)
150+
.familyWeight(GeologyFamily.SEDIMENTARY, 1.0D));
146151
provider.rock(ResourceLocation.parse(MODID + ":rock/dynamic_biome"), blockId(Blocks.CALCITE),
147152
GeologyFamily.SEDIMENTARY, rock -> {
148153
rock.dimensions(java.util.Collections.singleton(OPEN_ID));
149154
rock.geomeWeight(PROBE_GEOME, 1.0D);
155+
rock.geomeWeight(PROBE_GEOME_ALTERNATIVE, 0.0D);
156+
for (ResourceLocation geome : BUILT_IN_GEOMES) rock.geomeWeight(geome, 0.0D);
157+
});
158+
provider.rock(ResourceLocation.parse(MODID + ":rock/dynamic_biome_alternative"), blockId(Blocks.BASALT),
159+
GeologyFamily.SEDIMENTARY, rock -> {
160+
rock.dimensions(java.util.Collections.singleton(OPEN_ID));
161+
rock.geomeWeight(PROBE_GEOME, 0.0D);
162+
rock.geomeWeight(PROBE_GEOME_ALTERNATIVE, 1.0D);
150163
for (ResourceLocation geome : BUILT_IN_GEOMES) rock.geomeWeight(geome, 0.0D);
151164
});
152-
provider.rock(ResourceLocation.parse(MODID + ":rock/fallback"), blockId(Blocks.BASALT),
165+
provider.rock(ResourceLocation.parse(MODID + ":rock/fallback"), blockId(Blocks.DEEPSLATE),
153166
GeologyFamily.SEDIMENTARY, rock -> {
154167
rock.dimensions(java.util.Collections.singleton(OPEN_ID));
155168
rock.geomeWeight(PROBE_GEOME, 0.0D);
169+
rock.geomeWeight(PROBE_GEOME_ALTERNATIVE, 0.0D);
156170
for (ResourceLocation geome : BUILT_IN_GEOMES) rock.geomeWeight(geome, 1.0D);
157171
});
158-
provider.biome(BIOME_A, java.util.Collections.singletonMap(PROBE_GEOME, 100.0D));
172+
Map<ResourceLocation, Double> biomeAWeights = new LinkedHashMap<>();
173+
biomeAWeights.put(PROBE_GEOME, 6.0D);
174+
biomeAWeights.put(PROBE_GEOME_ALTERNATIVE, 14.0D);
175+
provider.biome(BIOME_A, biomeAWeights);
159176
provider.biome(BIOME_B, java.util.Collections.singletonMap(PROBE_GEOME, 100.0D));
160177
}
161178

@@ -170,6 +187,19 @@ private void enableGeologyProbe(ServerAboutToStartEvent event) {
170187
}
171188
try {
172189
root.addProperty("place_fluid_deposits", true);
190+
root.addProperty("place_ores", true);
191+
JsonObject dictionary = root.getAsJsonObject("biome_dictionary");
192+
if (dictionary == null) {
193+
dictionary = new JsonObject();
194+
root.add("biome_dictionary", dictionary);
195+
}
196+
JsonObject cold = dictionary.getAsJsonObject("COLD");
197+
if (cold == null) {
198+
cold = new JsonObject();
199+
dictionary.add("COLD", cold);
200+
}
201+
cold.addProperty(PROBE_GEOME.toString(), 8.0D);
202+
addDynamicBiomeOre(root);
173203
JsonObject terrain = root.getAsJsonObject("terrain_dimensions");
174204
if (terrain == null) {
175205
terrain = new JsonObject();
@@ -199,6 +229,49 @@ private void enableGeologyProbe(ServerAboutToStartEvent event) {
199229
}
200230
}
201231

232+
private static void addDynamicBiomeOre(JsonObject root) {
233+
JsonObject ores = root.getAsJsonObject("ores");
234+
if (ores == null) {
235+
ores = new JsonObject();
236+
root.add("ores", ores);
237+
}
238+
JsonObject ore = new JsonObject();
239+
ore.addProperty("block", blockId(Blocks.DIAMOND_BLOCK).toString());
240+
ore.addProperty("enabled", true);
241+
ore.addProperty("native_generation", false);
242+
ore.addProperty("suppress_vanilla", false);
243+
ore.addProperty("retrogen", false);
244+
JsonObject dimensions = new JsonObject();
245+
JsonObject end = new JsonObject();
246+
end.addProperty("enabled", true);
247+
end.addProperty("min_y", 16);
248+
end.addProperty("max_y", 48);
249+
end.addProperty("frequency", 16.0D);
250+
end.addProperty("quantity", 8);
251+
end.addProperty("pattern", "cluster");
252+
end.addProperty("height_distribution", "uniform");
253+
end.addProperty("discard_chance_on_air_exposure", 0.0D);
254+
end.addProperty("spread", 4);
255+
end.addProperty("vertical_spread", 3);
256+
end.addProperty("node_size", 3);
257+
end.add("host_families", new JsonArray());
258+
JsonArray hosts = new JsonArray();
259+
hosts.add(blockId(Blocks.CALCITE).toString());
260+
hosts.add(blockId(Blocks.BASALT).toString());
261+
end.add("host_blocks", hosts);
262+
end.add("host_tags", new JsonArray());
263+
end.add("geomes", new JsonObject());
264+
JsonArray biomes = new JsonArray();
265+
biomes.add(BIOME_A.toString());
266+
end.add("biome_ids", biomes);
267+
end.add("excluded_biome_ids", new JsonArray());
268+
end.add("biome_dictionary", new JsonArray());
269+
end.add("excluded_biome_dictionary", new JsonArray());
270+
dimensions.add(OPEN_ID.toString(), end);
271+
ore.add("dimensions", dimensions);
272+
ores.add(MODID + ":ore/dynamic_biome_filter", ore);
273+
}
274+
202275
private static void addPalette(WorldgenProvider.Builder provider, String name,
203276
ResourceLocation dimension, boolean ceiling) {
204277
BiomeSurfaceDefinition surfaceA = surface(DyeColor.PINK, DyeColor.WHITE,
@@ -307,6 +380,8 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
307380
long underwaterPockets = 0L;
308381
long rawBedrock = 0L;
309382
long rawBlockEntities = 0L;
383+
long dictionaryPrimary = 0L;
384+
long dictionaryAlternative = 0L;
310385
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
311386

312387
for (int chunkZ = MINIMUM_CHUNK; chunkZ <= MAXIMUM_CHUNK; chunkZ++) {
@@ -316,6 +391,10 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
316391
LevelChunk chunk = level.getChunk(chunkX, chunkZ);
317392
int chunkMinX = chunkX << 4;
318393
int chunkMinZ = chunkZ << 4;
394+
int centerGroundY = findMarkedGround(chunk, pos, chunkMinX + 8, chunkMinZ + 8,
395+
level.getMinBuildHeight(), level.getMaxBuildHeight());
396+
ResourceLocation generationBiomeId = biomeId(level.getBiome(
397+
pos.set(chunkMinX + 8, centerGroundY, chunkMinZ + 8)));
319398
for (int localZ = 0; localZ < 16; localZ++) {
320399
for (int localX = 0; localX < 16; localX++) {
321400
int x = chunkMinX + localX;
@@ -345,8 +424,15 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
345424
}
346425
if (!roofed) {
347426
for (int depth = 6; depth <= 8; depth++) {
348-
assertBlock(chunk, pos, x, groundY - depth, z,
349-
Blocks.CALCITE.defaultBlockState(), "dynamic-biome geome rock");
427+
BlockState geologyState = chunk.getBlockState(pos.set(x, groundY - depth, z));
428+
if (geologyState.is(Blocks.BASALT)) {
429+
dictionaryAlternative++;
430+
} else if (geologyState.is(Blocks.CALCITE)) {
431+
dictionaryPrimary++;
432+
} else {
433+
throw new IllegalStateException("Unexpected dynamic-biome geome rock at "
434+
+ pos + " in " + biomeId + ": " + geologyState);
435+
}
350436
geology++;
351437
}
352438
}
@@ -363,11 +449,8 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
363449
}
364450
}
365451
}
366-
ResourceLocation centerBiome = biomeId(level.getBiome(pos.set(chunkMinX + 8,
367-
findMarkedGround(chunk, pos, chunkMinX + 8, chunkMinZ + 8,
368-
level.getMinBuildHeight(), level.getMaxBuildHeight()), chunkMinZ + 8)));
369-
if (previousChunkBiome != null && !previousChunkBiome.equals(centerBiome)) edgeChanges++;
370-
previousChunkBiome = centerBiome;
452+
if (previousChunkBiome != null && !previousChunkBiome.equals(generationBiomeId)) edgeChanges++;
453+
previousChunkBiome = generationBiomeId;
371454
sentinels += auditSentinels(level, chunk, pos, chunkMinX, chunkMinZ);
372455
if (!roofed) {
373456
NaturalSourceAudit natural = auditNaturalSources(level, chunk, pos,
@@ -383,6 +466,7 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
383466
}
384467
}
385468

469+
long dynamicBiomeOre = roofed ? 0L : auditDynamicBiomeOre(level);
386470
if (top != EXPECTED_COLUMNS - 9 || underwater != 9 || filler != EXPECTED_FILLER
387471
|| biomeA == 0 || biomeB == 0 || edgeChanges == 0 || sentinels != 9 * 4
388472
|| geology != (roofed ? 0 : EXPECTED_FILLER)
@@ -391,7 +475,9 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
391475
|| structureNaturalSources != EXPECTED_NATURAL_SOURCES
392476
|| vegetationNaturalSources != EXPECTED_NATURAL_SOURCES
393477
|| cavePockets != 54 || underwaterPockets != 63
394-
|| rawBedrock != 9 || rawBlockEntities != 9))) {
478+
|| rawBedrock != 9 || rawBlockEntities != 9
479+
|| dictionaryPrimary != EXPECTED_FILLER || dictionaryAlternative != 0
480+
|| dynamicBiomeOre == 0))) {
395481
throw new IllegalStateException("Incomplete surface audit for " + level.dimension().location()
396482
+ ": top=" + top + ", underwater=" + underwater + ", filler=" + filler
397483
+ ", biomeA=" + biomeA + ", biomeB=" + biomeB + ", edges=" + edgeChanges
@@ -403,13 +489,38 @@ private static AuditResult auditDimension(ServerLevel level, boolean roofed) {
403489
+ ", cavePockets=" + cavePockets
404490
+ ", underwaterPockets=" + underwaterPockets
405491
+ ", rawBedrock=" + rawBedrock
406-
+ ", rawBlockEntities=" + rawBlockEntities);
492+
+ ", rawBlockEntities=" + rawBlockEntities
493+
+ ", dictionaryPrimary=" + dictionaryPrimary
494+
+ ", dictionaryAlternative=" + dictionaryAlternative
495+
+ ", dynamicBiomeOre=" + dynamicBiomeOre);
407496
}
408497
long aquiferFluid = roofed ? 0L : auditDynamicFluid(level);
409498
return new AuditResult(top, underwater, filler, geology, ceiling, roofTop,
410499
biomeA, biomeB, edgeChanges, sentinels, aquiferFluid,
411500
rawNaturalSources, structureNaturalSources, vegetationNaturalSources,
412-
cavePockets, underwaterPockets, rawBedrock, rawBlockEntities);
501+
cavePockets, underwaterPockets, rawBedrock, rawBlockEntities,
502+
dictionaryPrimary, dictionaryAlternative, dynamicBiomeOre);
503+
}
504+
505+
private static long auditDynamicBiomeOre(ServerLevel level) {
506+
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
507+
long count = 0L;
508+
for (int chunkZ = MINIMUM_CHUNK; chunkZ <= MAXIMUM_CHUNK; chunkZ++) {
509+
for (int chunkX = MINIMUM_CHUNK; chunkX <= MAXIMUM_CHUNK; chunkX++) {
510+
LevelChunk chunk = level.getChunk(chunkX, chunkZ);
511+
for (int x = chunk.getPos().getMinBlockX(); x <= chunk.getPos().getMaxBlockX(); x++) {
512+
for (int z = chunk.getPos().getMinBlockZ(); z <= chunk.getPos().getMaxBlockZ(); z++) {
513+
for (int y = 16; y <= 48; y++) {
514+
if (chunk.getBlockState(pos.set(x, y, z)).is(Blocks.DIAMOND_BLOCK)) count++;
515+
}
516+
}
517+
}
518+
}
519+
}
520+
if (count == 0L) {
521+
throw new IllegalStateException("Dynamic-registry biome filter produced no managed ore");
522+
}
523+
return count;
413524
}
414525

415526
private static NaturalSourceAudit auditNaturalSources(ServerLevel level, LevelChunk chunk,
@@ -426,7 +537,8 @@ private static NaturalSourceAudit auditNaturalSources(ServerLevel level, LevelCh
426537
int z = naturalZ(minZ, index);
427538
int groundY = findMarkedGround(chunk, pos, x, z,
428539
level.getMinBuildHeight(), level.getMaxBuildHeight());
429-
if (chunk.getBlockState(pos.set(x, groundY - 12, z)).is(Blocks.CALCITE)) rawConverted++;
540+
BlockState converted = chunk.getBlockState(pos.set(x, groundY - 12, z));
541+
if (converted.is(Blocks.CALCITE) || converted.is(Blocks.BASALT)) rawConverted++;
430542
Block pocket = chunk.getBlockState(pos.set(x, groundY - 11, z)).getBlock();
431543
if (index < NATURAL_SOURCES.length / 2) {
432544
if (pocket == Blocks.AIR) cavePreserved++;
@@ -600,6 +712,9 @@ private static Properties properties(long seed, Map<String, AuditResult> results
600712
values.setProperty(prefix + "underwater_pockets", Long.toString(result.underwaterPockets()));
601713
values.setProperty(prefix + "raw_bedrock", Long.toString(result.rawBedrock()));
602714
values.setProperty(prefix + "raw_block_entities", Long.toString(result.rawBlockEntities()));
715+
values.setProperty(prefix + "dictionary_primary", Long.toString(result.dictionaryPrimary()));
716+
values.setProperty(prefix + "dictionary_alternative", Long.toString(result.dictionaryAlternative()));
717+
values.setProperty(prefix + "dynamic_biome_ore", Long.toString(result.dynamicBiomeOre()));
603718
}
604719
return values;
605720
}
@@ -804,5 +919,6 @@ private record AuditResult(long top, long underwater, long filler, long geology,
804919
int edgeChanges, int sentinels, long aquiferFluid,
805920
long rawNaturalSources, long structureNaturalSources,
806921
long vegetationNaturalSources, long cavePockets, long underwaterPockets,
807-
long rawBedrock, long rawBlockEntities) { }
922+
long rawBedrock, long rawBlockEntities,
923+
long dictionaryPrimary, long dictionaryAlternative, long dynamicBiomeOre) { }
808924
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"replace": false,
3+
"values": [
4+
"surfaceprobe:surface_a"
5+
]
6+
}

0 commit comments

Comments
 (0)