From 9d0a640173540f3a950a071b5b7a090420b7f94d Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 24 May 2022 23:42:25 +0200 Subject: [PATCH] Datapack Biome Handling with Custom BiomeSource --- src/main/java/org/betterx/bclib/BCLib.java | 7 +- .../java/org/betterx/bclib/BCLibPatch.java | 12 +- .../betterx/bclib/api/biomes/BiomeAPI.java | 82 ++-- .../bclib/api/datafixer/DataFixerAPI.java | 4 +- .../bclib/client/presets/WorldPresetsUI.java | 4 +- .../bclib/gui/screens/WorldSetupScreen.java | 9 +- .../mixin/client/CreateWorldScreenMixin.java | 9 +- .../DedicatedServerPropertiesMixin.java | 4 +- .../mixin/common/PrimaryLevelDataMixin.java | 42 +- .../mixin/common/RegistryOpsAccessor.java | 13 + .../mixin/common/WorldGenPropertiesMixin.java | 4 +- .../mixin/common/WorldOpenFlowsMixin.java | 29 -- .../mixin/common/WorldPresetAccessor.java | 16 + .../common/WorldPresetsBootstrapMixin.java | 65 +-- .../presets/worldgen/BCLChunkGenerator.java | 116 ------ .../presets/worldgen/BCLWorldPreset.java | 52 +++ .../worldgen/BCLWorldPresetSettings.java | 169 ++++++++ .../presets/worldgen/BCLWorldPresets.java | 106 +++++ .../presets/worldgen/WorldGenUtilities.java | 382 ++++++++++++++++++ .../presets/worldgen/WorldPresetSettings.java | 48 +++ .../bclib/presets/worldgen/WorldPresets.java | 287 ------------- .../java/org/betterx/bclib/util/ModUtil.java | 4 +- .../betterx/bclib/world/biomes/BCLBiome.java | 13 +- .../bclib/world/generator/BCLBiomeSource.java | 33 ++ .../world/generator/BCLibEndBiomeSource.java | 70 ++-- .../generator/BCLibNetherBiomeSource.java | 56 ++- .../bclib/world/generator/BiomePicker.java | 90 +++-- src/main/resources/bclib.mixins.common.json | 2 +- 28 files changed, 1109 insertions(+), 619 deletions(-) create mode 100644 src/main/java/org/betterx/bclib/mixin/common/RegistryOpsAccessor.java create mode 100644 src/main/java/org/betterx/bclib/mixin/common/WorldPresetAccessor.java create mode 100644 src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPreset.java create mode 100644 src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPresetSettings.java create mode 100644 src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPresets.java create mode 100644 src/main/java/org/betterx/bclib/presets/worldgen/WorldGenUtilities.java create mode 100644 src/main/java/org/betterx/bclib/presets/worldgen/WorldPresetSettings.java delete mode 100644 src/main/java/org/betterx/bclib/presets/worldgen/WorldPresets.java diff --git a/src/main/java/org/betterx/bclib/BCLib.java b/src/main/java/org/betterx/bclib/BCLib.java index 57d3aeb5..3c7c415a 100644 --- a/src/main/java/org/betterx/bclib/BCLib.java +++ b/src/main/java/org/betterx/bclib/BCLib.java @@ -11,7 +11,7 @@ import org.betterx.bclib.api.dataexchange.DataExchangeAPI; import org.betterx.bclib.api.dataexchange.handler.autosync.*; import org.betterx.bclib.api.tag.TagAPI; import org.betterx.bclib.config.Configs; -import org.betterx.bclib.presets.worldgen.WorldPresets; +import org.betterx.bclib.presets.worldgen.BCLWorldPresets; import org.betterx.bclib.recipes.AnvilRecipe; import org.betterx.bclib.recipes.CraftingRecipes; import org.betterx.bclib.registry.BaseBlockEntities; @@ -25,6 +25,7 @@ import java.util.List; public class BCLib implements ModInitializer { public static final String MOD_ID = "bclib"; + public static final String TOGETHER_WORLDS = "worlds_together"; public static final Logger LOGGER = new Logger(MOD_ID); @Override @@ -37,9 +38,9 @@ public class BCLib implements ModInitializer { TagAPI.init(); CraftingRecipes.init(); WorldDataAPI.registerModCache(MOD_ID); - WorldDataAPI.registerModCache(MOD_ID); + WorldDataAPI.registerModCache(TOGETHER_WORLDS); DataExchangeAPI.registerMod(MOD_ID); - WorldPresets.registerPresets(); + BCLWorldPresets.registerPresets(); AnvilRecipe.register(); DataExchangeAPI.registerDescriptors(List.of( diff --git a/src/main/java/org/betterx/bclib/BCLibPatch.java b/src/main/java/org/betterx/bclib/BCLibPatch.java index 56887bc6..f88b1db7 100644 --- a/src/main/java/org/betterx/bclib/BCLibPatch.java +++ b/src/main/java/org/betterx/bclib/BCLibPatch.java @@ -16,7 +16,7 @@ import org.betterx.bclib.api.datafixer.DataFixerAPI; import org.betterx.bclib.api.datafixer.ForcedLevelPatch; import org.betterx.bclib.api.datafixer.MigrationProfile; import org.betterx.bclib.config.Configs; -import org.betterx.bclib.presets.worldgen.BCLChunkGenerator; +import org.betterx.bclib.presets.worldgen.WorldGenUtilities; import org.betterx.bclib.util.MHelper; import org.betterx.bclib.world.generator.GeneratorOptions; @@ -45,7 +45,7 @@ final class BiomeSourcePatch extends ForcedLevelPatch { @Override protected Boolean runLevelDatPatch(CompoundTag root, MigrationProfile profile) { //make sure we have a working generators file before attempting to patch - BCLChunkGenerator.migrateGeneratorSettings(); + WorldGenUtilities.migrateGeneratorSettings(); final CompoundTag worldGenSettings = root.getCompound("Data").getCompound("WorldGenSettings"); final CompoundTag dimensions = worldGenSettings.getCompound("dimensions"); @@ -109,16 +109,16 @@ final class BiomeSourcePatch extends ForcedLevelPatch { Optional oWorldGen = WorldGenSettings.CODEC .parse(new Dynamic<>(registryOps, worldGenSettings)) .result(); - + Optional oLevelStem = LevelStem.CODEC .parse(new Dynamic<>(registryOps, dimensionTag)) .resultOrPartial(BCLib.LOGGER::error); Optional netherGenerator = oLevelStem.map(l -> l.generator()); - int biomeSourceVersion = BCLChunkGenerator.getBiomeVersionForGenerator(netherGenerator.orElse(null)); - int targetVersion = BCLChunkGenerator.getBiomeVersionForCurrentWorld(dimensionKey); + int biomeSourceVersion = WorldGenUtilities.getBiomeVersionForGenerator(netherGenerator.orElse(null)); + int targetVersion = WorldGenUtilities.getBiomeVersionForCurrentWorld(dimensionKey); if (biomeSourceVersion != targetVersion) { - Optional> refLevelStem = BCLChunkGenerator.referenceStemForVersion( + Optional> refLevelStem = WorldGenUtilities.referenceStemForVersion( dimensionKey, targetVersion, registryAccess, diff --git a/src/main/java/org/betterx/bclib/api/biomes/BiomeAPI.java b/src/main/java/org/betterx/bclib/api/biomes/BiomeAPI.java index 85756c7a..9a164b1f 100644 --- a/src/main/java/org/betterx/bclib/api/biomes/BiomeAPI.java +++ b/src/main/java/org/betterx/bclib/api/biomes/BiomeAPI.java @@ -73,22 +73,30 @@ import org.jetbrains.annotations.Nullable; public class BiomeAPI { public static class Dimension { - public static final Dimension NONE = new Dimension(); - public static final Dimension OVERWORLD = new Dimension(); - public static final Dimension NETHER = new Dimension(); - public static final Dimension END = new Dimension(); - public static final Dimension END_LAND = new Dimension(END); - public static final Dimension END_VOID = new Dimension(END); + public static final Dimension NONE = new Dimension("NONE"); + public static final Dimension OVERWORLD = new Dimension("OVERWORLD"); + public static final Dimension NETHER = new Dimension("NETHER"); + public static final Dimension BCL_NETHER = new Dimension("BCL_NETHER", NETHER); + public static final Dimension OTHER_NETHER = new Dimension("OTHER_NETHER", NETHER); + public static final Dimension END = new Dimension("END"); + public static final Dimension END_LAND = new Dimension("END_LAND", END); + public static final Dimension END_VOID = new Dimension("END_VOID", END); + public static final Dimension BCL_END_LAND = new Dimension("BCL_END_LAND", END_LAND); + public static final Dimension BCL_END_VOID = new Dimension("BCL_END_VOID", END_VOID); + public static final Dimension OTHER_END_LAND = new Dimension("OTHER_END_LAND", END_LAND); + public static final Dimension OTHER_END_VOID = new Dimension("OTHER_END_VOID", END_VOID); private static final Map DIMENSION_MAP = Maps.newHashMap(); public final Dimension parentOrNull; + private final String debugName; - public Dimension() { - this(null); + public Dimension(String debugName) { + this(debugName, null); } - public Dimension(Dimension parentOrNull) { + public Dimension(String debugName, Dimension parentOrNull) { this.parentOrNull = parentOrNull; + this.debugName = debugName; } public boolean is(Dimension d) { @@ -96,6 +104,13 @@ public class BiomeAPI { if (parentOrNull != null) return parentOrNull.is(d); return false; } + + @Override + public String toString() { + String str = debugName; + if (parentOrNull != null) str += " -> " + parentOrNull.toString(); + return str; + } } /** @@ -207,17 +222,26 @@ public class BiomeAPI { } public static BCLBiome registerSubBiome(BCLBiome parent, BCLBiome subBiome) { - final Dimension dim = Dimension.DIMENSION_MAP.getOrDefault(parent.getID(), Dimension.NONE); + return registerSubBiome(parent, subBiome, Dimension.DIMENSION_MAP.getOrDefault(parent.getID(), Dimension.NONE)); + } + + public static BCLBiome registerSubBiome(BCLBiome parent, Biome subBiome, float genChance) { + return registerSubBiome(parent, + subBiome, + genChance, + Dimension.DIMENSION_MAP.getOrDefault(parent.getID(), Dimension.NONE)); + } + + public static BCLBiome registerSubBiome(BCLBiome parent, BCLBiome subBiome, Dimension dim) { registerBiome(subBiome, dim); parent.addSubBiome(subBiome); - return subBiome; } - public static BCLBiome registerSubBiome(BCLBiome parent, Biome biome, float genChance) { + public static BCLBiome registerSubBiome(BCLBiome parent, Biome biome, float genChance, Dimension dim) { BCLBiome subBiome = new BCLBiome(biome, VanillaBiomeSettings.createVanilla().setGenChance(genChance).build()); - return registerSubBiome(parent, subBiome); + return registerSubBiome(parent, subBiome, dim); } /** @@ -228,10 +252,12 @@ public class BiomeAPI { * @return {@link BCLBiome} */ public static BCLBiome registerNetherBiome(BCLBiome bclBiome) { - registerBiome(bclBiome, Dimension.NETHER); + registerBiome(bclBiome, Dimension.BCL_NETHER); ResourceKey key = BiomeAPI.getBiomeKeyOrThrow(bclBiome.getBiomeHolder()); - bclBiome.forEachClimateParameter(p -> NetherBiomeData.addNetherBiome(key, p)); + if (bclBiome.allowFabricRegistration()) { + bclBiome.forEachClimateParameter(p -> NetherBiomeData.addNetherBiome(key, p)); + } return bclBiome; } @@ -244,7 +270,7 @@ public class BiomeAPI { */ public static BCLBiome registerNetherBiome(Biome biome) { BCLBiome bclBiome = new BCLBiome(biome, null); - registerBiome(bclBiome, Dimension.NETHER); + registerBiome(bclBiome, Dimension.OTHER_NETHER); return bclBiome; } @@ -256,12 +282,14 @@ public class BiomeAPI { * @return {@link BCLBiome} */ public static BCLBiome registerEndLandBiome(BCLBiome biome) { - registerBiome(biome, Dimension.END_LAND); + registerBiome(biome, Dimension.BCL_END_LAND); float weight = biome.getGenChance(); ResourceKey key = BiomeAPI.getBiomeKey(biome.getBiome()); - TheEndBiomeData.addEndBiomeReplacement(Biomes.END_HIGHLANDS, key, weight); - TheEndBiomeData.addEndBiomeReplacement(Biomes.END_MIDLANDS, key, weight); + if (biome.allowFabricRegistration()) { + TheEndBiomeData.addEndBiomeReplacement(Biomes.END_HIGHLANDS, key, weight); + TheEndBiomeData.addEndBiomeReplacement(Biomes.END_MIDLANDS, key, weight); + } return biome; } @@ -275,7 +303,7 @@ public class BiomeAPI { public static BCLBiome registerEndLandBiome(Holder biome) { BCLBiome bclBiome = new BCLBiome(biome.value(), null); - registerBiome(bclBiome, Dimension.END_LAND); + registerBiome(bclBiome, Dimension.OTHER_END_LAND); return bclBiome; } @@ -291,7 +319,7 @@ public class BiomeAPI { BCLBiome bclBiome = new BCLBiome(biome.value(), VanillaBiomeSettings.createVanilla().setGenChance(genChance).build()); - registerBiome(bclBiome, Dimension.END_LAND); + registerBiome(bclBiome, Dimension.OTHER_END_LAND); return bclBiome; } @@ -307,7 +335,9 @@ public class BiomeAPI { float weight = biome.getGenChance(); ResourceKey key = BiomeAPI.getBiomeKeyOrThrow(biome.getBiomeHolder()); - TheEndBiomeData.addEndBiomeReplacement(Biomes.SMALL_END_ISLANDS, key, weight); + if (biome.allowFabricRegistration()) { + TheEndBiomeData.addEndBiomeReplacement(Biomes.SMALL_END_ISLANDS, key, weight); + } return biome; } @@ -501,8 +531,12 @@ public class BiomeAPI { } public static boolean wasRegisteredAs(ResourceLocation biomeID, Dimension dim) { - if (!Dimension.DIMENSION_MAP.containsKey(biomeID)) return false; - return Dimension.DIMENSION_MAP.get(biomeID).is(dim); + if (Dimension.DIMENSION_MAP.containsKey(biomeID) && Dimension.DIMENSION_MAP.get(biomeID).is(dim)) return true; + BCLBiome biome = getBiome(biomeID); + if (biome != null && biome != BiomeAPI.EMPTY_BIOME && biome.getParentBiome() != null) { + return wasRegisteredAs(biome.getParentBiome().getID(), dim); + } + return false; } public static boolean wasRegisteredAsNetherBiome(ResourceLocation biomeID) { diff --git a/src/main/java/org/betterx/bclib/api/datafixer/DataFixerAPI.java b/src/main/java/org/betterx/bclib/api/datafixer/DataFixerAPI.java index 6d5db612..ed5db74c 100644 --- a/src/main/java/org/betterx/bclib/api/datafixer/DataFixerAPI.java +++ b/src/main/java/org/betterx/bclib/api/datafixer/DataFixerAPI.java @@ -24,7 +24,7 @@ import org.betterx.bclib.gui.screens.ConfirmFixScreen; import org.betterx.bclib.gui.screens.LevelFixErrorScreen; import org.betterx.bclib.gui.screens.LevelFixErrorScreen.Listener; import org.betterx.bclib.gui.screens.ProgressScreen; -import org.betterx.bclib.presets.worldgen.BCLChunkGenerator; +import org.betterx.bclib.presets.worldgen.WorldGenUtilities; import org.betterx.bclib.util.Logger; import java.io.*; @@ -181,7 +181,7 @@ public class DataFixerAPI { public static void createWorldData(LevelStorageAccess access, WorldGenSettings settings) { initializeWorldData(access, true); - BCLChunkGenerator.initializeWorldData(settings); + WorldGenUtilities.initializeWorldData(settings); WorldDataAPI.saveFile(BCLib.MOD_ID); } diff --git a/src/main/java/org/betterx/bclib/client/presets/WorldPresetsUI.java b/src/main/java/org/betterx/bclib/client/presets/WorldPresetsUI.java index bbaa1d29..3ac0d316 100644 --- a/src/main/java/org/betterx/bclib/client/presets/WorldPresetsUI.java +++ b/src/main/java/org/betterx/bclib/client/presets/WorldPresetsUI.java @@ -8,7 +8,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import org.betterx.bclib.gui.screens.WorldSetupScreen; -import org.betterx.bclib.presets.worldgen.WorldPresets; +import org.betterx.bclib.presets.worldgen.BCLWorldPresets; import java.util.Optional; @@ -21,7 +21,7 @@ public class WorldPresetsUI { } public static void setupClientside() { - registerCustomizeUI(WorldPresets.BCL_WORLD, (createWorldScreen, worldCreationContext) -> { + registerCustomizeUI(BCLWorldPresets.BCL_WORLD, (createWorldScreen, worldCreationContext) -> { return new WorldSetupScreen(createWorldScreen, worldCreationContext); }); } diff --git a/src/main/java/org/betterx/bclib/gui/screens/WorldSetupScreen.java b/src/main/java/org/betterx/bclib/gui/screens/WorldSetupScreen.java index 1d5d9c2e..e3b77f6a 100644 --- a/src/main/java/org/betterx/bclib/gui/screens/WorldSetupScreen.java +++ b/src/main/java/org/betterx/bclib/gui/screens/WorldSetupScreen.java @@ -15,8 +15,7 @@ import net.fabricmc.api.Environment; import org.betterx.bclib.BCLib; import org.betterx.bclib.gui.gridlayout.GridCheckboxCell; import org.betterx.bclib.gui.gridlayout.GridLayout; -import org.betterx.bclib.presets.worldgen.BCLChunkGenerator; -import org.betterx.bclib.presets.worldgen.WorldPresets; +import org.betterx.bclib.presets.worldgen.WorldGenUtilities; import org.betterx.bclib.world.generator.BCLBiomeSource; import org.jetbrains.annotations.Nullable; @@ -40,14 +39,14 @@ public class WorldSetupScreen extends BCLibScreen { @Override protected void initLayout() { - final int netherVersion = BCLChunkGenerator.getBiomeVersionForGenerator(context + final int netherVersion = WorldGenUtilities.getBiomeVersionForGenerator(context .worldGenSettings() .dimensions() .getOrCreateHolderOrThrow( LevelStem.NETHER) .value() .generator()); - final int endVersion = BCLChunkGenerator.getBiomeVersionForGenerator(context + final int endVersion = WorldGenUtilities.getBiomeVersionForGenerator(context .worldGenSettings() .dimensions() .getOrCreateHolderOrThrow( @@ -150,7 +149,7 @@ public class WorldSetupScreen extends BCLibScreen { int biomeSourceVersion ) { createWorldScreen.worldGenSettingsComponent.updateSettings( - (registryAccess, worldGenSettings) -> WorldPresets.replaceGenerator( + (registryAccess, worldGenSettings) -> WorldGenUtilities.replaceGenerator( dimensionKey, dimensionTypeKey, biomeSourceVersion, diff --git a/src/main/java/org/betterx/bclib/mixin/client/CreateWorldScreenMixin.java b/src/main/java/org/betterx/bclib/mixin/client/CreateWorldScreenMixin.java index 73d4d0f8..8ca033c4 100644 --- a/src/main/java/org/betterx/bclib/mixin/client/CreateWorldScreenMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/client/CreateWorldScreenMixin.java @@ -13,7 +13,8 @@ import net.minecraft.world.level.levelgen.presets.WorldPreset; import com.mojang.datafixers.util.Pair; import org.betterx.bclib.api.biomes.BiomeAPI; -import org.betterx.bclib.presets.worldgen.WorldPresets; +import org.betterx.bclib.presets.worldgen.BCLWorldPresets; +import org.betterx.bclib.presets.worldgen.WorldGenUtilities; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -35,15 +36,15 @@ public class CreateWorldScreenMixin { //Change the WorldPreset that is selected by default on the Create World Screen @ModifyArg(method = "openFresh", index = 1, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/worldselection/WorldGenSettingsComponent;(Lnet/minecraft/client/gui/screens/worldselection/WorldCreationContext;Ljava/util/Optional;Ljava/util/OptionalLong;)V")) private static Optional> bcl_NewDefault(Optional> preset) { - return WorldPresets.DEFAULT; + return BCLWorldPresets.DEFAULT; } - //Make sure the WorldGenSettings match the default WorldPreset + //Make sure the WorldGenSettings used to populate the create screen match the default WorldPreset @ModifyArg(method = "openFresh", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/WorldLoader;load(Lnet/minecraft/server/WorldLoader$InitConfig;Lnet/minecraft/server/WorldLoader$WorldDataSupplier;Lnet/minecraft/server/WorldLoader$ResultFactory;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;")) private static WorldLoader.WorldDataSupplier bcl_NewDefaultSettings(WorldLoader.WorldDataSupplier worldDataSupplier) { return (resourceManager, dataPackConfig) -> { Pair res = worldDataSupplier.get(resourceManager, dataPackConfig); - return WorldPresets.defaultWorldDataSupplier(res.getSecond()); + return WorldGenUtilities.defaultWorldDataSupplier(res.getSecond()); }; } } diff --git a/src/main/java/org/betterx/bclib/mixin/common/DedicatedServerPropertiesMixin.java b/src/main/java/org/betterx/bclib/mixin/common/DedicatedServerPropertiesMixin.java index 95abbe57..44f8d977 100644 --- a/src/main/java/org/betterx/bclib/mixin/common/DedicatedServerPropertiesMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/common/DedicatedServerPropertiesMixin.java @@ -2,7 +2,7 @@ package org.betterx.bclib.mixin.common; import net.minecraft.server.dedicated.DedicatedServerProperties; -import org.betterx.bclib.presets.worldgen.WorldPresets; +import org.betterx.bclib.presets.worldgen.BCLWorldPresets; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; @@ -12,6 +12,6 @@ public class DedicatedServerPropertiesMixin { //Make sure the default server properties use our Default World Preset @ModifyArg(method = "", index = 3, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/dedicated/DedicatedServerProperties$WorldGenProperties;(Ljava/lang/String;Lcom/google/gson/JsonObject;ZLjava/lang/String;)V")) private String bcl_init(String levelType) { - return WorldPresets.DEFAULT.orElseThrow().location().toString(); + return BCLWorldPresets.DEFAULT.orElseThrow().location().toString(); } } diff --git a/src/main/java/org/betterx/bclib/mixin/common/PrimaryLevelDataMixin.java b/src/main/java/org/betterx/bclib/mixin/common/PrimaryLevelDataMixin.java index ccd668bf..3d3e1fba 100644 --- a/src/main/java/org/betterx/bclib/mixin/common/PrimaryLevelDataMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/common/PrimaryLevelDataMixin.java @@ -1,26 +1,52 @@ package org.betterx.bclib.mixin.common; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.dimension.BuiltinDimensionTypes; -import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.storage.LevelVersion; import net.minecraft.world.level.storage.PrimaryLevelData; -import org.betterx.bclib.presets.worldgen.WorldPresets; +import com.mojang.datafixers.DataFixer; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.Lifecycle; +import org.betterx.bclib.presets.worldgen.WorldGenUtilities; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Optional; +import org.jetbrains.annotations.Nullable; @Mixin(PrimaryLevelData.class) public class PrimaryLevelDataMixin { - @Shadow - private LevelSettings settings; + private static final ThreadLocal>> bcl_lastRegistryAccess = ThreadLocal.withInitial( + () -> Optional.empty()); + + @Inject(method = "parse", at = @At("HEAD")) + private static void bcl_parse(Dynamic dynamic, + DataFixer dataFixer, + int i, + @Nullable CompoundTag compoundTag, + LevelSettings levelSettings, + LevelVersion levelVersion, + WorldGenSettings worldGenSettings, + Lifecycle lifecycle, + CallbackInfoReturnable cir) { + if (dynamic.getOps() instanceof RegistryOps regOps) { + bcl_lastRegistryAccess.set(Optional.of(regOps)); + } + } @ModifyArg(method = "parse", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/storage/PrimaryLevelData;(Lcom/mojang/datafixers/DataFixer;ILnet/minecraft/nbt/CompoundTag;ZIIIFJJIIIZIZZZLnet/minecraft/world/level/border/WorldBorder$Settings;IILjava/util/UUID;Ljava/util/Set;Lnet/minecraft/world/level/timers/TimerQueue;Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/level/LevelSettings;Lnet/minecraft/world/level/levelgen/WorldGenSettings;Lcom/mojang/serialization/Lifecycle;)V")) private static WorldGenSettings bcl_fixSettings(WorldGenSettings settings) { - settings = WorldPresets.fixSettingsInCurrentWorld(LevelStem.NETHER, BuiltinDimensionTypes.NETHER, settings); - settings = WorldPresets.fixSettingsInCurrentWorld(LevelStem.END, BuiltinDimensionTypes.END, settings); + Optional> registryOps = bcl_lastRegistryAccess.get(); + settings = WorldGenUtilities.fixSettingsInCurrentWorld(registryOps, settings); + + bcl_lastRegistryAccess.set(Optional.empty()); return settings; } } diff --git a/src/main/java/org/betterx/bclib/mixin/common/RegistryOpsAccessor.java b/src/main/java/org/betterx/bclib/mixin/common/RegistryOpsAccessor.java new file mode 100644 index 00000000..0c96d19f --- /dev/null +++ b/src/main/java/org/betterx/bclib/mixin/common/RegistryOpsAccessor.java @@ -0,0 +1,13 @@ +package org.betterx.bclib.mixin.common; + +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.RegistryOps; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(RegistryOps.class) +public interface RegistryOpsAccessor { + @Accessor("registryAccess") + RegistryAccess bcl_getRegistryAccess(); +} diff --git a/src/main/java/org/betterx/bclib/mixin/common/WorldGenPropertiesMixin.java b/src/main/java/org/betterx/bclib/mixin/common/WorldGenPropertiesMixin.java index a1dc1ee5..d2c60f37 100644 --- a/src/main/java/org/betterx/bclib/mixin/common/WorldGenPropertiesMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/common/WorldGenPropertiesMixin.java @@ -4,7 +4,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.dedicated.DedicatedServerProperties; import net.minecraft.world.level.levelgen.presets.WorldPreset; -import org.betterx.bclib.presets.worldgen.WorldPresets; +import org.betterx.bclib.presets.worldgen.BCLWorldPresets; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; @@ -19,6 +19,6 @@ public class WorldGenPropertiesMixin { //Make sure Servers use our Default World Preset @ModifyArg(method = "create", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/core/Registry;getHolder(Lnet/minecraft/resources/ResourceKey;)Ljava/util/Optional;")) private ResourceKey bcl_foo(ResourceKey resourceKey) { - return WorldPresets.DEFAULT.orElseThrow(); + return BCLWorldPresets.DEFAULT.orElseThrow(); } } \ No newline at end of file diff --git a/src/main/java/org/betterx/bclib/mixin/common/WorldOpenFlowsMixin.java b/src/main/java/org/betterx/bclib/mixin/common/WorldOpenFlowsMixin.java index f7eae3ec..eae0c1c2 100644 --- a/src/main/java/org/betterx/bclib/mixin/common/WorldOpenFlowsMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/common/WorldOpenFlowsMixin.java @@ -3,20 +3,12 @@ package org.betterx.bclib.mixin.common; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.worldselection.WorldOpenFlows; import net.minecraft.core.RegistryAccess; -import net.minecraft.nbt.NbtOps; -import net.minecraft.nbt.Tag; -import net.minecraft.resources.RegistryOps; import net.minecraft.server.ReloadableServerResources; -import net.minecraft.server.WorldLoader; -import net.minecraft.server.WorldStem; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.world.level.DataPackConfig; import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.levelgen.WorldGenSettings; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.WorldData; -import com.mojang.datafixers.util.Pair; import org.betterx.bclib.api.LifeCycleAPI; import org.betterx.bclib.api.biomes.BiomeAPI; import org.betterx.bclib.api.dataexchange.DataExchangeAPI; @@ -28,7 +20,6 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(WorldOpenFlows.class) public abstract class WorldOpenFlowsMixin { @@ -86,24 +77,4 @@ public abstract class WorldOpenFlowsMixin { DataFixerAPI.createWorldData(levelStorageAccess, worldData.worldGenSettings()); LifeCycleAPI._runBeforeLevelLoad(); } - - @Inject(method = "loadWorldStem(Lnet/minecraft/server/WorldLoader$PackConfig;Lnet/minecraft/server/WorldLoader$WorldDataSupplier;)Lnet/minecraft/server/WorldStem;", at = @At("RETURN")) - public void bcl_loadWorldStem(WorldLoader.PackConfig packConfig, - WorldLoader.WorldDataSupplier worldDataSupplier, - CallbackInfoReturnable cir) { - WorldStem result = cir.getReturnValue(); - } - - @Inject(method = "method_41887", at = @At("RETURN")) - private static void bcl_loadWorldStem(LevelStorageSource.LevelStorageAccess levelStorageAccess, - ResourceManager resourceManager, - DataPackConfig dataPackConfig, - CallbackInfoReturnable cir) { - RegistryAccess.Writable writable = RegistryAccess.builtinCopy(); - RegistryOps dynamicOps = RegistryOps.create(NbtOps.INSTANCE, writable); - WorldData worldData = levelStorageAccess.getDataTag(dynamicOps, - dataPackConfig, - writable.allElementsLifecycle()); - Pair p = cir.getReturnValue(); - } } diff --git a/src/main/java/org/betterx/bclib/mixin/common/WorldPresetAccessor.java b/src/main/java/org/betterx/bclib/mixin/common/WorldPresetAccessor.java new file mode 100644 index 00000000..4cd67419 --- /dev/null +++ b/src/main/java/org/betterx/bclib/mixin/common/WorldPresetAccessor.java @@ -0,0 +1,16 @@ +package org.betterx.bclib.mixin.common; + +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.presets.WorldPreset; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(WorldPreset.class) +public interface WorldPresetAccessor { + @Accessor("dimensions") + public Map, LevelStem> bcl_getDimensions(); +} diff --git a/src/main/java/org/betterx/bclib/mixin/common/WorldPresetsBootstrapMixin.java b/src/main/java/org/betterx/bclib/mixin/common/WorldPresetsBootstrapMixin.java index 0ff95234..689fd2d9 100644 --- a/src/main/java/org/betterx/bclib/mixin/common/WorldPresetsBootstrapMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/common/WorldPresetsBootstrapMixin.java @@ -2,7 +2,6 @@ package org.betterx.bclib.mixin.common; import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.data.BuiltinRegistries; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; @@ -12,16 +11,15 @@ import net.minecraft.world.level.levelgen.presets.WorldPresets; import net.minecraft.world.level.levelgen.structure.StructureSet; import net.minecraft.world.level.levelgen.synth.NormalNoise; -import org.betterx.bclib.world.generator.BCLBiomeSource; +import org.betterx.bclib.presets.worldgen.BCLWorldPresets; +import org.betterx.bclib.presets.worldgen.WorldGenUtilities; +import org.betterx.bclib.presets.worldgen.WorldPresetSettings; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; -import java.util.Map; -import java.util.Optional; - @Mixin(WorldPresets.Bootstrap.class) public abstract class WorldPresetsBootstrapMixin { @Shadow @@ -53,52 +51,21 @@ public abstract class WorldPresetsBootstrapMixin { @ModifyArg(method = "run", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/world/level/levelgen/presets/WorldPresets$Bootstrap;registerCustomOverworldPreset(Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/world/level/dimension/LevelStem;)Lnet/minecraft/core/Holder;")) private LevelStem bcl_getOverworldStem(LevelStem overworldStem) { - WorldPreset preset_18 = new org.betterx.bclib.presets.worldgen.WorldPresets.SortableWorldPreset( - Map.of(LevelStem.OVERWORLD, - overworldStem, - LevelStem.NETHER, - org.betterx.bclib.presets.worldgen.WorldPresets.getBCLNetherLevelStem(this.biomes, - this.netherDimensionType, - this.structureSets, - this.noises, - this.netherNoiseSettings, - Optional.empty()), - LevelStem.END, - org.betterx.bclib.presets.worldgen.WorldPresets.getBCLEndLevelStem(this.biomes, - this.endDimensionType, - this.structureSets, - this.noises, - this.endNoiseSettings, - Optional.empty()) - ), 0 - ); + WorldPresetSettings.bootstrap(); + WorldGenUtilities.Context netherContext = new WorldGenUtilities.Context(this.biomes, + this.netherDimensionType, + this.structureSets, + this.noises, + this.netherNoiseSettings); + WorldGenUtilities.Context endContext = new WorldGenUtilities.Context(this.biomes, + this.endDimensionType, + this.structureSets, + this.noises, + this.endNoiseSettings); - WorldPreset preset_17 = new org.betterx.bclib.presets.worldgen.WorldPresets.SortableWorldPreset( - Map.of(LevelStem.OVERWORLD, - overworldStem, - LevelStem.NETHER, - org.betterx.bclib.presets.worldgen.WorldPresets.getBCLNetherLevelStem(this.biomes, - this.netherDimensionType, - this.structureSets, - this.noises, - this.netherNoiseSettings, - Optional.of(BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE)), - LevelStem.END, - org.betterx.bclib.presets.worldgen.WorldPresets.getBCLEndLevelStem(this.biomes, - this.endDimensionType, - this.structureSets, - this.noises, - this.endNoiseSettings, - Optional.of(BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE)) - ), 0 - ); - - BuiltinRegistries.register(this.presets, org.betterx.bclib.presets.worldgen.WorldPresets.BCL_WORLD, preset_18); - BuiltinRegistries.register(this.presets, - org.betterx.bclib.presets.worldgen.WorldPresets.BCL_WORLD_17, - preset_17); + BCLWorldPresets.bootstrapPresets(presets, overworldStem, netherContext, endContext); return overworldStem; } -} \ No newline at end of file +} diff --git a/src/main/java/org/betterx/bclib/presets/worldgen/BCLChunkGenerator.java b/src/main/java/org/betterx/bclib/presets/worldgen/BCLChunkGenerator.java index 2eb70567..6c8c295a 100644 --- a/src/main/java/org/betterx/bclib/presets/worldgen/BCLChunkGenerator.java +++ b/src/main/java/org/betterx/bclib/presets/worldgen/BCLChunkGenerator.java @@ -2,35 +2,20 @@ package org.betterx.bclib.presets.worldgen; import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.core.RegistryAccess; -import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.RegistryOps; -import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.WorldGenSettings; import net.minecraft.world.level.levelgen.structure.StructureSet; import net.minecraft.world.level.levelgen.synth.NormalNoise; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import org.betterx.bclib.BCLib; -import org.betterx.bclib.api.WorldDataAPI; import org.betterx.bclib.interfaces.NoiseGeneratorSettingsProvider; -import org.betterx.bclib.util.ModUtil; -import org.betterx.bclib.world.generator.BCLBiomeSource; - -import java.util.Optional; public class BCLChunkGenerator extends NoiseBasedChunkGenerator { - private static String TAG_GENERATOR = "generator"; - private static final String TAG_VERSION = "version"; - private static final String TAG_BN_GEN_VERSION = "generator_version"; - public static final Codec CODEC = RecordCodecBuilder .create((RecordCodecBuilder.Instance builderInstance) -> { final RecordCodecBuilder> noiseGetter = RegistryOps @@ -75,107 +60,6 @@ public class BCLChunkGenerator extends NoiseBasedChunkGenerator { return null; } - public static int getBiomeVersionForGenerator(ChunkGenerator generator) { - if (generator == null) return BCLBiomeSource.getVersionBiomeSource(null); - return BCLBiomeSource.getVersionBiomeSource(generator.getBiomeSource()); - } - - public static Optional> referenceStemForVersion( - ResourceKey dimensionKey, - int biomeSourceVersion, - RegistryAccess registryAccess, - long seed, - boolean generateStructures, - boolean generateBonusChest - ) { - final WorldGenSettings referenceSettings; - if (biomeSourceVersion == BCLBiomeSource.BIOME_SOURCE_VERSION_VANILLA) { - referenceSettings = net.minecraft.world.level.levelgen.presets.WorldPresets.createNormalWorldFromPreset( - registryAccess, - seed, - generateStructures, - generateBonusChest); - } else if (biomeSourceVersion == BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE) { - referenceSettings = WorldPresets.createWorldFromPreset( - WorldPresets.BCL_WORLD_17, - registryAccess, - seed, - generateStructures, - generateBonusChest); - } else { - referenceSettings = WorldPresets.createDefaultWorldFromPreset( - registryAccess, - seed, - generateStructures, - generateBonusChest); - } - return referenceSettings.dimensions().getHolder(dimensionKey); - } - - public static int getBiomeVersionForCurrentWorld(ResourceKey key) { - final CompoundTag settingsNbt = getSettingsNbt(); - if (!settingsNbt.contains(key.location().toString())) return BCLBiomeSource.DEFAULT_BIOME_SOURCE_VERSION; - return settingsNbt.getInt(key.location().toString()); - } - - private static void writeDimensionVersion(WorldGenSettings settings, - CompoundTag generatorSettings, - ResourceKey key) { - var dimension = settings.dimensions().getHolder(key); - if (dimension.isPresent()) { - generatorSettings.putInt(key.location().toString(), - getBiomeVersionForGenerator(dimension.get().value().generator())); - } else { - generatorSettings.putInt(key.location().toString(), getBiomeVersionForGenerator(null)); - } - } - - public static void initializeWorldData(WorldGenSettings settings) { - final CompoundTag settingsNbt = getSettingsNbt(); - writeDimensionVersion(settings, settingsNbt, LevelStem.NETHER); - writeDimensionVersion(settings, settingsNbt, LevelStem.END); - } - - private static CompoundTag getSettingsNbt() { - return WorldDataAPI.getCompoundTag(BCLib.MOD_ID, TAG_GENERATOR); - } - - public static void migrateGeneratorSettings() { - final CompoundTag settingsNbt = getSettingsNbt(); - - if (settingsNbt.size() == 0) { - BCLib.LOGGER.info("Found World without generator Settings. Setting up data..."); - int biomeSourceVersion = BCLBiomeSource.DEFAULT_BIOME_SOURCE_VERSION; - - final CompoundTag bclRoot = WorldDataAPI.getRootTag(BCLib.MOD_ID); - - String bclVersion = "0.0.0"; - if (bclRoot.contains(TAG_VERSION)) { - bclVersion = bclRoot.getString(TAG_VERSION); - } - boolean isPre18 = !ModUtil.isLargerOrEqualVersion(bclVersion, "1.0.0"); - - if (isPre18) { - BCLib.LOGGER.info("World was create pre 1.18!"); - biomeSourceVersion = BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE; - } - - if (WorldDataAPI.hasMod("betternether")) { - BCLib.LOGGER.info("Found Data from BetterNether, using for migration."); - final CompoundTag bnRoot = WorldDataAPI.getRootTag("betternether"); - biomeSourceVersion = "1.17".equals(bnRoot.getString(TAG_BN_GEN_VERSION)) - ? BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE - : BCLBiomeSource.BIOME_SOURCE_VERSION_HEX; - } - - BCLib.LOGGER.info("Set world to BiomeSource Version " + biomeSourceVersion); - settingsNbt.putInt(LevelStem.NETHER.location().toString(), biomeSourceVersion); - settingsNbt.putInt(LevelStem.END.location().toString(), biomeSourceVersion); - - WorldDataAPI.saveFile(BCLib.MOD_ID); - } - } - @Override public String toString() { return "BCLib - Chunk Generator (" + Integer.toHexString(hashCode()) + ")"; diff --git a/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPreset.java b/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPreset.java new file mode 100644 index 00000000..cdd96b95 --- /dev/null +++ b/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPreset.java @@ -0,0 +1,52 @@ +package org.betterx.bclib.presets.worldgen; + +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.RegistryFileCodec; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.presets.WorldPreset; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.betterx.bclib.mixin.common.WorldPresetAccessor; + +import java.util.Map; + +public class BCLWorldPreset extends WorldPreset { + public final WorldPresetSettings settings; + public final int sortOrder; + public static final Codec DIRECT_CODEC = RecordCodecBuilder.create(builderInstance -> { + RecordCodecBuilder, LevelStem>> dimensionsBuidler = Codec + .unboundedMap(ResourceKey.codec(Registry.LEVEL_STEM_REGISTRY), LevelStem.CODEC) + .fieldOf("dimensions") + .forGetter(worldPreset -> worldPreset.getDimensions()); + + RecordCodecBuilder sortBuilder = Codec.INT + .fieldOf("sort_order") + .forGetter(wp -> wp.sortOrder); + + RecordCodecBuilder settingsBuilder = WorldPresetSettings.CODEC + .fieldOf("settings") + .forGetter(wp -> wp.settings); + + return builderInstance + .group(dimensionsBuidler, sortBuilder, settingsBuilder) + .apply(builderInstance, BCLWorldPreset::new); + }); + + public static final Codec> CODEC = RegistryFileCodec.create( + Registry.WORLD_PRESET_REGISTRY, + (Codec) ((Object) DIRECT_CODEC)); + + public BCLWorldPreset(Map, LevelStem> map, int sortOrder, WorldPresetSettings settings) { + super(map); + this.sortOrder = sortOrder; + this.settings = settings; + } + + private Map, LevelStem> getDimensions() { + return WorldPresetAccessor.class.cast(this).bcl_getDimensions(); + } + +} diff --git a/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPresetSettings.java b/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPresetSettings.java new file mode 100644 index 00000000..85853772 --- /dev/null +++ b/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPresetSettings.java @@ -0,0 +1,169 @@ +package org.betterx.bclib.presets.worldgen; + +import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.dimension.BuiltinDimensionTypes; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldGenSettings; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.betterx.bclib.BCLib; +import org.betterx.bclib.interfaces.ChunkGeneratorAccessor; +import org.betterx.bclib.interfaces.NoiseGeneratorSettingsProvider; +import org.betterx.bclib.world.generator.BCLBiomeSource; +import org.betterx.bclib.world.generator.BCLibNetherBiomeSource; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +public class BCLWorldPresetSettings extends WorldPresetSettings { + public final static BCLWorldPresetSettings DEFAULT = new BCLWorldPresetSettings(BCLBiomeSource.DEFAULT_BIOME_SOURCE_VERSION); + + public static final Codec CODEC = RecordCodecBuilder + .create((RecordCodecBuilder.Instance builderInstance) -> { + RecordCodecBuilder netherVersion = Codec.INT + .fieldOf(LevelStem.NETHER.location().toString()) + .forGetter((BCLWorldPresetSettings settings) -> settings.netherVersion); + + RecordCodecBuilder endVersion = Codec.INT + .fieldOf(LevelStem.END.location().toString()) + .forGetter((BCLWorldPresetSettings settings) -> settings.endVersion); + + + return builderInstance.group(netherVersion, endVersion) + .apply(builderInstance, builderInstance.stable(BCLWorldPresetSettings::new)); + }); + public final int netherVersion; + public final int endVersion; + + public BCLWorldPresetSettings(int version) { + this(version, version); + } + + public BCLWorldPresetSettings(int netherVersion, int endVersion) { + this.netherVersion = netherVersion; + this.endVersion = endVersion; + } + + + @Override + public Codec codec() { + return CODEC; + } + + public BCLWorldPreset buildPreset(LevelStem overworldStem, + WorldGenUtilities.Context netherContext, + WorldGenUtilities.Context endContext) { + return new BCLWorldPreset(buildDimensionMap(overworldStem, netherContext, endContext), 1000, this); + } + + public Map, LevelStem> buildDimensionMap(LevelStem overworldStem, + WorldGenUtilities.Context netherContext, + WorldGenUtilities.Context endContext) { + return Map.of(LevelStem.OVERWORLD, + overworldStem, + LevelStem.NETHER, + createNetherStem(netherContext), + LevelStem.END, + createEndStem(endContext) + ); + } + + public int getVersion(ResourceKey key) { + if (key == LevelStem.NETHER) return netherVersion; + if (key == LevelStem.END) return endVersion; + + return BCLBiomeSource.BIOME_SOURCE_VERSION_VANILLA; + } + + public LevelStem createStem(WorldGenUtilities.Context ctx, ResourceKey key) { + if (key == LevelStem.NETHER) return createNetherStem(ctx); + if (key == LevelStem.END) return createEndStem(ctx); + return null; + } + + public LevelStem createNetherStem(WorldGenUtilities.Context ctx) { + return WorldGenUtilities.getBCLNetherLevelStem(ctx, Optional.of(netherVersion)); + } + + public LevelStem createEndStem(WorldGenUtilities.Context ctx) { + return WorldGenUtilities.getBCLEndLevelStem(ctx, Optional.of(endVersion)); + } + + public BiomeSource fixBiomeSource(BiomeSource biomeSource, Set> datapackBiomes) { + if (biomeSource instanceof BCLibNetherBiomeSource bs) { + return bs.createCopyForDatapack(datapackBiomes); + } + return biomeSource; + } + + + /** + * Datapacks can change the world's generator. This Method will ensure, that the Generators contain + * the correct BiomeSources for this world + * + * @param dimensionKey + * @param dimensionTypeKey + * @param settings + * @return + */ + public WorldGenSettings fixSettingsInCurrentWorld(RegistryAccess access, ResourceKey dimensionKey, + ResourceKey dimensionTypeKey, + WorldGenSettings settings) { + var oldNether = settings.dimensions().getHolder(dimensionKey); + int loaderVersion = WorldGenUtilities.getBiomeVersionForGenerator(oldNether + .map(h -> h.value().generator()) + .orElse(null)); + + int targetVersion = getVersion(dimensionKey); + if (loaderVersion != targetVersion) { + BCLib.LOGGER.info("Enforcing Correct Generator for " + dimensionKey.location().toString() + "."); + var chunkGenerator = oldNether.map(h -> h.value().generator()).orElse(null); + Optional> refLevelStem = WorldGenUtilities.referenceStemForVersion( + dimensionKey, + targetVersion, + access, + settings.seed(), + settings.generateStructures(), + settings.generateBonusChest() + ); + + ChunkGenerator referenceGenerator = refLevelStem.map(h -> h.value().generator()).orElse(null); + if (referenceGenerator == null) { + BCLib.LOGGER.error("Failed to create Generator for " + dimensionKey.location().toString()); + return settings; + } + + if (chunkGenerator instanceof ChunkGeneratorAccessor generator) { + if (chunkGenerator instanceof NoiseGeneratorSettingsProvider noiseProvider) { + final Set> biomes = chunkGenerator.getBiomeSource().possibleBiomes(); + + referenceGenerator = new BCLChunkGenerator(generator.bclib_getStructureSetsRegistry(), + noiseProvider.bclib_getNoises(), + fixBiomeSource(referenceGenerator.getBiomeSource(), biomes), + noiseProvider.bclib_getNoiseGeneratorSettingHolders()); + } + } + + return WorldGenUtilities.replaceGenerator(dimensionKey, + dimensionTypeKey, + access, + settings, + referenceGenerator); + } + return settings; + } + + public WorldGenSettings repairSettingsOnLoad(RegistryAccess registryAccess, WorldGenSettings settings) { + settings = fixSettingsInCurrentWorld(registryAccess, LevelStem.NETHER, BuiltinDimensionTypes.NETHER, settings); + settings = fixSettingsInCurrentWorld(registryAccess, LevelStem.END, BuiltinDimensionTypes.END, settings); + return settings; + } +} diff --git a/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPresets.java b/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPresets.java new file mode 100644 index 00000000..fd0ac408 --- /dev/null +++ b/src/main/java/org/betterx/bclib/presets/worldgen/BCLWorldPresets.java @@ -0,0 +1,106 @@ +package org.betterx.bclib.presets.worldgen; + +import net.minecraft.core.Registry; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.WorldPresetTags; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.presets.WorldPreset; + +import com.google.common.collect.Maps; +import org.betterx.bclib.BCLib; +import org.betterx.bclib.api.tag.TagAPI; +import org.betterx.bclib.api.tag.TagType; +import org.betterx.bclib.world.generator.BCLBiomeSource; + +import java.util.Map; +import java.util.Optional; + +public class BCLWorldPresets { + + public static final TagType.Simple WORLD_PRESETS = + TagAPI.registerType(BuiltinRegistries.WORLD_PRESET, "tags/worldgen/world_preset"); + private static Map, PresetBuilder> BUILDERS = Maps.newHashMap(); + private static Map, WorldPresetSettings> SETTINGS = Maps.newHashMap(); + public static final ResourceKey BCL_WORLD = + register(BCLib.makeID("normal"), + (overworldStem, netherContext, endContext) -> + new BCLWorldPresetSettings(BCLBiomeSource.DEFAULT_BIOME_SOURCE_VERSION).buildPreset( + overworldStem, + netherContext, + endContext), + true); + public static Optional> DEFAULT = Optional.of(BCL_WORLD); + public static final ResourceKey BCL_WORLD_17 = register(BCLib.makeID("legacy_17"), + (overworldStem, netherContext, endContext) -> + new BCLWorldPresetSettings(BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE).buildPreset( + overworldStem, + netherContext, + endContext), + true); + + /** + * Registers a custom WorldPreset (with custom rules and behaviour) + *

+ * See also {@link org.betterx.bclib.client.presets.WorldPresetsUI} if you need to add a Customize Button/Screen + * for your preset + * + * @param loc The ID of your Preset + * @return The key you may use to reference your new Preset + */ + private static ResourceKey register(ResourceLocation loc) { + return register(loc, true); + } + + private static ResourceKey register(ResourceLocation loc, boolean addToNormal) { + ResourceKey key = ResourceKey.create(Registry.WORLD_PRESET_REGISTRY, loc); + if (addToNormal) { + WORLD_PRESETS.addUntyped(WorldPresetTags.NORMAL, key.location()); + } + + return key; + } + + public static void registerPresets() { + + } + + public static ResourceKey register(ResourceLocation loc, + PresetBuilder builder, + boolean visibleInUI) { + ResourceKey key = register(loc, visibleInUI); + + if (BUILDERS == null) { + BCLib.LOGGER.error("Unable to register WorldPreset '" + loc + "'."); + + } else { + BUILDERS.put(key, builder); + } + return key; + } + + public static void bootstrapPresets(Registry presets, + LevelStem overworldStem, + WorldGenUtilities.Context netherContext, + WorldGenUtilities.Context endContext) { + + for (Map.Entry, PresetBuilder> e : BUILDERS.entrySet()) { + BCLWorldPreset preset = e.getValue().create(overworldStem, netherContext, endContext); + SETTINGS.put(e.getKey(), preset.settings); + BuiltinRegistries.register(presets, e.getKey(), preset); + } + BUILDERS = null; + } + + public static WorldPresetSettings getSettingsForPreset(ResourceKey key) { + return SETTINGS.getOrDefault(key, BCLWorldPresetSettings.DEFAULT); + } + + @FunctionalInterface + public interface PresetBuilder { + BCLWorldPreset create(LevelStem overworldStem, + WorldGenUtilities.Context netherContext, + WorldGenUtilities.Context endContext); + } +} diff --git a/src/main/java/org/betterx/bclib/presets/worldgen/WorldGenUtilities.java b/src/main/java/org/betterx/bclib/presets/worldgen/WorldGenUtilities.java new file mode 100644 index 00000000..a44bb8a9 --- /dev/null +++ b/src/main/java/org/betterx/bclib/presets/worldgen/WorldGenUtilities.java @@ -0,0 +1,382 @@ +package org.betterx.bclib.presets.worldgen; + +import net.minecraft.core.Holder; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.levelgen.presets.WorldPreset; +import net.minecraft.world.level.levelgen.structure.StructureSet; +import net.minecraft.world.level.levelgen.synth.NormalNoise; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.Lifecycle; +import org.betterx.bclib.BCLib; +import org.betterx.bclib.api.WorldDataAPI; +import org.betterx.bclib.mixin.common.RegistryOpsAccessor; +import org.betterx.bclib.util.ModUtil; +import org.betterx.bclib.world.generator.BCLBiomeSource; +import org.betterx.bclib.world.generator.BCLibEndBiomeSource; +import org.betterx.bclib.world.generator.BCLibNetherBiomeSource; + +import java.util.Map; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +public class WorldGenUtilities { + private static final String TAG_VERSION = "version"; + private static final String TAG_BN_GEN_VERSION = "generator_version"; + private static String TAG_GENERATOR = "generator"; + + @NotNull + public static LevelStem getBCLNetherLevelStem(Context context, Optional version) { + BCLibNetherBiomeSource netherSource = new BCLibNetherBiomeSource(context.biomes, version); + return getBCLNetherLevelStem(context, netherSource); + } + + public static LevelStem getBCLNetherLevelStem(StemContext context, BiomeSource biomeSource) { + return new LevelStem( + context.dimension, + new BCLChunkGenerator( + context.structureSets, + context.noiseParameters, + biomeSource, + context.generatorSettings) + ); + } + + @NotNull + public static LevelStem getBCLEndLevelStem(StemContext context, BiomeSource biomeSource) { + return new LevelStem( + context.dimension, + new BCLChunkGenerator( + context.structureSets, + context.noiseParameters, + biomeSource, + context.generatorSettings) + ); + } + + public static LevelStem getBCLEndLevelStem(Context context, Optional version) { + BCLibEndBiomeSource endSource = new BCLibEndBiomeSource(context.biomes, version); + return getBCLEndLevelStem(context, endSource); + } + + /** + * Datapacks can change the world's generator. This Method will ensure, that the Generators contain + * the correct BiomeSources for this world + * + * @param settings + * @return + */ + public static WorldGenSettings fixSettingsInCurrentWorld(Optional> registryOps, + WorldGenSettings settings) { + if (registryOps.orElse(null) instanceof RegistryOpsAccessor acc) { + return getWorldSettings().repairSettingsOnLoad(acc.bcl_getRegistryAccess(), settings); + } else { + BCLib.LOGGER.error("Unable to obtain registryAccess when enforcing generators."); + } + return settings; + } + + public static WorldGenSettings createWorldFromPreset(ResourceKey preset, + RegistryAccess registryAccess, + long seed, + boolean generateStructures, + boolean generateBonusChest) { + WorldGenSettings settings = registryAccess + .registryOrThrow(Registry.WORLD_PRESET_REGISTRY) + .getHolderOrThrow(preset) + .value() + .createWorldGenSettings(seed, generateStructures, generateBonusChest); + + for (LevelStem stem : settings.dimensions()) { + if (stem.generator().getBiomeSource() instanceof BCLBiomeSource bcl) { + bcl.setSeed(seed); + } + } + + return settings; + } + + public static WorldGenSettings createDefaultWorldFromPreset(RegistryAccess registryAccess, + long seed, + boolean generateStructures, + boolean generateBonusChest) { + return createWorldFromPreset(BCLWorldPresets.DEFAULT.orElseThrow(), + registryAccess, + seed, + generateStructures, + generateBonusChest); + } + + public static Pair defaultWorldDataSupplier(RegistryAccess.Frozen frozen) { + WorldGenSettings worldGenSettings = createDefaultWorldFromPreset(frozen); + return Pair.of(worldGenSettings, frozen); + } + + public static WorldGenSettings createDefaultWorldFromPreset(RegistryAccess registryAccess, long seed) { + return createDefaultWorldFromPreset(registryAccess, seed, true, false); + } + + public static WorldGenSettings createDefaultWorldFromPreset(RegistryAccess registryAccess) { + return createDefaultWorldFromPreset(registryAccess, RandomSource.create().nextLong()); + } + + public static WorldGenSettings replaceGenerator( + ResourceKey dimensionKey, + ResourceKey dimensionTypeKey, + int biomeSourceVersion, + RegistryAccess registryAccess, + WorldGenSettings worldGenSettings + ) { + Optional> oLevelStem = referenceStemForVersion( + dimensionKey, + biomeSourceVersion, + registryAccess, + worldGenSettings.seed(), + worldGenSettings.generateStructures(), + worldGenSettings.generateStructures() + ); + return replaceGenerator(dimensionKey, + dimensionTypeKey, + registryAccess, + worldGenSettings, + oLevelStem.map(l -> l.value().generator()).orElseThrow()); + } + + public static WorldGenSettings replaceGenerator( + ResourceKey dimensionKey, + ResourceKey dimensionTypeKey, + RegistryAccess registryAccess, + WorldGenSettings worldGenSettings, + ChunkGenerator generator + ) { + Registry dimensionTypeRegistry = registryAccess.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); + Registry newDimensions = withDimension(dimensionKey, + dimensionTypeKey, + dimensionTypeRegistry, + worldGenSettings.dimensions(), + generator); + return new WorldGenSettings(worldGenSettings.seed(), + worldGenSettings.generateStructures(), + worldGenSettings.generateBonusChest(), + newDimensions); + } + + public static WorldGenSettings replaceStem( + ResourceKey dimensionKey, + WorldGenSettings worldGenSettings, + LevelStem levelStem + ) { + Registry newDimensions = withDimension(dimensionKey, + worldGenSettings.dimensions(), + levelStem); + return new WorldGenSettings(worldGenSettings.seed(), + worldGenSettings.generateStructures(), + worldGenSettings.generateBonusChest(), + newDimensions); + } + + public static Registry withDimension(ResourceKey dimensionKey, + ResourceKey dimensionTypeKey, + Registry dimensionTypeRegistry, + Registry inputDimensions, + ChunkGenerator generator) { + + LevelStem levelStem = inputDimensions.get(dimensionKey); + Holder dimensionType = levelStem == null + ? dimensionTypeRegistry.getOrCreateHolderOrThrow(dimensionTypeKey) + : levelStem.typeHolder(); + return withDimension(dimensionKey, inputDimensions, new LevelStem(dimensionType, generator)); + } + + public static Registry withDimension(ResourceKey dimensionKey, + Registry inputDimensions, + LevelStem levelStem) { + MappedRegistry writableRegistry = new MappedRegistry<>(Registry.LEVEL_STEM_REGISTRY, + Lifecycle.experimental(), + null); + writableRegistry.register(dimensionKey, + levelStem, + Lifecycle.stable()); + for (Map.Entry, LevelStem> entry : inputDimensions.entrySet()) { + ResourceKey resourceKey = entry.getKey(); + if (resourceKey == dimensionKey) continue; + writableRegistry.register(resourceKey, + entry.getValue(), + inputDimensions.lifecycle(entry.getValue())); + } + return writableRegistry; + } + + public static int getBiomeVersionForGenerator(ChunkGenerator generator) { + if (generator == null) return BCLBiomeSource.getVersionBiomeSource(null); + return BCLBiomeSource.getVersionBiomeSource(generator.getBiomeSource()); + } + + public static Optional> referenceStemForVersion( + ResourceKey dimensionKey, + int biomeSourceVersion, + RegistryAccess registryAccess, + long seed, + boolean generateStructures, + boolean generateBonusChest + ) { + final WorldGenSettings referenceSettings; + if (biomeSourceVersion == BCLBiomeSource.BIOME_SOURCE_VERSION_VANILLA) { + referenceSettings = net.minecraft.world.level.levelgen.presets.WorldPresets.createNormalWorldFromPreset( + registryAccess, + seed, + generateStructures, + generateBonusChest); + } else if (biomeSourceVersion == BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE) { + referenceSettings = createWorldFromPreset( + BCLWorldPresets.BCL_WORLD_17, + registryAccess, + seed, + generateStructures, + generateBonusChest); + } else { + referenceSettings = createDefaultWorldFromPreset( + registryAccess, + seed, + generateStructures, + generateBonusChest); + } + return referenceSettings.dimensions().getHolder(dimensionKey); + } + + public static int getBiomeVersionForCurrentWorld(ResourceKey key) { + final CompoundTag settingsNbt = getSettingsNbt(); + if (!settingsNbt.contains(key.location().toString())) return BCLBiomeSource.DEFAULT_BIOME_SOURCE_VERSION; + return settingsNbt.getInt(key.location().toString()); + } + + private static int getDimensionVersion(WorldGenSettings settings, + ResourceKey key) { + var dimension = settings.dimensions().getHolder(key); + if (dimension.isPresent()) { + return getBiomeVersionForGenerator(dimension.get().value().generator()); + } else { + return getBiomeVersionForGenerator(null); + } + } + + private static void writeDimensionVersion(WorldGenSettings settings, + CompoundTag generatorSettings, + ResourceKey key) { + generatorSettings.putInt(key.location().toString(), getDimensionVersion(settings, key)); + } + + public static void initializeWorldData(WorldGenSettings settings) { + updateWorldData(getDimensionVersion(settings, LevelStem.NETHER), getDimensionVersion(settings, LevelStem.END)); + } + + public static void updateWorldData(int netherVersion, int endVersion) { + BCLWorldPresetSettings worldSettings = new BCLWorldPresetSettings(netherVersion, endVersion); + final RegistryAccess registryAccess = RegistryAccess.builtinCopy(); + final RegistryOps registryOps = RegistryOps.create(NbtOps.INSTANCE, registryAccess); + final var codec = WorldPresetSettings.CODEC.orElse(worldSettings); + final var encodeResult = codec.encodeStart(registryOps, worldSettings); + + if (encodeResult.result().isPresent()) { + final CompoundTag settingsNbt = WorldDataAPI.getRootTag(BCLib.TOGETHER_WORLDS); + settingsNbt.put(TAG_GENERATOR, encodeResult.result().get()); + } else { + BCLib.LOGGER.error("Unable to encode world generator settings generator for level.dat."); + } + + WorldDataAPI.saveFile(BCLib.TOGETHER_WORLDS); + } + + static CompoundTag getSettingsNbt() { + return WorldDataAPI.getCompoundTag(BCLib.TOGETHER_WORLDS, TAG_GENERATOR); + } + + public static WorldPresetSettings getWorldSettings() { + final RegistryAccess registryAccess = RegistryAccess.builtinCopy(); + final RegistryOps registryOps = RegistryOps.create(NbtOps.INSTANCE, registryAccess); + + Optional oLevelStem = WorldPresetSettings.CODEC + .parse(new Dynamic<>(registryOps, getSettingsNbt())) + .resultOrPartial(BCLib.LOGGER::error); + + return oLevelStem.orElse(BCLWorldPresetSettings.DEFAULT); + } + + public static void migrateGeneratorSettings() { + final CompoundTag settingsNbt = getSettingsNbt(); + + if (settingsNbt.size() == 0) { + BCLib.LOGGER.info("Found World without generator Settings. Setting up data..."); + int biomeSourceVersion = BCLBiomeSource.DEFAULT_BIOME_SOURCE_VERSION; + + final CompoundTag bclRoot = WorldDataAPI.getRootTag(BCLib.MOD_ID); + + String bclVersion = "0.0.0"; + if (bclRoot.contains(TAG_VERSION)) { + bclVersion = bclRoot.getString(TAG_VERSION); + } + boolean isPre18 = !ModUtil.isLargerOrEqualVersion(bclVersion, "1.0.0"); + + if (isPre18) { + BCLib.LOGGER.info("World was create pre 1.18!"); + biomeSourceVersion = BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE; + } + + if (WorldDataAPI.hasMod("betternether")) { + BCLib.LOGGER.info("Found Data from BetterNether, using for migration."); + final CompoundTag bnRoot = WorldDataAPI.getRootTag("betternether"); + biomeSourceVersion = "1.17".equals(bnRoot.getString(TAG_BN_GEN_VERSION)) + ? BCLBiomeSource.BIOME_SOURCE_VERSION_SQUARE + : BCLBiomeSource.BIOME_SOURCE_VERSION_HEX; + } + + BCLib.LOGGER.info("Set world to BiomeSource Version " + biomeSourceVersion); + updateWorldData(biomeSourceVersion, biomeSourceVersion); + } + } + + public static class StemContext { + public final Holder dimension; + public final Registry structureSets; + public final Registry noiseParameters; + public final Holder generatorSettings; + + public StemContext(Holder dimension, + Registry structureSets, + Registry noiseParameters, + Holder generatorSettings) { + this.dimension = dimension; + this.structureSets = structureSets; + this.noiseParameters = noiseParameters; + this.generatorSettings = generatorSettings; + } + } + + public static class Context extends StemContext { + public final Registry biomes; + + public Context(Registry biomes, Holder dimension, + Registry structureSets, + Registry noiseParameters, + Holder generatorSettings) { + super(dimension, structureSets, noiseParameters, generatorSettings); + this.biomes = biomes; + } + } +} diff --git a/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresetSettings.java b/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresetSettings.java new file mode 100644 index 00000000..a3759e43 --- /dev/null +++ b/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresetSettings.java @@ -0,0 +1,48 @@ +package org.betterx.bclib.presets.worldgen; + +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.levelgen.WorldGenSettings; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.Lifecycle; +import org.betterx.bclib.BCLib; + +import java.util.function.Function; + +public abstract class WorldPresetSettings { + public static final ResourceKey>> WORLD_PRESET_SETTINGS_REGISTRY = + createRegistryKey(BCLib.makeID("worldgen/world_preset_settings")); + + public static final Registry> WORLD_PRESET_SETTINGS = + registerSimple(WORLD_PRESET_SETTINGS_REGISTRY); + + public static final Codec CODEC = WORLD_PRESET_SETTINGS + .byNameCodec() + .dispatchStable(WorldPresetSettings::codec, Function.identity()); + + + private static ResourceKey> createRegistryKey(ResourceLocation location) { + + return ResourceKey.createRegistryKey(location); + } + + private static Registry registerSimple(ResourceKey> resourceKey) { + return new MappedRegistry<>(resourceKey, Lifecycle.stable(), null); + } + + public static Codec register(ResourceLocation loc, + Codec codec) { + return Registry.register(WORLD_PRESET_SETTINGS, loc, codec); + } + + public static void bootstrap() { + register(BCLib.makeID("bcl_world_preset_settings"), BCLWorldPresetSettings.CODEC); + } + + public abstract Codec codec(); + public abstract WorldGenSettings repairSettingsOnLoad(RegistryAccess registryAccess, WorldGenSettings settings); +} diff --git a/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresets.java b/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresets.java deleted file mode 100644 index 5444e68a..00000000 --- a/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresets.java +++ /dev/null @@ -1,287 +0,0 @@ -package org.betterx.bclib.presets.worldgen; - -import net.minecraft.core.Holder; -import net.minecraft.core.MappedRegistry; -import net.minecraft.core.Registry; -import net.minecraft.core.RegistryAccess; -import net.minecraft.data.BuiltinRegistries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.WorldPresetTags; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.WorldGenSettings; -import net.minecraft.world.level.levelgen.presets.WorldPreset; -import net.minecraft.world.level.levelgen.structure.StructureSet; -import net.minecraft.world.level.levelgen.synth.NormalNoise; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Lifecycle; -import org.betterx.bclib.BCLib; -import org.betterx.bclib.api.tag.TagAPI; -import org.betterx.bclib.api.tag.TagType; -import org.betterx.bclib.interfaces.ChunkGeneratorAccessor; -import org.betterx.bclib.interfaces.NoiseGeneratorSettingsProvider; -import org.betterx.bclib.world.generator.BCLBiomeSource; -import org.betterx.bclib.world.generator.BCLibEndBiomeSource; -import org.betterx.bclib.world.generator.BCLibNetherBiomeSource; - -import java.util.Map; -import java.util.Optional; -import org.jetbrains.annotations.NotNull; - -public class WorldPresets { - @NotNull - public static LevelStem getBCLNetherLevelStem(Registry biomes, - Holder dimension, - Registry structureSets, - Registry noiseParameters, - Holder generatorSettings, - Optional version) { - BCLibNetherBiomeSource netherSource = new BCLibNetherBiomeSource(biomes, version); - LevelStem bclNether = new LevelStem( - dimension, - new BCLChunkGenerator( - structureSets, - noiseParameters, - netherSource, - generatorSettings) - ); - return bclNether; - } - - @NotNull - public static LevelStem getBCLEndLevelStem(Registry biomes, - Holder dimension, - Registry structureSets, - Registry noiseParameters, - Holder generatorSettings, - Optional version) { - BCLibEndBiomeSource netherSource = new BCLibEndBiomeSource(biomes, version); - LevelStem bclEnd = new LevelStem( - dimension, - new BCLChunkGenerator( - structureSets, - noiseParameters, - netherSource, - generatorSettings) - ); - return bclEnd; - } - - public static class SortableWorldPreset extends WorldPreset { - public final int sortOrder; - - public SortableWorldPreset(Map, LevelStem> map, int sortOrder) { - super(map); - this.sortOrder = sortOrder; - } - } - - public static final TagType.Simple WORLD_PRESETS = - TagAPI.registerType(BuiltinRegistries.WORLD_PRESET, "tags/worldgen/world_preset"); - - public static final ResourceKey BCL_WORLD = register(BCLib.makeID("normal")); - public static final ResourceKey BCL_WORLD_17 = register(BCLib.makeID("legacy_17"), false); - - public static Optional> DEFAULT = Optional.of(BCL_WORLD); - - public static WorldGenSettings createWorldFromPreset(ResourceKey preset, - RegistryAccess registryAccess, - long seed, - boolean generateStructures, - boolean generateBonusChest) { - WorldGenSettings settings = registryAccess - .registryOrThrow(Registry.WORLD_PRESET_REGISTRY) - .getHolderOrThrow(preset) - .value() - .createWorldGenSettings(seed, generateStructures, generateBonusChest); - - for (LevelStem stem : settings.dimensions()) { - if (stem.generator().getBiomeSource() instanceof BCLBiomeSource bcl) { - bcl.setSeed(seed); - } - } - - return settings; - } - - public static WorldGenSettings createDefaultWorldFromPreset(RegistryAccess registryAccess, - long seed, - boolean generateStructures, - boolean generateBonusChest) { - return createWorldFromPreset(DEFAULT.orElseThrow(), - registryAccess, - seed, - generateStructures, - generateBonusChest); - } - - public static Pair defaultWorldDataSupplier(RegistryAccess.Frozen frozen) { - WorldGenSettings worldGenSettings = createDefaultWorldFromPreset(frozen); - return Pair.of(worldGenSettings, frozen); - } - - public static WorldGenSettings createDefaultWorldFromPreset(RegistryAccess registryAccess, long seed) { - return createDefaultWorldFromPreset(registryAccess, seed, true, false); - } - - public static WorldGenSettings createDefaultWorldFromPreset(RegistryAccess registryAccess) { - return createDefaultWorldFromPreset(registryAccess, RandomSource.create().nextLong()); - } - - /** - * Datapacks can change the world's generator. This Method will ensure, that the Generators contain - * the correct BiomeSources for this world - * - * @param dimensionKey - * @param dimensionTypeKey - * @param settings - * @return - */ - public static WorldGenSettings fixSettingsInCurrentWorld(ResourceKey dimensionKey, - ResourceKey dimensionTypeKey, - WorldGenSettings settings) { - var oldNether = settings.dimensions().getHolder(dimensionKey); - int loaderVersion = BCLChunkGenerator.getBiomeVersionForGenerator(oldNether - .map(h -> h.value().generator()) - .orElse(null)); - - int targetVersion = BCLChunkGenerator.getBiomeVersionForCurrentWorld(dimensionKey); - if (loaderVersion != targetVersion) { - BCLib.LOGGER.info("Enforcing Correct Generator for " + dimensionKey.location().toString() + "."); - var chunkGenerator = oldNether.map(h -> h.value().generator()).orElse(null); - RegistryAccess access = RegistryAccess.builtinCopy(); - Optional> refLevelStem = BCLChunkGenerator.referenceStemForVersion( - dimensionKey, - targetVersion, - access, - settings.seed(), - settings.generateStructures(), - settings.generateStructures() - ); - - ChunkGenerator referenceGenerator = refLevelStem.map(h -> h.value().generator()).orElse(null); - if (referenceGenerator == null) { - BCLib.LOGGER.error("Failed to create Generator for " + dimensionKey.location().toString()); - return settings; - } - - if (chunkGenerator instanceof ChunkGeneratorAccessor generator) { - if (chunkGenerator instanceof NoiseGeneratorSettingsProvider noiseProvider) { - //TODO: Make sure our BiomeSource reuses the BiomeList from the Datapack Source - referenceGenerator = new BCLChunkGenerator(generator.bclib_getStructureSetsRegistry(), - noiseProvider.bclib_getNoises(), - referenceGenerator.getBiomeSource(), - noiseProvider.bclib_getNoiseGeneratorSettingHolders()); - } - } - - return WorldPresets.replaceGenerator(dimensionKey, - dimensionTypeKey, - access, - settings, - referenceGenerator); - } - return settings; - } - - public static WorldGenSettings replaceGenerator( - ResourceKey dimensionKey, - ResourceKey dimensionTypeKey, - int biomeSourceVersion, - RegistryAccess registryAccess, - WorldGenSettings worldGenSettings - ) { - Optional> oLevelStem = BCLChunkGenerator.referenceStemForVersion( - dimensionKey, - biomeSourceVersion, - registryAccess, - worldGenSettings.seed(), - worldGenSettings.generateStructures(), - worldGenSettings.generateStructures() - ); - return replaceGenerator(dimensionKey, - dimensionTypeKey, - registryAccess, - worldGenSettings, - oLevelStem.map(l -> l.value().generator()).orElseThrow()); - } - - public static WorldGenSettings replaceGenerator( - ResourceKey dimensionKey, - ResourceKey dimensionTypeKey, - RegistryAccess registryAccess, - WorldGenSettings worldGenSettings, - ChunkGenerator generator - ) { - Registry registry = registryAccess.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); - Registry registry2 = withDimension(dimensionKey, dimensionTypeKey, registry, - worldGenSettings.dimensions(), - generator); - return new WorldGenSettings(worldGenSettings.seed(), - worldGenSettings.generateStructures(), - worldGenSettings.generateBonusChest(), - registry2); - } - - public static Registry withDimension(ResourceKey dimensionKey, - ResourceKey dimensionTypeKey, - Registry registry, - Registry registry2, - ChunkGenerator chunkGenerator) { - LevelStem levelStem = registry2.get(dimensionKey); - Holder holder = levelStem == null - ? registry.getOrCreateHolderOrThrow(dimensionTypeKey) - : levelStem.typeHolder(); - return withDimension(dimensionKey, registry2, holder, chunkGenerator); - } - - public static Registry withDimension(ResourceKey dimensionKey, Registry registry, - Holder holder, - ChunkGenerator chunkGenerator) { - MappedRegistry writableRegistry = new MappedRegistry(Registry.LEVEL_STEM_REGISTRY, - Lifecycle.experimental(), - null); - writableRegistry.register(dimensionKey, - new LevelStem(holder, chunkGenerator), - Lifecycle.stable()); - for (Map.Entry, LevelStem> entry : registry.entrySet()) { - ResourceKey resourceKey = entry.getKey(); - if (resourceKey == dimensionKey) continue; - writableRegistry.register(resourceKey, - entry.getValue(), - registry.lifecycle(entry.getValue())); - } - return writableRegistry; - } - - /** - * Registers a custom WorldPreset (with custom rules and behaviour) - *

- * See also {@link org.betterx.bclib.client.presets.WorldPresetsUI} if you need to add a Customize Button/Screen - * for your preset - * - * @param loc The ID of your Preset - * @return The key you may use to reference your new Preset - */ - public static ResourceKey register(ResourceLocation loc) { - return register(loc, true); - } - - private static ResourceKey register(ResourceLocation loc, boolean addToNormal) { - ResourceKey key = ResourceKey.create(Registry.WORLD_PRESET_REGISTRY, loc); - if (addToNormal) { - WORLD_PRESETS.addUntyped(WorldPresetTags.NORMAL, key.location()); - } - - return key; - } - - public static void registerPresets() { - } -} diff --git a/src/main/java/org/betterx/bclib/util/ModUtil.java b/src/main/java/org/betterx/bclib/util/ModUtil.java index e3d4a681..63d30e73 100644 --- a/src/main/java/org/betterx/bclib/util/ModUtil.java +++ b/src/main/java/org/betterx/bclib/util/ModUtil.java @@ -56,7 +56,7 @@ public class ModUtil { private static ModMetadata readJSON(InputStream is, String sourceFile) throws IOException { try (com.google.gson.stream.JsonReader reader = new JsonReader(new InputStreamReader(is, - StandardCharsets.UTF_8))) { + StandardCharsets.UTF_8))) { JsonObject data = new JsonParser().parse(reader) .getAsJsonObject(); Version ver; @@ -261,6 +261,8 @@ public class ModUtil { * @return The version of the locally installed Mod */ public static String getModVersion(String modID) { + if (modID == BCLib.TOGETHER_WORLDS) modID = BCLib.MOD_ID; + Optional optional = FabricLoader.getInstance() .getModContainer(modID); if (optional.isPresent()) { diff --git a/src/main/java/org/betterx/bclib/world/biomes/BCLBiome.java b/src/main/java/org/betterx/bclib/world/biomes/BCLBiome.java index 29cc75f2..c3b123cb 100644 --- a/src/main/java/org/betterx/bclib/world/biomes/BCLBiome.java +++ b/src/main/java/org/betterx/bclib/world/biomes/BCLBiome.java @@ -232,8 +232,8 @@ public class BCLBiome extends BCLBiomeSettings { public void afterRegistration() { if (!this.structureTags.isEmpty()) { structureTags.forEach(tagKey -> - TagAPI.addBiomeTag(tagKey, biome) - ); + TagAPI.addBiomeTag(tagKey, biome) + ); } if (this.surfaceInit != null) { @@ -358,4 +358,13 @@ public class BCLBiome extends BCLBiomeSettings { } private final boolean didLoadConfig = false; + + public boolean isEdgeBiome() { + if (getParentBiome() == null) return false; + return getParentBiome().edge == this; + } + + public boolean allowFabricRegistration() { + return !isEdgeBiome(); + } } diff --git a/src/main/java/org/betterx/bclib/world/generator/BCLBiomeSource.java b/src/main/java/org/betterx/bclib/world/generator/BCLBiomeSource.java index feac7454..53bd5ffd 100644 --- a/src/main/java/org/betterx/bclib/world/generator/BCLBiomeSource.java +++ b/src/main/java/org/betterx/bclib/world/generator/BCLBiomeSource.java @@ -2,13 +2,16 @@ package org.betterx.bclib.world.generator; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSource; +import com.google.common.collect.Sets; import org.betterx.bclib.api.biomes.BiomeAPI; import java.util.List; import java.util.Optional; +import java.util.Set; public abstract class BCLBiomeSource extends BiomeSource { public static int BIOME_SOURCE_VERSION_NONE = -1; @@ -66,4 +69,34 @@ public abstract class BCLBiomeSource extends BiomeSource { return BCLBiomeSource.BIOME_SOURCE_VERSION_VANILLA; } } + + public BCLBiomeSource createCopyForDatapack(Set> datapackBiomes) { + Set> mutableSet = Sets.newHashSet(); + mutableSet.addAll(datapackBiomes); + return cloneForDatapack(mutableSet); + } + + protected abstract BCLBiomeSource cloneForDatapack(Set> datapackBiomes); + + public interface ValidBiomePredicate { + boolean isValid(Holder biome, ResourceLocation location); + } + + protected static List> getBiomes(Registry biomeRegistry, + List exclude, + List include, + BCLibNetherBiomeSource.ValidBiomePredicate test) { + return biomeRegistry.stream() + .filter(biome -> biomeRegistry.getResourceKey(biome).isPresent()) + .map(biome -> biomeRegistry.getOrCreateHolderOrThrow(biomeRegistry.getResourceKey(biome) + .get())) + .filter(biome -> { + ResourceLocation location = biome.unwrapKey().orElseThrow().location(); + final String strLocation = location.toString(); + if (exclude.contains(strLocation)) return false; + if (include.contains(strLocation)) return true; + + return test.isValid(biome, location); + }).toList(); + } } diff --git a/src/main/java/org/betterx/bclib/world/generator/BCLibEndBiomeSource.java b/src/main/java/org/betterx/bclib/world/generator/BCLibEndBiomeSource.java index e4daba4a..747d3c11 100644 --- a/src/main/java/org/betterx/bclib/world/generator/BCLibEndBiomeSource.java +++ b/src/main/java/org/betterx/bclib/world/generator/BCLibEndBiomeSource.java @@ -27,8 +27,10 @@ import org.betterx.bclib.world.generator.map.hex.HexBiomeMap; import org.betterx.bclib.world.generator.map.square.SquareBiomeMap; import java.awt.*; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.function.Function; public class BCLibEndBiomeSource extends BCLBiomeSource { @@ -72,7 +74,15 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { } private BCLibEndBiomeSource(Registry biomeRegistry, long seed, Optional version, boolean initMaps) { - super(biomeRegistry, getBiomes(biomeRegistry), seed, version); + this(biomeRegistry, getBiomes(biomeRegistry), seed, version, initMaps); + } + + private BCLibEndBiomeSource(Registry biomeRegistry, + List> list, + long seed, + Optional version, + boolean initMaps) { + super(biomeRegistry, list, seed, version); endLandBiomePicker = new BiomePicker(biomeRegistry); endVoidBiomePicker = new BiomePicker(biomeRegistry); @@ -122,39 +132,47 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { } } - private static List> getBiomes(Registry biomeRegistry) { - List includeLand = Configs.BIOMES_CONFIG.getEntry("force_include", + protected BCLBiomeSource cloneForDatapack(Set> datapackBiomes) { + datapackBiomes.addAll(getBclBiomes(this.biomeRegistry)); + return new BCLibEndBiomeSource(this.biomeRegistry, + datapackBiomes.stream().toList(), + this.currentSeed, + Optional.of(biomeSourceVersion), + true); + } + + private static List> getBclBiomes(Registry biomeRegistry) { + List include = Configs.BIOMES_CONFIG.getEntry("force_include", "end_land_biomes", StringArrayEntry.class).getValue(); - List includeVoid = Configs.BIOMES_CONFIG.getEntry("force_include", + include.addAll(Configs.BIOMES_CONFIG.getEntry("force_include", "end_void_biomes", + StringArrayEntry.class).getValue()); + + return getBiomes(biomeRegistry, new ArrayList<>(0), include, BCLibEndBiomeSource::isValidBCLEndBiome); + } + + private static List> getBiomes(Registry biomeRegistry) { + List include = Configs.BIOMES_CONFIG.getEntry("force_include", + "end_land_biomes", StringArrayEntry.class).getValue(); + include.addAll(Configs.BIOMES_CONFIG.getEntry("force_include", + "end_void_biomes", + StringArrayEntry.class).getValue()); - return biomeRegistry.stream() - .filter(biome -> biomeRegistry.getResourceKey(biome).isPresent()) - .map(biome -> biomeRegistry.getOrCreateHolderOrThrow(biomeRegistry.getResourceKey(biome) - .get())) - .filter(biome -> { - ResourceLocation key = biome.unwrapKey().orElseThrow().location(); + return getBiomes(biomeRegistry, new ArrayList<>(0), include, BCLibEndBiomeSource::isValidEndBiome); + } - if (includeLand.contains(key.toString()) || includeVoid.contains(key.toString())) { - return true; - } + private static boolean isValidEndBiome(Holder biome, ResourceLocation location) { + return biome.is(BiomeTags.IS_END) || + BiomeAPI.wasRegisteredAsEndBiome(location); + } - final boolean isEndBiome = biome.is(BiomeTags.IS_END) || - BiomeAPI.wasRegisteredAsEndBiome(key); - - - BCLBiome bclBiome = BiomeAPI.getBiome(key); - if (bclBiome != BiomeAPI.EMPTY_BIOME) { - if (bclBiome.getParentBiome() != null) { - bclBiome = bclBiome.getParentBiome(); - } - key = bclBiome.getID(); - } - return isEndBiome; - }).toList(); + private static boolean isValidBCLEndBiome(Holder biome, ResourceLocation location) { + return biome.is(BiomeTags.IS_END) || + BiomeAPI.wasRegisteredAs(location, BiomeAPI.Dimension.BCL_END_LAND) || + BiomeAPI.wasRegisteredAs(location, BiomeAPI.Dimension.BCL_END_VOID); } public static float getLegacyHeightValue(SimplexNoise simplexNoise, int i, int j) { diff --git a/src/main/java/org/betterx/bclib/world/generator/BCLibNetherBiomeSource.java b/src/main/java/org/betterx/bclib/world/generator/BCLibNetherBiomeSource.java index ef84d0fd..fae0878b 100644 --- a/src/main/java/org/betterx/bclib/world/generator/BCLibNetherBiomeSource.java +++ b/src/main/java/org/betterx/bclib/world/generator/BCLibNetherBiomeSource.java @@ -26,6 +26,7 @@ import org.betterx.bclib.world.generator.map.square.SquareBiomeMap; import java.util.List; import java.util.Optional; +import java.util.Set; public class BCLibNetherBiomeSource extends BCLBiomeSource { private static int lastWorldHeight; @@ -65,7 +66,15 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { long seed, Optional version, boolean initMaps) { - super(biomeRegistry, getBiomes(biomeRegistry), seed, version); + this(biomeRegistry, getBiomes(biomeRegistry), seed, version, initMaps); + } + + private BCLibNetherBiomeSource(Registry biomeRegistry, + List> list, + long seed, + Optional version, + boolean initMaps) { + super(biomeRegistry, list, seed, version); biomePicker = new BiomePicker(biomeRegistry); @@ -77,6 +86,7 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { biomePicker.addBiome(bclBiome); } else { BCLBiome bclBiome = BiomeAPI.getBiome(key); + if (bclBiome != BiomeAPI.EMPTY_BIOME) { if (bclBiome.getParentBiome() == null) { biomePicker.addBiome(bclBiome); @@ -91,6 +101,15 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { } } + protected BCLBiomeSource cloneForDatapack(Set> datapackBiomes) { + datapackBiomes.addAll(getBclBiomes(this.biomeRegistry)); + return new BCLibNetherBiomeSource(this.biomeRegistry, + datapackBiomes.stream().toList(), + this.currentSeed, + Optional.of(biomeSourceVersion), + true); + } + /** * Set world height, used when Nether is larger than vanilla 128 blocks tall. * @@ -100,27 +119,34 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { BCLibNetherBiomeSource.worldHeight = worldHeight; } + private static List> getBclBiomes(Registry biomeRegistry) { + List include = Configs.BIOMES_CONFIG.getEntry("force_include", "nether_biomes", StringArrayEntry.class) + .getValue(); + List exclude = Configs.BIOMES_CONFIG.getEntry("force_exclude", "nether_biomes", StringArrayEntry.class) + .getValue(); + + return getBiomes(biomeRegistry, exclude, include, BCLibNetherBiomeSource::isValidBCLNetherBiome); + } + + private static List> getBiomes(Registry biomeRegistry) { List include = Configs.BIOMES_CONFIG.getEntry("force_include", "nether_biomes", StringArrayEntry.class) .getValue(); List exclude = Configs.BIOMES_CONFIG.getEntry("force_exclude", "nether_biomes", StringArrayEntry.class) .getValue(); - return biomeRegistry.stream() - .filter(biome -> biomeRegistry.getResourceKey(biome).isPresent()) - .map(biome -> biomeRegistry.getOrCreateHolderOrThrow(biomeRegistry.getResourceKey(biome) - .get())) - .filter(biome -> { - ResourceLocation location = biome.unwrapKey().orElseThrow().location(); - final String strLocation = location.toString(); - if (exclude.contains(strLocation)) return false; - if (include.contains(strLocation)) return true; + return getBiomes(biomeRegistry, exclude, include, BCLibNetherBiomeSource::isValidNetherBiome); + } - return - NetherBiomeData.canGenerateInNether(biome.unwrapKey().get()) || - biome.is(BiomeTags.IS_NETHER) || - BiomeAPI.wasRegisteredAsNetherBiome(location); - }).toList(); + + private static boolean isValidNetherBiome(Holder biome, ResourceLocation location) { + return NetherBiomeData.canGenerateInNether(biome.unwrapKey().get()) || + biome.is(BiomeTags.IS_NETHER) || + BiomeAPI.wasRegisteredAsNetherBiome(location); + } + + private static boolean isValidBCLNetherBiome(Holder biome, ResourceLocation location) { + return BiomeAPI.wasRegisteredAs(location, BiomeAPI.Dimension.BCL_NETHER); } public static void debug(Object el, Registry reg) { diff --git a/src/main/java/org/betterx/bclib/world/generator/BiomePicker.java b/src/main/java/org/betterx/bclib/world/generator/BiomePicker.java index 9cfbe213..d5545b6c 100644 --- a/src/main/java/org/betterx/bclib/world/generator/BiomePicker.java +++ b/src/main/java/org/betterx/bclib/world/generator/BiomePicker.java @@ -18,6 +18,53 @@ import java.util.Objects; public class BiomePicker { public final Map all = new HashMap<>(); + public final Registry biomeRegistry; + private final List biomes = Lists.newArrayList(); + private final List allowedBiomes; + private WeighTree tree; + + public BiomePicker(Registry biomeRegistry) { + this(biomeRegistry, null); + } + + public BiomePicker(Registry biomeRegistry, List> allowedBiomes) { + this.biomeRegistry = biomeRegistry; + this.allowedBiomes = allowedBiomes != null ? allowedBiomes + .stream() + .map(h -> h.unwrapKey()) + .filter(o -> o.isPresent()) + .map(o -> o.get().location().toString()).toList() : null; + } + + private boolean isAllowed(BCLBiome b) { + if (allowedBiomes == null) return true; + return allowedBiomes.contains(b.getID().toString()); + } + + private ActualBiome create(BCLBiome bclBiome) { + ActualBiome e = all.get(bclBiome); + if (e != null) return e; + return new ActualBiome(bclBiome); + } + + public void addBiome(BCLBiome biome) { + biomes.add(create(biome)); + } + + public ActualBiome getBiome(WorldgenRandom random) { + return biomes.isEmpty() ? null : tree.get(random); + } + + public void rebuild() { + if (biomes.isEmpty()) { + return; + } + WeightedList list = new WeightedList<>(); + biomes.forEach(biome -> { + list.add(biome, biome.bclBiome.getGenChance()); + }); + tree = new WeighTree<>(list); + } public class ActualBiome { public final BCLBiome bclBiome; @@ -36,10 +83,16 @@ public class BiomePicker { this.biome = biomeRegistry.getOrCreateHolderOrThrow(key); bclBiome.forEachSubBiome((b, w) -> { - subbiomes.add(create(b), w); + if (isAllowed(b)) + subbiomes.add(create(b), w); }); - edge = bclBiome.getEdge() != null ? create(bclBiome.getEdge()) : null; + if (bclBiome.getEdge() != null && isAllowed(bclBiome.getEdge())) { + edge = create(bclBiome.getEdge()); + } else { + edge = null; + } + parent = bclBiome.getParentBiome() != null ? create(bclBiome.getParentBiome()) : null; } @@ -72,37 +125,4 @@ public class BiomePicker { return bclBiome.isSame(e.bclBiome); } } - - private ActualBiome create(BCLBiome bclBiome) { - ActualBiome e = all.get(bclBiome); - if (e != null) return e; - return new ActualBiome(bclBiome); - } - - private final List biomes = Lists.newArrayList(); - public final Registry biomeRegistry; - private WeighTree tree; - - public BiomePicker(Registry biomeRegistry) { - this.biomeRegistry = biomeRegistry; - } - - public void addBiome(BCLBiome biome) { - biomes.add(create(biome)); - } - - public ActualBiome getBiome(WorldgenRandom random) { - return biomes.isEmpty() ? null : tree.get(random); - } - - public void rebuild() { - if (biomes.isEmpty()) { - return; - } - WeightedList list = new WeightedList<>(); - biomes.forEach(biome -> { - list.add(biome, biome.bclBiome.getGenChance()); - }); - tree = new WeighTree<>(list); - } } diff --git a/src/main/resources/bclib.mixins.common.json b/src/main/resources/bclib.mixins.common.json index 7c0a96bf..e33e50e7 100644 --- a/src/main/resources/bclib.mixins.common.json +++ b/src/main/resources/bclib.mixins.common.json @@ -23,7 +23,6 @@ "MainMixin", "MinecraftServerMixin", "MobSpawnSettingsAccessor", - "MultiPackResourceManagerMixin", "NetherBiomeDataMixin", "NoiseBasedChunkGeneratorMixin", "NoiseGeneratorSettingsMixin", @@ -34,6 +33,7 @@ "PrimaryLevelDataMixin", "RecipeManagerAccessor", "RecipeManagerMixin", + "RegistryOpsAccessor", "ServerLevelMixin", "ShovelItemAccessor", "StructuresAccessor",