diff --git a/src/main/java/org/betterx/bclib/api/v2/generator/BCLBiomeSource.java b/src/main/java/org/betterx/bclib/api/v2/generator/BCLBiomeSource.java index 411f4117..d6e19834 100644 --- a/src/main/java/org/betterx/bclib/api/v2/generator/BCLBiomeSource.java +++ b/src/main/java/org/betterx/bclib/api/v2/generator/BCLBiomeSource.java @@ -1,6 +1,7 @@ package org.betterx.bclib.api.v2.generator; import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI; +import org.betterx.bclib.api.v2.levelgen.biomes.InternalBiomeAPI; import org.betterx.worlds.together.biomesource.BiomeSourceFromRegistry; import org.betterx.worlds.together.biomesource.MergeableBiomeSource; import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings; @@ -21,6 +22,7 @@ import java.util.Set; public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceWithSeed, MergeableBiomeSource, BiomeSourceWithNoiseRelatedSettings, BiomeSourceFromRegistry { protected final Registry biomeRegistry; + private int registryModificationCounter; protected long currentSeed; protected int maxHeight; @@ -40,11 +42,16 @@ public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceW long seed ) { super(preInit(biomeRegistry, list)); - + this.registryModificationCounter = InternalBiomeAPI.getBiomeRegistryModificationCount(biomeRegistry); this.biomeRegistry = biomeRegistry; this.currentSeed = seed; } + @Override + public boolean didBiomeRegistryChange() { + return this.registryModificationCounter != InternalBiomeAPI.getBiomeRegistryModificationCount(biomeRegistry); + } + final public void setSeed(long seed) { if (seed != currentSeed) { System.out.println(this + " set Seed: " + seed); diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/biomes/InternalBiomeAPI.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/biomes/InternalBiomeAPI.java index 0b0cce96..5f35c4aa 100644 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/biomes/InternalBiomeAPI.java +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/biomes/InternalBiomeAPI.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.stream.Stream; import org.jetbrains.annotations.ApiStatus; @@ -60,6 +61,8 @@ public class InternalBiomeAPI { ); static final Map CLIENT = Maps.newHashMap(); static final Map, Integer> FEATURE_ORDER = Maps.newHashMap(); + + static final Map, AtomicInteger> BIOME_ADDITIONS = Maps.newHashMap(); static final MutableInt FEATURE_ORDER_ID = new MutableInt(0); static final Map, List>>> MODIFICATIONS = Maps.newHashMap(); static final Map>>> TAG_ADDERS = Maps.newHashMap(); @@ -359,13 +362,30 @@ public class InternalBiomeAPI { .register((rawId, id, biome) -> { BCLBiome b = BiomeAPI.getBiome(id); if (!"minecraft".equals(id.getNamespace()) && (b == null || b == BCLBiomeRegistry.EMPTY_BIOME)) { - //BCLib.LOGGER.info(" #### " + rawId + ", " + biome + ", " + id); + BCLib.LOGGER.info(" #### " + rawId + ", " + biome + ", " + id); BIOMES_TO_SORT.add(id); + BIOME_ADDITIONS.computeIfAbsent(oBiomeRegistry.get(), reg -> new AtomicInteger(0)) + .incrementAndGet(); } }); }); } + /** + * The BCLBiomeSource keeps track of Modifications that happen after the BiomeSource was initialized. + * This appears to happen especially for new Worlds where the Biome Source is deserialized + * when the WolrdPreset registry is built for the CreateScreen. However Farbic Biomes are not yet + * added to the biomeRegistry at this stage. + * The counter is incremented in the DynamicRegistrySetupCallback.EVENT for the Biome Registry + * + * @param registry The registry you want to check + * @return The current number of additions since the world creation was started + */ + public static int getBiomeRegistryModificationCount(Registry registry) { + if (registry == null) return 0; + return BIOME_ADDITIONS.computeIfAbsent(registry, reg -> new AtomicInteger(0)).get(); + } + public static boolean registryContainsBound(ResourceKey key) { Registry reg = biomeRegistry; if (reg == null) reg = BuiltinRegistries.BIOME; diff --git a/src/main/java/org/betterx/worlds/together/biomesource/BiomeSourceFromRegistry.java b/src/main/java/org/betterx/worlds/together/biomesource/BiomeSourceFromRegistry.java index 2b0b2fa3..ac82c8da 100644 --- a/src/main/java/org/betterx/worlds/together/biomesource/BiomeSourceFromRegistry.java +++ b/src/main/java/org/betterx/worlds/together/biomesource/BiomeSourceFromRegistry.java @@ -1,25 +1,16 @@ package org.betterx.worlds.together.biomesource; -import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSource; -import java.util.Set; - public interface BiomeSourceFromRegistry { Registry getBiomeRegistry(); + boolean didBiomeRegistryChange(); - default boolean sameRegistryButDifferentBiomes(BiomeSourceFromRegistry other) { - if (other.getBiomeRegistry() == getBiomeRegistry()) { - Set> mySet = ((T) this).possibleBiomes(); - Set> otherSet = ((R) other).possibleBiomes(); - if (otherSet.size() != mySet.size()) return true; - for (Holder b : mySet) { - if (!otherSet.contains(b)) - return true; - } - } + default boolean togetherBiomeSourceContentChanged(BiomeSourceFromRegistry other) { + if (other.getBiomeRegistry() != getBiomeRegistry()) return true; + if (other.didBiomeRegistryChange() || didBiomeRegistryChange()) return true; return false; } diff --git a/src/main/java/org/betterx/worlds/together/biomesource/MergeableBiomeSource.java b/src/main/java/org/betterx/worlds/together/biomesource/MergeableBiomeSource.java index 93cb1e66..d742fb47 100644 --- a/src/main/java/org/betterx/worlds/together/biomesource/MergeableBiomeSource.java +++ b/src/main/java/org/betterx/worlds/together/biomesource/MergeableBiomeSource.java @@ -1,8 +1,24 @@ package org.betterx.worlds.together.biomesource; +import net.minecraft.core.Holder; +import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSource; +import java.util.Set; + public interface MergeableBiomeSource { + default boolean togetherShouldMerge(BiomeSource inputBiomeSource) { + Set> mySet = ((B) this).possibleBiomes(); + Set> otherSet = inputBiomeSource.possibleBiomes(); + if (otherSet.size() != mySet.size()) return true; + + for (Holder b : mySet) { + if (!otherSet.contains(b)) + return true; + } + + return false; + } /** * Returns a BiomeSource that merges the settings of this one with the Biomes (and possibly settings) from the diff --git a/src/main/java/org/betterx/worlds/together/chunkgenerator/EnforceableChunkGenerator.java b/src/main/java/org/betterx/worlds/together/chunkgenerator/EnforceableChunkGenerator.java index 505b3bbb..00f68e8b 100644 --- a/src/main/java/org/betterx/worlds/together/chunkgenerator/EnforceableChunkGenerator.java +++ b/src/main/java/org/betterx/worlds/together/chunkgenerator/EnforceableChunkGenerator.java @@ -2,6 +2,7 @@ package org.betterx.worlds.together.chunkgenerator; import org.betterx.worlds.together.biomesource.BiomeSourceFromRegistry; import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig; +import org.betterx.worlds.together.biomesource.MergeableBiomeSource; import net.minecraft.core.RegistryAccess; import net.minecraft.resources.ResourceKey; @@ -20,7 +21,7 @@ public interface EnforceableChunkGenerator { WorldGenSettings settings ); - default boolean needsChunkGeneratorRepair(ChunkGenerator chunkGenerator) { + default boolean togetherShouldRepair(ChunkGenerator chunkGenerator) { ChunkGenerator self = (ChunkGenerator) this; if (this == chunkGenerator || chunkGenerator == null) return false; @@ -33,7 +34,11 @@ public interface EnforceableChunkGenerator { return true; } if (one instanceof BiomeSourceFromRegistry ba && two instanceof BiomeSourceFromRegistry bb) { - if (ba.sameRegistryButDifferentBiomes(bb)) + if (ba.togetherBiomeSourceContentChanged(bb)) + return true; + } + if (one instanceof MergeableBiomeSource ba) { + if (ba.togetherShouldMerge(two)) return true; } diff --git a/src/main/java/org/betterx/worlds/together/levelgen/WorldGenUtil.java b/src/main/java/org/betterx/worlds/together/levelgen/WorldGenUtil.java index 3fe9c066..0d86d867 100644 --- a/src/main/java/org/betterx/worlds/together/levelgen/WorldGenUtil.java +++ b/src/main/java/org/betterx/worlds/together/levelgen/WorldGenUtil.java @@ -30,6 +30,8 @@ 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 org.jetbrains.annotations.ApiStatus; + public class WorldGenUtil { public static final String TAG_PRESET = "preset"; public static final String TAG_GENERATOR = "generator"; @@ -136,6 +138,7 @@ public class WorldGenUtil { @SuppressWarnings("unchecked") + @ApiStatus.Internal public static WorldGenSettings repairBiomeSourceInAllDimensions( RegistryAccess registryAccess, WorldGenSettings settings @@ -148,9 +151,25 @@ public class WorldGenUtil { ChunkGenerator referenceGenerator = dimensions.get(key); if (referenceGenerator instanceof EnforceableChunkGenerator enforcer) { + // This list contains the vanilla default level stem (only available if a new world is loaded) as well as + // The currently loaded stem + if (WorldBootstrap.getDefaultCreateWorldPresetSettings() != null) { + LevelStem vanillaDefaultStem = WorldBootstrap.getDefaultCreateWorldPresetSettings() + .dimensions() + .get(key); + + loadedStem = vanillaDefaultStem; + } + + + // now compare the reference world settings (the ones that were created when the world was + // started) with the settings that were loaded by the game. + // If those do not match, we will create a new ChunkGenerator / BiomeSources with appropriate + // settings + final ChunkGenerator loadedChunkGenerator = loadedStem.generator(); - if (enforcer.needsChunkGeneratorRepair(loadedChunkGenerator)) { + if (enforcer.togetherShouldRepair(loadedChunkGenerator)) { settings = enforcer.enforceGeneratorInWorldGenSettings( registryAccess, key, @@ -168,11 +187,13 @@ public class WorldGenUtil { } } + if (!didRepair) { if (loadedStem.generator().getBiomeSource() instanceof ReloadableBiomeSource reload) { reload.reloadBiomes(); } } + } return settings; } diff --git a/src/main/java/org/betterx/worlds/together/mixin/client/CreateWorldScreenMixin.java b/src/main/java/org/betterx/worlds/together/mixin/client/CreateWorldScreenMixin.java index bf97ed5a..72bb69a6 100644 --- a/src/main/java/org/betterx/worlds/together/mixin/client/CreateWorldScreenMixin.java +++ b/src/main/java/org/betterx/worlds/together/mixin/client/CreateWorldScreenMixin.java @@ -54,6 +54,7 @@ public class CreateWorldScreenMixin { private static WorldLoader.WorldDataSupplier wt_NewDefaultSettings(WorldLoader.WorldDataSupplier worldDataSupplier) { return (resourceManager, dataPackConfig) -> { Pair res = worldDataSupplier.get(resourceManager, dataPackConfig); + WorldBootstrap.InGUI.setDefaultCreateWorldSettings(res.getFirst()); return WorldGenUtil.defaultWorldDataSupplier(res.getSecond()); }; } diff --git a/src/main/java/org/betterx/worlds/together/world/event/WorldBootstrap.java b/src/main/java/org/betterx/worlds/together/world/event/WorldBootstrap.java index a87d5db2..2ce79614 100644 --- a/src/main/java/org/betterx/worlds/together/world/event/WorldBootstrap.java +++ b/src/main/java/org/betterx/worlds/together/world/event/WorldBootstrap.java @@ -33,6 +33,12 @@ import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal public class WorldBootstrap { + private static WorldGenSettings DEFAULT_CREATE_WORLD_PRESET_SETTINGS; + + public static WorldGenSettings getDefaultCreateWorldPresetSettings() { + return DEFAULT_CREATE_WORLD_PRESET_SETTINGS; + } + private static RegistryAccess LAST_REGISTRY_ACCESS = null; public static RegistryAccess getLastRegistryAccess() { @@ -144,6 +150,12 @@ public class WorldBootstrap { } public static class InGUI { + + + public static void setDefaultCreateWorldSettings(WorldGenSettings worldGenSettings) { + DEFAULT_CREATE_WORLD_PRESET_SETTINGS = worldGenSettings; + } + public static void registryReadyOnNewWorld(WorldGenSettingsComponent worldGenSettingsComponent) { Helpers.onRegistryReady(worldGenSettingsComponent.registryHolder()); } @@ -228,6 +240,8 @@ public class WorldBootstrap { String levelID, LevelStorageSource levelSource ) { + //when we load a world, we do not want to reuse the default world settings + DEFAULT_CREATE_WORLD_PRESET_SETTINGS = null; try { var levelStorageAccess = levelSource.createAccess(levelID); try {