diff --git a/src/main/java/org/betterx/bclib/BCLib.java b/src/main/java/org/betterx/bclib/BCLib.java index 1e412b1b..57d3aeb5 100644 --- a/src/main/java/org/betterx/bclib/BCLib.java +++ b/src/main/java/org/betterx/bclib/BCLib.java @@ -37,6 +37,7 @@ public class BCLib implements ModInitializer { TagAPI.init(); CraftingRecipes.init(); WorldDataAPI.registerModCache(MOD_ID); + WorldDataAPI.registerModCache(MOD_ID); DataExchangeAPI.registerMod(MOD_ID); WorldPresets.registerPresets(); AnvilRecipe.register(); diff --git a/src/main/java/org/betterx/bclib/BCLibPatch.java b/src/main/java/org/betterx/bclib/BCLibPatch.java index 8e28cf25..56887bc6 100644 --- a/src/main/java/org/betterx/bclib/BCLibPatch.java +++ b/src/main/java/org/betterx/bclib/BCLibPatch.java @@ -1,13 +1,27 @@ package org.betterx.bclib; +import net.minecraft.core.Holder; +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.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldGenSettings; +import com.mojang.serialization.Dynamic; 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.util.MHelper; import org.betterx.bclib.world.generator.GeneratorOptions; +import java.util.Optional; + public final class BCLibPatch { public static void register() { // TODO separate values in config on client side (config screen) @@ -27,30 +41,110 @@ final class BiomeSourcePatch extends ForcedLevelPatch { super(BCLib.MOD_ID, "1.2.1"); } + @Override protected Boolean runLevelDatPatch(CompoundTag root, MigrationProfile profile) { - CompoundTag worldGenSettings = root.getCompound("Data").getCompound("WorldGenSettings"); - CompoundTag dimensions = worldGenSettings.getCompound("dimensions"); - long seed = worldGenSettings.getLong("seed"); + //make sure we have a working generators file before attempting to patch + BCLChunkGenerator.migrateGeneratorSettings(); + + final CompoundTag worldGenSettings = root.getCompound("Data").getCompound("WorldGenSettings"); + final CompoundTag dimensions = worldGenSettings.getCompound("dimensions"); + final RegistryAccess registryAccess = RegistryAccess.builtinCopy(); + final RegistryOps registryOps = RegistryOps.create(NbtOps.INSTANCE, registryAccess); + + boolean result = false; - if (GeneratorOptions.fixNetherBiomeSource()) { - if (!dimensions.contains(MC_NETHER) || !isBCLibEntry(dimensions.getCompound(MC_NETHER))) { - CompoundTag dimRoot = new CompoundTag(); - dimRoot.put("generator", makeNetherGenerator(seed)); - dimRoot.putString("type", MC_NETHER); - dimensions.put(MC_NETHER, dimRoot); - result = true; - } - } + result |= checkDimension(worldGenSettings, dimensions, registryAccess, registryOps, LevelStem.NETHER); + result |= checkDimension(worldGenSettings, dimensions, registryAccess, registryOps, LevelStem.END); - if (GeneratorOptions.fixEndBiomeSource()) { - if (!dimensions.contains(MC_END) || !isBCLibEntry(dimensions.getCompound(MC_END))) { - CompoundTag dimRoot = new CompoundTag(); - dimRoot.put("generator", makeEndGenerator(seed)); - dimRoot.putString("type", MC_END); - dimensions.put(MC_END, dimRoot); - result = true; + System.out.println("Dimensions:" + dimensions); + return result; +// if (root != null) return false; +// +// boolean result = false; +// +// if (GeneratorOptions.fixNetherBiomeSource()) { +// if (!dimensions.contains(MC_NETHER) || !isBCLibEntry(dimensions.getCompound(MC_NETHER))) { +// CompoundTag dimRoot = new CompoundTag(); +// dimRoot.put("generator", makeNetherGenerator(seed)); +// dimRoot.putString("type", MC_NETHER); +// dimensions.put(MC_NETHER, dimRoot); +// result = true; +// } +// } +// +// if (GeneratorOptions.fixEndBiomeSource()) { +// if (!dimensions.contains(MC_END) || !isBCLibEntry(dimensions.getCompound(MC_END))) { +// CompoundTag dimRoot = new CompoundTag(); +// dimRoot.put("generator", makeEndGenerator(seed)); +// dimRoot.putString("type", MC_END); +// dimensions.put(MC_END, dimRoot); +// result = true; +// } +// } +// +// return result; + } + + private boolean checkDimension(CompoundTag worldGenSettings, + CompoundTag dimensions, + RegistryAccess registryAccess, + RegistryOps registryOps, + ResourceKey dimensionKey + ) { + + final long seed = worldGenSettings.contains("seed") + ? worldGenSettings.getLong("seed") + : MHelper.RANDOM.nextLong(); + + final boolean genStructures = worldGenSettings.contains("generate_features") ? worldGenSettings.getBoolean( + "generate_features") : true; + + final boolean genBonusChest = worldGenSettings.contains("bonus_chest") ? worldGenSettings.getBoolean( + "bonus_chest") : false; + + boolean result = false; + CompoundTag dimensionTag = dimensions.getCompound(dimensionKey.location().toString()); + 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); + if (biomeSourceVersion != targetVersion) { + Optional> refLevelStem = BCLChunkGenerator.referenceStemForVersion( + dimensionKey, + targetVersion, + registryAccess, + oWorldGen.map(g -> g.seed()).orElse(seed), + oWorldGen.map(g -> g.generateStructures()).orElse(genStructures), + oWorldGen.map(g -> g.generateBonusChest()).orElse(genBonusChest) + ); + + BCLib.LOGGER.warning("The world uses the BiomeSource Version " + biomeSourceVersion + " but should have " + targetVersion + "."); + BCLib.LOGGER.warning("Dimension: " + dimensionKey); + BCLib.LOGGER.warning("Found: " + netherGenerator); + BCLib.LOGGER.warning("Should: " + refLevelStem.map(l -> l.value().generator())); + + if (refLevelStem.isPresent()) { + var levelStem = refLevelStem.get(); + BCLib.LOGGER.warning("Repairing level.dat in order to ensure world continuity."); + var codec = LevelStem.CODEC.orElse(levelStem.value()); + var encodeResult = codec.encodeStart(registryOps, levelStem.value()); + if (encodeResult.result().isPresent()) { + dimensions.put(dimensionKey.location().toString(), encodeResult.result().get()); + result = true; + } else { + BCLib.LOGGER.error("Unable to encode '" + dimensionKey + "' generator for level.dat."); + } + } else { + BCLib.LOGGER.error("Unable to update '" + dimensionKey + "' generator in level.dat."); } } diff --git a/src/main/java/org/betterx/bclib/api/WorldDataAPI.java b/src/main/java/org/betterx/bclib/api/WorldDataAPI.java index 0cad8947..909589f7 100644 --- a/src/main/java/org/betterx/bclib/api/WorldDataAPI.java +++ b/src/main/java/org/betterx/bclib/api/WorldDataAPI.java @@ -30,6 +30,9 @@ import java.util.function.Consumer; public class WorldDataAPI { private static final Map TAGS = Maps.newHashMap(); private static final List MODS = Lists.newArrayList(); + + private static final String TAG_CREATED = "create_version"; + private static final String TAG_MODIFIED = "modify_version"; private static File dataDir; public static void load(File dataDir) { @@ -84,11 +87,16 @@ public class WorldDataAPI { CompoundTag root = TAGS.get(modID); if (root == null) { root = new CompoundTag(); + root.putString(TAG_CREATED, ModUtil.getModVersion(modID)); TAGS.put(modID, root); } return root; } + public static boolean hasMod(String modID) { + return MODS.contains(modID); + } + /** * Get {@link CompoundTag} with specified path from mod cache in world data folder. * @@ -120,7 +128,9 @@ public class WorldDataAPI { if (!dataDir.exists()) { dataDir.mkdirs(); } - NbtIo.writeCompressed(getRootTag(modID), new File(dataDir, modID + ".nbt")); + CompoundTag tag = getRootTag(modID); + tag.putString(TAG_MODIFIED, ModUtil.getModVersion(modID)); + NbtIo.writeCompressed(tag, new File(dataDir, modID + ".nbt")); } catch (IOException e) { BCLib.LOGGER.error("World data saving failed", e); } 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 237b9ef4..6d5db612 100644 --- a/src/main/java/org/betterx/bclib/api/datafixer/DataFixerAPI.java +++ b/src/main/java/org/betterx/bclib/api/datafixer/DataFixerAPI.java @@ -3,12 +3,12 @@ package org.betterx.bclib.api.datafixer; import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.toasts.SystemToast; -import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.worldselection.EditWorldScreen; import net.minecraft.nbt.*; import net.minecraft.network.chat.Component; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.storage.RegionFile; +import net.minecraft.world.level.levelgen.WorldGenSettings; import net.minecraft.world.level.storage.LevelResource; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess; @@ -24,6 +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.util.Logger; import java.io.*; @@ -160,6 +161,13 @@ public class DataFixerAPI { }); } + public static void createWorldData(LevelStorageSource levelSource, String levelID, WorldGenSettings settings) { + wrapCall(levelSource, levelID, (levelStorageAccess) -> { + createWorldData(levelStorageAccess, settings); + return true; + }); + } + /** * Initializes the DataStorage for this world. If the world is new, the patch registry is initialized to the * current versions of the plugins. @@ -171,6 +179,12 @@ public class DataFixerAPI { initializeWorldData(access.getLevelPath(LevelResource.ROOT).toFile(), newWorld); } + public static void createWorldData(LevelStorageAccess access, WorldGenSettings settings) { + initializeWorldData(access, true); + BCLChunkGenerator.initializeWorldData(settings); + WorldDataAPI.saveFile(BCLib.MOD_ID); + } + /** * Initializes the DataStorage for this world. If the world is new, the patch registry is initialized to the * current versions of the plugins. @@ -190,8 +204,8 @@ public class DataFixerAPI { @Environment(EnvType.CLIENT) private static AtomicProgressListener showProgressScreen() { ProgressScreen ps = new ProgressScreen(Minecraft.getInstance().screen, - Component.translatable("title.bclib.datafixer.progress"), - Component.translatable("message.bclib.datafixer.progress")); + Component.translatable("title.bclib.datafixer.progress"), + Component.translatable("message.bclib.datafixer.progress")); Minecraft.getInstance().setScreen(ps); return ps; } @@ -298,8 +312,8 @@ public class DataFixerAPI { private static void showLevelFixErrorScreen(State state, Listener onContinue) { Minecraft.getInstance() .setScreen(new LevelFixErrorScreen(Minecraft.getInstance().screen, - state.getErrorMessages(), - onContinue)); + state.getErrorMessages(), + onContinue)); } private static MigrationProfile loadProfileIfNeeded(File levelBaseDir) { @@ -511,8 +525,8 @@ public class DataFixerAPI { try { changed[0] |= data.patchBlockState(palette, - ((CompoundTag) tag).getList("BlockStates", - Tag.TAG_LONG)); + ((CompoundTag) tag).getList("BlockStates", + Tag.TAG_LONG)); } catch (PatchDidiFailException e) { BCLib.LOGGER.error("Failed fixing BlockState in " + pos); state.addError("Failed fixing BlockState in " + pos + " (" + e.getMessage() + ")"); diff --git a/src/main/java/org/betterx/bclib/config/GeneratorConfig.java b/src/main/java/org/betterx/bclib/config/GeneratorConfig.java index 8e4e9680..48091087 100644 --- a/src/main/java/org/betterx/bclib/config/GeneratorConfig.java +++ b/src/main/java/org/betterx/bclib/config/GeneratorConfig.java @@ -3,16 +3,8 @@ package org.betterx.bclib.config; import org.betterx.bclib.BCLib; public class GeneratorConfig extends NamedPathConfig { - public static final ConfigToken USE_OLD_GENERATOR = ConfigToken.Boolean(false, - "useOldBiomeGenerator", - "options"); - - public GeneratorConfig() { super(BCLib.MOD_ID, "generator", false); } - public boolean useOldGenerator() { - return get(USE_OLD_GENERATOR); - } } 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 fc58d7ca..eae0c1c2 100644 --- a/src/main/java/org/betterx/bclib/mixin/common/WorldOpenFlowsMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/common/WorldOpenFlowsMixin.java @@ -61,7 +61,7 @@ public abstract class WorldOpenFlowsMixin { DataExchangeAPI.prepareServerside(); BiomeAPI.prepareNewLevel(); - DataFixerAPI.initializeWorldData(this.levelSource, levelID, true); + DataFixerAPI.createWorldData(this.levelSource, levelID, worldGenSettings); LifeCycleAPI._runBeforeLevelLoad(); } @@ -74,7 +74,7 @@ public abstract class WorldOpenFlowsMixin { DataExchangeAPI.prepareServerside(); BiomeAPI.prepareNewLevel(); - DataFixerAPI.initializeWorldData(levelStorageAccess, true); + DataFixerAPI.createWorldData(levelStorageAccess, worldData.worldGenSettings()); LifeCycleAPI._runBeforeLevelLoad(); } } 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 f55cd222..cb194357 100644 --- a/src/main/java/org/betterx/bclib/mixin/common/WorldPresetsBootstrapMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/common/WorldPresetsBootstrapMixin.java @@ -12,6 +12,7 @@ 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.presets.worldgen.BCLChunkGenerator; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -19,6 +20,7 @@ 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 { @@ -51,7 +53,7 @@ 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 = new org.betterx.bclib.presets.worldgen.WorldPresets.SortableWorldPreset( + WorldPreset preset_18 = new org.betterx.bclib.presets.worldgen.WorldPresets.SortableWorldPreset( Map.of(LevelStem.OVERWORLD, overworldStem, LevelStem.NETHER, @@ -59,17 +61,42 @@ public abstract class WorldPresetsBootstrapMixin { this.netherDimensionType, this.structureSets, this.noises, - this.netherNoiseSettings), + this.netherNoiseSettings, + Optional.empty()), LevelStem.END, org.betterx.bclib.presets.worldgen.WorldPresets.getBCLEndLevelStem(this.biomes, this.endDimensionType, this.structureSets, this.noises, - this.endNoiseSettings) + this.endNoiseSettings, + Optional.empty()) ), 0 ); - BuiltinRegistries.register(this.presets, org.betterx.bclib.presets.worldgen.WorldPresets.BCL_WORLD, preset); + 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(BCLChunkGenerator.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(BCLChunkGenerator.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); return overworldStem; } 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 555023ad..dbef40be 100644 --- a/src/main/java/org/betterx/bclib/presets/worldgen/BCLChunkGenerator.java +++ b/src/main/java/org/betterx/bclib/presets/worldgen/BCLChunkGenerator.java @@ -2,19 +2,40 @@ 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 { + public static int BIOME_SOURCE_VERSION_NONE = -1; + public static int BIOME_SOURCE_VERSION_VANILLA = 0; + public static int BIOME_SOURCE_VERSION_SQUARE = 17; + public static int BIOME_SOURCE_VERSION_HEX = 18; + public static int DEFAULT_BIOME_SOURCE_VERSION = BIOME_SOURCE_VERSION_HEX; + + 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 @@ -38,12 +59,12 @@ public class BCLChunkGenerator extends NoiseBasedChunkGenerator { .apply(builderInstance, builderInstance.stable(BCLChunkGenerator::new)); }); - public BCLChunkGenerator(Registry registry, Registry registry2, BiomeSource biomeSource, Holder holder) { super(registry, registry2, biomeSource, holder); + System.out.println("Chunk Generator: " + this); } @Override @@ -58,4 +79,115 @@ public class BCLChunkGenerator extends NoiseBasedChunkGenerator { } return null; } + + public static int getBiomeVersionForGenerator(ChunkGenerator generator) { + if (generator == null) return BIOME_SOURCE_VERSION_NONE; + + if (generator.getBiomeSource() instanceof BCLBiomeSource bcl) { + return bcl.biomeSourceVersion; + } else { + return BIOME_SOURCE_VERSION_VANILLA; + } + } + + public static Optional> referenceStemForVersion( + ResourceKey dimensionKey, + int biomeSourceVersion, + RegistryAccess registryAccess, + long seed, + boolean generateStructures, + boolean generateBonusChest + ) { + final WorldGenSettings referenceSettings; + if (biomeSourceVersion == BIOME_SOURCE_VERSION_VANILLA) { + referenceSettings = net.minecraft.world.level.levelgen.presets.WorldPresets.createNormalWorldFromPreset( + registryAccess, + seed, + generateStructures, + generateBonusChest); + } else if (biomeSourceVersion == 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 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 = 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 = 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)) + ? BIOME_SOURCE_VERSION_SQUARE + : 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/WorldPresets.java b/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresets.java index 112fb2e2..b8d1bdd5 100644 --- a/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresets.java +++ b/src/main/java/org/betterx/bclib/presets/worldgen/WorldPresets.java @@ -21,6 +21,7 @@ import com.mojang.datafixers.util.Pair; 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 org.betterx.bclib.world.generator.BCLibEndBiomeSource; import org.betterx.bclib.world.generator.BCLibNetherBiomeSource; @@ -34,8 +35,9 @@ public class WorldPresets { Holder dimension, Registry structureSets, Registry noiseParameters, - Holder generatorSettings) { - BCLibNetherBiomeSource netherSource = new BCLibNetherBiomeSource(biomes); + Holder generatorSettings, + Optional version) { + BCLibNetherBiomeSource netherSource = new BCLibNetherBiomeSource(biomes, version); LevelStem bclNether = new LevelStem( dimension, new BCLChunkGenerator( @@ -52,8 +54,9 @@ public class WorldPresets { Holder dimension, Registry structureSets, Registry noiseParameters, - Holder generatorSettings) { - BCLibEndBiomeSource netherSource = new BCLibEndBiomeSource(biomes); + Holder generatorSettings, + Optional version) { + BCLibEndBiomeSource netherSource = new BCLibEndBiomeSource(biomes, version); LevelStem bclEnd = new LevelStem( dimension, new BCLChunkGenerator( @@ -78,18 +81,39 @@ public class WorldPresets { 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 registryAccess - .registryOrThrow(Registry.WORLD_PRESET_REGISTRY) - .getHolderOrThrow(DEFAULT.orElseThrow()) - .value() - .createWorldGenSettings(seed, generateStructures, generateBonusChest); + return createWorldFromPreset(DEFAULT.orElseThrow(), + registryAccess, + seed, + generateStructures, + generateBonusChest); } public static Pair defaultWorldDataSupplier(RegistryAccess.Frozen frozen) { @@ -115,8 +139,14 @@ public class WorldPresets { * @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); - WORLD_PRESETS.addUntyped(WorldPresetTags.NORMAL, key.location()); + if (addToNormal) { + WORLD_PRESETS.addUntyped(WorldPresetTags.NORMAL, key.location()); + } return key; } 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 c27f8792..9d7edc87 100644 --- a/src/main/java/org/betterx/bclib/world/generator/BCLBiomeSource.java +++ b/src/main/java/org/betterx/bclib/world/generator/BCLBiomeSource.java @@ -6,29 +6,50 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSource; import org.betterx.bclib.api.biomes.BiomeAPI; +import org.betterx.bclib.presets.worldgen.BCLChunkGenerator; import java.util.List; +import java.util.Optional; public abstract class BCLBiomeSource extends BiomeSource { protected final Registry biomeRegistry; protected long currentSeed; + public final int biomeSourceVersion; + private static List> preInit(Registry biomeRegistry, List> biomes) { biomes.forEach(biome -> BiomeAPI.sortBiomeFeatures(biome)); return biomes; } - protected BCLBiomeSource(Registry biomeRegistry, List> list) { + protected BCLBiomeSource(Registry biomeRegistry, + List> list, + long seed, + Optional biomeSourceVersion) { super(preInit(biomeRegistry, list)); + + this.biomeRegistry = biomeRegistry; + this.biomeSourceVersion = biomeSourceVersion.orElse(BCLChunkGenerator.DEFAULT_BIOME_SOURCE_VERSION); + this.currentSeed = seed; + System.out.println(this + " with Registry: " + biomeRegistry.getClass().getName() + "@" + Integer.toHexString( biomeRegistry.hashCode())); - this.biomeRegistry = biomeRegistry; BiomeAPI.initRegistry(biomeRegistry); } - public void setSeed(long seed) { - System.out.println(this + " set Seed: " + seed); - this.currentSeed = seed; + final public void setSeed(long seed) { + if (seed != currentSeed) { + System.out.println(this + " set Seed: " + seed); + this.currentSeed = seed; + initMap(seed); + } } + + protected final void initMap(long seed) { + System.out.println(this + " updates Map"); + onInitMap(seed); + } + + protected abstract void onInitMap(long newSeed); } 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 dea904a4..ca626fda 100644 --- a/src/main/java/org/betterx/bclib/world/generator/BCLibEndBiomeSource.java +++ b/src/main/java/org/betterx/bclib/world/generator/BCLibEndBiomeSource.java @@ -22,12 +22,14 @@ import org.betterx.bclib.config.ConfigKeeper.StringArrayEntry; import org.betterx.bclib.config.Configs; import org.betterx.bclib.interfaces.BiomeMap; import org.betterx.bclib.noise.OpenSimplexNoise; +import org.betterx.bclib.presets.worldgen.BCLChunkGenerator; import org.betterx.bclib.world.biomes.BCLBiome; import org.betterx.bclib.world.generator.map.hex.HexBiomeMap; import org.betterx.bclib.world.generator.map.square.SquareBiomeMap; import java.awt.*; import java.util.List; +import java.util.Optional; import java.util.function.Function; public class BCLibEndBiomeSource extends BCLBiomeSource { @@ -41,11 +43,16 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { .LONG .fieldOf("seed") .stable() - .forGetter(source -> source.currentSeed)) + .forGetter(source -> source.currentSeed), + Codec + .INT + .optionalFieldOf("version") + .stable() + .forGetter(source -> Optional.of(source.biomeSourceVersion))) .apply(instance, - instance.stable(BCLibEndBiomeSource::new) - ) - ); + instance.stable(BCLibEndBiomeSource::new) + ) + ); private final Holder centerBiome; private final Holder barrens; private final Point pos; @@ -57,20 +64,23 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { private final BiomePicker endLandBiomePicker; private final BiomePicker endVoidBiomePicker; - public BCLibEndBiomeSource(Registry biomeRegistry, long seed) { - this(biomeRegistry); - this.setSeed(seed); + public BCLibEndBiomeSource(Registry biomeRegistry, long seed, Optional version) { + this(biomeRegistry, seed, version, true); } - public BCLibEndBiomeSource(Registry biomeRegistry) { - super(biomeRegistry, getBiomes(biomeRegistry)); + public BCLibEndBiomeSource(Registry biomeRegistry, Optional version) { + this(biomeRegistry, 0, version, false); + } + + private BCLibEndBiomeSource(Registry biomeRegistry, long seed, Optional version, boolean initMaps) { + super(biomeRegistry, getBiomes(biomeRegistry), seed, version); endLandBiomePicker = new BiomePicker(biomeRegistry); endVoidBiomePicker = new BiomePicker(biomeRegistry); List includeVoid = Configs.BIOMES_CONFIG.getEntry("force_include", - "end_void_biomes", - StringArrayEntry.class).getValue(); + "end_void_biomes", + StringArrayEntry.class).getValue(); this.possibleBiomes().forEach(biome -> { ResourceLocation key = biome.unwrapKey().orElseThrow().location(); String group = key.getNamespace() + "." + key.getPath(); @@ -107,15 +117,19 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { this.endLandFunction = GeneratorOptions.getEndLandFunction(); this.pos = new Point(); + + if (initMaps) { + initMap(seed); + } } private static List> getBiomes(Registry biomeRegistry) { List includeLand = Configs.BIOMES_CONFIG.getEntry("force_include", - "end_land_biomes", - StringArrayEntry.class).getValue(); + "end_land_biomes", + StringArrayEntry.class).getValue(); List includeVoid = Configs.BIOMES_CONFIG.getEntry("force_include", - "end_void_biomes", - StringArrayEntry.class).getValue(); + "end_void_biomes", + StringArrayEntry.class).getValue(); return biomeRegistry.stream() .filter(biome -> biomeRegistry.getResourceKey(biome).isPresent()) @@ -171,21 +185,22 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { Registry.register(Registry.BIOME_SOURCE, BCLib.makeID("end_biome_source"), CODEC); } - private void initMap(long seed) { - if (GeneratorOptions.useOldBiomeGenerator()) { + @Override + protected void onInitMap(long seed) { + if ((biomeSourceVersion != BCLChunkGenerator.BIOME_SOURCE_VERSION_HEX)) { this.mapLand = new SquareBiomeMap(seed, - GeneratorOptions.getBiomeSizeEndLand(), - endLandBiomePicker); + GeneratorOptions.getBiomeSizeEndLand(), + endLandBiomePicker); this.mapVoid = new SquareBiomeMap(seed, - GeneratorOptions.getBiomeSizeEndVoid(), - endVoidBiomePicker); + GeneratorOptions.getBiomeSizeEndVoid(), + endVoidBiomePicker); } else { this.mapLand = new HexBiomeMap(seed, - GeneratorOptions.getBiomeSizeEndLand(), - endLandBiomePicker); + GeneratorOptions.getBiomeSizeEndLand(), + endLandBiomePicker); this.mapVoid = new HexBiomeMap(seed, - GeneratorOptions.getBiomeSizeEndVoid(), - endVoidBiomePicker); + GeneratorOptions.getBiomeSizeEndVoid(), + endVoidBiomePicker); } WorldgenRandom chunkRandom = new WorldgenRandom(new LegacyRandomSource(seed)); @@ -193,13 +208,6 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { this.noise = new SimplexNoise(chunkRandom); } - @Override - public void setSeed(long seed) { - if (seed == currentSeed) return; - - super.setSeed(seed); - initMap(seed); - } @Override public Holder getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler sampler) { @@ -221,7 +229,7 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { noise, (biomeX >> 1) + 1, (biomeZ >> 1) + 1 - ) + (float) SMALL_NOISE.eval(biomeX, biomeZ) * 5; + ) + (float) SMALL_NOISE.eval(biomeX, biomeZ) * 5; if (height > -20F && height < -5F) { return barrens; @@ -249,6 +257,6 @@ public class BCLibEndBiomeSource extends BCLBiomeSource { @Override public String toString() { - return "BCLib - The End BiomeSource"; + return "BCLib - The End BiomeSource (" + Integer.toHexString(hashCode()) + ", version=" + biomeSourceVersion + ", seed=" + currentSeed + ")"; } } 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 5a824c0b..bb312867 100644 --- a/src/main/java/org/betterx/bclib/world/generator/BCLibNetherBiomeSource.java +++ b/src/main/java/org/betterx/bclib/world/generator/BCLibNetherBiomeSource.java @@ -19,15 +19,16 @@ import org.betterx.bclib.api.biomes.BiomeAPI; import org.betterx.bclib.config.ConfigKeeper.StringArrayEntry; import org.betterx.bclib.config.Configs; import org.betterx.bclib.interfaces.BiomeMap; +import org.betterx.bclib.presets.worldgen.BCLChunkGenerator; import org.betterx.bclib.world.biomes.BCLBiome; import org.betterx.bclib.world.generator.map.MapStack; import org.betterx.bclib.world.generator.map.hex.HexBiomeMap; import org.betterx.bclib.world.generator.map.square.SquareBiomeMap; import java.util.List; +import java.util.Optional; public class BCLibNetherBiomeSource extends BCLBiomeSource { - private static boolean forceLegacyGenerator = false; private static int lastWorldHeight; private static int worldHeight; public static final Codec CODEC = RecordCodecBuilder @@ -41,15 +42,32 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { .stable() .forGetter(source -> { return source.currentSeed; - }) + }), + Codec + .INT + .optionalFieldOf("version") + .stable() + .forGetter(source -> Optional.of(source.biomeSourceVersion)) ) .apply(instance, instance.stable(BCLibNetherBiomeSource::new)) ); private BiomeMap biomeMap; private final BiomePicker biomePicker; - public BCLibNetherBiomeSource(Registry biomeRegistry) { - super(biomeRegistry, getBiomes(biomeRegistry)); + public BCLibNetherBiomeSource(Registry biomeRegistry, Optional version) { + this(biomeRegistry, 0, version, false); + } + + public BCLibNetherBiomeSource(Registry biomeRegistry, long seed, Optional version) { + this(biomeRegistry, seed, version, true); + } + + private BCLibNetherBiomeSource(Registry biomeRegistry, + long seed, + Optional version, + boolean initMaps) { + super(biomeRegistry, getBiomes(biomeRegistry), seed, version); + biomePicker = new BiomePicker(biomeRegistry); this.possibleBiomes().forEach(biome -> { @@ -69,23 +87,9 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { }); biomePicker.rebuild(); - } - - public BCLibNetherBiomeSource(Registry biomeRegistry, long seed) { - this(biomeRegistry); - setSeed(seed); - } - - /** - * When true, the older square generator is used for the nether. - *

- * This override is used (for example) by BetterNether to force the legacy generation for worlds - * that were created before 1.18 - * - * @param val wether or not you want to force the old generatore. - */ - public static void setForceLegacyGeneration(boolean val) { - forceLegacyGenerator = val; + if (initMaps) { + initMap(seed); + } } /** @@ -128,12 +132,6 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { Registry.register(Registry.BIOME_SOURCE, BCLib.makeID("nether_biome_source"), CODEC); } - @Override - public void setSeed(long seed) { - if (seed == currentSeed) return; - super.setSeed(seed); - initMap(seed); - } @Override public Holder getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler var4) { @@ -156,9 +154,9 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { return CODEC; } - private void initMap(long seed) { - boolean useLegacy = GeneratorOptions.useOldBiomeGenerator() || forceLegacyGenerator; - TriFunction mapConstructor = useLegacy + @Override + protected void onInitMap(long seed) { + TriFunction mapConstructor = (biomeSourceVersion != BCLChunkGenerator.BIOME_SOURCE_VERSION_HEX) ? SquareBiomeMap::new : HexBiomeMap::new; if (worldHeight > 128 && GeneratorOptions.useVerticalBiomes()) { @@ -179,6 +177,6 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource { @Override public String toString() { - return "BCLib - Nether BiomeSource (" + Integer.toHexString(hashCode()) + ")"; + return "BCLib - Nether BiomeSource (" + Integer.toHexString(hashCode()) + ", version=" + biomeSourceVersion + ", seed=" + currentSeed + ")"; } } diff --git a/src/main/java/org/betterx/bclib/world/generator/GeneratorOptions.java b/src/main/java/org/betterx/bclib/world/generator/GeneratorOptions.java index 61456b12..a8603ef7 100644 --- a/src/main/java/org/betterx/bclib/world/generator/GeneratorOptions.java +++ b/src/main/java/org/betterx/bclib/world/generator/GeneratorOptions.java @@ -15,7 +15,6 @@ public class GeneratorOptions { private static Function endLandFunction; private static boolean customNetherBiomeSource = true; private static boolean customEndBiomeSource = true; - private static boolean useOldBiomeGenerator = false; private static boolean verticalBiomes = true; private static long farEndBiomesSqr = 1000000; private static boolean fixEndBiomeSource = true; @@ -24,13 +23,12 @@ public class GeneratorOptions { public static void init() { biomeSizeNether = Configs.GENERATOR_CONFIG.getInt("nether.biomeMap", "biomeSize", 256); biomeVSizeNether = Configs.GENERATOR_CONFIG.getInt("nether.biomeMap", - "biomeVerticalSize(onlyInTallNether)", - 86); + "biomeVerticalSize(onlyInTallNether)", + 86); biomeSizeEndLand = Configs.GENERATOR_CONFIG.getInt("end.biomeMap", "biomeSizeLand", 256); biomeSizeEndVoid = Configs.GENERATOR_CONFIG.getInt("end.biomeMap", "biomeSizeVoid", 256); customNetherBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options", "customNetherBiomeSource", true); customEndBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options", "customEndBiomeSource", true); - useOldBiomeGenerator = Configs.GENERATOR_CONFIG.useOldGenerator(); verticalBiomes = Configs.GENERATOR_CONFIG.getBoolean("options", "verticalBiomesInTallNether", true); fixEndBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options.biomeSource", "fixEndBiomeSource", true); fixNetherBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options.biomeSource", "fixNetherBiomeSource", true); @@ -90,9 +88,6 @@ public class GeneratorOptions { return customEndBiomeSource; } - public static boolean useOldBiomeGenerator() { - return useOldBiomeGenerator; - } public static boolean useVerticalBiomes() { return verticalBiomes;