package net.minecraft.client.gui.screens.worldselection; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.OptionalLong; import java.util.function.Consumer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.FileUtil; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; import net.minecraft.tags.WorldPresetTags; import net.minecraft.world.Difficulty; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameType; import net.minecraft.world.level.WorldDataConfiguration; import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorPreset; import net.minecraft.world.level.levelgen.presets.WorldPreset; import net.minecraft.world.level.levelgen.presets.WorldPresets; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class WorldCreationUiState { private static final Component DEFAULT_WORLD_NAME = Component.translatable("selectWorld.newWorld"); private final List> listeners = new ArrayList(); private String name = DEFAULT_WORLD_NAME.getString(); private WorldCreationUiState.SelectedGameMode gameMode = WorldCreationUiState.SelectedGameMode.SURVIVAL; private Difficulty difficulty = Difficulty.NORMAL; @Nullable private Boolean allowCommands; private String seed; private boolean generateStructures; private boolean bonusChest; private final Path savesFolder; private String targetFolder; private WorldCreationContext settings; private WorldCreationUiState.WorldTypeEntry worldType; private final List normalPresetList = new ArrayList(); private final List altPresetList = new ArrayList(); private GameRules gameRules; public WorldCreationUiState(Path savesFolder, WorldCreationContext settings, Optional> preset, OptionalLong seed) { this.savesFolder = savesFolder; this.settings = settings; this.worldType = new WorldCreationUiState.WorldTypeEntry((Holder)findPreset(settings, preset).orElse(null)); this.updatePresetLists(); this.seed = seed.isPresent() ? Long.toString(seed.getAsLong()) : ""; this.generateStructures = settings.options().generateStructures(); this.bonusChest = settings.options().generateBonusChest(); this.targetFolder = this.findResultFolder(this.name); this.gameMode = settings.initialWorldCreationOptions().selectedGameMode(); this.gameRules = new GameRules(settings.dataConfiguration().enabledFeatures()); settings.initialWorldCreationOptions().disabledGameRules().forEach(key -> this.gameRules.getRule(key).set(false, null)); Optional.ofNullable(settings.initialWorldCreationOptions().flatLevelPreset()) .flatMap(resourceKey -> settings.worldgenLoadContext().lookup(Registries.FLAT_LEVEL_GENERATOR_PRESET).flatMap(registry -> registry.get(resourceKey))) .map(reference -> ((FlatLevelGeneratorPreset)reference.value()).settings()) .ifPresent(flatLevelGeneratorSettings -> this.updateDimensions(PresetEditor.flatWorldConfigurator(flatLevelGeneratorSettings))); } public void addListener(Consumer listener) { this.listeners.add(listener); } public void onChanged() { boolean bl = this.isBonusChest(); if (bl != this.settings.options().generateBonusChest()) { this.settings = this.settings.withOptions(worldOptions -> worldOptions.withBonusChest(bl)); } boolean bl2 = this.isGenerateStructures(); if (bl2 != this.settings.options().generateStructures()) { this.settings = this.settings.withOptions(worldOptions -> worldOptions.withStructures(bl2)); } for (Consumer consumer : this.listeners) { consumer.accept(this); } } public void setName(String name) { this.name = name; this.targetFolder = this.findResultFolder(name); this.onChanged(); } private String findResultFolder(String name) { String string = name.trim(); try { return FileUtil.findAvailableName(this.savesFolder, !string.isEmpty() ? string : DEFAULT_WORLD_NAME.getString(), ""); } catch (Exception var5) { try { return FileUtil.findAvailableName(this.savesFolder, "World", ""); } catch (IOException var4) { throw new RuntimeException("Could not create save folder", var4); } } } public String getName() { return this.name; } public String getTargetFolder() { return this.targetFolder; } public void setGameMode(WorldCreationUiState.SelectedGameMode gameMode) { this.gameMode = gameMode; this.onChanged(); } public WorldCreationUiState.SelectedGameMode getGameMode() { return this.isDebug() ? WorldCreationUiState.SelectedGameMode.DEBUG : this.gameMode; } public void setDifficulty(Difficulty difficulty) { this.difficulty = difficulty; this.onChanged(); } public Difficulty getDifficulty() { return this.isHardcore() ? Difficulty.HARD : this.difficulty; } public boolean isHardcore() { return this.getGameMode() == WorldCreationUiState.SelectedGameMode.HARDCORE; } public void setAllowCommands(boolean allowCommands) { this.allowCommands = allowCommands; this.onChanged(); } public boolean isAllowCommands() { if (this.isDebug()) { return true; } else if (this.isHardcore()) { return false; } else { return this.allowCommands == null ? this.getGameMode() == WorldCreationUiState.SelectedGameMode.CREATIVE : this.allowCommands; } } public void setSeed(String seed) { this.seed = seed; this.settings = this.settings.withOptions(worldOptions -> worldOptions.withSeed(WorldOptions.parseSeed(this.getSeed()))); this.onChanged(); } public String getSeed() { return this.seed; } public void setGenerateStructures(boolean generateStructures) { this.generateStructures = generateStructures; this.onChanged(); } public boolean isGenerateStructures() { return this.isDebug() ? false : this.generateStructures; } public void setBonusChest(boolean bonusChest) { this.bonusChest = bonusChest; this.onChanged(); } public boolean isBonusChest() { return !this.isDebug() && !this.isHardcore() ? this.bonusChest : false; } public void setSettings(WorldCreationContext settings) { this.settings = settings; this.updatePresetLists(); this.onChanged(); } public WorldCreationContext getSettings() { return this.settings; } public void updateDimensions(WorldCreationContext.DimensionsUpdater dimensionsUpdater) { this.settings = this.settings.withDimensions(dimensionsUpdater); this.onChanged(); } protected boolean tryUpdateDataConfiguration(WorldDataConfiguration worldDataConfiguration) { WorldDataConfiguration worldDataConfiguration2 = this.settings.dataConfiguration(); if (worldDataConfiguration2.dataPacks().getEnabled().equals(worldDataConfiguration.dataPacks().getEnabled()) && worldDataConfiguration2.enabledFeatures().equals(worldDataConfiguration.enabledFeatures())) { this.settings = new WorldCreationContext( this.settings.options(), this.settings.datapackDimensions(), this.settings.selectedDimensions(), this.settings.worldgenRegistries(), this.settings.dataPackResources(), worldDataConfiguration, this.settings.initialWorldCreationOptions() ); return true; } else { return false; } } public boolean isDebug() { return this.settings.selectedDimensions().isDebug(); } public void setWorldType(WorldCreationUiState.WorldTypeEntry worldType) { this.worldType = worldType; Holder holder = worldType.preset(); if (holder != null) { this.updateDimensions((frozen, worldDimensions) -> holder.value().createWorldDimensions()); } } public WorldCreationUiState.WorldTypeEntry getWorldType() { return this.worldType; } @Nullable public PresetEditor getPresetEditor() { Holder holder = this.getWorldType().preset(); return holder != null ? (PresetEditor)PresetEditor.EDITORS.get(holder.unwrapKey()) : null; } public List getNormalPresetList() { return this.normalPresetList; } public List getAltPresetList() { return this.altPresetList; } private void updatePresetLists() { Registry registry = this.getSettings().worldgenLoadContext().lookupOrThrow(Registries.WORLD_PRESET); this.normalPresetList.clear(); this.normalPresetList .addAll( (Collection)getNonEmptyList(registry, WorldPresetTags.NORMAL) .orElseGet(() -> registry.listElements().map(WorldCreationUiState.WorldTypeEntry::new).toList()) ); this.altPresetList.clear(); this.altPresetList.addAll((Collection)getNonEmptyList(registry, WorldPresetTags.EXTENDED).orElse(this.normalPresetList)); Holder holder = this.worldType.preset(); if (holder != null) { WorldCreationUiState.WorldTypeEntry worldTypeEntry = (WorldCreationUiState.WorldTypeEntry)findPreset(this.getSettings(), holder.unwrapKey()) .map(WorldCreationUiState.WorldTypeEntry::new) .orElse((WorldCreationUiState.WorldTypeEntry)this.normalPresetList.getFirst()); boolean bl = PresetEditor.EDITORS.get(holder.unwrapKey()) != null; if (bl) { this.worldType = worldTypeEntry; } else { this.setWorldType(worldTypeEntry); } } } private static Optional> findPreset(WorldCreationContext context, Optional> preset) { return preset.flatMap(resourceKey -> context.worldgenLoadContext().lookupOrThrow(Registries.WORLD_PRESET).get(resourceKey)); } private static Optional> getNonEmptyList(Registry registry, TagKey key) { return registry.get(key).map(named -> named.stream().map(WorldCreationUiState.WorldTypeEntry::new).toList()).filter(list -> !list.isEmpty()); } public void setGameRules(GameRules gameRules) { this.gameRules = gameRules; this.onChanged(); } public GameRules getGameRules() { return this.gameRules; } @Environment(EnvType.CLIENT) public static enum SelectedGameMode { SURVIVAL("survival", GameType.SURVIVAL), HARDCORE("hardcore", GameType.SURVIVAL), CREATIVE("creative", GameType.CREATIVE), DEBUG("spectator", GameType.SPECTATOR); public final GameType gameType; public final Component displayName; private final Component info; private SelectedGameMode(final String id, final GameType gameType) { this.gameType = gameType; this.displayName = Component.translatable("selectWorld.gameMode." + id); this.info = Component.translatable("selectWorld.gameMode." + id + ".info"); } public Component getInfo() { return this.info; } } @Environment(EnvType.CLIENT) public record WorldTypeEntry(@Nullable Holder preset) { private static final Component CUSTOM_WORLD_DESCRIPTION = Component.translatable("generator.custom"); public Component describePreset() { return (Component)Optional.ofNullable(this.preset) .flatMap(Holder::unwrapKey) .map(resourceKey -> Component.translatable(resourceKey.location().toLanguageKey("generator"))) .orElse(CUSTOM_WORLD_DESCRIPTION); } public boolean isAmplified() { return Optional.ofNullable(this.preset).flatMap(Holder::unwrapKey).filter(resourceKey -> resourceKey.equals(WorldPresets.AMPLIFIED)).isPresent(); } } }