[Fix] Make sure WorldPresets are loaded with corresponding Mod-Data (#20)

This commit is contained in:
Frank 2022-07-09 04:22:25 +02:00
parent e7df54bb5b
commit 72e8d8ff0f
5 changed files with 138 additions and 60 deletions

View file

@ -362,10 +362,10 @@ 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)) // BIOME_ADDITIONS.computeIfAbsent(oBiomeRegistry.get(), reg -> new AtomicInteger(0))
.incrementAndGet(); // .incrementAndGet();
} }
}); });
}); });

View file

@ -4,6 +4,7 @@ import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig; import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig;
import org.betterx.worlds.together.biomesource.ReloadableBiomeSource; import org.betterx.worlds.together.biomesource.ReloadableBiomeSource;
import org.betterx.worlds.together.chunkgenerator.EnforceableChunkGenerator; import org.betterx.worlds.together.chunkgenerator.EnforceableChunkGenerator;
import org.betterx.worlds.together.mixin.common.WorldPresetAccessor;
import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings; import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings;
import org.betterx.worlds.together.world.BiomeSourceWithSeed; import org.betterx.worlds.together.world.BiomeSourceWithSeed;
import org.betterx.worlds.together.world.WorldConfig; import org.betterx.worlds.together.world.WorldConfig;
@ -12,12 +13,16 @@ import org.betterx.worlds.together.worldPreset.TogetherWorldPreset;
import org.betterx.worlds.together.worldPreset.WorldPresets; import org.betterx.worlds.together.worldPreset.WorldPresets;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.JsonOps;
import net.minecraft.Util;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkGenerator;
@ -30,6 +35,11 @@ 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 com.google.common.collect.ImmutableMap;
import com.google.gson.JsonElement;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
public class WorldGenUtil { public class WorldGenUtil {
@ -78,11 +88,95 @@ public class WorldGenUtil {
); );
} }
public static Pair<WorldGenSettings, RegistryAccess.Frozen> defaultWorldDataSupplier(RegistryAccess.Frozen frozen) { @ApiStatus.Internal
WorldGenSettings worldGenSettings = createDefaultWorldFromPreset(frozen); public static Pair<WorldGenSettings, RegistryAccess.Frozen> defaultWorldDataSupplier(
RegistryOps<JsonElement> loaderOps,
RegistryAccess.Frozen frozen
) {
WorldGenSettings defaultGen = createDefaultWorldFromPreset(frozen);
RegistryOps<JsonElement> registryOps = RegistryOps.create(JsonOps.INSTANCE, frozen);
WorldGenSettings worldGenSettings = WorldGenSettings.CODEC
.encodeStart(registryOps, defaultGen)
.flatMap(json -> WorldGenSettings.CODEC.parse(
loaderOps,
json
))
.getOrThrow(
false,
Util.prefix(
"Error parsing worldgen settings after loading data packs: ",
WorldsTogether.LOGGER::error
)
);
// WorldGenSettings worldGenSettings = createDefaultWorldFromPreset(frozen);
return Pair.of(worldGenSettings, frozen); return Pair.of(worldGenSettings, frozen);
} }
private static final Map<ResourceKey<WorldPreset>, Map<ResourceKey<LevelStem>, LevelStem>> WORLD_PRESET_MAP = new HashMap<>();
@ApiStatus.Internal
public static Map<ResourceKey<LevelStem>, LevelStem> getDimensionsWithModData(ResourceKey<WorldPreset> preset) {
var data = WORLD_PRESET_MAP.get(preset);
if (data == null) return new HashMap<>();
return data;
}
@ApiStatus.Internal
public static Holder<WorldPreset> reloadWithModData(Holder<WorldPreset> preset) {
if (preset.value() instanceof WorldPresetAccessor acc) {
var data = WORLD_PRESET_MAP.get(preset.unwrapKey().orElseThrow());
if (data != null) {
acc.bcl_setDimensions(data);
}
}
return preset;
}
public static void clearPreloadedWorldPresets() {
WORLD_PRESET_MAP.clear();
}
public static void preloadWorldPresets(ResourceManager resourceManager, RegistryAccess.Writable writable) {
clearPreloadedWorldPresets();
Registry<WorldPreset> registry = writable.registryOrThrow(Registry.WORLD_PRESET_REGISTRY);
//for (ResourceKey<WorldPreset> key : registry.registryKeySet())
ResourceKey<WorldPreset> key = net.minecraft.world.level.levelgen.presets.WorldPresets.NORMAL;
{
RegistryOps<JsonElement> loaderOps = RegistryOps.createAndLoad(
JsonOps.INSTANCE, writable, resourceManager
);
Holder<WorldPreset> in = registry.getHolderOrThrow(key);
if (in.unwrapKey().isPresent()) {
RegistryOps<JsonElement> registryOps = RegistryOps.create(JsonOps.INSTANCE, writable);
WorldGenSettings settings = WorldGenUtil.createWorldFromPreset(
in.unwrapKey().orElseThrow(),
writable,
RandomSource.create().nextLong(),
true,
false
);
WorldGenSettings worldGenSettings = WorldGenSettings.CODEC
.encodeStart(registryOps, settings)
.flatMap(json -> WorldGenSettings.CODEC.parse(
loaderOps,
json
))
.getOrThrow(
false,
Util.prefix(
"Error parsing world preset settings after loading data packs: ",
WorldsTogether.LOGGER::error
)
);
ImmutableMap.Builder<ResourceKey<LevelStem>, LevelStem> map = ImmutableMap.builder();
for (Map.Entry<ResourceKey<LevelStem>, LevelStem> entry : worldGenSettings.dimensions().entrySet()) {
map.put(entry.getKey(), entry.getValue());
}
WORLD_PRESET_MAP.put(key, map.build());
}
}
}
public static WorldGenSettings createDefaultWorldFromPreset(RegistryAccess registryAccess, long seed) { public static WorldGenSettings createDefaultWorldFromPreset(RegistryAccess registryAccess, long seed) {
return createDefaultWorldFromPreset(registryAccess, seed, true, false); return createDefaultWorldFromPreset(registryAccess, seed, true, false);
} }
@ -153,11 +247,10 @@ public class WorldGenUtil {
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 // This list contains the vanilla default level stem (only available if a new world is loaded) as well as
// The currently loaded stem // The currently loaded stem
if (WorldBootstrap.getDefaultCreateWorldPresetSettings() != null) { var vanillaDimensionMap = WorldGenUtil.getDimensionsWithModData(net.minecraft.world.level.levelgen.presets.WorldPresets.NORMAL);
LevelStem vanillaDefaultStem = WorldBootstrap.getDefaultCreateWorldPresetSettings()
.dimensions()
.get(key);
LevelStem vanillaDefaultStem = vanillaDimensionMap.get(key);
if (vanillaDefaultStem != null) {
loadedStem = vanillaDefaultStem; loadedStem = vanillaDefaultStem;
} }

View file

@ -4,11 +4,12 @@ import org.betterx.worlds.together.levelgen.WorldGenUtil;
import org.betterx.worlds.together.world.event.WorldBootstrap; import org.betterx.worlds.together.world.event.WorldBootstrap;
import org.betterx.worlds.together.worldPreset.WorldPresets; import org.betterx.worlds.together.worldPreset.WorldPresets;
import com.mojang.datafixers.util.Pair; import com.mojang.serialization.JsonOps;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen; import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
import net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent; import net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.server.WorldLoader; import net.minecraft.server.WorldLoader;
import net.minecraft.world.level.DataPackConfig; import net.minecraft.world.level.DataPackConfig;
@ -16,6 +17,7 @@ import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.presets.WorldPreset; import net.minecraft.world.level.levelgen.presets.WorldPreset;
import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.LevelStorageSource;
import com.google.gson.JsonElement;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -33,6 +35,7 @@ public class CreateWorldScreenMixin {
@Final @Final
public WorldGenSettingsComponent worldGenSettingsComponent; public WorldGenSettingsComponent worldGenSettingsComponent;
@Inject(method = "<init>", at = @At("TAIL")) @Inject(method = "<init>", at = @At("TAIL"))
private void wt_init( private void wt_init(
Screen screen, Screen screen,
@ -48,14 +51,36 @@ public class CreateWorldScreenMixin {
private static Optional<ResourceKey<WorldPreset>> wt_NewDefault(Optional<ResourceKey<WorldPreset>> preset) { private static Optional<ResourceKey<WorldPreset>> wt_NewDefault(Optional<ResourceKey<WorldPreset>> preset) {
return Optional.of(WorldPresets.getDEFAULT()); return Optional.of(WorldPresets.getDEFAULT());
} }
//
// @Redirect(method = "method_41854", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/RegistryAccess$Writable;freeze()Lnet/minecraft/core/RegistryAccess$Frozen;"))
// private static RegistryAccess.Frozen loadDynamicRegistry(
// RegistryAccess.Writable mutableRegistryManager,
// ResourceManager dataPackManager
// ) {
// // This loads the dynamic registry from the data pack
// RegistryOps.createAndLoad(JsonOps.INSTANCE, mutableRegistryManager, dataPackManager);
// return mutableRegistryManager.freeze();
// }
//Make sure the WorldGenSettings used to populate the create screen 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;")) @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<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()); // WorldGenSettings defaultGen = net.minecraft.world.level.levelgen.presets.WorldPresets.createNormalWorldFromPreset(frozen);
return WorldGenUtil.defaultWorldDataSupplier(res.getSecond()); // WorldBootstrap.InGUI.setDefaultCreateWorldSettings(defaultGen);
RegistryAccess.Writable writable = RegistryAccess.builtinCopy();
WorldGenUtil.preloadWorldPresets(resourceManager, writable);
RegistryOps<JsonElement> registryOps = RegistryOps.createAndLoad(
JsonOps.INSTANCE, writable, resourceManager
);
RegistryAccess.Frozen frozen = writable.freeze();
WorldBootstrap.InGUI.registryReady(frozen);
return WorldGenUtil.defaultWorldDataSupplier(registryOps, frozen);
}; };
} }

View file

@ -1,19 +1,13 @@
package org.betterx.worlds.together.mixin.client; package org.betterx.worlds.together.mixin.client;
import org.betterx.worlds.together.mixin.common.WorldPresetAccessor; import org.betterx.worlds.together.levelgen.WorldGenUtil;
import org.betterx.worlds.together.world.event.WorldBootstrap;
import org.betterx.worlds.together.worldPreset.WorldGenSettingsComponentAccessor; import org.betterx.worlds.together.worldPreset.WorldGenSettingsComponentAccessor;
import net.minecraft.client.gui.screens.worldselection.WorldCreationContext; import net.minecraft.client.gui.screens.worldselection.WorldCreationContext;
import net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent; import net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.presets.WorldPreset; import net.minecraft.world.level.levelgen.presets.WorldPreset;
import net.minecraft.world.level.levelgen.presets.WorldPresets;
import com.google.common.collect.ImmutableMap;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
@ -22,7 +16,6 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -47,38 +40,17 @@ public abstract class WorldGenSettingsComponentMixin implements WorldGenSettings
.location() .location()
.getNamespace() .getNamespace()
.equals("minecraft")); .equals("minecraft"));
List<Holder<WorldPreset>> custom = list List<Holder<WorldPreset>> custom = list
.stream() .stream()
.filter(p -> !vanilla.test(p)) .filter(p -> !vanilla.test(p))
.collect(Collectors.toCollection(LinkedList::new)); .collect(Collectors.toCollection(LinkedList::new));
Registry<WorldPreset> registry = settings.registryAccess().registryOrThrow(Registry.WORLD_PRESET_REGISTRY);
custom.addAll(list custom.addAll(list
.stream() .stream()
.filter(vanilla) .filter(vanilla)
// this code will inject the original vanilla default dimensions into the WorldPreset list that is .map(WorldGenUtil::reloadWithModData)
// used on the world type selection button. This is supposed to mitigate the issue described
// here: https://github.com/quiqueck/BCLib/issues/20
// it may be removed once this behaviour is fixed in either fabric or vanilla
.map(p -> {
if (WorldBootstrap.getDefaultCreateWorldPresetSettings() != null) {
ResourceKey<WorldPreset> key = p.unwrapKey().orElseThrow();
if (key.location().equals(WorldPresets.NORMAL.location())) {
ImmutableMap.Builder<ResourceKey<LevelStem>, LevelStem> map = ImmutableMap.builder();
for (Map.Entry<ResourceKey<LevelStem>, LevelStem> entry : WorldBootstrap.getDefaultCreateWorldPresetSettings()
.dimensions()
.entrySet()) {
map.put(entry.getKey(), entry.getValue());
}
if (p.value() instanceof WorldPresetAccessor ax) {
ax.bcl_setDimensions(map.build());
}
}
}
return p;
})
.toList()); .toList());
return custom; return custom;

View file

@ -33,12 +33,6 @@ 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() {
@ -150,12 +144,6 @@ 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());
} }
@ -240,8 +228,7 @@ 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 WorldGenUtil.clearPreloadedWorldPresets();
DEFAULT_CREATE_WORLD_PRESET_SETTINGS = null;
try { try {
var levelStorageAccess = levelSource.createAccess(levelID); var levelStorageAccess = levelSource.createAccess(levelID);
try { try {
@ -285,6 +272,7 @@ public class WorldBootstrap {
) { ) {
//LifeCycleAPI._runBeforeLevelLoad(); //LifeCycleAPI._runBeforeLevelLoad();
WorldEventsImpl.ON_WORLD_LOAD.emit(OnWorldLoad::onLoad); WorldEventsImpl.ON_WORLD_LOAD.emit(OnWorldLoad::onLoad);
WorldGenUtil.clearPreloadedWorldPresets();
} }
} }