diff --git a/core/src/main/java/art/arcane/iris/pack/ingest/IngestPackModel.java b/core/src/main/java/art/arcane/iris/pack/ingest/IngestPackModel.java index a9fe360c8..c6fa1082b 100644 --- a/core/src/main/java/art/arcane/iris/pack/ingest/IngestPackModel.java +++ b/core/src/main/java/art/arcane/iris/pack/ingest/IngestPackModel.java @@ -44,17 +44,19 @@ final class IngestPackModel { private final WorldgenCatalogIndex index; private final String dimensionPath; private final String environment; + private final String borrowedDimensionType; private final int packMinY; private final int packMaxY; private final List regions; private final Map reachableBiomes; - private IngestPackModel(IngestPack pack, WorldgenCatalogIndex index, String dimensionPath, String environment, + private IngestPackModel(IngestPack pack, WorldgenCatalogIndex index, String dimensionPath, JsonObject dimension, int[] heightRange, List regions, Map reachableBiomes) { this.pack = pack; this.index = index; this.dimensionPath = dimensionPath; - this.environment = environment; + this.environment = text(dimension.get("environment"), "NORMAL").toUpperCase(Locale.ROOT); + this.borrowedDimensionType = text(dimension.get("borrowedDimensionType"), ""); this.packMinY = heightRange[0]; this.packMaxY = heightRange[1]; this.regions = regions; @@ -64,10 +66,6 @@ final class IngestPackModel { static IngestPackModel load(IngestPack pack, String dimensionKey, WorldgenCatalogIndex index) throws IOException { String dimensionPath = IngestPack.dimensionPath(dimensionKey); JsonObject dimension = pack.require(dimensionPath); - JsonElement environmentValue = dimension.get("environment"); - String environment = environmentValue != null && environmentValue.isJsonPrimitive() - ? environmentValue.getAsString().trim().toUpperCase(Locale.ROOT) - : "NORMAL"; Map reachable = new LinkedHashMap<>(); List regionKeys = IngestJson.strings(dimension.get("regions")); List regionJson = new ArrayList<>(regionKeys.size()); @@ -84,7 +82,7 @@ final class IngestPackModel { for (int position = 0; position < regionJson.size(); position++) { profiles.add(profile(loadedRegionKeys.get(position), regionJson.get(position), reachable, index)); } - return new IngestPackModel(pack, index, dimensionPath, environment, heightRange(pack, dimension), + return new IngestPackModel(pack, index, dimensionPath, dimension, heightRange(pack, dimension), Collections.unmodifiableList(profiles), Collections.unmodifiableMap(reachable)); } @@ -118,15 +116,11 @@ final class IngestPackModel { } VanillaHeights.VerticalBounds verticalBounds() { - String typeKey = switch (environment) { - case "NORMAL" -> "minecraft:overworld"; - case "NETHER" -> "minecraft:the_nether"; - case "THE_END" -> "minecraft:the_end"; - default -> ""; - }; - Optional type = index.dimensionType(typeKey); - if (type.isPresent() && type.get().height() > 0) { - return new VanillaHeights.VerticalBounds(type.get().minY(), type.get().height()); + if (!borrowedDimensionType.isEmpty()) { + Optional borrowed = index.dimensionType(borrowedDimensionType); + if (borrowed.isPresent() && borrowed.get().height() > 0) { + return new VanillaHeights.VerticalBounds(borrowed.get().minY(), borrowed.get().height()); + } } return new VanillaHeights.VerticalBounds(packMinY, Math.max(1, packMaxY - packMinY)); } @@ -183,6 +177,10 @@ final class IngestPackModel { return new int[]{(int) number(range.get("min"), DEFAULT_MIN_Y), (int) number(range.get("max"), DEFAULT_MAX_Y)}; } + private static String text(JsonElement value, String fallback) { + return value != null && value.isJsonPrimitive() ? value.getAsString().trim() : fallback; + } + private static double number(JsonElement value, double fallback) { if (value == null || !value.isJsonPrimitive()) { return fallback; diff --git a/core/src/test/java/art/arcane/iris/pack/ingest/IngestHeightBoundsTest.java b/core/src/test/java/art/arcane/iris/pack/ingest/IngestHeightBoundsTest.java new file mode 100644 index 000000000..9a226a4a0 --- /dev/null +++ b/core/src/test/java/art/arcane/iris/pack/ingest/IngestHeightBoundsTest.java @@ -0,0 +1,82 @@ +/* + * 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 . + */ + +package art.arcane.iris.pack.ingest; + +import art.arcane.iris.pack.ingest.catalog.CatalogDimensionType; +import art.arcane.iris.pack.ingest.catalog.WorldgenCatalog; +import com.google.gson.JsonObject; +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.assertNotNull; + +public class IngestHeightBoundsTest { + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @Test + public void relativeAnchorsResolveAgainstThePacksOwnHeight() throws Exception { + JsonObject stone = tinDeposit("\"dimensionHeight\": {\"min\": 0, \"max\": 256}", ModIngestFixture.catalog()); + + assertEquals(16, stone.get("minHeight").getAsInt()); + assertEquals(235, stone.get("maxHeight").getAsInt()); + } + + @Test + public void relativeAnchorsResolveAgainstTheBorrowedTypeWhenSet() throws Exception { + WorldgenCatalog fixture = ModIngestFixture.catalog(); + List types = new ArrayList<>(fixture.dimensionTypes()); + types.add(new CatalogDimensionType("examplemod:skyrealm", 0, 256, 256, null)); + WorldgenCatalog catalog = new WorldgenCatalog(fixture.format(), fixture.minecraftVersion(), fixture.platform(), + fixture.capturedAtEpochMillis(), fixture.contentFingerprint(), fixture.namespaces(), fixture.biomes(), + fixture.placedFeatures(), fixture.structures(), types, fixture.levelStems()); + + JsonObject stone = tinDeposit("\"dimensionHeight\": {\"min\": 0, \"max\": 192}, \"borrowedDimensionType\": \"examplemod:skyrealm\"", + catalog); + + assertEquals(16, stone.get("minHeight").getAsInt()); + assertEquals(235, stone.get("maxHeight").getAsInt()); + } + + private JsonObject tinDeposit(String heightFields, WorldgenCatalog catalog) throws Exception { + Path root = folder.getRoot().toPath(); + Path source = ModIngestFixture.writeSourcePack(root); + ModIngestFixture.write(source, "dimensions/overworld.json", """ + { + "name": "Overworld", + "environment": "NORMAL", + "regions": ["hot", "temperate"], + %s + } + """.formatted(heightFields)); + Path target = root.resolve("packs").resolve("modded"); + ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog, Set.of(ModIngestFixture.MOD), false)); + JsonObject dimension = ModIngestFixture.readJson(target.resolve("dimensions/modded.json")); + JsonObject stone = ModIngestFixture.findByPaletteBlock(dimension.getAsJsonArray("deposits"), "examplemod:tin_ore"); + assertNotNull(stone); + return stone; + } +} diff --git a/core/src/test/java/art/arcane/iris/pack/ingest/ModIngesterFeatureTest.java b/core/src/test/java/art/arcane/iris/pack/ingest/ModIngesterFeatureTest.java index 05cfba906..d31c71408 100644 --- a/core/src/test/java/art/arcane/iris/pack/ingest/ModIngesterFeatureTest.java +++ b/core/src/test/java/art/arcane/iris/pack/ingest/ModIngesterFeatureTest.java @@ -63,7 +63,7 @@ public class ModIngesterFeatureTest { assertEquals(4, deposits.size()); assertNotNull(stone); assertNotNull(deepslate); - assertEquals(80, stone.get("minHeight").getAsInt()); + assertEquals(16, stone.get("minHeight").getAsInt()); assertEquals(427, stone.get("maxHeight").getAsInt()); assertEquals("UNIFORM", stone.get("heightDistribution").getAsString()); assertEquals(12, stone.get("minPerChunk").getAsInt());