WorldPreset serialization and better structure for BiomeGenerator builder;

This commit is contained in:
Frank 2022-06-19 19:59:29 +02:00
parent d63d773bb8
commit c74b7b2d28
20 changed files with 365 additions and 244 deletions

View file

@ -1,44 +1,38 @@
package org.betterx.bclib.presets.worldgen;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.WorldDataAPI;
import org.betterx.bclib.api.v2.levelgen.LevelGenUtil;
import org.betterx.bclib.mixin.common.WorldPresetAccessor;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.RegistryFileCodec;
import net.minecraft.data.BuiltinRegistries;
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.dimension.LevelStem;
import net.minecraft.world.level.levelgen.presets.WorldPreset;
import java.util.Map;
import java.util.Optional;
public class BCLWorldPreset extends WorldPreset {
public final WorldPresetSettings settings;
public final int sortOrder;
public static final Codec<BCLWorldPreset> DIRECT_CODEC = RecordCodecBuilder.create(builderInstance -> {
RecordCodecBuilder<BCLWorldPreset, Map<ResourceKey<LevelStem>, LevelStem>> dimensionsBuidler = Codec
.unboundedMap(ResourceKey.codec(Registry.LEVEL_STEM_REGISTRY), LevelStem.CODEC)
.fieldOf("dimensions")
.forGetter(worldPreset -> worldPreset.getDimensions());
RecordCodecBuilder<BCLWorldPreset, Integer> sortBuilder = Codec.INT
.fieldOf("sort_order")
.forGetter(wp -> wp.sortOrder);
private static final String TAG_GENERATOR = LevelGenUtil.TAG_GENERATOR;
RecordCodecBuilder<BCLWorldPreset, WorldPresetSettings> settingsBuilder = WorldPresetSettings.CODEC
.fieldOf("settings")
.forGetter(wp -> wp.settings);
private static int NEXT_IN_SORT_ORDER = 1000;
return builderInstance
.group(dimensionsBuidler, sortBuilder, settingsBuilder)
.apply(builderInstance, BCLWorldPreset::new);
});
public static final Codec<Holder<WorldPreset>> CODEC = RegistryFileCodec.create(
Registry.WORLD_PRESET_REGISTRY,
(Codec<WorldPreset>) ((Object) DIRECT_CODEC)
);
public BCLWorldPreset(
Map<ResourceKey<LevelStem>, LevelStem> map,
Optional<Integer> sortOrder,
Optional<WorldPresetSettings> settings
) {
this(map, sortOrder.orElse(NEXT_IN_SORT_ORDER++), settings.orElse(VanillaWorldPresetSettings.DEFAULT));
}
public BCLWorldPreset(Map<ResourceKey<LevelStem>, LevelStem> map, int sortOrder, WorldPresetSettings settings) {
super(map);
@ -50,4 +44,28 @@ public class BCLWorldPreset extends WorldPreset {
return ((WorldPresetAccessor) this).bcl_getDimensions();
}
public static WorldPresetSettings writeWorldPresetSettings(Optional<Holder<WorldPreset>> worldPreset) {
if (worldPreset.isPresent() && worldPreset.get().value() instanceof BCLWorldPreset wp) {
writeWorldPresetSettings(wp.settings);
return wp.settings;
} else {
writeWorldPresetSettings(VanillaWorldPresetSettings.DEFAULT);
return VanillaWorldPresetSettings.DEFAULT;
}
}
public static void writeWorldPresetSettings(WorldPresetSettings presetSettings) {
final RegistryOps<Tag> registryOps = RegistryOps.create(NbtOps.INSTANCE, BuiltinRegistries.ACCESS);
final var codec = WorldPresetSettings.CODEC.orElse(presetSettings);
final var encodeResult = codec.encodeStart(registryOps, presetSettings);
if (encodeResult.result().isPresent()) {
final CompoundTag settingsNbt = WorldDataAPI.getRootTag(BCLib.TOGETHER_WORLDS);
settingsNbt.put(TAG_GENERATOR, encodeResult.result().get());
} else {
BCLib.LOGGER.error("Unable to encode world generator settings generator for level.dat.");
}
WorldDataAPI.saveFile(BCLib.TOGETHER_WORLDS);
}
}

View file

@ -0,0 +1,30 @@
package org.betterx.bclib.presets.worldgen;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import java.util.Set;
public class VanillaWorldPresetSettings extends WorldPresetSettings {
public static final VanillaWorldPresetSettings DEFAULT = new VanillaWorldPresetSettings();
public static final Codec<VanillaWorldPresetSettings> CODEC = Codec.unit(VanillaWorldPresetSettings::new);
@Override
public Codec<? extends WorldPresetSettings> codec() {
return CODEC;
}
@Override
public WorldGenSettings repairSettingsOnLoad(RegistryAccess registryAccess, WorldGenSettings settings) {
return settings;
}
@Override
public BiomeSource fixBiomeSource(BiomeSource biomeSource, Set<Holder<Biome>> datapackBiomes) {
return biomeSource;
}
}

View file

@ -0,0 +1,162 @@
package org.betterx.bclib.presets.worldgen;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.LifeCycleAPI;
import org.betterx.bclib.api.v2.WorldDataAPI;
import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
import org.betterx.bclib.api.v2.datafixer.DataFixerAPI;
import org.betterx.bclib.api.v2.levelgen.LevelGenUtil;
import org.betterx.bclib.api.v2.levelgen.biomes.InternalBiomeAPI;
import org.betterx.bclib.interfaces.WorldGenSettingsComponentAccessor;
import org.betterx.bclib.mixin.common.RegistryOpsAccessor;
import net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent;
import net.minecraft.core.Holder;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.RegistryOps;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.presets.WorldPreset;
import net.minecraft.world.level.storage.LevelResource;
import net.minecraft.world.level.storage.LevelStorageSource;
import java.io.File;
import java.util.Optional;
public class WorldBootstrap {
private static class Helpers {
private static void initializeWorldDataAPI(
LevelStorageSource.LevelStorageAccess levelStorageAccess,
boolean newWorld
) {
File levelPath = levelStorageAccess.getLevelPath(LevelResource.ROOT).toFile();
initializeWorldDataAPI(levelPath, newWorld);
}
private static void setupWorld() {
InternalBiomeAPI.prepareNewLevel();
DataExchangeAPI.prepareServerside();
}
private static void initializeWorldDataAPI(File levelBaseDir, boolean newWorld) {
WorldDataAPI.load(new File(levelBaseDir, "data"));
if (newWorld) {
WorldDataAPI.saveFile(BCLib.MOD_ID);
}
}
}
public static class DedicatedServer {
public static void registryReady(RegistryOps<Tag> regOps) {
InternalBiomeAPI.initRegistry(regOps);
}
public static void setupWorld(LevelStorageSource.LevelStorageAccess levelStorageAccess) {
Helpers.setupWorld();
File levelDat = levelStorageAccess.getLevelPath(LevelResource.LEVEL_DATA_FILE).toFile();
if (!levelDat.exists()) {
BCLib.LOGGER.info("Creating a new World, no fixes needed");
Helpers.initializeWorldDataAPI(levelStorageAccess, true);
BCLWorldPreset.writeWorldPresetSettings(Optional.empty());
DataFixerAPI.initializePatchData();
} else {
Helpers.initializeWorldDataAPI(levelStorageAccess, false);
DataFixerAPI.fixData(levelStorageAccess, false, (didFix) -> {/* not called when showUI==false */});
}
LifeCycleAPI._runBeforeLevelLoad();
}
}
public static class InGUI {
public static void registryReady(WorldGenSettingsComponent worldGenSettingsComponent) {
InternalBiomeAPI.initRegistry(worldGenSettingsComponent.registryHolder());
}
public static void registryReady(Optional<RegistryOps<Tag>> registryOps) {
if (registryOps.orElse(null) instanceof RegistryOpsAccessor acc) {
InternalBiomeAPI.initRegistry(acc.bcl_getRegistryAccess());
}
}
public static void setupNewWorld(
Optional<LevelStorageSource.LevelStorageAccess> levelStorageAccess,
WorldGenSettingsComponent worldGenSettingsComponent
) {
if (levelStorageAccess.isPresent()) {
Helpers.setupWorld();
Helpers.initializeWorldDataAPI(levelStorageAccess.get(), true);
if (worldGenSettingsComponent instanceof WorldGenSettingsComponentAccessor acc) {
BCLWorldPreset.writeWorldPresetSettings(acc.bcl_getPreset());
}
DataFixerAPI.initializePatchData();
// DataFixerAPI.createWorldData(
// levelStorageAccess.get(),
// worldGenSettingsComponent.settings().worldGenSettings()
// );
LifeCycleAPI._runBeforeLevelLoad();
}
}
/**
* Does not call {@link LifeCycleAPI#_runBeforeLevelLoad()}
*/
public static void setupLoadedWorld(
String levelID,
LevelStorageSource levelSource
) {
Helpers.setupWorld();
try {
var levelStorageAccess = levelSource.createAccess(levelID);
Helpers.initializeWorldDataAPI(levelStorageAccess, true);
levelStorageAccess.close();
} catch (Exception e) {
BCLib.LOGGER.error("Failed to initialize data in world", e);
}
}
}
public static class InFreshLevel {
public static void setupNewWorld(
String levelID,
WorldGenSettings worldGenSettings,
LevelStorageSource levelSource,
Optional<Holder<WorldPreset>> worldPreset
) {
InGUI.setupLoadedWorld(levelID, levelSource);
BCLWorldPreset.writeWorldPresetSettings(worldPreset);
DataFixerAPI.initializePatchData();
LifeCycleAPI._runBeforeLevelLoad();
}
}
public static WorldGenSettings enforceInNewWorld(WorldGenSettings worldGenSettings) {
worldGenSettings = LevelGenUtil
.getWorldSettings()
.repairSettingsOnLoad(InternalBiomeAPI.worldRegistryAccess(), worldGenSettings);
return worldGenSettings;
}
public static WorldGenSettings enforceInLoadedWorld(
Optional<RegistryOps<Tag>> registryOps,
WorldGenSettings worldGenSettings
) {
if (registryOps.orElse(null) instanceof RegistryOpsAccessor acc) {
return LevelGenUtil
.getWorldSettings()
.repairSettingsOnLoad(acc.bcl_getRegistryAccess(), worldGenSettings);
//.repairSettingsOnLoad(InternalBiomeAPI.worldRegistryAccess(), worldGenSettings);
} else {
BCLib.LOGGER.error("Unable to obtain registryAccess when enforcing generators.");
}
return worldGenSettings;
}
}

View file

@ -47,6 +47,7 @@ public abstract class WorldPresetSettings {
public static void bootstrap() {
register(BCLib.makeID("bcl_world_preset_settings"), BCLWorldPresetSettings.CODEC);
register(BCLib.makeID("vanilla_world_preset_settings"), VanillaWorldPresetSettings.CODEC);
}
public abstract Codec<? extends WorldPresetSettings> codec();