[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;
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<BCLBiomeSource>, BiomeSourceWithNoiseRelatedSettings, BiomeSourceFromRegistry<BCLBiomeSource> {
protected final Registry<Biome> 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);

View file

@ -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<Biome, BCLBiome> CLIENT = 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 Map<ResourceKey<LevelStem>, List<BiConsumer<ResourceLocation, Holder<Biome>>>> MODIFICATIONS = 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) -> {
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<Biome> registry) {
if (registry == null) return 0;
return BIOME_ADDITIONS.computeIfAbsent(registry, reg -> new AtomicInteger(0)).get();
}
public static boolean registryContainsBound(ResourceKey<Biome> key) {
Registry<Biome> reg = biomeRegistry;
if (reg == null) reg = BuiltinRegistries.BIOME;

View file

@ -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<T extends BiomeSource> {
Registry<Biome> getBiomeRegistry();
boolean didBiomeRegistryChange();
default <R extends BiomeSource> boolean sameRegistryButDifferentBiomes(BiomeSourceFromRegistry<R> other) {
if (other.getBiomeRegistry() == getBiomeRegistry()) {
Set<Holder<Biome>> mySet = ((T) this).possibleBiomes();
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;
}
}
default <R extends BiomeSource> boolean togetherBiomeSourceContentChanged(BiomeSourceFromRegistry<R> other) {
if (other.getBiomeRegistry() != getBiomeRegistry()) return true;
if (other.didBiomeRegistryChange() || didBiomeRegistryChange()) return true;
return false;
}

View file

@ -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<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

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.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<G extends ChunkGenerator> {
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<G extends ChunkGenerator> {
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;
}

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.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;
}

View file

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

View file

@ -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 {