mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 14:00:26 +00:00
Merged mod ingester
This commit is contained in:
commit
7fc8d20516
27 files changed
+3793
-2
No files matched your search
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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.CatalogPlacedFeature;
|
||||
import art.arcane.iris.pack.ingest.catalog.WorldgenCatalog;
|
||||
import art.arcane.iris.pack.ingest.catalog.WorldgenCatalogIndex;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class FeatureConverterFormatTest {
|
||||
private static final VanillaHeights.VerticalBounds OVERWORLD = new VanillaHeights.VerticalBounds(-64, 384);
|
||||
private static final String PATCH_TAIL = """
|
||||
{"type": "minecraft:offset",
|
||||
"x": {"type": "minecraft:trapezoid", "max": 7, "min": -7, "plateau": 0},
|
||||
"y": {"type": "minecraft:trapezoid", "max": 3, "min": -3, "plateau": 0},
|
||||
"z": {"type": "minecraft:trapezoid", "max": 7, "min": -7, "plateau": 0}},
|
||||
{"type": "minecraft:block_predicate_filter", "predicate": {"type": "minecraft:matching_block_tag", "tag": "minecraft:air"}}
|
||||
""";
|
||||
|
||||
@Test
|
||||
public void currentVanillaIronOreSplitsIntoStoneAndDeepslateDeposits() throws Exception {
|
||||
CatalogPlacedFeature iron = feature("minecraft:ore", """
|
||||
{"type": "minecraft:ore", "discard_chance_on_air_exposure": 0.0, "size": 9, "targets": [
|
||||
{"state": "minecraft:iron_ore", "target": {"predicate_type": "minecraft:any_of", "rules": [
|
||||
{"predicate_type": "minecraft:all_of", "rules": [
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"},
|
||||
{"max_inclusive": 2031, "min_inclusive": 0, "predicate_type": "minecraft:height_match"}]},
|
||||
{"predicate_type": "minecraft:all_of", "rules": [
|
||||
{"predicate_type": "minecraft:not", "rule": {"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"}},
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:stone_ore_replaceables"}]}]}},
|
||||
{"state": "minecraft:deepslate_iron_ore", "target": {"predicate_type": "minecraft:any_of", "rules": [
|
||||
{"predicate_type": "minecraft:all_of", "rules": [
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"},
|
||||
{"max_inclusive": 8, "min_inclusive": -2032, "predicate_type": "minecraft:height_match"}]},
|
||||
{"predicate_type": "minecraft:all_of", "rules": [
|
||||
{"predicate_type": "minecraft:not", "rule": {"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"}},
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:deepslate_ore_replaceables"}]}]}}]}
|
||||
""", """
|
||||
[{"type": "minecraft:count", "count": 10}, {"type": "minecraft:in_square"},
|
||||
{"type": "minecraft:height_range", "height": {"type": "minecraft:trapezoid", "max_inclusive": {"absolute": 56}, "min_inclusive": {"absolute": -24}}},
|
||||
{"type": "minecraft:biome"}]
|
||||
""");
|
||||
|
||||
List<JsonObject> deposits = OreDepositConverter.convert(iron, OVERWORLD, -64);
|
||||
|
||||
assertEquals(2, deposits.size());
|
||||
assertEquals("minecraft:iron_ore", deposits.get(0).getAsJsonArray("palette").get(0).getAsJsonObject().get("block").getAsString());
|
||||
assertEquals(40, deposits.get(0).get("minHeight").getAsInt());
|
||||
assertEquals(120, deposits.get(0).get("maxHeight").getAsInt());
|
||||
assertEquals("TRIANGLE", deposits.get(0).get("heightDistribution").getAsString());
|
||||
assertEquals(10, deposits.get(0).get("maxPerChunk").getAsInt());
|
||||
assertEquals(List.of("minecraft:deepslate"), IngestJson.strings(deposits.get(1).get("replaceableBlocks")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void environmentScanOrePassesThroughWithTheModifierNamed() {
|
||||
CatalogPlacedFeature buried = feature("minecraft:ore",
|
||||
"{\"size\": 4, \"targets\": [{\"state\": \"minecraft:stone\", \"target\": {\"predicate_type\": \"minecraft:always_true\"}}]}",
|
||||
"[{\"type\": \"minecraft:environment_scan\", \"direction_of_search\": \"down\", \"max_steps\": 16, \"target_condition\": {\"type\": \"minecraft:solid\"}}]");
|
||||
|
||||
IngestConversionException failure = assertThrows(IngestConversionException.class, () -> OreDepositConverter.convert(buried, OVERWORLD, -64));
|
||||
|
||||
assertTrue(failure.getMessage(), failure.getMessage().contains("minecraft:environment_scan"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void densePatchCountsBeforeAndAfterTheHeightmapSaturateCoverage() throws Exception {
|
||||
CatalogPlacedFeature lavender = feature(PatchDecoratorConverter.SIMPLE_BLOCK,
|
||||
"{\"type\": \"minecraft:simple_block\", \"to_place\": {\"id\": \"examplemod:lavender\"}}",
|
||||
"[{\"type\": \"minecraft:count\", \"count\": 15}, {\"type\": \"minecraft:in_square\"},"
|
||||
+ "{\"type\": \"minecraft:heightmap\", \"heightmap\": \"WORLD_SURFACE_WG\"}, {\"type\": \"minecraft:biome\"},"
|
||||
+ "{\"type\": \"minecraft:count\", \"count\": 96}," + PATCH_TAIL + "]");
|
||||
|
||||
JsonObject decorator = PatchDecoratorConverter.convert(lavender, index());
|
||||
|
||||
assertEquals(1.0D - Math.exp(-(15.0D * 96.0D * 0.25D) / 256.0D), decorator.get("chance").getAsDouble(), 0.000001D);
|
||||
assertTrue(decorator.get("chance").getAsDouble() < 1.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unnamespacedTypesAndClampedCountsConvert() throws Exception {
|
||||
CatalogPlacedFeature flowers = feature("simple_block", "{\"type\": \"simple_block\", \"to_place\": {\"id\": \"minecraft:poppy\"}}", """
|
||||
[{"type": "rarity_filter", "chance": 2}, {"type": "minecraft:in_square"},
|
||||
{"type": "count", "count": {"type": "minecraft:clamped", "min_inclusive": 0, "max_inclusive": 64,
|
||||
"source": {"type": "minecraft:uniform", "min_inclusive": -3, "max_inclusive": 1}}},
|
||||
{"type": "minecraft:heightmap", "heightmap": "MOTION_BLOCKING_NO_LEAVES"},
|
||||
{"type": "minecraft:offset", "x": {"type": "minecraft:trapezoid", "plateau": 0, "min": -7, "max": 7},
|
||||
"y": {"type": "minecraft:trapezoid", "plateau": 0, "min": -3, "max": 3}, "z": {"type": "minecraft:trapezoid", "plateau": 0, "min": -7, "max": 7}},
|
||||
{"type": "minecraft:block_predicate_filter", "predicate": {"type": "minecraft:all_of", "predicates": [
|
||||
{"type": "minecraft:matching_blocks", "blocks": ["minecraft:grass_block"], "offset": [0, -1, 0]}]}},
|
||||
{"type": "minecraft:biome"}]
|
||||
""");
|
||||
|
||||
JsonObject decorator = PatchDecoratorConverter.convert(flowers, index());
|
||||
|
||||
assertEquals(1.0D - Math.exp(-(0.5D * 0.2D * 0.25D) / 256.0D), decorator.get("chance").getAsDouble(), 0.000001D);
|
||||
assertEquals("minecraft:grass_block", decorator.getAsJsonArray("whitelist").get(0).getAsJsonObject().get("block").getAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void underwaterAndRegistryProviderPatchesPassThrough() {
|
||||
CatalogPlacedFeature seagrass = feature(PatchDecoratorConverter.SIMPLE_BLOCK,
|
||||
"{\"to_place\": {\"id\": \"minecraft:seagrass\"}}",
|
||||
"[{\"type\": \"minecraft:heightmap\", \"heightmap\": \"OCEAN_FLOOR_WG\"}]");
|
||||
CatalogPlacedFeature plains = feature(PatchDecoratorConverter.SIMPLE_BLOCK,
|
||||
"{\"type\": \"minecraft:simple_block\", \"to_place\": \"minecraft:flower_plain\"}",
|
||||
"[{\"type\": \"minecraft:heightmap\", \"heightmap\": \"MOTION_BLOCKING\"}]");
|
||||
|
||||
assertThrows(IngestConversionException.class, () -> PatchDecoratorConverter.convert(seagrass, index()));
|
||||
IngestConversionException reference = assertThrows(IngestConversionException.class, () -> PatchDecoratorConverter.convert(plains, index()));
|
||||
assertTrue(reference.getMessage(), reference.getMessage().contains("minecraft:flower_plain"));
|
||||
}
|
||||
|
||||
private static CatalogPlacedFeature feature(String type, String config, String placement) {
|
||||
return new CatalogPlacedFeature("examplemod:sample", "examplemod:sample", type,
|
||||
JsonParser.parseString(config), JsonParser.parseString(placement));
|
||||
}
|
||||
|
||||
private static WorldgenCatalogIndex index() {
|
||||
return WorldgenCatalogIndex.of(new WorldgenCatalog(WorldgenCatalog.FORMAT, "26.3", "fabric", 0L, "",
|
||||
List.of(), List.of(), List.of(), List.of(), List.of(), List.of()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* 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.CatalogPlacedFeature;
|
||||
import art.arcane.iris.pack.ingest.catalog.CatalogStructure;
|
||||
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 java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
final class ModIngestFixture {
|
||||
static final String MOD = "examplemod";
|
||||
static final String OTHER_MOD = "othermod";
|
||||
static final int ORE_STEP = 6;
|
||||
static final int VEGETAL_STEP = 9;
|
||||
private static final List<String> OVERWORLD = List.of("minecraft:is_overworld");
|
||||
private static final String STONE_THEN_DEEPSLATE_TIN = """
|
||||
{
|
||||
"type": "minecraft:ore",
|
||||
"discard_chance_on_air_exposure": 0.0,
|
||||
"size": 7,
|
||||
"targets": [
|
||||
{
|
||||
"state": "examplemod:tin_ore",
|
||||
"target": {
|
||||
"predicate_type": "minecraft:any_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"},
|
||||
{"predicate_type": "minecraft:height_match", "min_inclusive": 0, "max_inclusive": 2031}
|
||||
]
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{"predicate_type": "minecraft:not", "rule": {"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"}},
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:stone_ore_replaceables"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"state": {"id": "examplemod:deepslate_tin_ore"},
|
||||
"target": {
|
||||
"predicate_type": "minecraft:any_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"},
|
||||
{"predicate_type": "minecraft:height_match", "min_inclusive": -2032, "max_inclusive": 8}
|
||||
]
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{"predicate_type": "minecraft:not", "rule": {"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"}},
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:deepslate_ore_replaceables"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
private static final String TIN_PLACEMENT = """
|
||||
[
|
||||
{"type": "minecraft:count", "count": 12},
|
||||
{"type": "minecraft:rarity_filter", "chance": 2},
|
||||
{"type": "minecraft:in_square"},
|
||||
{"type": "minecraft:height_range", "height": {"type": "minecraft:uniform", "min_inclusive": {"above_bottom": 16}, "max_inclusive": {"below_top": 20}}},
|
||||
{"type": "minecraft:biome"}
|
||||
]
|
||||
""";
|
||||
private static final String RUBY_CONFIG = """
|
||||
{
|
||||
"discard_chance_on_air_exposure": 0.5,
|
||||
"size": 3,
|
||||
"targets": [
|
||||
{"state": {"Name": "examplemod:ruby_ore", "Properties": {"lit": "false"}}, "target": {"predicate_type": "minecraft:block_match", "block": "minecraft:stone"}}
|
||||
]
|
||||
}
|
||||
""";
|
||||
private static final String RUBY_PLACEMENT = """
|
||||
[
|
||||
{"type": "minecraft:count", "count": {"type": "minecraft:uniform", "min_inclusive": 1, "max_inclusive": 3}},
|
||||
{"type": "minecraft:in_square"},
|
||||
{"type": "minecraft:height_range", "height": {"type": "minecraft:trapezoid", "min_inclusive": {"absolute": -16}, "max_inclusive": {"absolute": 48}, "plateau": 0}},
|
||||
{"type": "minecraft:biome"}
|
||||
]
|
||||
""";
|
||||
private static final String SAPPHIRE_CONFIG = """
|
||||
{"size": 4, "targets": [{"state": "examplemod:sapphire_ore", "target": {"predicate_type": "minecraft:tag_match", "tag": "minecraft:base_stone_overworld"}}]}
|
||||
""";
|
||||
private static final String SAPPHIRE_PLACEMENT = """
|
||||
[
|
||||
{"type": "count", "count": 2},
|
||||
{"type": "minecraft:height_range", "height": {"type": "minecraft:uniform", "min_inclusive": {"absolute": 0}, "max_inclusive": {"absolute": 32}}}
|
||||
]
|
||||
""";
|
||||
private static final String GLOW_FLOWERS_CONFIG = """
|
||||
{
|
||||
"type": "minecraft:simple_block",
|
||||
"to_place": {
|
||||
"type": "minecraft:weighted",
|
||||
"entries": [
|
||||
{"data": "examplemod:glowcap", "weight": 3},
|
||||
{"data": {"id": "examplemod:glowbell", "properties": {"lit": "true"}}, "weight": 1}
|
||||
]
|
||||
}
|
||||
}
|
||||
""";
|
||||
private static final String GLOW_FLOWERS_PLACEMENT = """
|
||||
[
|
||||
{"type": "minecraft:rarity_filter", "chance": 4},
|
||||
{"type": "minecraft:in_square"},
|
||||
{"type": "minecraft:heightmap", "heightmap": "MOTION_BLOCKING"},
|
||||
{"type": "minecraft:biome"},
|
||||
{"type": "minecraft:count", "count": 32},
|
||||
{"type": "minecraft:offset", "x": {"type": "minecraft:trapezoid", "min": -7, "max": 7, "plateau": 0}, "y": {"type": "minecraft:trapezoid", "min": -3, "max": 3, "plateau": 0}, "z": {"type": "minecraft:trapezoid", "min": -7, "max": 7, "plateau": 0}},
|
||||
{"type": "minecraft:block_predicate_filter", "predicate": {"type": "minecraft:all_of", "predicates": [{"type": "minecraft:matching_block_tag", "tag": "minecraft:air"}, {"type": "minecraft:matching_blocks", "blocks": "minecraft:grass_block", "offset": [0, -1, 0]}]}}
|
||||
]
|
||||
""";
|
||||
private static final String BLUEBELL_PATCH_CONFIG = """
|
||||
{
|
||||
"tries": 64,
|
||||
"xz_spread": 7,
|
||||
"y_spread": 3,
|
||||
"feature": {
|
||||
"feature": {"type": "minecraft:simple_block", "config": {"to_place": {"type": "minecraft:simple_state_provider", "state": {"Name": "examplemod:bluebell"}}}},
|
||||
"placement": [{"type": "minecraft:block_predicate_filter", "predicate": {"type": "minecraft:matching_blocks", "blocks": ["minecraft:air"]}}]
|
||||
}
|
||||
}
|
||||
""";
|
||||
private static final String BLUEBELL_PATCH_PLACEMENT = """
|
||||
[
|
||||
{"type": "minecraft:rarity_filter", "chance": 2},
|
||||
{"type": "minecraft:in_square"},
|
||||
{"type": "minecraft:heightmap", "heightmap": "MOTION_BLOCKING"},
|
||||
{"type": "minecraft:biome"}
|
||||
]
|
||||
""";
|
||||
private static final String BURIED_TIN_PLACEMENT = """
|
||||
[
|
||||
{"type": "minecraft:count", "count": 2},
|
||||
{"type": "minecraft:environment_scan", "direction_of_search": "down", "max_steps": 8, "target_condition": {"type": "minecraft:solid"}}
|
||||
]
|
||||
""";
|
||||
private static final String WEIRD_ORE_CONFIG = """
|
||||
{"size": 5, "targets": [{"state": "examplemod:weird_ore", "target": {"predicate_type": "minecraft:tag_match", "tag": "examplemod:custom_stone"}}]}
|
||||
""";
|
||||
|
||||
private ModIngestFixture() {
|
||||
}
|
||||
|
||||
static Path writeSourcePack(Path root) throws IOException {
|
||||
Path pack = root.resolve("source");
|
||||
write(pack, "dimensions/overworld.json", """
|
||||
{
|
||||
"name": "Overworld",
|
||||
"environment": "NORMAL",
|
||||
"regions": ["hot", "temperate"],
|
||||
"dimensionHeight": {"min": -128, "max": 320},
|
||||
"deposits": [{"minHeight": 10, "maxHeight": 40, "palette": [{"block": "minecraft:coal_ore"}]}],
|
||||
"importedStructures": {"disabled": ["examplemod:old_ruin"]},
|
||||
"importedFeatures": {"enabled": false, "disabled": ["minecraft:ore_diamond"], "disabledSteps": ["LAKES"]}
|
||||
}
|
||||
""");
|
||||
write(pack, "regions/hot.json", """
|
||||
{
|
||||
"name": "Hot",
|
||||
"landBiomes": ["hot/desert", "hot/savanna"],
|
||||
"seaBiomes": ["hot/warm-ocean"],
|
||||
"shoreBiomes": ["hot/beach"],
|
||||
"caveBiomes": ["caves/dripstone"]
|
||||
}
|
||||
""");
|
||||
write(pack, "regions/temperate.json", """
|
||||
{
|
||||
"name": "Temperate",
|
||||
"landBiomes": ["temperate/forest", "temperate/plains"],
|
||||
"seaBiomes": ["temperate/ocean"],
|
||||
"shoreBiomes": ["temperate/beach"]
|
||||
}
|
||||
""");
|
||||
write(pack, "biomes/hot/desert.json", """
|
||||
{
|
||||
"name": "Desert",
|
||||
"derivative": "minecraft:desert",
|
||||
"layers": [{"palette": [{"block": "minecraft:sand"}]}],
|
||||
"objects": [{"chance": 0.1, "place": ["desert/cactus"]}]
|
||||
}
|
||||
""");
|
||||
write(pack, "biomes/hot/savanna.json", """
|
||||
{"name": "Savanna", "derivative": "minecraft:savanna", "children": ["hot/desert"]}
|
||||
""");
|
||||
write(pack, "biomes/hot/warm-ocean.json", """
|
||||
{"name": "Warm Ocean", "derivative": "minecraft:warm_ocean"}
|
||||
""");
|
||||
write(pack, "biomes/hot/beach.json", """
|
||||
{"name": "Hot Beach", "derivative": "minecraft:beach"}
|
||||
""");
|
||||
write(pack, "biomes/caves/dripstone.json", """
|
||||
{"name": "Dripstone", "derivative": "minecraft:dripstone_caves"}
|
||||
""");
|
||||
write(pack, "biomes/temperate/forest.json", """
|
||||
{
|
||||
"name": "Forest",
|
||||
"derivative": "minecraft:forest",
|
||||
"vanillaDerivative": "minecraft:forest",
|
||||
"customDerivitives": [{"id": "forest", "grassColor": "#91BD59"}],
|
||||
"biomeScatter": ["minecraft:birch_forest"],
|
||||
"children": ["temperate/plains"],
|
||||
"objects": [{"chance": 0.4, "place": ["trees/oak"]}],
|
||||
"proceduralObjects": {"trees": [{"chance": 0.2}], "ruins": [{"chance": 0.01}]},
|
||||
"decorators": [{"chance": 0.3, "palette": [{"block": "minecraft:short_grass"}]}]
|
||||
}
|
||||
""");
|
||||
write(pack, "biomes/temperate/plains.json", """
|
||||
{"name": "Plains", "derivative": "plains"}
|
||||
""");
|
||||
write(pack, "biomes/temperate/ocean.json", """
|
||||
{"name": "Ocean", "derivative": "minecraft:ocean"}
|
||||
""");
|
||||
write(pack, "biomes/temperate/beach.json", """
|
||||
{"name": "Beach", "derivative": "minecraft:beach"}
|
||||
""");
|
||||
write(pack, "biomes/unused/orphan.json", """
|
||||
{"name": "Orphan", "derivative": "minecraft:forest"}
|
||||
""");
|
||||
write(pack, ".git/HEAD", "ref: refs/heads/main\n");
|
||||
write(pack, "source.code-workspace", "{}");
|
||||
return pack;
|
||||
}
|
||||
|
||||
static WorldgenCatalog catalog() {
|
||||
List<CatalogBiome> biomes = new ArrayList<>();
|
||||
List<String> sharedOres = List.of("minecraft:ore_iron", MOD + ":ore_tin", MOD + ":ore_tin_buried");
|
||||
biomes.add(biome("minecraft:desert", 2.0F, 0.0F, OVERWORLD, steps(ORE_STEP, concat(sharedOres, MOD + ":ore_sapphire"))));
|
||||
biomes.add(biome("minecraft:savanna", 1.2F, 0.4F, OVERWORLD, steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome("minecraft:warm_ocean", 0.5F, 0.5F, List.of("minecraft:is_overworld", "minecraft:is_ocean"), steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome("minecraft:ocean", 0.5F, 0.5F, List.of("minecraft:is_overworld", "minecraft:is_ocean"), steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome("minecraft:beach", 0.8F, 0.4F, List.of("minecraft:is_overworld", "minecraft:is_beach"), steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome("minecraft:dripstone_caves", 0.8F, 0.4F, OVERWORLD, steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome("minecraft:forest", 0.7F, 0.8F, OVERWORLD, merge(steps(ORE_STEP, sharedOres),
|
||||
steps(VEGETAL_STEP, List.of("minecraft:trees_birch_and_oak", MOD + ":glow_flowers")))));
|
||||
biomes.add(biome("minecraft:plains", 0.8F, 0.4F, OVERWORLD, merge(steps(ORE_STEP, sharedOres),
|
||||
steps(VEGETAL_STEP, List.of(MOD + ":bluebell_patch", OTHER_MOD + ":daisies")))));
|
||||
biomes.add(biome("minecraft:river", 0.5F, 0.5F, List.of("minecraft:is_overworld", "minecraft:is_river"), steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome("minecraft:nether_wastes", 2.0F, 0.0F, List.of("minecraft:is_nether"), steps(ORE_STEP, List.of())));
|
||||
biomes.add(biome(MOD + ":scorched_mesa", 1.9F, 0.05F, OVERWORLD, steps(ORE_STEP, concat(sharedOres, MOD + ":ore_ruby"))));
|
||||
biomes.add(biome(MOD + ":maple_woods", 0.6F, 0.8F, List.of("minecraft:is_overworld", "c:is_forest"), merge(steps(ORE_STEP, sharedOres),
|
||||
steps(VEGETAL_STEP, List.of(MOD + ":maple_trees", MOD + ":glow_flowers", "minecraft:patch_grass")))));
|
||||
biomes.add(biome(MOD + ":coral_depths", 0.5F, 0.5F, List.of("minecraft:is_overworld", "minecraft:is_ocean"), steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome(MOD + ":dune_beach", 1.8F, 0.1F, List.of("minecraft:is_overworld", "minecraft:is_beach"), steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome(MOD + ":crystal_caves", 0.8F, 0.4F, List.of("minecraft:is_overworld", "c:is_cave"),
|
||||
steps(ORE_STEP, concat(sharedOres, MOD + ":weird_ore"))));
|
||||
biomes.add(biome(MOD + ":misty_river", 0.5F, 0.5F, List.of("minecraft:is_overworld", "minecraft:is_river"), steps(ORE_STEP, sharedOres)));
|
||||
biomes.add(biome(MOD + ":ashen_wastes", 2.0F, 0.0F, List.of("minecraft:is_nether"), steps(ORE_STEP, List.of(MOD + ":nether_ore"))));
|
||||
biomes.add(biome(MOD + ":void_garden", 0.5F, 0.5F, List.of(), steps(ORE_STEP, List.of())));
|
||||
biomes.add(biome(OTHER_MOD + ":bamboo_marsh", 0.9F, 0.9F, OVERWORLD, steps(VEGETAL_STEP, List.of(OTHER_MOD + ":daisies"))));
|
||||
|
||||
List<CatalogPlacedFeature> features = new ArrayList<>();
|
||||
features.add(feature("minecraft:ore_iron", "minecraft:ore", "{\"size\": 9, \"targets\": []}", "[]"));
|
||||
features.add(feature(MOD + ":ore_tin", "minecraft:ore", STONE_THEN_DEEPSLATE_TIN, TIN_PLACEMENT));
|
||||
features.add(feature(MOD + ":ore_tin_buried", "minecraft:ore", STONE_THEN_DEEPSLATE_TIN, BURIED_TIN_PLACEMENT));
|
||||
features.add(feature(MOD + ":ore_ruby", "minecraft:scattered_ore", RUBY_CONFIG, RUBY_PLACEMENT));
|
||||
features.add(feature(MOD + ":ore_sapphire", "minecraft:ore", SAPPHIRE_CONFIG, SAPPHIRE_PLACEMENT));
|
||||
features.add(feature(MOD + ":weird_ore", "minecraft:ore", WEIRD_ORE_CONFIG, SAPPHIRE_PLACEMENT));
|
||||
features.add(feature(MOD + ":nether_ore", "minecraft:ore", WEIRD_ORE_CONFIG, "[]"));
|
||||
features.add(feature(MOD + ":glow_flowers", "minecraft:simple_block", GLOW_FLOWERS_CONFIG, GLOW_FLOWERS_PLACEMENT));
|
||||
features.add(feature(MOD + ":bluebell_patch", "minecraft:random_patch", BLUEBELL_PATCH_CONFIG, BLUEBELL_PATCH_PLACEMENT));
|
||||
features.add(feature(MOD + ":maple_trees", "minecraft:tree", "{\"trunk_provider\": {}}", "[]"));
|
||||
features.add(feature(OTHER_MOD + ":daisies", "minecraft:simple_block",
|
||||
"{\"to_place\": {\"id\": \"othermod:daisy\"}}", GLOW_FLOWERS_PLACEMENT));
|
||||
|
||||
List<CatalogStructure> structures = List.of(
|
||||
structure(MOD + ":maple_tower", List.of(MOD + ":maple_woods")),
|
||||
structure(MOD + ":old_ruin", List.of("minecraft:plains")),
|
||||
structure(MOD + ":nether_fort", List.of(MOD + ":ashen_wastes")),
|
||||
structure("minecraft:village_plains", List.of("minecraft:plains")));
|
||||
return new WorldgenCatalog(WorldgenCatalog.FORMAT, "26.3", "fabric", 1000L, "fingerprint-1",
|
||||
List.of(new CatalogNamespace(MOD, "Example Mod", "1.0.0"), new CatalogNamespace(OTHER_MOD, "Other Mod", "2.0.0")),
|
||||
biomes, features, structures,
|
||||
List.of(new CatalogDimensionType("minecraft:overworld", -64, 384, 384, null)),
|
||||
List.of());
|
||||
}
|
||||
|
||||
static ModIngestRequest request(Path source, Path target, Set<String> namespaces, boolean replace) {
|
||||
return new ModIngestRequest(source, target, "overworld", catalog(), namespaces, replace);
|
||||
}
|
||||
|
||||
static JsonObject readJson(Path file) throws IOException {
|
||||
return JsonParser.parseString(Files.readString(file, StandardCharsets.UTF_8)).getAsJsonObject();
|
||||
}
|
||||
|
||||
static List<String> strings(JsonElement element) {
|
||||
List<String> values = new ArrayList<>();
|
||||
if (element == null || !element.isJsonArray()) {
|
||||
return values;
|
||||
}
|
||||
for (JsonElement value : element.getAsJsonArray()) {
|
||||
values.add(value.getAsString());
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
static JsonObject findByPaletteBlock(JsonArray entries, String block) {
|
||||
for (JsonElement entry : entries) {
|
||||
if (!entry.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
JsonArray palette = entry.getAsJsonObject().getAsJsonArray("palette");
|
||||
if (palette == null) {
|
||||
continue;
|
||||
}
|
||||
for (JsonElement paletteEntry : palette) {
|
||||
if (block.equals(paletteEntry.getAsJsonObject().get("block").getAsString())) {
|
||||
return entry.getAsJsonObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static ModIngestItem item(ModIngestReport report, String sourceKey) {
|
||||
for (ModIngestItem item : report.items()) {
|
||||
if (item.sourceKey().equals(sourceKey)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void write(Path root, String relative, String content) throws IOException {
|
||||
Path file = root.resolve(relative);
|
||||
Files.createDirectories(file.getParent());
|
||||
Files.writeString(file, content, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static CatalogBiome biome(String key, float temperature, float downfall, List<String> tags, List<List<String>> steps) {
|
||||
return new CatalogBiome(key, temperature, downfall, true, tags, steps, List.of(), null);
|
||||
}
|
||||
|
||||
private static CatalogPlacedFeature feature(String key, String type, String config, String placement) {
|
||||
return new CatalogPlacedFeature(key, key, type, JsonParser.parseString(config), JsonParser.parseString(placement));
|
||||
}
|
||||
|
||||
private static CatalogStructure structure(String key, List<String> biomes) {
|
||||
return new CatalogStructure(key, "minecraft:jigsaw", "surface_structures", "beard_thin", "", biomes, List.of());
|
||||
}
|
||||
|
||||
private static List<List<String>> steps(int step, List<String> keys) {
|
||||
List<List<String>> steps = new ArrayList<>(11);
|
||||
for (int index = 0; index < 11; index++) {
|
||||
steps.add(index == step ? keys : List.of());
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
|
||||
private static List<List<String>> merge(List<List<String>> first, List<List<String>> second) {
|
||||
List<List<String>> merged = new ArrayList<>(11);
|
||||
for (int index = 0; index < 11; index++) {
|
||||
merged.add(concat(first.get(index), second.get(index)));
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
private static List<String> concat(List<String> first, List<String> second) {
|
||||
List<String> values = new ArrayList<>(first);
|
||||
values.addAll(second);
|
||||
return values;
|
||||
}
|
||||
|
||||
private static List<String> concat(List<String> first, String extra) {
|
||||
return concat(first, List.of(extra));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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 com.google.gson.JsonObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
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 ModIngesterBiomeTest {
|
||||
@Rule
|
||||
public TemporaryFolder folder = new TemporaryFolder();
|
||||
|
||||
private Path target;
|
||||
private ModIngestReport report;
|
||||
|
||||
@Before
|
||||
public void ingest() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
target = root.resolve("packs").resolve("modded");
|
||||
report = ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hotModBiomeJoinsHotRegionFromNearestTemplate() throws Exception {
|
||||
JsonObject biome = ModIngestFixture.readJson(target.resolve("biomes/ingest/examplemod/scorched_mesa.json"));
|
||||
|
||||
assertEquals("examplemod:scorched_mesa", biome.get("derivative").getAsString());
|
||||
assertEquals("Scorched Mesa", biome.get("name").getAsString());
|
||||
assertTrue(biome.has("layers"));
|
||||
assertTrue("template objects stay when the mod brings no vegetation", biome.has("objects"));
|
||||
List<String> hotLand = ModIngestFixture.strings(ModIngestFixture.readJson(target.resolve("regions/hot.json")).get("landBiomes"));
|
||||
assertEquals("ingest/examplemod/scorched_mesa", hotLand.get(hotLand.size() - 1));
|
||||
assertFalse(ModIngestFixture.strings(ModIngestFixture.readJson(target.resolve("regions/temperate.json")).get("landBiomes"))
|
||||
.contains("ingest/examplemod/scorched_mesa"));
|
||||
|
||||
ModIngestItem item = ModIngestFixture.item(report, "examplemod:scorched_mesa");
|
||||
assertNotNull(item);
|
||||
assertEquals(ModIngestTier.ADOPTED, item.tier());
|
||||
assertEquals("biome", item.kind());
|
||||
assertEquals("ingest/examplemod/scorched_mesa", item.target());
|
||||
assertTrue(item.reason(), item.reason().contains("hot/desert"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forestModBiomeDropsOverridesChildrenAndTreesWhenItBringsItsOwn() throws Exception {
|
||||
JsonObject biome = ModIngestFixture.readJson(target.resolve("biomes/ingest/examplemod/maple_woods.json"));
|
||||
|
||||
assertEquals("examplemod:maple_woods", biome.get("derivative").getAsString());
|
||||
assertFalse(biome.has("vanillaDerivative"));
|
||||
assertFalse(biome.has("customDerivitives"));
|
||||
assertFalse(biome.has("biomeScatter"));
|
||||
assertFalse(biome.has("children"));
|
||||
assertFalse(biome.has("objects"));
|
||||
assertFalse(biome.getAsJsonObject("proceduralObjects").has("trees"));
|
||||
assertTrue(biome.getAsJsonObject("proceduralObjects").has("ruins"));
|
||||
assertTrue(ModIngestFixture.strings(ModIngestFixture.readJson(target.resolve("regions/temperate.json")).get("landBiomes"))
|
||||
.contains("ingest/examplemod/maple_woods"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oceanShoreAndCaveBiomesJoinTheMatchingPools() throws Exception {
|
||||
JsonObject temperate = ModIngestFixture.readJson(target.resolve("regions/temperate.json"));
|
||||
JsonObject hot = ModIngestFixture.readJson(target.resolve("regions/hot.json"));
|
||||
|
||||
assertTrue(ModIngestFixture.strings(temperate.get("seaBiomes")).contains("ingest/examplemod/coral_depths"));
|
||||
assertTrue(ModIngestFixture.strings(hot.get("shoreBiomes")).contains("ingest/examplemod/dune_beach"));
|
||||
assertTrue(ModIngestFixture.strings(hot.get("caveBiomes")).contains("ingest/examplemod/crystal_caves"));
|
||||
assertFalse(temperate.has("caveBiomes"));
|
||||
assertEquals("Ocean", ModIngestFixture.readJson(target.resolve("biomes/temperate/ocean.json")).get("name").getAsString());
|
||||
assertTrue(ModIngestFixture.item(report, "examplemod:coral_depths").reason().contains("temperate/ocean"));
|
||||
assertTrue(ModIngestFixture.item(report, "examplemod:dune_beach").reason().contains("hot/beach"));
|
||||
assertTrue(ModIngestFixture.item(report, "examplemod:crystal_caves").reason().contains("caves/dripstone"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void riverNetherAndUntaggedBiomesAreSkippedWithReasons() {
|
||||
ModIngestItem river = ModIngestFixture.item(report, "examplemod:misty_river");
|
||||
ModIngestItem nether = ModIngestFixture.item(report, "examplemod:ashen_wastes");
|
||||
ModIngestItem untagged = ModIngestFixture.item(report, "examplemod:void_garden");
|
||||
|
||||
assertEquals(ModIngestTier.SKIPPED, river.tier());
|
||||
assertTrue(river.reason(), river.reason().contains("river"));
|
||||
assertEquals(ModIngestTier.SKIPPED, nether.tier());
|
||||
assertTrue(nether.reason(), nether.reason().contains("nether"));
|
||||
assertEquals(ModIngestTier.SKIPPED, untagged.tier());
|
||||
assertTrue(untagged.reason(), untagged.reason().contains("minecraft:is_overworld"));
|
||||
assertFalse(Files.exists(target.resolve("biomes/ingest/examplemod/misty_river.json")));
|
||||
assertFalse(Files.exists(target.resolve("biomes/ingest/examplemod/ashen_wastes.json")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unselectedNamespacesAreLeftAlone() {
|
||||
assertNull(ModIngestFixture.item(report, "othermod:bamboo_marsh"));
|
||||
assertNull(ModIngestFixture.item(report, "othermod:daisies"));
|
||||
assertFalse(Files.exists(target.resolve("biomes/ingest/othermod")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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 com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.nio.file.Path;
|
||||
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 ModIngesterFeatureTest {
|
||||
private static final double EPSILON = 0.0000005D;
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder folder = new TemporaryFolder();
|
||||
|
||||
private Path target;
|
||||
private ModIngestReport report;
|
||||
private JsonObject dimension;
|
||||
|
||||
@Before
|
||||
public void ingest() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
target = root.resolve("packs").resolve("modded");
|
||||
report = ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), false));
|
||||
dimension = ModIngestFixture.readJson(target.resolve("dimensions/modded.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oreInjectedIntoVanillaBiomesBecomesDimensionDepositsPerTarget() {
|
||||
JsonArray deposits = dimension.getAsJsonArray("deposits");
|
||||
JsonObject stone = ModIngestFixture.findByPaletteBlock(deposits, "examplemod:tin_ore");
|
||||
JsonObject deepslate = ModIngestFixture.findByPaletteBlock(deposits, "examplemod:deepslate_tin_ore");
|
||||
|
||||
assertEquals(4, deposits.size());
|
||||
assertNotNull(stone);
|
||||
assertNotNull(deepslate);
|
||||
assertEquals(80, stone.get("minHeight").getAsInt());
|
||||
assertEquals(427, stone.get("maxHeight").getAsInt());
|
||||
assertEquals("UNIFORM", stone.get("heightDistribution").getAsString());
|
||||
assertEquals(12, stone.get("minPerChunk").getAsInt());
|
||||
assertEquals(12, stone.get("maxPerChunk").getAsInt());
|
||||
assertEquals(0.5D, stone.get("spawnChance").getAsDouble(), EPSILON);
|
||||
assertEquals(7, stone.get("minSize").getAsInt());
|
||||
assertEquals(7, stone.get("maxSize").getAsInt());
|
||||
assertEquals("VANILLA_ELLIPSOID", stone.get("shape").getAsString());
|
||||
assertEquals(0, stone.get("surfaceClearance").getAsInt());
|
||||
assertEquals(List.of("minecraft:andesite", "minecraft:diorite", "minecraft:granite", "minecraft:stone", "minecraft:tuff"),
|
||||
ModIngestFixture.strings(stone.get("replaceableBlocks")));
|
||||
assertEquals(List.of("minecraft:deepslate"), ModIngestFixture.strings(deepslate.get("replaceableBlocks")));
|
||||
assertFalse(stone.has("includedBiomes"));
|
||||
assertEquals(ModIngestTier.NATIVE, ModIngestFixture.item(report, "examplemod:ore_tin").tier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oreDeclaredByOneVanillaBiomeIsFilteredToThatBiome() {
|
||||
JsonObject sapphire = ModIngestFixture.findByPaletteBlock(dimension.getAsJsonArray("deposits"), "examplemod:sapphire_ore");
|
||||
|
||||
assertNotNull(sapphire);
|
||||
assertEquals(List.of("minecraft:desert"), ModIngestFixture.strings(sapphire.get("includedBiomes")));
|
||||
assertEquals("SURFACE", sapphire.get("biomeScope").getAsString());
|
||||
assertEquals(128, sapphire.get("minHeight").getAsInt());
|
||||
assertEquals(160, sapphire.get("maxHeight").getAsInt());
|
||||
assertEquals(2, sapphire.get("maxPerChunk").getAsInt());
|
||||
assertEquals(6, ModIngestFixture.strings(sapphire.get("replaceableBlocks")).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modOnlyScatteredOreBecomesBiomeDeposit() throws Exception {
|
||||
JsonObject biome = ModIngestFixture.readJson(target.resolve("biomes/ingest/examplemod/scorched_mesa.json"));
|
||||
JsonObject ruby = ModIngestFixture.findByPaletteBlock(biome.getAsJsonArray("deposits"), "examplemod:ruby_ore");
|
||||
|
||||
assertNotNull(ruby);
|
||||
assertEquals("false", ruby.getAsJsonArray("palette").get(0).getAsJsonObject().getAsJsonObject("data").get("lit").getAsString());
|
||||
assertEquals(112, ruby.get("minHeight").getAsInt());
|
||||
assertEquals(176, ruby.get("maxHeight").getAsInt());
|
||||
assertEquals("TRIANGLE", ruby.get("heightDistribution").getAsString());
|
||||
assertEquals(1, ruby.get("minPerChunk").getAsInt());
|
||||
assertEquals(3, ruby.get("maxPerChunk").getAsInt());
|
||||
assertEquals("VANILLA_SCATTERED", ruby.get("shape").getAsString());
|
||||
assertEquals(0.5D, ruby.get("discardChanceOnAirExposure").getAsDouble(), EPSILON);
|
||||
assertEquals(List.of("minecraft:stone"), ModIngestFixture.strings(ruby.get("replaceableBlocks")));
|
||||
assertNull(ModIngestFixture.findByPaletteBlock(dimension.getAsJsonArray("deposits"), "examplemod:ruby_ore"));
|
||||
assertEquals("ingest/examplemod/scorched_mesa", ModIngestFixture.item(report, "examplemod:ore_ruby").target());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flowerPatchLandsInModBiomeAndExistingVanillaDerivativeBiome() throws Exception {
|
||||
JsonObject maple = ModIngestFixture.readJson(target.resolve("biomes/ingest/examplemod/maple_woods.json"));
|
||||
JsonObject forest = ModIngestFixture.readJson(target.resolve("biomes/temperate/forest.json"));
|
||||
JsonObject orphan = ModIngestFixture.readJson(target.resolve("biomes/unused/orphan.json"));
|
||||
JsonObject mapleFlowers = ModIngestFixture.findByPaletteBlock(maple.getAsJsonArray("decorators"), "examplemod:glowcap");
|
||||
JsonObject forestFlowers = ModIngestFixture.findByPaletteBlock(forest.getAsJsonArray("decorators"), "examplemod:glowcap");
|
||||
|
||||
assertNotNull(mapleFlowers);
|
||||
assertNotNull(forestFlowers);
|
||||
assertEquals(2, forest.getAsJsonArray("decorators").size());
|
||||
assertEquals(1.0D - Math.exp(-(1.0D / 4.0D * 32.0D * 0.25D) / 256.0D), forestFlowers.get("chance").getAsDouble(), 0.000001D);
|
||||
JsonArray palette = forestFlowers.getAsJsonArray("palette");
|
||||
assertEquals(3, palette.get(0).getAsJsonObject().get("weight").getAsInt());
|
||||
assertEquals("examplemod:glowbell", palette.get(1).getAsJsonObject().get("block").getAsString());
|
||||
assertEquals("true", palette.get(1).getAsJsonObject().getAsJsonObject("data").get("lit").getAsString());
|
||||
assertEquals("minecraft:grass_block", forestFlowers.getAsJsonArray("whitelist").get(0).getAsJsonObject().get("block").getAsString());
|
||||
assertFalse(orphan.has("decorators"));
|
||||
ModIngestItem item = ModIngestFixture.item(report, "examplemod:glow_flowers");
|
||||
assertEquals(ModIngestTier.NATIVE, item.tier());
|
||||
assertTrue(item.target(), item.target().contains("temperate/forest"));
|
||||
assertTrue(item.target(), item.target().contains("ingest/examplemod/maple_woods"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void legacyRandomPatchConvertsIntoPlainsDecorator() throws Exception {
|
||||
JsonObject plains = ModIngestFixture.readJson(target.resolve("biomes/temperate/plains.json"));
|
||||
JsonObject bluebell = ModIngestFixture.findByPaletteBlock(plains.getAsJsonArray("decorators"), "examplemod:bluebell");
|
||||
|
||||
assertNotNull(bluebell);
|
||||
assertEquals(1.0D - Math.exp(-(0.5D * 64.0D * 0.25D) / 256.0D), bluebell.get("chance").getAsDouble(), 0.000001D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unconvertibleFeaturesPassThroughAndConvertedOnesAreDisabled() {
|
||||
ModIngestItem trees = ModIngestFixture.item(report, "examplemod:maple_trees");
|
||||
ModIngestItem weird = ModIngestFixture.item(report, "examplemod:weird_ore");
|
||||
JsonObject imported = dimension.getAsJsonObject("importedFeatures");
|
||||
|
||||
assertEquals(ModIngestTier.PASSTHROUGH, trees.tier());
|
||||
assertEquals(ModIngestTier.PASSTHROUGH, weird.tier());
|
||||
assertTrue(weird.reason(), weird.reason().contains("examplemod:custom_stone"));
|
||||
assertTrue(imported.get("enabled").getAsBoolean());
|
||||
assertEquals(List.of("minecraft:ore_diamond", "minecraft:", "examplemod:bluebell_patch", "examplemod:glow_flowers",
|
||||
"examplemod:ore_ruby", "examplemod:ore_sapphire", "examplemod:ore_tin"),
|
||||
ModIngestFixture.strings(imported.get("disabled")));
|
||||
assertEquals(List.of("LAKES"), ModIngestFixture.strings(imported.get("disabledSteps")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void featuresWithoutHostsOrShadowedByDisabledPrefixesAreSkipped() {
|
||||
ModIngestItem nether = ModIngestFixture.item(report, "examplemod:nether_ore");
|
||||
ModIngestItem buried = ModIngestFixture.item(report, "examplemod:ore_tin_buried");
|
||||
|
||||
assertEquals(ModIngestTier.SKIPPED, nether.tier());
|
||||
assertEquals(ModIngestTier.SKIPPED, buried.tier());
|
||||
assertTrue(buried.reason(), buried.reason().contains("examplemod:ore_tin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structuresAreAdoptedUnlessDisabledOrHostless() {
|
||||
assertEquals(ModIngestTier.ADOPTED, ModIngestFixture.item(report, "examplemod:maple_tower").tier());
|
||||
ModIngestItem ruin = ModIngestFixture.item(report, "examplemod:old_ruin");
|
||||
assertEquals(ModIngestTier.SKIPPED, ruin.tier());
|
||||
assertTrue(ruin.reason(), ruin.reason().contains("importedStructures"));
|
||||
assertEquals(ModIngestTier.SKIPPED, ModIngestFixture.item(report, "examplemod:nether_fort").tier());
|
||||
assertNull(ModIngestFixture.item(report, "minecraft:village_plains"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.PackValidationResult;
|
||||
import art.arcane.iris.pack.PackValidator;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModIngesterPackTest {
|
||||
@Rule
|
||||
public TemporaryFolder folder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void writesLoadableTargetPackWithoutTouchingSource() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
Map<String, String> before = snapshot(source);
|
||||
Path target = root.resolve("packs").resolve("modded");
|
||||
|
||||
ModIngestReport report = ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), false));
|
||||
|
||||
assertEquals(before, snapshot(source));
|
||||
assertEquals(target, report.targetPack());
|
||||
assertTrue(Files.isRegularFile(target.resolve("dimensions/modded.json")));
|
||||
assertFalse(Files.exists(target.resolve("dimensions/overworld.json")));
|
||||
assertFalse(Files.exists(target.resolve(".git")));
|
||||
assertFalse(Files.exists(target.resolve("source.code-workspace")));
|
||||
PackValidationResult validation = PackValidator.validate(target.toFile());
|
||||
assertTrue(validation.getBlockingErrors().toString(), validation.isLoadable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void manifestAndSummaryDescribeTheIngest() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
Path target = root.resolve("packs").resolve("modded");
|
||||
|
||||
ModIngestReport report = ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), false));
|
||||
JsonObject manifest = ModIngestFixture.readJson(target.resolve("ingest/manifest.json"));
|
||||
|
||||
assertEquals("fingerprint-1", manifest.get("catalogFingerprint").getAsString());
|
||||
assertEquals("modded", manifest.get("dimension").getAsString());
|
||||
assertEquals(List.of("examplemod"), ModIngestFixture.strings(manifest.get("namespaces")));
|
||||
List<String> generated = ModIngestFixture.strings(manifest.get("generatedFiles"));
|
||||
List<String> modified = ModIngestFixture.strings(manifest.get("modifiedFiles"));
|
||||
assertTrue(generated.toString(), generated.contains("biomes/ingest/examplemod/scorched_mesa.json"));
|
||||
assertTrue(modified.toString(), modified.containsAll(List.of("dimensions/modded.json", "regions/hot.json",
|
||||
"regions/temperate.json", "biomes/temperate/forest.json", "biomes/temperate/plains.json")));
|
||||
assertFalse(modified.contains("biomes/unused/orphan.json"));
|
||||
assertEquals(report.items().size(), manifest.getAsJsonArray("items").size());
|
||||
assertTrue(report.summaryLines().toString(),
|
||||
report.summaryLines().contains("examplemod: 5 native, 6 adopted, 2 passthrough, 7 skipped"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void existingTargetIsRejectedUnlessReplaceIsRequested() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
Path target = root.resolve("packs").resolve("modded");
|
||||
ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), false));
|
||||
|
||||
assertThrows(FileAlreadyExistsException.class,
|
||||
() -> ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replacingTargetProducesIdenticalOutput() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
Path target = root.resolve("packs").resolve("modded");
|
||||
ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), true));
|
||||
Map<String, String> first = snapshot(target);
|
||||
ModIngestFixture.write(target, "biomes/stale.json", "{\"name\": \"Stale\"}");
|
||||
|
||||
ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(ModIngestFixture.MOD), true));
|
||||
|
||||
assertEquals(first, snapshot(target));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetInsideSourceIsRejected() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
|
||||
assertThrows(IOException.class, () -> ModIngester.ingest(
|
||||
ModIngestFixture.request(source, source.resolve("nested"), Set.of(), true)));
|
||||
assertThrows(IOException.class, () -> ModIngester.ingest(
|
||||
ModIngestFixture.request(source, source, Set.of(), true)));
|
||||
assertTrue(Files.isRegularFile(source.resolve("dimensions/overworld.json")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ingestedPackCannotBeUsedAsSource() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
Path target = root.resolve("packs").resolve("modded");
|
||||
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)));
|
||||
|
||||
assertTrue(failure.getMessage(), failure.getMessage().contains("original pack"));
|
||||
assertFalse(Files.exists(root.resolve("packs").resolve("again")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyNamespaceSelectionIngestsEveryModNamespace() throws Exception {
|
||||
Path root = folder.getRoot().toPath();
|
||||
Path source = ModIngestFixture.writeSourcePack(root);
|
||||
Path target = root.resolve("packs").resolve("everything");
|
||||
|
||||
ModIngestReport report = ModIngester.ingest(ModIngestFixture.request(source, target, Set.of(), false));
|
||||
|
||||
assertNotNull(ModIngestFixture.item(report, "othermod:bamboo_marsh"));
|
||||
assertEquals(ModIngestTier.NATIVE, ModIngestFixture.item(report, "othermod:daisies").tier());
|
||||
assertTrue(Files.isRegularFile(target.resolve("biomes/ingest/othermod/bamboo_marsh.json")));
|
||||
assertEquals(List.of("examplemod", "othermod"),
|
||||
ModIngestFixture.strings(ModIngestFixture.readJson(target.resolve("ingest/manifest.json")).get("namespaces")));
|
||||
assertTrue(report.items().stream().noneMatch(item -> item.namespace().equals("minecraft")));
|
||||
}
|
||||
|
||||
private static Map<String, String> snapshot(Path root) throws IOException {
|
||||
Map<String, String> files = new TreeMap<>();
|
||||
try (Stream<Path> walk = Files.walk(root)) {
|
||||
for (Path path : walk.filter(Files::isRegularFile).toList()) {
|
||||
files.put(root.relativize(path).toString().replace('\\', '/'), Files.readString(path, StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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 com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.junit.Test;
|
||||
|
||||
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.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class VanillaFeatureParsersTest {
|
||||
private static final double EPSILON = 0.000001D;
|
||||
private static final VanillaHeights.VerticalBounds OVERWORLD = new VanillaHeights.VerticalBounds(-64, 384);
|
||||
|
||||
@Test
|
||||
public void intProvidersReportMeanAndRange() throws Exception {
|
||||
assertStats(7, 7, 7, VanillaIntProviders.stats(json("7")));
|
||||
assertStats(4, 4, 4, VanillaIntProviders.stats(json("{\"type\": \"minecraft:constant\", \"value\": 4}")));
|
||||
assertStats(2, 1, 3, VanillaIntProviders.stats(json("{\"type\": \"minecraft:uniform\", \"min_inclusive\": 1, \"max_inclusive\": 3}")));
|
||||
assertStats(0.2D, 0, 1, VanillaIntProviders.stats(json("""
|
||||
{"type": "minecraft:clamped", "min_inclusive": 0, "max_inclusive": 64,
|
||||
"source": {"type": "minecraft:uniform", "min_inclusive": -3, "max_inclusive": 1}}
|
||||
""")));
|
||||
assertStats(0, -3, 3, VanillaIntProviders.stats(json("{\"type\": \"minecraft:trapezoid\", \"min\": -3, \"max\": 3, \"plateau\": 0}")));
|
||||
assertStats(2.5D, 1, 4, VanillaIntProviders.stats(json("""
|
||||
{"type": "minecraft:weighted_list", "distribution": [{"data": 1, "weight": 1}, {"data": 4, "weight": 1}]}
|
||||
""")));
|
||||
assertThrows(IngestConversionException.class, () -> VanillaIntProviders.stats(json("{\"type\": \"minecraft:mystery\"}")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void offsetProvidersReportTheChanceOfLandingOnTheSurface() throws Exception {
|
||||
assertEquals(0.25D, VanillaIntProviders.probabilityOf(json("{\"type\": \"minecraft:trapezoid\", \"min\": -3, \"max\": 3, \"plateau\": 0}"), 0), EPSILON);
|
||||
assertEquals(1.0D / 16.0D, VanillaIntProviders.probabilityOf(json("{\"type\": \"minecraft:trapezoid\", \"min\": -3, \"max\": 3, \"plateau\": 0}"), 3), EPSILON);
|
||||
assertEquals(1.0D / 7.0D, VanillaIntProviders.probabilityOf(json("{\"type\": \"minecraft:trapezoid\", \"min\": -3, \"max\": 3, \"plateau\": 6}"), 0), EPSILON);
|
||||
assertEquals(0.2D, VanillaIntProviders.probabilityOf(json("{\"type\": \"minecraft:uniform\", \"min_inclusive\": -2, \"max_inclusive\": 2}"), 0), EPSILON);
|
||||
assertEquals(1.0D, VanillaIntProviders.probabilityOf(json("0"), 0), EPSILON);
|
||||
assertEquals(0.0D, VanillaIntProviders.probabilityOf(json("2"), 0), EPSILON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void heightProvidersResolveAnchorsAgainstTheDimensionType() throws Exception {
|
||||
VanillaHeights.HeightBand uniform = VanillaHeights.band(json("""
|
||||
{"type": "minecraft:uniform", "min_inclusive": {"above_bottom": 16}, "max_inclusive": {"below_top": 20}}
|
||||
"""), OVERWORLD);
|
||||
VanillaHeights.HeightBand trapezoid = VanillaHeights.band(json("""
|
||||
{"type": "minecraft:trapezoid", "min_inclusive": {"above_bottom": -80}, "max_inclusive": {"above_bottom": 80}}
|
||||
"""), OVERWORLD);
|
||||
VanillaHeights.HeightBand flat = VanillaHeights.band(json("""
|
||||
{"type": "minecraft:trapezoid", "min_inclusive": {"absolute": 0}, "max_inclusive": {"absolute": 40}, "plateau": 40}
|
||||
"""), OVERWORLD);
|
||||
VanillaHeights.HeightBand constant = VanillaHeights.band(json("{\"absolute\": 12}"), OVERWORLD);
|
||||
|
||||
assertEquals(new VanillaHeights.HeightBand(-48, 299, "UNIFORM"), uniform);
|
||||
assertEquals(new VanillaHeights.HeightBand(-144, 16, "TRIANGLE"), trapezoid);
|
||||
assertEquals("UNIFORM", flat.distribution());
|
||||
assertEquals(new VanillaHeights.HeightBand(12, 12, "UNIFORM"), constant);
|
||||
assertThrows(IngestConversionException.class, () -> VanillaHeights.band(json("""
|
||||
{"type": "minecraft:very_biased_to_bottom", "min_inclusive": {"absolute": 0}, "max_inclusive": {"absolute": 9}}
|
||||
"""), OVERWORLD));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ruleTestsFlattenVanillaHeightSpecificTargets() throws Exception {
|
||||
VanillaRuleTests.HostSet stone = VanillaRuleTests.hosts(json("""
|
||||
{"predicate_type": "minecraft:any_of", "rules": [
|
||||
{"predicate_type": "minecraft:all_of", "rules": [
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"},
|
||||
{"predicate_type": "minecraft:height_match", "min_inclusive": 0, "max_inclusive": 2031}]},
|
||||
{"predicate_type": "minecraft:all_of", "rules": [
|
||||
{"predicate_type": "minecraft:not", "rule": {"predicate_type": "minecraft:tag_match", "tag": "minecraft:height_specific_ore_replaceables"}},
|
||||
{"predicate_type": "minecraft:tag_match", "tag": "minecraft:stone_ore_replaceables"}]}]}
|
||||
"""));
|
||||
|
||||
assertFalse(stone.any());
|
||||
assertEquals(Set.of("minecraft:tuff", "minecraft:stone", "minecraft:granite", "minecraft:diorite", "minecraft:andesite"), stone.blocks());
|
||||
assertEquals(Set.of("minecraft:netherrack"),
|
||||
VanillaRuleTests.hosts(json("{\"predicate_type\": \"minecraft:block_match\", \"block\": \"minecraft:netherrack\"}")).blocks());
|
||||
assertEquals(Set.of("minecraft:end_stone"), VanillaRuleTests.hosts(json(
|
||||
"{\"predicate_type\": \"minecraft:blockstate_match\", \"block_state\": {\"Name\": \"minecraft:end_stone\"}}")).blocks());
|
||||
assertTrue(VanillaRuleTests.hosts(json("{\"predicate_type\": \"minecraft:always_true\"}")).any());
|
||||
assertThrows(IngestConversionException.class, () -> VanillaRuleTests.hosts(json(
|
||||
"{\"predicate_type\": \"minecraft:random_block_match\", \"block\": \"minecraft:stone\", \"probability\": 0.5}")));
|
||||
IngestConversionException unknownTag = assertThrows(IngestConversionException.class, () -> VanillaRuleTests.hosts(json(
|
||||
"{\"predicate_type\": \"minecraft:tag_match\", \"tag\": \"examplemod:moon_rock\"}")));
|
||||
assertTrue(unknownTag.getMessage().contains("examplemod:moon_rock"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockStatesAcceptEveryCodecShape() throws Exception {
|
||||
JsonObject compact = VanillaBlockStates.irisBlock(json("\"minecraft:iron_ore\""));
|
||||
JsonObject bracketed = VanillaBlockStates.irisBlock(json("\"minecraft:oak_log[axis=x]\""));
|
||||
JsonObject modern = VanillaBlockStates.irisBlock(json("{\"id\": \"minecraft:sunflower\", \"properties\": {\"half\": \"lower\"}}"));
|
||||
JsonObject legacy = VanillaBlockStates.irisBlock(json("{\"Name\": \"minecraft:sweet_berry_bush\", \"Properties\": {\"age\": \"3\"}}"));
|
||||
|
||||
assertEquals("minecraft:iron_ore", compact.get("block").getAsString());
|
||||
assertFalse(compact.has("data"));
|
||||
assertEquals("x", bracketed.getAsJsonObject("data").get("axis").getAsString());
|
||||
assertEquals("lower", modern.getAsJsonObject("data").get("half").getAsString());
|
||||
assertEquals("3", legacy.getAsJsonObject("data").get("age").getAsString());
|
||||
assertThrows(IngestConversionException.class, () -> VanillaBlockStates.irisBlock(json("{\"oops\": true}")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stateProvidersBecomeWeightedPalettes() throws Exception {
|
||||
List<JsonObject> threshold = VanillaBlockStates.palette(json("""
|
||||
{"type": "minecraft:noise_threshold", "default_state": "minecraft:dandelion",
|
||||
"low_states": ["minecraft:red_tulip"], "high_states": ["minecraft:poppy", "minecraft:dandelion"],
|
||||
"noise": {"base_amplitude": 1.0, "base_octave": 0}, "scale": 0.005, "seed": 2345, "threshold": -0.8, "high_chance": 0.33}
|
||||
"""));
|
||||
List<JsonObject> legacy = VanillaBlockStates.palette(json("""
|
||||
{"type": "minecraft:weighted_state_provider", "entries": [{"data": {"Name": "minecraft:poppy"}, "weight": 2}]}
|
||||
"""));
|
||||
|
||||
assertEquals(List.of("minecraft:dandelion", "minecraft:red_tulip", "minecraft:poppy"),
|
||||
threshold.stream().map(entry -> entry.get("block").getAsString()).toList());
|
||||
assertEquals(2, legacy.get(0).get("weight").getAsInt());
|
||||
assertEquals("minecraft:short_grass", VanillaBlockStates.palette(json("{\"id\": \"minecraft:short_grass\"}")).get(0).get("block").getAsString());
|
||||
IngestConversionException reference = assertThrows(IngestConversionException.class,
|
||||
() -> VanillaBlockStates.palette(json("\"minecraft:flower_plain\"")));
|
||||
assertTrue(reference.getMessage().contains("minecraft:flower_plain"));
|
||||
}
|
||||
|
||||
private static void assertStats(double mean, int min, int max, VanillaIntProviders.IntStats stats) {
|
||||
assertEquals(mean, stats.mean(), EPSILON);
|
||||
assertEquals(min, stats.min());
|
||||
assertEquals(max, stats.max());
|
||||
}
|
||||
|
||||
private static JsonElement json(String value) {
|
||||
return JsonParser.parseString(value);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user