Routed cave biome ores

- Ores declared only by adopted cave biomes are written to the deposits of the region each cave biome joined, scoped to those cave biomes, instead of to the cave biome itself where the deposit stage never reads them
- Ores of adopted surface biomes still go to the biome
This commit is contained in:
Brian Neumann-Fopiano committed 2026-10-14 22:38:42 -04:00
1 parent 965e19801d
commit d749633829
3 files changed
+132 -16

No files matched your search

@@ -85,7 +85,7 @@ final class ModBiomeAdopter {
transform(json, biome, ownsVegetation(biome, namespace));
model.pack().create(IngestPack.biomePath(irisKey), json);
appendToPool(region.key(), role, irisKey);
adopted.put(biome.key(), new AdoptedBiome(biome.key(), irisKey, role));
adopted.put(biome.key(), new AdoptedBiome(biome.key(), irisKey, role, region.key()));
items.add(new ModIngestItem(namespace, biome.key(), "biome", ModIngestTier.ADOPTED, irisKey,
role.label() + " biome in region " + region.key() + " from template " + template));
}
@@ -196,7 +196,7 @@ final class ModBiomeAdopter {
return name.isEmpty() ? key : name.toString();
}
record AdoptedBiome(String modKey, String irisKey, BiomeRole role) {
record AdoptedBiome(String modKey, String irisKey, BiomeRole role, String regionKey) {
}
private record Placement(IngestPackModel.RegionProfile region, String template) {
@@ -221,36 +221,53 @@ final class ModFeatureIngester {
}
private String applyDeposits(FeaturePlan plan, Map<String, ModBiomeAdopter.AdoptedBiome> adopted, Set<String> universe, Set<String> caveKeys) throws IOException {
List<String> adoptedTargets = new ArrayList<>();
List<ModBiomeAdopter.AdoptedBiome> adoptedTargets = new ArrayList<>();
boolean vanillaDeclared = false;
for (String biome : plan.declaring()) {
vanillaDeclared |= WorldgenCatalogIndex.namespaceOf(biome).equals("minecraft");
ModBiomeAdopter.AdoptedBiome adoptedBiome = adopted.get(biome);
if (adoptedBiome != null) {
adoptedTargets.add(adoptedBiome.irisKey());
adoptedTargets.add(adoptedBiome);
}
}
if (!vanillaDeclared && !adoptedTargets.isEmpty()) {
for (String irisKey : adoptedTargets) {
appendAll(model.pack().require(IngestPack.biomePath(irisKey)), "deposits", plan.deposits());
List<String> targets = new ArrayList<>(adoptedTargets.size());
Map<String, List<String>> caveBiomesByRegion = new TreeMap<>();
for (ModBiomeAdopter.AdoptedBiome target : adoptedTargets) {
if (target.role() == BiomeRole.CAVE) {
caveBiomesByRegion.computeIfAbsent(target.regionKey(), ignored -> new ArrayList<>()).add(target.irisKey());
continue;
}
appendAll(model.pack().require(IngestPack.biomePath(target.irisKey())), "deposits", plan.deposits());
targets.add(target.irisKey());
}
return String.join(",", adoptedTargets);
for (Map.Entry<String, List<String>> region : caveBiomesByRegion.entrySet()) {
appendAll(model.pack().edit(IngestPack.regionPath(region.getKey())), "deposits",
scoped(plan.deposits(), region.getValue(), "CAVE"));
targets.add("region " + region.getKey());
}
return String.join(",", targets);
}
Set<String> included = new TreeSet<>(plan.declaring());
included.retainAll(universe);
List<JsonObject> deposits = new ArrayList<>(plan.deposits().size());
for (JsonObject deposit : plan.deposits()) {
JsonObject copy = deposit.deepCopy();
if (!included.containsAll(universe)) {
copy.add("includedBiomes", IngestJson.stringArray(included));
copy.addProperty("biomeScope", caveKeys.containsAll(included) ? "CAVE" : "SURFACE");
}
deposits.add(copy);
}
List<JsonObject> deposits = included.containsAll(universe)
? plan.deposits()
: scoped(plan.deposits(), List.copyOf(included), caveKeys.containsAll(included) ? "CAVE" : "SURFACE");
appendAll(model.pack().edit(model.dimensionPath()), "deposits", deposits);
return "dimension";
}
private static List<JsonObject> scoped(List<JsonObject> deposits, List<String> includedBiomes, String biomeScope) {
List<JsonObject> scoped = new ArrayList<>(deposits.size());
for (JsonObject deposit : deposits) {
JsonObject copy = deposit.deepCopy();
copy.add("includedBiomes", IngestJson.stringArray(includedBiomes));
copy.addProperty("biomeScope", biomeScope);
scoped.add(copy);
}
return scoped;
}
private String applyDecorator(FeaturePlan plan, Map<String, ModBiomeAdopter.AdoptedBiome> adopted) throws IOException {
List<String> targets = new ArrayList<>();
for (String biome : plan.declaring()) {
@@ -0,0 +1,99 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package art.arcane.iris.pack.ingest;
import art.arcane.iris.pack.ingest.catalog.CatalogBiome;
import art.arcane.iris.pack.ingest.catalog.CatalogPlacedFeature;
import art.arcane.iris.pack.ingest.catalog.WorldgenCatalog;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class IngestCaveOreTest {
private static final String MOD = ModIngestFixture.MOD;
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void oresOfAdoptedCaveBiomesRunFromTheRegionScopedToThoseCaves() throws Exception {
Path root = folder.getRoot().toPath();
Path source = ModIngestFixture.writeSourcePack(root);
Path target = root.resolve("packs").resolve("caves");
ModIngestReport report = ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog(), Set.of(MOD), Set.of(), false));
JsonArray regionDeposits = ModIngestFixture.readJson(target.resolve("regions/hot.json")).getAsJsonArray("deposits");
assertNotNull(regionDeposits);
JsonObject geode = ModIngestFixture.findByPaletteBlock(regionDeposits, MOD + ":geode_ore");
assertNotNull(geode);
assertEquals(List.of("ingest/" + MOD + "/crystal_caves"), ModIngestFixture.strings(geode.get("includedBiomes")));
assertEquals("CAVE", geode.get("biomeScope").getAsString());
JsonElement caveDeposits = ModIngestFixture.readJson(target.resolve("biomes/ingest/" + MOD + "/crystal_caves.json")).get("deposits");
assertTrue(caveDeposits == null || ModIngestFixture.findByPaletteBlock(caveDeposits.getAsJsonArray(), MOD + ":geode_ore") == null);
assertNull(ModIngestFixture.findByPaletteBlock(ModIngestFixture.readJson(target.resolve("dimensions/caves.json")).getAsJsonArray("deposits"), MOD + ":geode_ore"));
ModIngestItem item = ModIngestFixture.item(report, MOD + ":geode_ore");
assertEquals(ModIngestTier.NATIVE, item.tier());
assertTrue(item.target(), item.target().contains("region hot"));
assertFalse(ModIngestFixture.readJson(target.resolve("regions/temperate.json")).has("deposits"));
}
private static WorldgenCatalog catalog() {
WorldgenCatalog fixture = ModIngestFixture.catalog();
List<CatalogBiome> biomes = new ArrayList<>();
for (CatalogBiome biome : fixture.biomes()) {
if (!biome.key().equals(MOD + ":crystal_caves")) {
biomes.add(biome);
continue;
}
List<List<String>> steps = new ArrayList<>(biome.featureSteps());
List<String> ores = new ArrayList<>(steps.get(ModIngestFixture.ORE_STEP));
ores.add(MOD + ":geode_ore");
steps.set(ModIngestFixture.ORE_STEP, ores);
biomes.add(new CatalogBiome(biome.key(), biome.temperature(), biome.downfall(), true, biome.tags(), steps, biome.spawns(), null));
}
List<CatalogPlacedFeature> features = new ArrayList<>(fixture.placedFeatures());
String key = MOD + ":geode_ore";
features.add(new CatalogPlacedFeature(key, key, "minecraft:ore", JsonParser.parseString("""
{"size": 6, "targets": [{"state": "examplemod:geode_ore", "target": {"predicate_type": "minecraft:block_match", "block": "minecraft:stone"}}]}
"""), JsonParser.parseString("""
[{"type": "minecraft:count", "count": 3}, {"type": "minecraft:in_square"},
{"type": "minecraft:height_range", "height": {"type": "minecraft:uniform", "min_inclusive": {"absolute": -40}, "max_inclusive": {"absolute": 20}}},
{"type": "minecraft:biome"}]
""")));
return new WorldgenCatalog(fixture.format(), fixture.minecraftVersion(), fixture.platform(), fixture.capturedAtEpochMillis(),
fixture.contentFingerprint(), fixture.namespaces(), biomes, features, fixture.structures(), fixture.dimensionTypes(),
fixture.levelStems(), fixture.blockTags());
}
}