From 8521216be92cc9be7e4a4ba48f8c4bdb59123840 Mon Sep 17 00:00:00 2001 From: KenopsicManiac Date: Sat, 27 Jun 2026 16:31:38 +1200 Subject: [PATCH] Add Piece Pool System --- .../670404fc38c38f10433c6d717c37d9914ac13e68 | 3 +- .../ac273c87971f83c879b0c3ad613d3e6a2a1a14bf | 4 +- .../world_preset/debug_dynamic_nbt.json | 10 ++ .../tags/worldgen/world_preset/extended.json | 4 + .../chunk/AbstractDynamicChunkGenerator.java | 33 ++++ .../chunk/AbstractNbtChunkGenerator.java | 25 ++- .../api/world/chunk/DynamicNbtUpdater.java | 25 +++ .../limlib/api/world/maze/MazeGenerator.java | 5 +- .../limlib/api/world/pool/LimlibPoolApi.java | 18 ++ .../limlib/api/world/pool/POOL_GUIDE.md | 167 ++++++++++++++++++ .../limlib/api/world/pool/PiecePool.java | 83 +++++++++ .../limlib/api/world/pool/PoolStorage.java | 79 +++++++++ .../limlib/datagen/DataGenInitalizer.java | 9 +- .../net/ludocrypt/limlib/impl/Limlib.java | 7 + .../debug/DebugDynamicChunkGenerator.java | 101 +++++++++++ .../limlib/impl/mixin/ChunkStatusMixin.java | 10 +- .../resources/assets/limlib/lang/en_us.json | 3 +- .../nbt/debug_dynamic/end/data_end.nbt | Bin 0 -> 891 bytes .../nbt/debug_dynamic/end/default_end.nbt | Bin 0 -> 866 bytes .../nbt/debug_dynamic/nether/data_nether.nbt | Bin 0 -> 913 bytes .../debug_dynamic/nether/default_nether.nbt | Bin 0 -> 878 bytes .../nbt/debug_dynamic/stone/data_stone.nbt | Bin 0 -> 895 bytes .../nbt/debug_dynamic/stone/default_stone.nbt | Bin 0 -> 870 bytes .../worldgen/piece_pools/debug_dynamic.json | 17 ++ 24 files changed, 588 insertions(+), 15 deletions(-) create mode 100644 src/main/generated/data/limlib/worldgen/world_preset/debug_dynamic_nbt.json create mode 100644 src/main/java/net/ludocrypt/limlib/api/world/chunk/AbstractDynamicChunkGenerator.java create mode 100644 src/main/java/net/ludocrypt/limlib/api/world/chunk/DynamicNbtUpdater.java create mode 100644 src/main/java/net/ludocrypt/limlib/api/world/pool/LimlibPoolApi.java create mode 100644 src/main/java/net/ludocrypt/limlib/api/world/pool/POOL_GUIDE.md create mode 100644 src/main/java/net/ludocrypt/limlib/api/world/pool/PiecePool.java create mode 100644 src/main/java/net/ludocrypt/limlib/api/world/pool/PoolStorage.java create mode 100644 src/main/java/net/ludocrypt/limlib/impl/debug/DebugDynamicChunkGenerator.java create mode 100644 src/main/resources/data/limlib/structures/nbt/debug_dynamic/end/data_end.nbt create mode 100644 src/main/resources/data/limlib/structures/nbt/debug_dynamic/end/default_end.nbt create mode 100644 src/main/resources/data/limlib/structures/nbt/debug_dynamic/nether/data_nether.nbt create mode 100644 src/main/resources/data/limlib/structures/nbt/debug_dynamic/nether/default_nether.nbt create mode 100644 src/main/resources/data/limlib/structures/nbt/debug_dynamic/stone/data_stone.nbt create mode 100644 src/main/resources/data/limlib/structures/nbt/debug_dynamic/stone/default_stone.nbt create mode 100644 src/main/resources/data/limlib/worldgen/piece_pools/debug_dynamic.json diff --git a/src/main/generated/.cache/670404fc38c38f10433c6d717c37d9914ac13e68 b/src/main/generated/.cache/670404fc38c38f10433c6d717c37d9914ac13e68 index 2084809..abd1a02 100644 --- a/src/main/generated/.cache/670404fc38c38f10433c6d717c37d9914ac13e68 +++ b/src/main/generated/.cache/670404fc38c38f10433c6d717c37d9914ac13e68 @@ -1,2 +1,3 @@ -// 1.21.1 2026-02-07T20:57:09.6940347 Liminal Library/Liminal Test +// 1.21.1 2026-06-25T02:08:28.4109926 Liminal Library/Liminal Test +3fb71931ad339015729a8052c2fe0d45c95d0b01 data\limlib\worldgen\world_preset\debug_dynamic_nbt.json c4d20d32c179a90e60333fb84b40a371767160b6 data\limlib\worldgen\world_preset\debug_nbt.json diff --git a/src/main/generated/.cache/ac273c87971f83c879b0c3ad613d3e6a2a1a14bf b/src/main/generated/.cache/ac273c87971f83c879b0c3ad613d3e6a2a1a14bf index ccb6409..f0a2265 100644 --- a/src/main/generated/.cache/ac273c87971f83c879b0c3ad613d3e6a2a1a14bf +++ b/src/main/generated/.cache/ac273c87971f83c879b0c3ad613d3e6a2a1a14bf @@ -1,2 +1,2 @@ -// 1.21.1 2026-02-07T20:57:09.6930366 Liminal Library/Tags for minecraft:worldgen/world_preset -624fcdfaa797001ceed40d0a1e985ecfeca8c150 data\minecraft\tags\worldgen\world_preset\extended.json +// 1.21.1 2026-06-25T02:08:28.4099944 Liminal Library/Tags for minecraft:worldgen/world_preset +5e03860ba448137bcf194f6d915d5af1fe89cba3 data\minecraft\tags\worldgen\world_preset\extended.json diff --git a/src/main/generated/data/limlib/worldgen/world_preset/debug_dynamic_nbt.json b/src/main/generated/data/limlib/worldgen/world_preset/debug_dynamic_nbt.json new file mode 100644 index 0000000..51e92b5 --- /dev/null +++ b/src/main/generated/data/limlib/worldgen/world_preset/debug_dynamic_nbt.json @@ -0,0 +1,10 @@ +{ + "dimensions": { + "minecraft:overworld": { + "type": "minecraft:overworld", + "generator": { + "type": "limlib:debug_dynamic_chunk_generator" + } + } + } +} \ No newline at end of file diff --git a/src/main/generated/data/minecraft/tags/worldgen/world_preset/extended.json b/src/main/generated/data/minecraft/tags/worldgen/world_preset/extended.json index d224942..de70bd0 100644 --- a/src/main/generated/data/minecraft/tags/worldgen/world_preset/extended.json +++ b/src/main/generated/data/minecraft/tags/worldgen/world_preset/extended.json @@ -3,6 +3,10 @@ { "id": "limlib:debug_nbt", "required": false + }, + { + "id": "limlib:debug_dynamic_nbt", + "required": false } ] } \ No newline at end of file diff --git a/src/main/java/net/ludocrypt/limlib/api/world/chunk/AbstractDynamicChunkGenerator.java b/src/main/java/net/ludocrypt/limlib/api/world/chunk/AbstractDynamicChunkGenerator.java new file mode 100644 index 0000000..e56c8e4 --- /dev/null +++ b/src/main/java/net/ludocrypt/limlib/api/world/chunk/AbstractDynamicChunkGenerator.java @@ -0,0 +1,33 @@ +package net.ludocrypt.limlib.api.world.chunk; + +import net.ludocrypt.limlib.api.world.NbtGroup; +import net.minecraft.world.level.biome.BiomeSource; + +public abstract class AbstractDynamicChunkGenerator extends AbstractNbtChunkGenerator implements DynamicNbtUpdater { + public AbstractDynamicChunkGenerator(BiomeSource biomeSource, NbtGroup defaultNbtGroup) { + super(biomeSource, defaultNbtGroup); + } + + /** + * Use this method to get your NbtGroup for generating and placing NBTs down + * @return Your dynamically-referenced {@link NbtGroup}, + * or your default one set via the {@link AbstractDynamicChunkGenerator#AbstractDynamicChunkGenerator(BiomeSource, NbtGroup) initializer} + */ + @Override + public NbtGroup getGroup() { + try { + return getDynamicGroup(); + } catch (Exception e) { + return getStandardNbtGroup(); + } + } + + /** + * Responsible for pulling a dynamically-referenced {@link NbtGroup}. + * This means that, rather than changing data within the group, + * you're changing the group reference itself based on conditionals and where you retrieve it from. + * @return a dynamically-referenced {@link NbtGroup} + * @see net.ludocrypt.limlib.impl.debug.DebugDynamicChunkGenerator DebugDynamicChunkGenerator for an example implementation + */ + public abstract NbtGroup getDynamicGroup(); +} diff --git a/src/main/java/net/ludocrypt/limlib/api/world/chunk/AbstractNbtChunkGenerator.java b/src/main/java/net/ludocrypt/limlib/api/world/chunk/AbstractNbtChunkGenerator.java index 9410460..5a9ecf7 100644 --- a/src/main/java/net/ludocrypt/limlib/api/world/chunk/AbstractNbtChunkGenerator.java +++ b/src/main/java/net/ludocrypt/limlib/api/world/chunk/AbstractNbtChunkGenerator.java @@ -24,8 +24,8 @@ public abstract class AbstractNbtChunkGenerator extends LiminalChunkGenerator { - public final NbtGroup nbtGroup; - public final FunctionMap structures; + protected NbtGroup nbtGroup; + protected FunctionMap structures; public AbstractNbtChunkGenerator(BiomeSource biomeSource, NbtGroup nbtGroup) { this(biomeSource, nbtGroup, new FunctionMap(NbtPlacerUtil::load)); @@ -39,14 +39,28 @@ public AbstractNbtChunkGenerator(BiomeSource biomeSource, NbtGroup nbtGroup, this.nbtGroup.fill(structures); } + /** + * Only use this for nbt generation if you aren't extending from {@link AbstractDynamicChunkGenerator}, + * and aren't implementing {@link DynamicNbtUpdater} + * @return The standard {@link NbtGroup} object passed into the initializer + * @see DynamicNbtUpdater#getGroup() + * @see AbstractDynamicChunkGenerator#getDynamicGroup() + */ + public NbtGroup getStandardNbtGroup() { + return this.nbtGroup; + } + + public FunctionMap getStructures() { + return this.structures; + } + public void generateNbt(WorldGenRegion region, BlockPos at, ResourceLocation id) { generateNbt(region, at, id, Manipulation.NONE); } public void generateNbt(WorldGenRegion region, BlockPos at, ResourceLocation id, Manipulation manipulation) { - try { - structures + getStructures() .eval(id, region.getServer().getResourceManager()) .manipulate(manipulation) .generateNbt(region, at, (pos, state, nbt) -> this.modifyStructure(region, pos, state, nbt)) @@ -64,9 +78,8 @@ public void generateNbt(WorldGenRegion region, BlockPos offset, BlockPos from, B public void generateNbt(WorldGenRegion region, BlockPos offset, BlockPos from, BlockPos to, ResourceLocation id, Manipulation manipulation) { - try { - structures + getStructures() .eval(id, region.getServer().getResourceManager()) .manipulate(manipulation) .generateNbt(region, offset, from, to, (pos, state, nbt) -> this.modifyStructure(region, pos, state, nbt)) diff --git a/src/main/java/net/ludocrypt/limlib/api/world/chunk/DynamicNbtUpdater.java b/src/main/java/net/ludocrypt/limlib/api/world/chunk/DynamicNbtUpdater.java new file mode 100644 index 0000000..b4887c1 --- /dev/null +++ b/src/main/java/net/ludocrypt/limlib/api/world/chunk/DynamicNbtUpdater.java @@ -0,0 +1,25 @@ +package net.ludocrypt.limlib.api.world.chunk; + +import net.ludocrypt.limlib.api.world.FunctionMap; +import net.ludocrypt.limlib.api.world.NbtGroup; +import net.ludocrypt.limlib.api.world.NbtPlacerUtil; + +public interface DynamicNbtUpdater { + /** + * Tells the updater how to get the NbtGroup for dynamically updating. + * You are advised to use {@link AbstractDynamicChunkGenerator} whenever possible, + * as it handles most of the boilerplate for this automatically + * @return the {@link NbtGroup} intended for nbt generation + * @see AbstractDynamicChunkGenerator + * @see AbstractNbtChunkGenerator#getStandardNbtGroup() + */ + NbtGroup getGroup(); + + default void update(AbstractNbtChunkGenerator chunkGenerator) { + if (chunkGenerator.nbtGroup != getGroup()) { + chunkGenerator.nbtGroup = getGroup(); + chunkGenerator.structures = new FunctionMap<>(NbtPlacerUtil::load); + chunkGenerator.nbtGroup.fill(chunkGenerator.structures); + } + } +} diff --git a/src/main/java/net/ludocrypt/limlib/api/world/maze/MazeGenerator.java b/src/main/java/net/ludocrypt/limlib/api/world/maze/MazeGenerator.java index 0f4e025..3ae9a91 100644 --- a/src/main/java/net/ludocrypt/limlib/api/world/maze/MazeGenerator.java +++ b/src/main/java/net/ludocrypt/limlib/api/world/maze/MazeGenerator.java @@ -20,7 +20,7 @@ public class MazeGenerator { /** * Creates a rectangular maze generator. *

- * + * * @param width of the maze * @param height of the maze * @param thicknessX of the cells in real world coordinates. @@ -39,9 +39,8 @@ public MazeGenerator(int width, int height, int thicknessX, int thicknessY, long /** * Begins generating a maze starting at pos. This should be run in every chunk * with the pos being the beginning position of the chunk. - * + * * @param pos the starting position for the maze logic to work. - * @param seed the world seed * @param mazeCreator functional interface to create a new maze at a position * @param cellDecorator funcional interface to generate a single maze block, or * 'cell' diff --git a/src/main/java/net/ludocrypt/limlib/api/world/pool/LimlibPoolApi.java b/src/main/java/net/ludocrypt/limlib/api/world/pool/LimlibPoolApi.java new file mode 100644 index 0000000..f33d95c --- /dev/null +++ b/src/main/java/net/ludocrypt/limlib/api/world/pool/LimlibPoolApi.java @@ -0,0 +1,18 @@ +package net.ludocrypt.limlib.api.world.pool; + +import net.ludocrypt.limlib.api.world.NbtGroup; +import net.minecraft.resources.ResourceLocation; + +public class LimlibPoolApi { + public static PiecePool getPool(ResourceLocation id) { + return PoolStorage.getPool(id); + } + + public static NbtGroup getPoolAsGroup(ResourceLocation id) { + return getPool(id).convertToGroup(); + } + + public static void initialize() { + PoolStorage.initializePoolStorage(); + } +} diff --git a/src/main/java/net/ludocrypt/limlib/api/world/pool/POOL_GUIDE.md b/src/main/java/net/ludocrypt/limlib/api/world/pool/POOL_GUIDE.md new file mode 100644 index 0000000..e5bdfdf --- /dev/null +++ b/src/main/java/net/ludocrypt/limlib/api/world/pool/POOL_GUIDE.md @@ -0,0 +1,167 @@ +# Guide to Piece Pools +> AKA Making your NBT-based dimensions more datapack-modifiable +## Introduction +When making chunk generators that use NbtGroups, you may realize that adding more nbt pieces to your chunk generator's +Nbt-Group requires manually editing your NbtGroup variable. +This makes it near-impossible for 3rd-party addon and modpack developers +to expand your dimension and add variety to it, without very risky mixin or reflection usage. + +### The Solution? We create a datapack-definable and datapack-modifiable object that gets converted into a Nbt-Group +This is the purpose of the Piece-Pool system: to create a dynamically-referencable object that can be modified via +datapacks, and converted into a Nbt-Group on-command. + +# For Mod Developers +## Preparation +The first step is to prepare our chunk generator to use a Piece Pool. + +This is done by making it either extend `AbstractDynamicChunkGenerator`, or implement the `DynamicNbtUpdater` interface. +You are highly recommended to extend the former as it handles errors by returning the initializer-passed NbtGroup as a +fail-safe; for the sake of this guide, we will assume you're extending `AbstractDynamicChunkGenerator` + +You may use `DynamicNbtUpdater` ***ONLY** when you feel the need to use your own default-NbtGroup and/or error handling.* + +### AbstractDynamicChunkGenerator +When extending `AbstractDynamicChunkGenerator`, you will need to pass a default NbtGroup into your super constructor; +this is done to assure that, even when the Piece Pool cannot be found, there is still an NbtGroup to be used for generation. + +Next, we override `getDynamicGroup`; this will be the method we use to tell the chunk generator how to get our dynamic +Nbt-Group, that will be prioritized over our default Nbt-Group. + +Once you have done these steps, your chunk generator will be ready for Piece Pool usage. + +### Note: to actually use your nbt-group, simply use `this.nbtgroup` like you normally would; it is updated automatically +the `DynamicNbtUpdater` interface to be the Nbt-Group referenced in `getDynamicGroup` + +Example: + +```java +import net.ludocrypt.limlib.api.world.NbtGroup; +import net.ludocrypt.limlib.api.world.chunk.AbstractDynamicChunkGenerator; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.biome.BiomeSource; + +public class ExampleDynamicChunkGenerator extends AbstractDynamicChunkGenerator { + public static final ResourceLocation POOL_ID = ResourceLocation.fromNamespaceAndPath("example_mod", "example"); + + // Declare and initialize our default nbt-group + public static final NbtGroup DEFAULT_NBTGROUP = NbtGroup.Builder + .create(POOL_ID) + .with("set_1", "a", "b") + .with("set_2", "c", "d") + .build(); + + public ExampleDynamicChunkGenerator(BiomeSource source) { + // Pass our default nbt-group into the super constructor + super(source, DEFAULT_NBTGROUP); + } + + @Override + public NbtGroup getDynamicGroup() { + //TODO + } +} +``` + +## Using Piece Pools +Now that your chunk generator is ready, we can make use of Piece Pools + +A piece-pool is an object containing the following data: +- `pool`, which corresponds to the NbtGroup's identifier and the location of its nbt files in `modid:structures/nbt/[pool_name]` +- `sub_pools`, a map where each entry has the name of the sub-pool as the key, and the value as a list of strings, +corresponding to the nbt names +- `override`, optional and intended for modpack-creators, this allows for your sub-pool to replace all entries in the nbt group with +your own. + +To create a piece-pool, we add a JSON file to `modid:worldgen/piece_pools`; it can be any name, as it is the internal +`pool` value that's used as the name of the piece-pool and not the file-name itself. + +Next, we call the `LimlibPoolApi` in `getDynamicGroup`, to retrieve our Piece Pool and convert it to a Nbt Group. +Whenever the piece-pool is detected to have changed (from datapack-reloading, for example), the chunk generator will +update its `nbtgroup` variable accordingly. + +`LimlibPoolApi#getPoolAsGroup()` is the intended method to handle retrieval-and-conversion of piece pools in your code, +but you may choose to call `LimlibPoolApi#getPool()` for if you want to make some pre-conversion changes in-code instead; +simply call `PiecePool#convertToGroup()` once you're done. + +Example (JSON), with additional pieces added +```json +{ + "pool": "example_mod:example", + "sub_pools": { + "set_1": [ + "a", + "b", + "c", + "d" + ], + "set_2": [ + "c", + "d", + "e", + "f" + ] + } +} +``` + +Example (Code) +```java +import net.ludocrypt.limlib.api.world.NbtGroup; +import net.ludocrypt.limlib.api.world.chunk.AbstractDynamicChunkGenerator; +import net.ludocrypt.limlib.api.world.pool.LimlibPoolApi; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.biome.BiomeSource; + +public class ExampleDynamicChunkGenerator extends AbstractDynamicChunkGenerator { + public static final ResourceLocation POOL_ID = ResourceLocation.fromNamespaceAndPath("example_mod", "example"); + + // Declare and initialize our default nbt-group + public static final NbtGroup DEFAULT_NBTGROUP = NbtGroup.Builder + .create(POOL_ID) + .with("set_1", "a", "b") + .with("set_2", "c", "d") + .build(); + + public ExampleDynamicChunkGenerator(BiomeSource source) { + // Pass our default nbt-group into the super constructor + super(source, DEFAULT_NBTGROUP); + } + + @Override + public NbtGroup getDynamicGroup() { + return LimlibPoolApi.getPoolAsGroup(POOL_ID); + } +} +``` + +Congratulations, your chunk generator is now datapack-modifiable! Now, addon-developers and modpack-developers can +add their own nbts to the generator by creating a Piece Pool JSON in their datapack, and targeting your generator's +piece pool by using the same identifier in the `pool` entry. + +### For add-on, and modpack developers +To add nbts into a dimension's chunk generator, it must be configured to use the Piece Pool system; incompatible generators +are not affected by the Piece Pool system, and as-such cannot be modified using it. + +A piece-pool is an object containing the following data: +- `pool`, which corresponds to the pool's identifier and the location of its nbt files in `modid:structures/nbt/[pool_name]` +- `sub_pools`, a map where each entry has the name of the sub-pool as the key, and the value as a list of strings, + corresponding to the nbt names +- `override`, optional and intended for modpack-creators, this allows for your pool to replace all entries in the nbt group with + your own. + +If we know the `pool` identifier used by the chunk generator, we can create a JSON representing our additions to the +Piece Pool using it + +Example of an addon-modification; this would add nbts "addon_a" and "addon_b" to the "set_1" sub-pool of +example mod's "example" pool +```json + { + "pool": "example_mod:example", + "sub_pools": { + "set_1": [ + "addon_a", + "addon_b" + ] + } +} +``` diff --git a/src/main/java/net/ludocrypt/limlib/api/world/pool/PiecePool.java b/src/main/java/net/ludocrypt/limlib/api/world/pool/PiecePool.java new file mode 100644 index 0000000..1409c06 --- /dev/null +++ b/src/main/java/net/ludocrypt/limlib/api/world/pool/PiecePool.java @@ -0,0 +1,83 @@ +package net.ludocrypt.limlib.api.world.pool; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.ludocrypt.limlib.api.world.NbtGroup; +import net.minecraft.resources.ResourceLocation; + +import java.util.*; + +public class PiecePool { + private final ResourceLocation pool; + protected final HashMap> subPools; + public final boolean shouldOverride; + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group( + ResourceLocation.CODEC.fieldOf("pool").stable().forGetter(PiecePool::getPool), + Codec.unboundedMap(Codec.STRING, Codec.list(Codec.STRING)).fieldOf("sub_pools").forGetter(PiecePool::getSubPools), + Codec.BOOL.optionalFieldOf("override", false) + .stable().forGetter(pool -> pool.shouldOverride) + ).apply(instance, PiecePool::new)); + + public PiecePool(ResourceLocation pool, Map> subPools, boolean shouldOverride) { + this.pool = pool; + this.subPools = new HashMap<>(subPools); + this.shouldOverride = shouldOverride; + } + + public PiecePool(ResourceLocation pool, Map> subPools) { + this(pool, subPools, false); + } + + public ResourceLocation getPool() { + return pool; + } + + public Map> getSubPools() { + return Map.copyOf(subPools); + } + + public boolean hasSubPool(String subPool) { + return subPools.containsKey(subPool); + } + + public void addSubPool(String subPool, String... pieces) { + if (!hasSubPool(subPool)) { + subPools.put(subPool, List.of(pieces)); + } + } + + public void addPiecesToSubPool(String subPool, String... pieces) { + if (hasSubPool(subPool)) { + List filteredList = Arrays.stream(pieces) + .filter(piece -> !subPools.get(subPool).contains(piece)) + .toList(); + subPools.get(subPool).addAll(filteredList); + } + } + + public void removeSubPool(String subPool) { + subPools.remove(subPool); + } + + public void removePiecesFromSubPool(String subPool, String... pieces) { + if (hasSubPool(subPool)) { + List filteredList = Arrays.stream(pieces) + .filter(piece -> subPools.get(subPool).contains(piece)) + .toList(); + subPools.get(subPool).removeAll(filteredList); + } + } + + public NbtGroup convertToGroup() { + NbtGroup.Builder builder = NbtGroup.Builder + .create(pool); + + for (String subPool : subPools.keySet()) { + builder = builder.with(subPool, subPools.get(subPool).toArray(String[]::new)); + } + + return builder.build(); + } +} diff --git a/src/main/java/net/ludocrypt/limlib/api/world/pool/PoolStorage.java b/src/main/java/net/ludocrypt/limlib/api/world/pool/PoolStorage.java new file mode 100644 index 0000000..22575a0 --- /dev/null +++ b/src/main/java/net/ludocrypt/limlib/api/world/pool/PoolStorage.java @@ -0,0 +1,79 @@ +package net.ludocrypt.limlib.api.world.pool; + +import com.google.gson.JsonObject; +import com.mojang.serialization.JsonOps; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener; +import net.ludocrypt.limlib.impl.Limlib; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +public class PoolStorage { + private static Map POOLS = new HashMap<>(); + + private static void loadPoolData(Map newPoolMap) { + POOLS = newPoolMap; + } + + public static PiecePool getPool(ResourceLocation id) throws NoSuchElementException { + if (!POOLS.containsKey(id)) Limlib.LOGGER.error("This pool does not exist: {}", id, new NoSuchElementException()); + return POOLS.get(id); + } + + private static class PoolListener implements SimpleResourceReloadListener> { + @Override + public CompletableFuture> load(ResourceManager manager, ProfilerFiller profiler, Executor executor) { + return CompletableFuture.supplyAsync(() -> { + HashMap map = new HashMap<>(); + + for (var resource : manager.listResources("worldgen/piece_pools", id + -> id.getPath().endsWith(".json")).entrySet()) { + try (var inputStream = resource.getValue().open()) { + var json = Limlib.GSON.fromJson(new InputStreamReader(inputStream), JsonObject.class); + + PiecePool pool = PiecePool.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(); + if (map.containsKey(pool.getPool()) && !pool.shouldOverride) { + ResourceLocation id = pool.getPool(); + for (String subPool : pool.getSubPools().keySet()) { + if (map.get(id).hasSubPool(subPool)) { + map.get(id).addPiecesToSubPool(subPool, pool.getSubPools().get(subPool).toArray(String[]::new)); + } else { + map.get(id).addSubPool(subPool, pool.getSubPools().get(subPool).toArray(String[]::new)); + } + } + } else { + map.put(pool.getPool(), pool); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return Map.copyOf(map); + }, executor); + } + + @Override + public CompletableFuture apply(Map data, ResourceManager manager, ProfilerFiller profiler, Executor executor) { + return CompletableFuture.runAsync(() -> loadPoolData(data), executor); + } + + @Override + public ResourceLocation getFabricId() { + return Limlib.id("pool_listener"); + } + } + + public static void initializePoolStorage() { + ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(new PoolListener()); + } +} diff --git a/src/main/java/net/ludocrypt/limlib/datagen/DataGenInitalizer.java b/src/main/java/net/ludocrypt/limlib/datagen/DataGenInitalizer.java index f0ebaba..196a73e 100644 --- a/src/main/java/net/ludocrypt/limlib/datagen/DataGenInitalizer.java +++ b/src/main/java/net/ludocrypt/limlib/datagen/DataGenInitalizer.java @@ -14,6 +14,7 @@ import net.ludocrypt.limlib.api.skybox.Skybox; import net.ludocrypt.limlib.api.skybox.TexturedSkybox; import net.ludocrypt.limlib.impl.Limlib; +import net.ludocrypt.limlib.impl.debug.DebugDynamicChunkGenerator; import net.ludocrypt.limlib.impl.debug.DebugNbtChunkGenerator; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -37,6 +38,7 @@ public class DataGenInitalizer implements DataGeneratorEntrypoint { public static final ResourceKey DEBUG_KEY = ResourceKey.create(Registries.WORLD_PRESET, ResourceLocation.fromNamespaceAndPath("limlib", "debug_nbt")); + public static final ResourceKey DEBUG_DYNAMIC_KEY = ResourceKey.create(Registries.WORLD_PRESET, ResourceLocation.fromNamespaceAndPath("limlib", "debug_dynamic_nbt")); @Override public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { @@ -52,6 +54,11 @@ protected void configure(HolderLookup.Provider registries, Entries entries) { dimension, new DebugNbtChunkGenerator(biome) )) )); + entries.add(DEBUG_DYNAMIC_KEY, new WorldPreset( + Map.of(LevelStem.OVERWORLD, new LevelStem( + dimension, new DebugDynamicChunkGenerator(biome) + )) + )); }); }); } @@ -68,7 +75,7 @@ public DataProvider create(FabricDataOutput output, CompletableFuture(output, Registries.WORLD_PRESET, registriesFuture) { @Override protected void addTags(HolderLookup.Provider wrapperLookup) { - this.tag(WorldPresetTags.EXTENDED).addOptional(DEBUG_KEY.location()); + this.tag(WorldPresetTags.EXTENDED).addOptional(DEBUG_KEY.location()).addOptional(DEBUG_DYNAMIC_KEY.location()); } }; } diff --git a/src/main/java/net/ludocrypt/limlib/impl/Limlib.java b/src/main/java/net/ludocrypt/limlib/impl/Limlib.java index d36039a..ddbd94f 100644 --- a/src/main/java/net/ludocrypt/limlib/impl/Limlib.java +++ b/src/main/java/net/ludocrypt/limlib/impl/Limlib.java @@ -1,5 +1,7 @@ package net.ludocrypt.limlib.impl; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.registry.DynamicRegistries; import net.ludocrypt.limlib.api.Utils; @@ -9,6 +11,8 @@ import net.ludocrypt.limlib.api.effects.sound.distortion.DistortionEffect; import net.ludocrypt.limlib.api.effects.sound.reverb.ReverbEffect; import net.ludocrypt.limlib.api.skybox.Skybox; +import net.ludocrypt.limlib.api.world.pool.LimlibPoolApi; +import net.ludocrypt.limlib.impl.debug.DebugDynamicChunkGenerator; import net.ludocrypt.limlib.impl.debug.DebugNbtChunkGenerator; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; @@ -18,6 +22,7 @@ public class Limlib implements ModInitializer { public static final Logger LOGGER = LoggerFactory.getLogger("Limlib"); + public static final Gson GSON = new GsonBuilder().create(); public static ResourceLocation id(String id) { return ResourceLocation.fromNamespaceAndPath("limlib", id); @@ -31,8 +36,10 @@ public void onInitialize() { PostEffect.init(); Skybox.init(); DynamicRegistries.registerSynced(SoundEffects.SOUND_EFFECTS_KEY, SoundEffects.CODEC); + LimlibPoolApi.initialize(); Utils.register(BuiltInRegistries.CHUNK_GENERATOR, "debug_nbt_chunk_generator", DebugNbtChunkGenerator.CODEC); + Utils.register(BuiltInRegistries.CHUNK_GENERATOR, "debug_dynamic_chunk_generator", DebugDynamicChunkGenerator.CODEC); } } diff --git a/src/main/java/net/ludocrypt/limlib/impl/debug/DebugDynamicChunkGenerator.java b/src/main/java/net/ludocrypt/limlib/impl/debug/DebugDynamicChunkGenerator.java new file mode 100644 index 0000000..920255d --- /dev/null +++ b/src/main/java/net/ludocrypt/limlib/impl/debug/DebugDynamicChunkGenerator.java @@ -0,0 +1,101 @@ +package net.ludocrypt.limlib.impl.debug; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.ludocrypt.limlib.api.world.NbtGroup; +import net.ludocrypt.limlib.api.world.chunk.AbstractDynamicChunkGenerator; +import net.ludocrypt.limlib.api.world.pool.LimlibPoolApi; +import net.ludocrypt.limlib.impl.Limlib; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.biome.FixedBiomeSource; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public class DebugDynamicChunkGenerator extends AbstractDynamicChunkGenerator { + public static final NbtGroup DEFAULT = NbtGroup.Builder.create(Limlib.id("debug_dynamic")) + .with("stone", "default_stone") + .with("nether", "default_nether") + .with("end", "default_end") + .build(); + + public static final MapCodec CODEC = RecordCodecBuilder + .mapCodec(instance -> instance + .group(RegistryOps.retrieveElement(Biomes.THE_VOID)) + .apply(instance, instance.stable(DebugDynamicChunkGenerator::new))); + + public DebugDynamicChunkGenerator(Holder.Reference reference) { + super(new FixedBiomeSource(reference), DEFAULT); + } + + @Override + public NbtGroup getDynamicGroup() { + return LimlibPoolApi.getPoolAsGroup(Limlib.id("debug_dynamic")); + } + + @Override + public int getPlacementRadius() { + return 0; + } + + @Override + public CompletableFuture populateNoise(WorldGenRegion chunkRegion, ServerLevel level, ChunkGenerator generator, ChunkAccess chunk, Blender blender, RandomState randomState, StructureManager structureManager) { + ChunkPos pos = chunk.getPos(); + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + chunkRegion.setBlock(pos.getWorldPosition().offset(x, 3, y), Blocks.WHITE_CONCRETE.defaultBlockState(), Block.UPDATE_KNOWN_SHAPE); + + chunkRegion.setBlock(pos.getWorldPosition().offset(x, -16, y), Blocks.BARRIER.defaultBlockState(), Block.UPDATE_KNOWN_SHAPE); + } + } + + if (chunk.getPos().getWorldPosition().getX() == 0 && chunk.getPos().getWorldPosition().getZ() == 0) { + return CompletableFuture.completedFuture(chunk); + } + + RandomSource source = RandomSource.create(chunkRegion.getSeed() + pos.x + pos.z); + BlockPos structurePos = pos.getWorldPosition().offset(6, 4, 6); + int randInt = source.nextInt(3); + + if (randInt == 0) { + generateNbt(chunkRegion, structurePos, this.nbtGroup.pick("stone", source)); + } else if (randInt == 1) { + generateNbt(chunkRegion, structurePos, this.nbtGroup.pick("nether", source)); + } else if (randInt == 2){ + generateNbt(chunkRegion, structurePos, this.nbtGroup.pick("end", source)); + } + + return CompletableFuture.completedFuture(chunk); + } + + @Override + protected @NotNull MapCodec codec() { + return CODEC; + } + + @Override + public int getGenDepth() { + return 448; + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomState, BlockPos blockPos) { + + } +} diff --git a/src/main/java/net/ludocrypt/limlib/impl/mixin/ChunkStatusMixin.java b/src/main/java/net/ludocrypt/limlib/impl/mixin/ChunkStatusMixin.java index 70f9241..70d4824 100644 --- a/src/main/java/net/ludocrypt/limlib/impl/mixin/ChunkStatusMixin.java +++ b/src/main/java/net/ludocrypt/limlib/impl/mixin/ChunkStatusMixin.java @@ -5,6 +5,8 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; +import net.ludocrypt.limlib.api.world.chunk.AbstractNbtChunkGenerator; +import net.ludocrypt.limlib.api.world.chunk.DynamicNbtUpdater; import net.minecraft.server.level.*; import net.minecraft.util.StaticCache2D; import net.minecraft.world.level.StructureManager; @@ -29,7 +31,13 @@ public class ChunkStatusMixin { @WrapOperation(method = "generateNoise", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/ChunkGenerator;fillFromNoise(Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/levelgen/RandomState;Lnet/minecraft/world/level/StructureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)Ljava/util/concurrent/CompletableFuture;")) private static CompletableFuture limlib$liminalChunkGenerator1(ChunkGenerator instance, Blender blender, RandomState randomState, StructureManager structureManager, ChunkAccess chunkAccess, Operation> original, @Local WorldGenRegion worldGenRegion, @Local ServerLevel serverLevel) { - if(instance instanceof LiminalChunkGenerator liminalChunkGenerator) { + if (instance instanceof LiminalChunkGenerator liminalChunkGenerator) { + if (liminalChunkGenerator instanceof AbstractNbtChunkGenerator nbtChunkGenerator) { + if (nbtChunkGenerator instanceof DynamicNbtUpdater updater) { + updater.update(nbtChunkGenerator); + } + } + return liminalChunkGenerator.populateNoise(worldGenRegion, serverLevel, instance, chunkAccess, blender, randomState, structureManager); } diff --git a/src/main/resources/assets/limlib/lang/en_us.json b/src/main/resources/assets/limlib/lang/en_us.json index d18628e..eb3ef5a 100644 --- a/src/main/resources/assets/limlib/lang/en_us.json +++ b/src/main/resources/assets/limlib/lang/en_us.json @@ -1,3 +1,4 @@ { - "generator.limlib.debug_nbt": "Nbt Debug" + "generator.limlib.debug_nbt": "Nbt Debug", + "generator.limlib.debug_dynamic_nbt": "Nbt Dynamic Data" } diff --git a/src/main/resources/data/limlib/structures/nbt/debug_dynamic/end/data_end.nbt b/src/main/resources/data/limlib/structures/nbt/debug_dynamic/end/data_end.nbt new file mode 100644 index 0000000000000000000000000000000000000000..decd135d50193aeca80667e3adcb2ea2c2bff802 GIT binary patch literal 891 zcmb2|=3oGW|95Ac?z(Lt($-&k@`mIxaSf4O8V7&xbGWX1mp67wUh^c4&dy|3@62Vj zU3NuNUut}0iT;(z&1@=Rd{TYx|H+G-)sh!AwXChn@N+p{{UpDzMr_LKW1;IVP3sGH zTpXGEOxpTe{U4o<_dUGL5`XtesAtYC`jzM+e^{A^{n^6}p|Sr&Qy!n|-h2jk zZ5A`Sxn<4$#+;B;$s~MQct(UA2{JL>UcmhbN=!_6~@5L zUkAnUe0bC#&c4Uu!BIwizKX&F-VAX}AA}mFzxXJX6!h2NsVXCq4SVB~ADunZyK=_L zpJ}hY%su_$Xw=P@tIXP0Mc&=-VtI1sN?-4yu)(7? z@b1f@{?w~Y^Kw_aosZsH@;-NK)-jW~ZOaPlV?KudOpU$SdEV}0|Eifgw(5CKlb`MC z>6-a{^IXHP?@gHh|0yw7`+r{S(Xtqg<@a=Ny_%ipwM#Gm@9+6ho9}h~xt*L1I?^oumZt>;Xttg=`CJQkFYcdlnu)czfh&#%4t^4pKs#eUb> z;}@+xoAq?Mt6pgCR{0nE-kbEM9kbkQ>-(i_!;LG~vdSz!XRLfy_p;+{`Et!TyLpRD zyH5uut$mfMVJqN&YwM?r Dc2Kup literal 0 HcmV?d00001 diff --git a/src/main/resources/data/limlib/structures/nbt/debug_dynamic/end/default_end.nbt b/src/main/resources/data/limlib/structures/nbt/debug_dynamic/end/default_end.nbt new file mode 100644 index 0000000000000000000000000000000000000000..91f08e0fccd3788494c991f696501541a1374892 GIT binary patch literal 866 zcmb2|=3oGW|95Ac?z(Lt($-&k@`hwpqzG5+ln2LO>{_~eVfUrn3Bsy|g=-QtQ*JGP zp?rO&Wa_1Z*M4SlGn-0GezN)BXU~fVPfl5(@btBOn9#+SbG|IMise3)EBz`U+JE`t z1)f)T9KGiMTil*|QuXu4zD@7=6+M3^G}Z1%?wH8w#`M@DVNP%u+m*?TUkiY2nU4iU zkut@0dNXobPBJ{Z(w}UbtMVv}I5W^-l@<>Y^6f&veb!Xk}^tnWww_-6S{-fJ~pPyQU9BXHE%E3Hohf zw6azT%#17lY7{r|;ji7Z9HK<`a(;kxtOBwZfD>4swGsj7NSk(Sr;JP`>V^PU<`8KtE zQpr2^DN3y8`Ow94-P~gRiGteZ&!-sl87nvsc=J^7+TJcO~@LgK)Zk{f!>gKK9v#V z+=l54dyX_*4_NyYa1%D@eMmGJW<9f}L z+qiC}`*`zr5!+wy-mam(x1jg6N4W2K(JAlOd{4`*tus$vq*HHg zd@9@CepdAEH}6HiPKtZ?>YAR_W-j@fy?M(`VoTTY*3bE|?9Z;1f7h(9y%ztfOw4SX zN^D)$bXC!%_94~JXZ_A{tNRn9cjjunnV{>=E!xEyPM+7F`u@N9{G9B!=F5ugz;v{F zZ)Oh1w=drd=1tyZXzl%8ZuR!JMemxk-|l(!>gcuLlsFrsW$%7<&aHcS=U& z?7j)cKEC$4&g;u5lY8IH+um1uPd?T9pzL|$z5cedwaKfNE3fX&3@e;4QQ@umGXGPx zFMRgiYnh{_z4?Xu>?x*pa~7v}zPJ$mvtD}LUh9^#o0o21SG}*KbW6SQ$L37sw0wE? o^0eFernh@ll2H`)MNc zn%vVarv(e&+-)D~F?GX}9iH~@&zMh^Rh=m$s*>~9yI9F;j&Oa~;jIf|wy!JOx~;^5 zYt|X*%{OkWtpBuIVV|+tog*(ECd^qp#p}?!n7^`TMLM zgTFO;ZW5B6rLWiz9QnlQqca~!2|CN`y9A%X#(nH+*UC97Sk<=qGYj8d z-q`u}@_{4YG82;GzW-F)!!&u8{qy3|o`(!TM&u!F<~>ZppSgU_Xd4)=KX7D^(SdHp zIG&E94G}UOM;n2JYC}Y0=T~imjdiSQ*Yp`HI1hL;#R+|w)G(c8kIDm8Mt!S&?Lo!O zsvv`Y{r#437qSBK5+SD3mPl zG|sV{u$iGq%;8*;!gE74)8j#LOh|@vR(KxhJ|vnDRNSKuGAr5Uq3Db>xP}V5NXR9y-yZS>CbDZ;Ly{AVR^!X|Z4|Frf$$WU!AkMyr<$)>#(CM9w>wz}#2ctOO z@`b7Dy>oY`bnT4FN%OnEvnOut)VZO(H?QZG{-5+ePFH-Hq3p@Z$2*%ot=$$Ddh6MD z(d5*h*JlRC-M$%j_vO<4)3170ZCo3@_r;Y{wVO(>`ep8V<@0);%*WE7xv{si=l|Zi z|H|8~(XS_c`sDW8e%GX~OZU!|A2Z?S?5+9#^82zM=d%h!^`-{PPmlfUyj?YRn)$!~ z@m9sVrFA&vbvzx#t*>T0|MD>WQKsJ`w_MY`wI&(wx$S0`e@#l(WRRC*{J-PIi>Emf zd#YGM@BS3?*;8*>?_|z8(_5TY9rfaFftT^^ z6_#7x9F5vKb^Xtet(OnwSKT$*es)dZ+Wk9i_{rPd1+W?Qu=qMt+cDxq@vgB7}p

(-(ChYKU+Od-6M4P>-^=lr9BfFfQ+V(S`6!t6#Q-f>;k?YmttlXXHQ(@a%3Avz(FapqNr zXNGOBljlrlf|;9nz?&Ip)uIwsiFN&+$AC_gpWFj9&+b?y(5hsR(Lg55Xa;@52c}nE zTj(=ZcpmU(iWB-UsbM)yK(_VL@_-6(neIXYxg+^%b1mx$*+(b6ivR=s)KKAZD1R=nPSuIbdV^Zn1x-8)w8 zTI{{P+&6vt-pE$}eUatCv({BzZ%q%c39r9xQYW_g{G+8W(-M=jwO&h0$A2*m-Dl#nalC*3wL4Y zq+N#A-tXlvmp?x_Pybii&aYD%ZYpo+*_o4_|NQWi)$W%}YUliadHvqo-1=X=yOz98 z_PMk@Z*QOR^6+I}&F)Fmz0vg*(_`6QE%D-T!LptCXCJ-Xkd=HZR4Q>v*Eeb5(^Kre zEQ`!{@|-+1@))aPYA-*3seRv7-iyco-#&F~xAToXJ}=LG)eni1eY^R2^@b}QmyZU& oJ!6)4ecRmmX6bjNug~{2xS#u8`nurWk6)z!Z=Z8LRg!@L0BRn$b^rhX literal 0 HcmV?d00001 diff --git a/src/main/resources/data/limlib/structures/nbt/debug_dynamic/stone/data_stone.nbt b/src/main/resources/data/limlib/structures/nbt/debug_dynamic/stone/data_stone.nbt new file mode 100644 index 0000000000000000000000000000000000000000..6980c3255dffb553361c4540c84720b32ba10af7 GIT binary patch literal 895 zcmV-_1AzP=iwFP!00000|J|5fYuhjshL81;*eTryYz)ROitqOac0JhL7;Nk|$cd7e zI##gMrQ5IAPoCUHNmgv>r3?x)7^m^$bIx-V9n#E*3KF*dr8yDx=ft0)zZR71*43`o zminWhN!6IewVnAteiy`d#)gL&-5-pTv`#sFcw&g*5rzYCI1s1Ll>zl+Ks~8A9EigX zXDU~UIUZ+BHo{~8bMD1P7!EK3$R#6826zSL+>4Je=U!rj;Q%9mTrscknWsn(19R>r zN0{?^CL@fDD+9a&6Y~m8%quW4ufW8-GQf)g zUJS^^fLt8N#erNL$R&VWfr+hGU}EbPnAmy=z)JvL67Z6Mmjt{d;3WYs33$=rGnASe zEa4TH)ZBRZJ!*_e%?+0D$^fsxq~=D-D=?|Kk@Cs_F9vuqz>5ud4Slys)y#mJIZ!hP zYUV)A9H^NCH4C6-0n{u8Y93=!b1da0051u6Nx(}2UJ~$i#aaXokX)@Af!qwIX$ zn0?)@@7|)ErY{H|lHEdM$)%4<8{t6RPF&$4<+&$e}|7oA$U z54K*nGn%bB)4E4zd{uti)b`5Pe&sK9d*wE|q-pupnbyB3N_$i7jA`!c8Tt3;d};Fk ztQD8#QaSa0+0{REThc}O+28-vnVa2UOZZ?*3YzXzqn*?JkHkez;U5*pweREMjbq%Gr?`!3{d4WZaAKpHRj6kqy0jbRi_Wdbi@knqvj;Pc7`-_KHtO1M=%$(X+t=@$i;sS% Veb=3>O-uCL(jV0&PIiVF006g`#5e!| literal 0 HcmV?d00001 diff --git a/src/main/resources/data/limlib/structures/nbt/debug_dynamic/stone/default_stone.nbt b/src/main/resources/data/limlib/structures/nbt/debug_dynamic/stone/default_stone.nbt new file mode 100644 index 0000000000000000000000000000000000000000..c73c161e02bc1b22e4b737fbcfc2b5cba0e7dea3 GIT binary patch literal 870 zcmb2|=3oGW|5s<+&ARO%;O74Ou?Jsn@x>sGy#{qXapG0tT)KNrwbOIEPed(_eZ0m0 zqWiijDYDl+tmPL9XbGrYyjWM9w)Wt+DJvA7u8t2A3at0r75sHQ>(gzVp)1xb|EG}= zbS&(jOGKne&mVi0$E4{uL7%h*>YO!4F z-fv(vvGfjqgXdM@nIX0lJ+CfqsO|U3y02Wk>-}UwHzp8s@~v{-3RktKqBE})OM&r} z@RXpq?_Z7LCO&+2{%4GAvdV#i&+5s0j1FiU-TCtnYz>cjy@ftw1*d{HL!{7&Ne5lzTxM=M|mCS*ih>S+b@%oaI^( z$!NN|an^B(yuQLXE)>%<4|G4$K2T8X19tU{ls!s^&l;Wsx>x2gl*tS-nE~kLPR8{M zBac^d9`I(06Z$ZzVLHnml?SSf`m7aTS7#l_?s@o3@j2MhnFqX?LH=lt3!daFxh!N# zTIFtzZ+a;uTMg?ruDiQ1>)QAKi{^Z}bakC->^0f&fPGu<&EER;XYKJLHUF;942=7E z^x&PFv){!9-o5ZT_v($*?68NE*Izq3W!dU$rVnp+hJSuP`_%b$rwv}mtxEHo{&~a3 z&G`pS%lwYsd4GCt@mFVC<@kEP?avlMxw2VGCget9?et9SUctzT=8YsS@mEx8$zd;Rju>(}1q-2VS& z&gG{IqxY`8TXnb8dA-lu-16ifJ2#tX#&YCU$GkY4aPH9cWj67lxjuWlxO-YM_8Z1} zy>rf9^;PYON#xAb>&ZdaeiZclwGfiFlK!9HytVxIhRTUgj&0SSyoT@F&a-kpQifIk rw`?%pe)n?t_3nR>ukXE@KHt~CKIgUeb%DJfzp#5XKe95GWMBXQ`;D-Q literal 0 HcmV?d00001 diff --git a/src/main/resources/data/limlib/worldgen/piece_pools/debug_dynamic.json b/src/main/resources/data/limlib/worldgen/piece_pools/debug_dynamic.json new file mode 100644 index 0000000..5d9fbe8 --- /dev/null +++ b/src/main/resources/data/limlib/worldgen/piece_pools/debug_dynamic.json @@ -0,0 +1,17 @@ +{ + "pool": "limlib:debug_dynamic", + "sub_pools": { + "stone": [ + "default_stone", + "data_stone" + ], + "nether": [ + "default_nether", + "data_nether" + ], + "end": [ + "default_end", + "data_end" + ] + } +}