[Fix] Modded WorldGenSettings are not properly loaded for new Worlds (#20)

This commit is contained in:
Frank 2022-07-08 23:23:17 +02:00
parent 5fd087d8b7
commit 13acf48894
8 changed files with 93 additions and 18 deletions

View file

@ -1,6 +1,7 @@
package org.betterx.bclib.api.v2.generator; package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI; 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.BiomeSourceFromRegistry;
import org.betterx.worlds.together.biomesource.MergeableBiomeSource; import org.betterx.worlds.together.biomesource.MergeableBiomeSource;
import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings; import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings;
@ -21,6 +22,7 @@ import java.util.Set;
public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceWithSeed, MergeableBiomeSource<BCLBiomeSource>, BiomeSourceWithNoiseRelatedSettings, BiomeSourceFromRegistry<BCLBiomeSource> { public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceWithSeed, MergeableBiomeSource<BCLBiomeSource>, BiomeSourceWithNoiseRelatedSettings, BiomeSourceFromRegistry<BCLBiomeSource> {
protected final Registry<Biome> biomeRegistry; protected final Registry<Biome> biomeRegistry;
private int registryModificationCounter;
protected long currentSeed; protected long currentSeed;
protected int maxHeight; protected int maxHeight;
@ -40,11 +42,16 @@ public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceW
long seed long seed
) { ) {
super(preInit(biomeRegistry, list)); super(preInit(biomeRegistry, list));
this.registryModificationCounter = InternalBiomeAPI.getBiomeRegistryModificationCount(biomeRegistry);
this.biomeRegistry = biomeRegistry; this.biomeRegistry = biomeRegistry;
this.currentSeed = seed; this.currentSeed = seed;
} }
@Override
public boolean didBiomeRegistryChange() {
return this.registryModificationCounter != InternalBiomeAPI.getBiomeRegistryModificationCount(biomeRegistry);
}
final public void setSeed(long seed) { final public void setSeed(long seed) {
if (seed != currentSeed) { if (seed != currentSeed) {
System.out.println(this + " set Seed: " + seed); System.out.println(this + " set Seed: " + seed);

View file

@ -32,6 +32,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
@ -60,6 +61,8 @@ public class InternalBiomeAPI {
); );
static final Map<Biome, BCLBiome> CLIENT = Maps.newHashMap(); static final Map<Biome, BCLBiome> CLIENT = Maps.newHashMap();
static final Map<Holder<PlacedFeature>, Integer> FEATURE_ORDER = Maps.newHashMap(); static final Map<Holder<PlacedFeature>, Integer> FEATURE_ORDER = Maps.newHashMap();
static final Map<Registry<Biome>, AtomicInteger> BIOME_ADDITIONS = Maps.newHashMap();
static final MutableInt FEATURE_ORDER_ID = new MutableInt(0); static final MutableInt FEATURE_ORDER_ID = new MutableInt(0);
static final Map<ResourceKey<LevelStem>, List<BiConsumer<ResourceLocation, Holder<Biome>>>> MODIFICATIONS = Maps.newHashMap(); static final Map<ResourceKey<LevelStem>, List<BiConsumer<ResourceLocation, Holder<Biome>>>> MODIFICATIONS = Maps.newHashMap();
static final Map<ResourceKey, List<BiConsumer<ResourceLocation, Holder<Biome>>>> TAG_ADDERS = Maps.newHashMap(); static final Map<ResourceKey, List<BiConsumer<ResourceLocation, Holder<Biome>>>> TAG_ADDERS = Maps.newHashMap();
@ -359,13 +362,30 @@ public class InternalBiomeAPI {
.register((rawId, id, biome) -> { .register((rawId, id, biome) -> {
BCLBiome b = BiomeAPI.getBiome(id); BCLBiome b = BiomeAPI.getBiome(id);
if (!"minecraft".equals(id.getNamespace()) && (b == null || b == BCLBiomeRegistry.EMPTY_BIOME)) { 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); 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<Biome> registry) {
if (registry == null) return 0;
return BIOME_ADDITIONS.computeIfAbsent(registry, reg -> new AtomicInteger(0)).get();
}
public static boolean registryContainsBound(ResourceKey<Biome> key) { public static boolean registryContainsBound(ResourceKey<Biome> key) {
Registry<Biome> reg = biomeRegistry; Registry<Biome> reg = biomeRegistry;
if (reg == null) reg = BuiltinRegistries.BIOME; if (reg == null) reg = BuiltinRegistries.BIOME;

View file

@ -1,25 +1,16 @@
package org.betterx.worlds.together.biomesource; package org.betterx.worlds.together.biomesource;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.BiomeSource;
import java.util.Set;
public interface BiomeSourceFromRegistry<T extends BiomeSource> { public interface BiomeSourceFromRegistry<T extends BiomeSource> {
Registry<Biome> getBiomeRegistry(); Registry<Biome> getBiomeRegistry();
boolean didBiomeRegistryChange();
default <R extends BiomeSource> boolean sameRegistryButDifferentBiomes(BiomeSourceFromRegistry<R> other) { default <R extends BiomeSource> boolean togetherBiomeSourceContentChanged(BiomeSourceFromRegistry<R> other) {
if (other.getBiomeRegistry() == getBiomeRegistry()) { if (other.getBiomeRegistry() != getBiomeRegistry()) return true;
Set<Holder<Biome>> mySet = ((T) this).possibleBiomes(); if (other.didBiomeRegistryChange() || didBiomeRegistryChange()) return true;
Set<Holder<Biome>> otherSet = ((R) other).possibleBiomes();
if (otherSet.size() != mySet.size()) return true;
for (Holder<Biome> b : mySet) {
if (!otherSet.contains(b))
return true;
}
}
return false; return false;
} }

View file

@ -1,8 +1,24 @@
package org.betterx.worlds.together.biomesource; 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 net.minecraft.world.level.biome.BiomeSource;
import java.util.Set;
public interface MergeableBiomeSource<B extends BiomeSource> { public interface MergeableBiomeSource<B extends BiomeSource> {
default boolean togetherShouldMerge(BiomeSource inputBiomeSource) {
Set<Holder<Biome>> mySet = ((B) this).possibleBiomes();
Set<Holder<Biome>> otherSet = inputBiomeSource.possibleBiomes();
if (otherSet.size() != mySet.size()) return true;
for (Holder<Biome> 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 * Returns a BiomeSource that merges the settings of this one with the Biomes (and possibly settings) from the

View file

@ -2,6 +2,7 @@ package org.betterx.worlds.together.chunkgenerator;
import org.betterx.worlds.together.biomesource.BiomeSourceFromRegistry; import org.betterx.worlds.together.biomesource.BiomeSourceFromRegistry;
import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig; import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig;
import org.betterx.worlds.together.biomesource.MergeableBiomeSource;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
@ -20,7 +21,7 @@ public interface EnforceableChunkGenerator<G extends ChunkGenerator> {
WorldGenSettings settings WorldGenSettings settings
); );
default boolean needsChunkGeneratorRepair(ChunkGenerator chunkGenerator) { default boolean togetherShouldRepair(ChunkGenerator chunkGenerator) {
ChunkGenerator self = (ChunkGenerator) this; ChunkGenerator self = (ChunkGenerator) this;
if (this == chunkGenerator || chunkGenerator == null) return false; if (this == chunkGenerator || chunkGenerator == null) return false;
@ -33,7 +34,11 @@ public interface EnforceableChunkGenerator<G extends ChunkGenerator> {
return true; return true;
} }
if (one instanceof BiomeSourceFromRegistry ba && two instanceof BiomeSourceFromRegistry bb) { 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; return true;
} }

View file

@ -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.structure.StructureSet;
import net.minecraft.world.level.levelgen.synth.NormalNoise; import net.minecraft.world.level.levelgen.synth.NormalNoise;
import org.jetbrains.annotations.ApiStatus;
public class WorldGenUtil { public class WorldGenUtil {
public static final String TAG_PRESET = "preset"; public static final String TAG_PRESET = "preset";
public static final String TAG_GENERATOR = "generator"; public static final String TAG_GENERATOR = "generator";
@ -136,6 +138,7 @@ public class WorldGenUtil {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ApiStatus.Internal
public static WorldGenSettings repairBiomeSourceInAllDimensions( public static WorldGenSettings repairBiomeSourceInAllDimensions(
RegistryAccess registryAccess, RegistryAccess registryAccess,
WorldGenSettings settings WorldGenSettings settings
@ -148,9 +151,25 @@ public class WorldGenUtil {
ChunkGenerator referenceGenerator = dimensions.get(key); ChunkGenerator referenceGenerator = dimensions.get(key);
if (referenceGenerator instanceof EnforceableChunkGenerator enforcer) { 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(); final ChunkGenerator loadedChunkGenerator = loadedStem.generator();
if (enforcer.needsChunkGeneratorRepair(loadedChunkGenerator)) { if (enforcer.togetherShouldRepair(loadedChunkGenerator)) {
settings = enforcer.enforceGeneratorInWorldGenSettings( settings = enforcer.enforceGeneratorInWorldGenSettings(
registryAccess, registryAccess,
key, key,
@ -168,11 +187,13 @@ public class WorldGenUtil {
} }
} }
if (!didRepair) { if (!didRepair) {
if (loadedStem.generator().getBiomeSource() instanceof ReloadableBiomeSource reload) { if (loadedStem.generator().getBiomeSource() instanceof ReloadableBiomeSource reload) {
reload.reloadBiomes(); reload.reloadBiomes();
} }
} }
} }
return settings; return settings;
} }

View file

@ -54,6 +54,7 @@ public class CreateWorldScreenMixin {
private static WorldLoader.WorldDataSupplier<WorldGenSettings> wt_NewDefaultSettings(WorldLoader.WorldDataSupplier<WorldGenSettings> worldDataSupplier) { private static WorldLoader.WorldDataSupplier<WorldGenSettings> wt_NewDefaultSettings(WorldLoader.WorldDataSupplier<WorldGenSettings> worldDataSupplier) {
return (resourceManager, dataPackConfig) -> { return (resourceManager, dataPackConfig) -> {
Pair<WorldGenSettings, RegistryAccess.Frozen> res = worldDataSupplier.get(resourceManager, dataPackConfig); Pair<WorldGenSettings, RegistryAccess.Frozen> res = worldDataSupplier.get(resourceManager, dataPackConfig);
WorldBootstrap.InGUI.setDefaultCreateWorldSettings(res.getFirst());
return WorldGenUtil.defaultWorldDataSupplier(res.getSecond()); return WorldGenUtil.defaultWorldDataSupplier(res.getSecond());
}; };
} }

View file

@ -33,6 +33,12 @@ import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal @ApiStatus.Internal
public class WorldBootstrap { 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; private static RegistryAccess LAST_REGISTRY_ACCESS = null;
public static RegistryAccess getLastRegistryAccess() { public static RegistryAccess getLastRegistryAccess() {
@ -144,6 +150,12 @@ public class WorldBootstrap {
} }
public static class InGUI { public static class InGUI {
public static void setDefaultCreateWorldSettings(WorldGenSettings worldGenSettings) {
DEFAULT_CREATE_WORLD_PRESET_SETTINGS = worldGenSettings;
}
public static void registryReadyOnNewWorld(WorldGenSettingsComponent worldGenSettingsComponent) { public static void registryReadyOnNewWorld(WorldGenSettingsComponent worldGenSettingsComponent) {
Helpers.onRegistryReady(worldGenSettingsComponent.registryHolder()); Helpers.onRegistryReady(worldGenSettingsComponent.registryHolder());
} }
@ -228,6 +240,8 @@ public class WorldBootstrap {
String levelID, String levelID,
LevelStorageSource levelSource LevelStorageSource levelSource
) { ) {
//when we load a world, we do not want to reuse the default world settings
DEFAULT_CREATE_WORLD_PRESET_SETTINGS = null;
try { try {
var levelStorageAccess = levelSource.createAccess(levelID); var levelStorageAccess = levelSource.createAccess(levelID);
try { try {