mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 14:00:26 +00:00
Scored ingest biome placement
- Mod biomes pick their template across all regions by climate distance, biome category agreement from minecraft and c tags, a reuse penalty that spreads biomes over equally good templates, and the region's overall climate - Regions much rarer than the dimension's median region are treated as themed and only receive a mod biome when nothing else fits - Templates derived from void biomes no longer act as climate references - /iris ingest mods accepts excludeRegions=<a,b> to keep mod biomes out of named regions; unknown region names are refused
This commit is contained in:
1 parent
8388194129
commit
0bc235afb6
34 files changed
+389
-66
No files matched your search
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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.CatalogDimensionType;
|
||||
import art.arcane.iris.pack.ingest.catalog.CatalogNamespace;
|
||||
import art.arcane.iris.pack.ingest.catalog.WorldgenCatalog;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IngestBiomePlacementTest {
|
||||
private static final String MOD = "modpack";
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder folder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void modBiomesAvoidThemedRegionsAndFollowTheirCategory() throws Exception {
|
||||
ModIngestReport report = ingest(Set.of());
|
||||
|
||||
assertEquals("temperate", region(report, "lavender_fields"));
|
||||
assertEquals("temperate", region(report, "redwood_forest"));
|
||||
assertTrue(reason(report, "redwood_forest").contains("temperate/forest"));
|
||||
assertEquals("hot", region(report, "brushland"));
|
||||
assertTrue(reason(report, "brushland").contains("hot/savanna"));
|
||||
for (int index = 0; index < 6; index++) {
|
||||
assertEquals("temperate", region(report, "prairie_" + index));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void repeatedClimatesSpreadOverEquallyGoodTemplates() throws Exception {
|
||||
ModIngestReport report = ingest(Set.of());
|
||||
|
||||
Set<String> templates = new TreeSet<>();
|
||||
for (int index = 0; index < 6; index++) {
|
||||
String reason = reason(report, "prairie_" + index);
|
||||
templates.add(reason.substring(reason.indexOf("from template ") + "from template ".length()));
|
||||
}
|
||||
assertEquals(Set.of("temperate/meadow", "temperate/plains"), templates);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void excludedRegionsNeverReceiveModBiomes() throws Exception {
|
||||
ModIngestReport report = ingest(Set.of("temperate"));
|
||||
|
||||
for (ModIngestItem item : report.items()) {
|
||||
if (item.kind().equals("biome") && item.tier() == ModIngestTier.ADOPTED) {
|
||||
assertFalse(item.reason(), item.reason().contains("in region temperate "));
|
||||
}
|
||||
}
|
||||
assertThrows(IllegalArgumentException.class, () -> ingest(Set.of("missing")));
|
||||
}
|
||||
|
||||
private ModIngestReport ingest(Set<String> excludedRegions) throws IOException {
|
||||
Path root = folder.newFolder().toPath();
|
||||
Path source = root.resolve("source");
|
||||
ModIngestFixture.write(source, "dimensions/overworld.json", """
|
||||
{"name": "Overworld", "environment": "NORMAL", "regions": ["temperate", "hot", "prismatic"], "dimensionHeight": {"min": -64, "max": 320}}
|
||||
""");
|
||||
ModIngestFixture.write(source, "regions/temperate.json", """
|
||||
{"name": "Temperate", "landBiomes": ["temperate/plains", "temperate/meadow", "temperate/forest"], "seaBiomes": ["temperate/ocean"]}
|
||||
""");
|
||||
ModIngestFixture.write(source, "regions/hot.json", """
|
||||
{"name": "Hot", "landBiomes": ["hot/desert", "hot/savanna"]}
|
||||
""");
|
||||
ModIngestFixture.write(source, "regions/prismatic.json", """
|
||||
{"name": "Prismatic", "rarity": 20, "landBiomes": ["prismatic/white", "prismatic/red", "prismatic/blue"]}
|
||||
""");
|
||||
biome(source, "temperate/plains", "minecraft:plains");
|
||||
biome(source, "temperate/meadow", "minecraft:plains");
|
||||
biome(source, "temperate/forest", "minecraft:forest");
|
||||
biome(source, "temperate/ocean", "minecraft:ocean");
|
||||
biome(source, "hot/desert", "minecraft:desert");
|
||||
biome(source, "hot/savanna", "minecraft:savanna");
|
||||
biome(source, "prismatic/white", "minecraft:plains");
|
||||
biome(source, "prismatic/red", "minecraft:plains");
|
||||
biome(source, "prismatic/blue", "minecraft:plains");
|
||||
Path target = root.resolve("packs").resolve("placed");
|
||||
return ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog(), Set.of(MOD), excludedRegions, false));
|
||||
}
|
||||
|
||||
private static void biome(Path pack, String key, String derivative) throws IOException {
|
||||
ModIngestFixture.write(pack, "biomes/" + key + ".json", "{\"name\": \"" + key + "\", \"derivative\": \"" + derivative + "\"}");
|
||||
}
|
||||
|
||||
private static WorldgenCatalog catalog() {
|
||||
List<CatalogBiome> biomes = new ArrayList<>();
|
||||
biomes.add(biome("minecraft:plains", 0.8F, 0.4F, "c:is_plains"));
|
||||
biomes.add(biome("minecraft:forest", 0.7F, 0.8F, "minecraft:is_forest"));
|
||||
biomes.add(biome("minecraft:desert", 2.0F, 0.0F, "c:is_desert"));
|
||||
biomes.add(biome("minecraft:savanna", 1.2F, 0.4F, "minecraft:is_savanna"));
|
||||
biomes.add(biome("minecraft:ocean", 0.5F, 0.5F, "minecraft:is_ocean"));
|
||||
biomes.add(biome(MOD + ":lavender_fields", 0.8F, 0.5F, "c:is_plains"));
|
||||
biomes.add(biome(MOD + ":redwood_forest", 0.8F, 0.6F, "minecraft:is_forest"));
|
||||
biomes.add(biome(MOD + ":brushland", 1.3F, 0.3F, "minecraft:is_savanna"));
|
||||
for (int index = 0; index < 6; index++) {
|
||||
biomes.add(biome(MOD + ":prairie_" + index, 0.8F, 0.4F, "c:is_plains"));
|
||||
}
|
||||
return new WorldgenCatalog(WorldgenCatalog.FORMAT, "26.3", "fabric", 1000L, "fingerprint-placement",
|
||||
List.of(new CatalogNamespace(MOD, "Mod Pack", "1.0.0")), biomes, List.of(), List.of(),
|
||||
List.of(new CatalogDimensionType("minecraft:overworld", -64, 384, 384, null)), List.of());
|
||||
}
|
||||
|
||||
private static CatalogBiome biome(String key, float temperature, float downfall, String categoryTag) {
|
||||
List<List<String>> steps = new ArrayList<>(11);
|
||||
for (int index = 0; index < 11; index++) {
|
||||
steps.add(List.of());
|
||||
}
|
||||
return new CatalogBiome(key, temperature, downfall, true, List.of("minecraft:is_overworld", categoryTag), steps, List.of(), null);
|
||||
}
|
||||
|
||||
private static String region(ModIngestReport report, String biome) {
|
||||
String reason = reason(report, biome);
|
||||
int start = reason.indexOf("in region ") + "in region ".length();
|
||||
return reason.substring(start, reason.indexOf(' ', start));
|
||||
}
|
||||
|
||||
private static String reason(ModIngestReport report, String biome) {
|
||||
ModIngestItem item = ModIngestFixture.item(report, MOD + ":" + biome);
|
||||
assertEquals(ModIngestTier.ADOPTED, item.tier());
|
||||
return item.reason();
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ public class IngestHeightBoundsTest {
|
||||
}
|
||||
""".formatted(heightFields));
|
||||
Path target = root.resolve("packs").resolve("modded");
|
||||
ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog, Set.of(ModIngestFixture.MOD), false));
|
||||
ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog, Set.of(ModIngestFixture.MOD), Set.of(), false));
|
||||
JsonObject dimension = ModIngestFixture.readJson(target.resolve("dimensions/modded.json"));
|
||||
JsonObject stone = ModIngestFixture.findByPaletteBlock(dimension.getAsJsonArray("deposits"), "examplemod:tin_ore");
|
||||
assertNotNull(stone);
|
||||
|
||||
@@ -45,7 +45,7 @@ public class IngestReservedNamespaceTest {
|
||||
ModIngestFixture.write(root.resolve("packs").resolve("underworld"), "dimensions/underworld.json", "{\"name\": \"Underworld\"}");
|
||||
Path target = root.resolve("packs").resolve("modded");
|
||||
|
||||
ModIngestReport report = ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog(), Set.of(), false));
|
||||
ModIngestReport report = ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog(), Set.of(), Set.of(), false));
|
||||
|
||||
assertNull(ModIngestFixture.item(report, "irisworldgen:packs/6f76/dimensions/6f76/biomes/dunes"));
|
||||
assertNull(ModIngestFixture.item(report, "overworld:dunes"));
|
||||
@@ -63,7 +63,7 @@ public class IngestReservedNamespaceTest {
|
||||
|
||||
for (String namespace : List.of("irisworldgen", "overworld")) {
|
||||
assertThrows(namespace, IllegalArgumentException.class, () -> ModIngester.ingest(
|
||||
new ModIngestRequest(source, target, "overworld", catalog(), Set.of(namespace), false)));
|
||||
new ModIngestRequest(source, target, "overworld", catalog(), Set.of(namespace), Set.of(), false)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -320,7 +320,7 @@ final class ModIngestFixture {
|
||||
}
|
||||
|
||||
static ModIngestRequest request(Path source, Path target, Set<String> namespaces, boolean replace) {
|
||||
return new ModIngestRequest(source, target, "overworld", catalog(), namespaces, replace);
|
||||
return new ModIngestRequest(source, target, "overworld", catalog(), namespaces, Set.of(), replace);
|
||||
}
|
||||
|
||||
static JsonObject readJson(Path file) throws IOException {
|
||||
|
||||
@@ -158,7 +158,7 @@ public class ModIngesterPackTest {
|
||||
Map<String, String> first = snapshot(target);
|
||||
|
||||
assertThrows(IOException.class, () -> ModIngester.ingest(new ModIngestRequest(
|
||||
source, target, "missing", ModIngestFixture.catalog(), Set.of(ModIngestFixture.MOD), true)));
|
||||
source, target, "missing", ModIngestFixture.catalog(), Set.of(ModIngestFixture.MOD), Set.of(), true)));
|
||||
|
||||
assertEquals(first, snapshot(target));
|
||||
assertEquals(List.of("modded"), directoryNames(root.resolve("packs")));
|
||||
@@ -184,7 +184,7 @@ public class ModIngesterPackTest {
|
||||
ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), false));
|
||||
|
||||
IOException failure = assertThrows(IOException.class, () -> ModIngester.ingest(new ModIngestRequest(
|
||||
target, root.resolve("packs").resolve("again"), "modded", ModIngestFixture.catalog(), Set.of(), false)));
|
||||
target, root.resolve("packs").resolve("again"), "modded", ModIngestFixture.catalog(), Set.of(), Set.of(), false)));
|
||||
|
||||
assertTrue(failure.getMessage(), failure.getMessage().contains("original pack"));
|
||||
assertFalse(Files.exists(root.resolve("packs").resolve("again")));
|
||||
@@ -218,7 +218,7 @@ public class ModIngesterPackTest {
|
||||
fixture.capturedAtEpochMillis(), fixture.contentFingerprint(), namespaces, fixture.biomes(),
|
||||
fixture.placedFeatures(), fixture.structures(), fixture.dimensionTypes(), fixture.levelStems());
|
||||
|
||||
ModIngestReport report = ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog, Set.of(), false));
|
||||
ModIngestReport report = ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog, Set.of(), Set.of(), false));
|
||||
|
||||
assertEquals(List.of("examplemod", "othermod"),
|
||||
ModIngestFixture.strings(ModIngestFixture.readJson(target.resolve("ingest/manifest.json")).get("namespaces")));
|
||||
|
||||
Reference in new issue
Block a user