WorldOpenFlows.java

net.minecraft.client.gui.screens.worldselection.WorldOpenFlows

信息

  • 全限定名:net.minecraft.client.gui.screens.worldselection.WorldOpenFlows
  • 类型:public class
  • 包:net.minecraft.client.gui.screens.worldselection
  • 源码路径:src/main/java/net/minecraft/client/gui/screens/worldselection/WorldOpenFlows.java
  • 起始行号:L84
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L85
    • 说明:

      TODO

  • WORLD_PACK_ID

    • 类型: UUID
    • 修饰符: private static final
    • 源码定位: L86
    • 说明:

      TODO

  • minecraft

    • 类型: Minecraft
    • 修饰符: private final
    • 源码定位: L87
    • 说明:

      TODO

  • levelSource

    • 类型: LevelStorageSource
    • 修饰符: private final
    • 源码定位: L88
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.screens.worldselection.WorldOpenFlows.Data
    • 类型: record
    • 修饰符: package-private
    • 源码定位: L194
    • 说明:

      TODO

构造器

public WorldOpenFlows(Minecraft minecraft, LevelStorageSource levelSource) @ L90

  • 构造器名:WorldOpenFlows
  • 源码定位:L90
  • 修饰符:public

参数:

  • minecraft: Minecraft
  • levelSource: LevelStorageSource

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void createFreshLevel(String levelId, LevelSettings levelSettings, WorldOptions options, Function<HolderLookup.Provider,WorldDimensions> dimensionsProvider, Screen parentScreen) @ L95

  • 方法名:createFreshLevel
  • 源码定位:L95
  • 返回类型:void
  • 修饰符:public

参数:

  • levelId: String
  • levelSettings: LevelSettings
  • options: WorldOptions
  • dimensionsProvider: Function<HolderLookup.Provider,WorldDimensions>
  • parentScreen: Screen

说明:

TODO

private LevelStorageSource.LevelStorageAccess createWorldAccess(String levelId) @ L134

  • 方法名:createWorldAccess
  • 源码定位:L134
  • 返回类型:LevelStorageSource.LevelStorageAccess
  • 修饰符:private

参数:

  • levelId: String

说明:

TODO

public void createLevelFromExistingSettings(LevelStorageSource.LevelStorageAccess levelSourceAccess, ReloadableServerResources serverResources, LayeredRegistryAccess<RegistryLayer> registryAccess, LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings, Optional<GameRules> gameRules) @ L149

  • 方法名:createLevelFromExistingSettings
  • 源码定位:L149
  • 返回类型:void
  • 修饰符:public

参数:

  • levelSourceAccess: LevelStorageSource.LevelStorageAccess
  • serverResources: ReloadableServerResources
  • registryAccess: LayeredRegistryAccess
  • worldDataAndGenSettings: LevelDataAndDimensions.WorldDataAndGenSettings
  • gameRules: Optional

说明:

TODO

public WorldStem loadWorldStem(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, boolean safeMode, PackRepository packRepository) @ L168

  • 方法名:loadWorldStem
  • 源码定位:L168
  • 返回类型:WorldStem
  • 修饰符:public

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • levelDataTag: Dynamic<?>
  • safeMode: boolean
  • packRepository: PackRepository

说明:

TODO

public Pair<LevelSettings,WorldCreationContext> recreateWorldData(LevelStorageSource.LevelStorageAccess levelSourceAccess) @ L183

  • 方法名:recreateWorldData
  • 源码定位:L183
  • 返回类型:Pair<LevelSettings,WorldCreationContext>
  • 修饰符:public

参数:

  • levelSourceAccess: LevelStorageSource.LevelStorageAccess

说明:

TODO

private <D,R> R loadWorldDataBlocking(WorldLoader.PackConfig packConfig, WorldLoader.WorldDataSupplier<D> worldDataGetter, WorldLoader.ResultFactory<D,R> worldDataSupplier) @ L238

  • 方法名:loadWorldDataBlocking
  • 源码定位:L238
  • 返回类型:<D,R> R
  • 修饰符:private

参数:

  • packConfig: WorldLoader.PackConfig
  • worldDataGetter: WorldLoader.WorldDataSupplier
  • worldDataSupplier: WorldLoader.ResultFactory<D,R>

说明:

TODO

private void askForBackup(LevelStorageSource.LevelStorageAccess levelAccess, boolean oldCustomized, Runnable proceedCallback, Runnable cancelCallback) @ L250

  • 方法名:askForBackup
  • 源码定位:L250
  • 返回类型:void
  • 修饰符:private

参数:

  • levelAccess: LevelStorageSource.LevelStorageAccess
  • oldCustomized: boolean
  • proceedCallback: Runnable
  • cancelCallback: Runnable

说明:

TODO

public static void confirmWorldCreation(Minecraft minecraft, CreateWorldScreen parent, Lifecycle lifecycle, Runnable task, boolean skipWarning) @ L274

  • 方法名:confirmWorldCreation
  • 源码定位:L274
  • 返回类型:void
  • 修饰符:public static

参数:

  • minecraft: Minecraft
  • parent: CreateWorldScreen
  • lifecycle: Lifecycle
  • task: Runnable
  • skipWarning: boolean

说明:

TODO

public void openWorld(String levelId, Runnable onCancel) @ L301

  • 方法名:openWorld
  • 源码定位:L301
  • 返回类型:void
  • 修饰符:public

参数:

  • levelId: String
  • onCancel: Runnable

说明:

TODO

private void openWorldLoadLevelData(LevelStorageSource.LevelStorageAccess worldAccess, Runnable onCancel) @ L309

  • 方法名:openWorldLoadLevelData
  • 源码定位:L309
  • 返回类型:void
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • onCancel: Runnable

说明:

TODO

private void openWorldCheckVersionCompatibility(LevelStorageSource.LevelStorageAccess worldAccess, LevelSummary summary, Dynamic<?> levelDataTag, Runnable onCancel) @ L342

  • 方法名:openWorldCheckVersionCompatibility
  • 源码定位:L342
  • 返回类型:void
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • summary: LevelSummary
  • levelDataTag: Dynamic<?>
  • onCancel: Runnable

说明:

TODO

private void createBackupAndOpenWorld(LevelStorageSource.LevelStorageAccess levelAccess, Dynamic<?> levelDataTag, Runnable onCancel, boolean backup) @ L376

  • 方法名:createBackupAndOpenWorld
  • 源码定位:L376
  • 返回类型:void
  • 修饰符:private

参数:

  • levelAccess: LevelStorageSource.LevelStorageAccess
  • levelDataTag: Dynamic<?>
  • onCancel: Runnable
  • backup: boolean

说明:

TODO

private void upgradeAndOpenWorld(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, Runnable onCancel) @ L381

  • 方法名:upgradeAndOpenWorld
  • 源码定位:L381
  • 返回类型:void
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • levelDataTag: Dynamic<?>
  • onCancel: Runnable

说明:

TODO

private Dynamic<?> tryFileFixAndReportErrors(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, UpgradeProgress upgradeProgress, Runnable cleanup) @ L415

  • 方法名:tryFileFixAndReportErrors
  • 源码定位:L415
  • 返回类型:Dynamic<?>
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • levelDataTag: Dynamic<?>
  • upgradeProgress: UpgradeProgress
  • cleanup: Runnable

说明:

TODO

private void openWorldLoadLevelStem(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, boolean safeMode, Runnable onCancel) @ L476

  • 方法名:openWorldLoadLevelStem
  • 源码定位:L476
  • 返回类型:void
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • levelDataTag: Dynamic<?>
  • safeMode: boolean
  • onCancel: Runnable

说明:

TODO

private void openWorldCheckWorldStemCompatibility(LevelStorageSource.LevelStorageAccess worldAccess, WorldStem worldStem, PackRepository packRepository, Runnable onCancel) @ L514

  • 方法名:openWorldCheckWorldStemCompatibility
  • 源码定位:L514
  • 返回类型:void
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • worldStem: WorldStem
  • packRepository: PackRepository
  • onCancel: Runnable

说明:

TODO

private void openWorldLoadBundledResourcePack(LevelStorageSource.LevelStorageAccess worldAccess, WorldStem worldStem, PackRepository packRepository, Runnable onCancel) @ L534

  • 方法名:openWorldLoadBundledResourcePack
  • 源码定位:L534
  • 返回类型:void
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • worldStem: WorldStem
  • packRepository: PackRepository
  • onCancel: Runnable

说明:

TODO

private void openWorldCheckDiskSpace(LevelStorageSource.LevelStorageAccess worldAccess, WorldStem worldStem, DownloadedPackSource packSource, PackRepository packRepository, Runnable onCancel) @ L556

  • 方法名:openWorldCheckDiskSpace
  • 源码定位:L556
  • 返回类型:void
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • worldStem: WorldStem
  • packSource: DownloadedPackSource
  • packRepository: PackRepository
  • onCancel: Runnable

说明:

TODO

private void openWorldDoLoad(LevelStorageSource.LevelStorageAccess worldAccess, WorldStem worldStem, PackRepository packRepository) @ L588

  • 方法名:openWorldDoLoad
  • 源码定位:L588
  • 返回类型:void
  • 修饰符:private

参数:

  • worldAccess: LevelStorageSource.LevelStorageAccess
  • worldStem: WorldStem
  • packRepository: PackRepository

说明:

TODO

private CompletableFuture<Void> loadBundledResourcePack(DownloadedPackSource packSource, LevelStorageSource.LevelStorageAccess levelSourceAccess) @ L592

  • 方法名:loadBundledResourcePack
  • 源码定位:L592
  • 返回类型:CompletableFuture
  • 修饰符:private

参数:

  • packSource: DownloadedPackSource
  • levelSourceAccess: LevelStorageSource.LevelStorageAccess

说明:

TODO

private CompletableFuture<Boolean> promptBundledPackLoadFailure() @ L604

  • 方法名:promptBundledPackLoadFailure
  • 源码定位:L604
  • 返回类型:CompletableFuture
  • 修饰符:private

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class WorldOpenFlows {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final UUID WORLD_PACK_ID = UUID.fromString("640a6a92-b6cb-48a0-b391-831586500359");
    private final Minecraft minecraft;
    private final LevelStorageSource levelSource;
 
    public WorldOpenFlows(Minecraft minecraft, LevelStorageSource levelSource) {
        this.minecraft = minecraft;
        this.levelSource = levelSource;
    }
 
    public void createFreshLevel(
        String levelId,
        LevelSettings levelSettings,
        WorldOptions options,
        Function<HolderLookup.Provider, WorldDimensions> dimensionsProvider,
        Screen parentScreen
    ) {
        this.minecraft.setScreenAndShow(new GenericMessageScreen(Component.translatable("selectWorld.data_read")));
        LevelStorageSource.LevelStorageAccess levelSourceAccess = this.createWorldAccess(levelId);
        if (levelSourceAccess != null) {
            PackRepository packRepository = ServerPacksSource.createPackRepository(levelSourceAccess);
            WorldDataConfiguration dataConfiguration = levelSettings.dataConfiguration();
 
            try {
                WorldLoader.PackConfig packConfig = new WorldLoader.PackConfig(packRepository, dataConfiguration, false, false);
                WorldStem worldStem = this.loadWorldDataBlocking(
                    packConfig,
                    context -> {
                        WorldDimensions dimensions = dimensionsProvider.apply(context.datapackWorldgen());
                        WorldDimensions.Complete completeDimensions = dimensions.bake(context.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM));
                        return new WorldLoader.DataLoadOutput<>(
                            new LevelDataAndDimensions.WorldDataAndGenSettings(
                                new PrimaryLevelData(levelSettings, completeDimensions.specialWorldProperty(), completeDimensions.lifecycle()),
                                new WorldGenSettings(options, dimensions)
                            ),
                            completeDimensions.dimensionsRegistryAccess()
                        );
                    },
                    WorldStem::new
                );
                this.minecraft.doWorldLoad(levelSourceAccess, packRepository, worldStem, Optional.empty(), true);
            } catch (Exception var11) {
                LOGGER.warn("Failed to load datapacks, can't proceed with server load", (Throwable)var11);
                levelSourceAccess.safeClose();
                this.minecraft.setScreen(parentScreen);
            }
        }
    }
 
    private LevelStorageSource.@Nullable LevelStorageAccess createWorldAccess(String levelId) {
        try {
            return this.levelSource.validateAndCreateAccess(levelId);
        } catch (IOException var3) {
            LOGGER.warn("Failed to read level {} data", levelId, var3);
            SystemToast.onWorldAccessFailure(this.minecraft, levelId);
            this.minecraft.setScreen(null);
            return null;
        } catch (ContentValidationException var4) {
            LOGGER.warn("{}", var4.getMessage());
            this.minecraft.setScreen(NoticeWithLinkScreen.createWorldSymlinkWarningScreen(() -> this.minecraft.setScreen(null)));
            return null;
        }
    }
 
    public void createLevelFromExistingSettings(
        LevelStorageSource.LevelStorageAccess levelSourceAccess,
        ReloadableServerResources serverResources,
        LayeredRegistryAccess<RegistryLayer> registryAccess,
        LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings,
        Optional<GameRules> gameRules
    ) {
        PackRepository packRepository = ServerPacksSource.createPackRepository(levelSourceAccess);
        CloseableResourceManager resourceManager = new WorldLoader.PackConfig(
                packRepository, worldDataAndGenSettings.data().getDataConfiguration(), false, false
            )
            .createResourceManager()
            .getSecond();
        this.minecraft
            .doWorldLoad(
                levelSourceAccess, packRepository, new WorldStem(resourceManager, serverResources, registryAccess, worldDataAndGenSettings), gameRules, true
            );
    }
 
    public WorldStem loadWorldStem(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, boolean safeMode, PackRepository packRepository) throws Exception {
        WorldLoader.PackConfig packConfig = LevelStorageSource.getPackConfig(levelDataTag, packRepository, safeMode);
        return this.loadWorldDataBlocking(
            packConfig,
            context -> {
                Registry<LevelStem> datapackDimensions = context.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM);
                LevelDataAndDimensions data = LevelStorageSource.getLevelDataAndDimensions(
                    worldAccess, levelDataTag, context.dataConfiguration(), datapackDimensions, context.datapackWorldgen()
                );
                return new WorldLoader.DataLoadOutput<>(data.worldDataAndGenSettings(), data.dimensions().dimensionsRegistryAccess());
            },
            WorldStem::new
        );
    }
 
    public Pair<LevelSettings, WorldCreationContext> recreateWorldData(LevelStorageSource.LevelStorageAccess levelSourceAccess) throws Exception {
        PackRepository packRepository = ServerPacksSource.createPackRepository(levelSourceAccess);
        Dynamic<?> unfixedDataTag = levelSourceAccess.getUnfixedDataTag(false);
        int dataVersion = NbtUtils.getDataVersion(unfixedDataTag);
        if (DataFixers.getFileFixer().requiresFileFixing(dataVersion)) {
            throw new IllegalStateException("Can't recreate world before file fixing; shouldn't be able to get here");
        } else {
            Dynamic<?> levelDataTag = DataFixTypes.LEVEL.updateToCurrentVersion(DataFixers.getDataFixer(), unfixedDataTag, dataVersion);
            WorldLoader.PackConfig packConfig = LevelStorageSource.getPackConfig(levelDataTag, packRepository, false);
 
            @OnlyIn(Dist.CLIENT)
            record Data(LevelSettings levelSettings, WorldOptions options, Registry<LevelStem> existingDimensions) {
            }
 
            return this.loadWorldDataBlocking(
                packConfig,
                context -> {
                    Registry<LevelStem> noDatapackDimensions = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.stable()).freeze();
                    LevelDataAndDimensions existingData = LevelStorageSource.getLevelDataAndDimensions(
                        levelSourceAccess, levelDataTag, context.dataConfiguration(), noDatapackDimensions, context.datapackWorldgen()
                    );
                    return new WorldLoader.DataLoadOutput<>(
                        new Data(
                            existingData.worldDataAndGenSettings().data().getLevelSettings(),
                            existingData.worldDataAndGenSettings().genSettings().options(),
                            existingData.dimensions().dimensions()
                        ),
                        context.datapackDimensions()
                    );
                },
                (resources, managers, registries, loadedData) -> {
                    resources.close();
                    DataResult<GameRuleMap> existingGameRules = LevelStorageSource.readExistingSavedData(
                        levelSourceAccess, registries.compositeAccess(), GameRuleMap.TYPE
                    );
                    existingGameRules.ifError(e -> LOGGER.error("Failed to parse existing game rules: {}", e.message()));
                    InitialWorldCreationOptions initialWorldCreationOptions = new InitialWorldCreationOptions(
                        WorldCreationUiState.SelectedGameMode.SURVIVAL, existingGameRules.result().orElse(GameRuleMap.of()), null
                    );
                    return Pair.of(
                        loadedData.levelSettings,
                        new WorldCreationContext(
                            loadedData.options,
                            new WorldDimensions(loadedData.existingDimensions),
                            registries,
                            managers,
                            loadedData.levelSettings.dataConfiguration(),
                            initialWorldCreationOptions
                        )
                    );
                }
            );
        }
    }
 
    private <D, R> R loadWorldDataBlocking(
        WorldLoader.PackConfig packConfig, WorldLoader.WorldDataSupplier<D> worldDataGetter, WorldLoader.ResultFactory<D, R> worldDataSupplier
    ) throws Exception {
        long start = Util.getMillis();
        WorldLoader.InitConfig config = new WorldLoader.InitConfig(packConfig, Commands.CommandSelection.INTEGRATED, LevelBasedPermissionSet.GAMEMASTER);
        CompletableFuture<R> resourceLoad = WorldLoader.load(config, worldDataGetter, worldDataSupplier, Util.backgroundExecutor(), this.minecraft);
        this.minecraft.managedBlock(resourceLoad::isDone);
        long end = Util.getMillis();
        LOGGER.debug("World resource load blocked for {} ms", end - start);
        return resourceLoad.get();
    }
 
    private void askForBackup(LevelStorageSource.LevelStorageAccess levelAccess, boolean oldCustomized, Runnable proceedCallback, Runnable cancelCallback) {
        Component backupQuestion;
        Component backupWarning;
        if (oldCustomized) {
            backupQuestion = Component.translatable("selectWorld.backupQuestion.customized");
            backupWarning = Component.translatable("selectWorld.backupWarning.customized");
        } else {
            backupQuestion = Component.translatable("selectWorld.backupQuestion.experimental");
            backupWarning = Component.translatable("selectWorld.backupWarning.experimental");
        }
 
        this.minecraft
            .setScreen(
                new BackupConfirmScreen(
                    cancelCallback,
                    (backup, eraseCache) -> EditWorldScreen.conditionallyMakeBackupAndShowToast(backup, levelAccess)
                        .thenAcceptAsync(var1x -> proceedCallback.run(), this.minecraft),
                    backupQuestion,
                    backupWarning,
                    false
                )
            );
    }
 
    public static void confirmWorldCreation(Minecraft minecraft, CreateWorldScreen parent, Lifecycle lifecycle, Runnable task, boolean skipWarning) {
        BooleanConsumer callback = confirmed -> {
            if (confirmed) {
                task.run();
            } else {
                minecraft.setScreen(parent);
            }
        };
        if (skipWarning || lifecycle == Lifecycle.stable()) {
            task.run();
        } else if (lifecycle == Lifecycle.experimental()) {
            minecraft.setScreen(
                new ConfirmScreen(
                    callback,
                    Component.translatable("selectWorld.warning.experimental.title"),
                    Component.translatable("selectWorld.warning.experimental.question")
                )
            );
        } else {
            minecraft.setScreen(
                new ConfirmScreen(
                    callback, Component.translatable("selectWorld.warning.deprecated.title"), Component.translatable("selectWorld.warning.deprecated.question")
                )
            );
        }
    }
 
    public void openWorld(String levelId, Runnable onCancel) {
        this.minecraft.setScreenAndShow(new GenericMessageScreen(Component.translatable("selectWorld.data_read")));
        LevelStorageSource.LevelStorageAccess worldAccess = this.createWorldAccess(levelId);
        if (worldAccess != null) {
            this.openWorldLoadLevelData(worldAccess, onCancel);
        }
    }
 
    private void openWorldLoadLevelData(LevelStorageSource.LevelStorageAccess worldAccess, Runnable onCancel) {
        this.minecraft.setScreenAndShow(new GenericMessageScreen(Component.translatable("selectWorld.data_read")));
 
        Dynamic<?> levelDataTag;
        LevelSummary summary;
        try {
            levelDataTag = worldAccess.getUnfixedDataTag(false);
            summary = worldAccess.fixAndGetSummaryFromTag(levelDataTag);
        } catch (NbtException | ReportedNbtException | IOException var10) {
            this.minecraft.setScreen(new RecoverWorldDataScreen(this.minecraft, success -> {
                if (success) {
                    this.openWorldLoadLevelData(worldAccess, onCancel);
                } else {
                    worldAccess.safeClose();
                    onCancel.run();
                }
            }, worldAccess));
            return;
        } catch (OutOfMemoryError var11) {
            MemoryReserve.release();
            String detailedMessage = "Ran out of memory trying to read level data of world folder \"" + worldAccess.getLevelId() + "\"";
            LOGGER.error(LogUtils.FATAL_MARKER, detailedMessage);
            OutOfMemoryError detailedException = new OutOfMemoryError("Ran out of memory reading level data");
            detailedException.initCause(var11);
            CrashReport crashReport = CrashReport.forThrowable(detailedException, detailedMessage);
            CrashReportCategory worldDetails = crashReport.addCategory("World details");
            worldDetails.setDetail("World folder", worldAccess.getLevelId());
            throw new ReportedException(crashReport);
        }
 
        this.openWorldCheckVersionCompatibility(worldAccess, summary, levelDataTag, onCancel);
    }
 
    private void openWorldCheckVersionCompatibility(
        LevelStorageSource.LevelStorageAccess worldAccess, LevelSummary summary, Dynamic<?> levelDataTag, Runnable onCancel
    ) {
        if (!summary.isCompatible()) {
            worldAccess.safeClose();
            this.minecraft
                .setScreen(
                    new AlertScreen(
                        onCancel,
                        Component.translatable("selectWorld.incompatible.title").withColor(-65536),
                        Component.translatable("selectWorld.incompatible.description", summary.getWorldVersionName())
                    )
                );
        } else {
            LevelSummary.BackupStatus backupStatus = summary.backupStatus();
            if (backupStatus.shouldBackup()) {
                String questionKey = "selectWorld.backupQuestion." + backupStatus.getTranslationKey();
                String warningKey = "selectWorld.backupWarning." + backupStatus.getTranslationKey();
                MutableComponent backupQuestion = Component.translatable(questionKey);
                if (backupStatus.isSevere()) {
                    backupQuestion.withColor(-2142128);
                }
 
                Component backupWarning = Component.translatable(warningKey, summary.getWorldVersionName(), SharedConstants.getCurrentVersion().name());
                this.minecraft.setScreen(new BackupConfirmScreen(() -> {
                    worldAccess.safeClose();
                    onCancel.run();
                }, (backup, eraseCache) -> this.createBackupAndOpenWorld(worldAccess, levelDataTag, onCancel, backup), backupQuestion, backupWarning, false));
            } else {
                this.upgradeAndOpenWorld(worldAccess, levelDataTag, onCancel);
            }
        }
    }
 
    private void createBackupAndOpenWorld(LevelStorageSource.LevelStorageAccess levelAccess, Dynamic<?> levelDataTag, Runnable onCancel, boolean backup) {
        EditWorldScreen.conditionallyMakeBackupAndShowToast(backup, levelAccess)
            .thenAcceptAsync(var4 -> this.upgradeAndOpenWorld(levelAccess, levelDataTag, onCancel), this.minecraft);
    }
 
    private void upgradeAndOpenWorld(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, Runnable onCancel) {
        Runnable cleanup = () -> {
            worldAccess.safeClose();
            onCancel.run();
        };
        int dataVersion = NbtUtils.getDataVersion(levelDataTag);
        boolean requiresFileFixing = DataFixers.getFileFixer().requiresFileFixing(dataVersion);
        UpgradeProgress upgradeProgress = new UpgradeProgress();
        if (requiresFileFixing) {
            FileFixerProgressScreen progressScreen = new FileFixerProgressScreen(upgradeProgress);
            this.minecraft.setScreenAndShow(progressScreen);
        }
 
        Util.backgroundExecutor().execute(() -> {
            Dynamic<?> levelDataTagFixed = this.tryFileFixAndReportErrors(worldAccess, levelDataTag, upgradeProgress, cleanup);
            if (levelDataTagFixed != null) {
                this.minecraft.execute(() -> {
                    if (requiresFileFixing) {
                        ConfirmScreen loadConfirmScreen = new ConfirmScreen(result -> {
                            if (result) {
                                this.openWorldLoadLevelStem(worldAccess, levelDataTagFixed, false, onCancel);
                            } else {
                                cleanup.run();
                            }
                        }, Component.translatable("upgradeWorld.done"), Component.translatable("upgradeWorld.joinNow"));
                        this.minecraft.setScreenAndShow(loadConfirmScreen);
                    } else {
                        this.openWorldLoadLevelStem(worldAccess, levelDataTagFixed, false, onCancel);
                    }
                });
            }
        });
    }
 
    private @Nullable Dynamic<?> tryFileFixAndReportErrors(
        LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, UpgradeProgress upgradeProgress, Runnable cleanup
    ) {
        try {
            return DataFixers.getFileFixer().fix(worldAccess, levelDataTag, upgradeProgress);
        } catch (CanceledFileFixException var8) {
            this.minecraft
                .execute(
                    () -> this.minecraft
                        .setScreenAndShow(
                            new AlertScreen(
                                cleanup,
                                Component.translatable("upgradeWorld.canceled.title"),
                                Component.translatable("upgradeWorld.canceled.message"),
                                CommonComponents.GUI_OK,
                                true
                            )
                        )
                );
            return null;
        } catch (AbortedFileFixException var9) {
            this.minecraft
                .execute(
                    () -> {
                        if (var9.getCause() instanceof CowFSSymlinkException) {
                            this.minecraft
                                .setScreenAndShow(
                                    new AlertScreen(
                                        cleanup, Component.translatable("upgradeWorld.symlink.title"), Component.translatable("upgradeWorld.symlink.message")
                                    )
                                );
                        } else {
                            this.minecraft.setScreenAndShow(new FileFixerAbortedScreen(cleanup, Component.translatable("upgradeWorld.aborted.message")));
                        }
                    }
                );
            return null;
        } catch (FailedCleanupFileFixException var10) {
            this.minecraft
                .execute(
                    () -> this.minecraft
                        .setScreenAndShow(
                            new AlertScreen(
                                cleanup,
                                Component.translatable("upgradeWorld.failed_cleanup.title"),
                                Component.translatable("upgradeWorld.failed_cleanup.message", Component.literal(var10.newWorldFolderName()).withColor(-8355712))
                            )
                        )
                );
            return null;
        } catch (FileFixException var11) {
            this.minecraft.delayCrash(var11.makeReportedException().getReport());
            return null;
        } catch (Exception var12) {
            LOGGER.error("Failed to upgrade the file structure of the world.", (Throwable)var12);
            CrashReport report = CrashReport.forThrowable(var12, "Failed to update file structure");
            this.minecraft.delayCrash(report);
            return null;
        }
    }
 
    private void openWorldLoadLevelStem(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, boolean safeMode, Runnable onCancel) {
        this.minecraft.setScreenAndShow(new GenericMessageScreen(Component.translatable("selectWorld.resource_load")));
        PackRepository packRepository = ServerPacksSource.createPackRepository(worldAccess);
 
        WorldStem worldStem;
        try {
            worldStem = this.loadWorldStem(worldAccess, levelDataTag, safeMode, packRepository);
 
            for (LevelStem levelStem : worldStem.registries().compositeAccess().lookupOrThrow(Registries.LEVEL_STEM)) {
                levelStem.generator().validate();
            }
        } catch (Exception var9) {
            LOGGER.warn("Failed to load level data or datapacks, can't proceed with server load", (Throwable)var9);
            if (!safeMode) {
                this.minecraft.setScreen(new DatapackLoadFailureScreen(() -> {
                    worldAccess.safeClose();
                    onCancel.run();
                }, () -> this.openWorldLoadLevelStem(worldAccess, levelDataTag, true, onCancel)));
            } else {
                worldAccess.safeClose();
                this.minecraft
                    .setScreen(
                        new AlertScreen(
                            onCancel,
                            Component.translatable("datapackFailure.safeMode.failed.title"),
                            Component.translatable("datapackFailure.safeMode.failed.description"),
                            CommonComponents.GUI_BACK,
                            true
                        )
                    );
            }
 
            return;
        }
 
        this.openWorldCheckWorldStemCompatibility(worldAccess, worldStem, packRepository, onCancel);
    }
 
    private void openWorldCheckWorldStemCompatibility(
        LevelStorageSource.LevelStorageAccess worldAccess, WorldStem worldStem, PackRepository packRepository, Runnable onCancel
    ) {
        LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings = worldStem.worldDataAndGenSettings();
        WorldData data = worldDataAndGenSettings.data();
        boolean oldCustomized = worldDataAndGenSettings.genSettings().options().isOldCustomizedWorld();
        boolean unstable = data.worldGenSettingsLifecycle() != Lifecycle.stable();
        if (!oldCustomized && !unstable) {
            this.openWorldLoadBundledResourcePack(worldAccess, worldStem, packRepository, onCancel);
        } else {
            this.askForBackup(
                worldAccess, oldCustomized, () -> this.openWorldLoadBundledResourcePack(worldAccess, worldStem, packRepository, onCancel), () -> {
                    worldStem.close();
                    worldAccess.safeClose();
                    onCancel.run();
                }
            );
        }
    }
 
    private void openWorldLoadBundledResourcePack(
        LevelStorageSource.LevelStorageAccess worldAccess, WorldStem worldStem, PackRepository packRepository, Runnable onCancel
    ) {
        DownloadedPackSource packSource = this.minecraft.getDownloadedPackSource();
        this.loadBundledResourcePack(packSource, worldAccess).thenApply(unused -> true).exceptionallyComposeAsync(t -> {
            LOGGER.warn("Failed to load pack: ", t);
            return this.promptBundledPackLoadFailure();
        }, this.minecraft).thenAcceptAsync(result -> {
            if (result) {
                this.openWorldCheckDiskSpace(worldAccess, worldStem, packSource, packRepository, onCancel);
            } else {
                packSource.popAll();
                worldStem.close();
                worldAccess.safeClose();
                onCancel.run();
            }
        }, this.minecraft).exceptionally(e -> {
            this.minecraft.delayCrash(CrashReport.forThrowable(e, "Load world"));
            return null;
        });
    }
 
    private void openWorldCheckDiskSpace(
        LevelStorageSource.LevelStorageAccess worldAccess,
        WorldStem worldStem,
        DownloadedPackSource packSource,
        PackRepository packRepository,
        Runnable onCancel
    ) {
        if (worldAccess.checkForLowDiskSpace()) {
            this.minecraft
                .setScreen(
                    new ConfirmScreen(
                        skip -> {
                            if (skip) {
                                this.openWorldDoLoad(worldAccess, worldStem, packRepository);
                            } else {
                                packSource.popAll();
                                worldStem.close();
                                worldAccess.safeClose();
                                onCancel.run();
                            }
                        },
                        Component.translatable("selectWorld.warning.lowDiskSpace.title").withStyle(ChatFormatting.RED),
                        Component.translatable("selectWorld.warning.lowDiskSpace.description"),
                        CommonComponents.GUI_CONTINUE,
                        CommonComponents.GUI_BACK
                    )
                );
        } else {
            this.openWorldDoLoad(worldAccess, worldStem, packRepository);
        }
    }
 
    private void openWorldDoLoad(LevelStorageSource.LevelStorageAccess worldAccess, WorldStem worldStem, PackRepository packRepository) {
        this.minecraft.doWorldLoad(worldAccess, packRepository, worldStem, Optional.empty(), false);
    }
 
    private CompletableFuture<Void> loadBundledResourcePack(DownloadedPackSource packSource, LevelStorageSource.LevelStorageAccess levelSourceAccess) {
        Path mapResourceFile = levelSourceAccess.getLevelPath(LevelResource.MAP_RESOURCE_FILE);
        if (Files.exists(mapResourceFile) && !Files.isDirectory(mapResourceFile)) {
            packSource.configureForLocalWorld();
            CompletableFuture<Void> result = packSource.waitForPackFeedback(WORLD_PACK_ID);
            packSource.pushLocalPack(WORLD_PACK_ID, mapResourceFile);
            return result;
        } else {
            return CompletableFuture.completedFuture(null);
        }
    }
 
    private CompletableFuture<Boolean> promptBundledPackLoadFailure() {
        CompletableFuture<Boolean> result = new CompletableFuture<>();
        this.minecraft
            .setScreen(
                new ConfirmScreen(
                    result::complete,
                    Component.translatable("multiplayer.texturePrompt.failure.line1"),
                    Component.translatable("multiplayer.texturePrompt.failure.line2"),
                    CommonComponents.GUI_PROCEED,
                    CommonComponents.GUI_CANCEL
                )
            );
        return result;
    }
}

引用的其他类

  • CrashReport

    • 引用位置: 方法调用
    • 关联成员: CrashReport.forThrowable()
  • ReportedException

    • 引用位置: 构造调用
    • 关联成员: ReportedException()
  • SharedConstants

    • 引用位置: 方法调用
    • 关联成员: SharedConstants.getCurrentVersion()
  • Minecraft

    • 引用位置: 参数/字段
  • SystemToast

    • 引用位置: 方法调用
    • 关联成员: SystemToast.onWorldAccessFailure()
  • AlertScreen

    • 引用位置: 构造调用
    • 关联成员: AlertScreen()
  • BackupConfirmScreen

    • 引用位置: 构造调用
    • 关联成员: BackupConfirmScreen()
  • ConfirmScreen

    • 引用位置: 构造调用
    • 关联成员: ConfirmScreen()
  • DatapackLoadFailureScreen

    • 引用位置: 构造调用
    • 关联成员: DatapackLoadFailureScreen()
  • FileFixerAbortedScreen

    • 引用位置: 构造调用
    • 关联成员: FileFixerAbortedScreen()
  • GenericMessageScreen

    • 引用位置: 构造调用
    • 关联成员: GenericMessageScreen()
  • NoticeWithLinkScreen

    • 引用位置: 方法调用
    • 关联成员: NoticeWithLinkScreen.createWorldSymlinkWarningScreen()
  • RecoverWorldDataScreen

    • 引用位置: 构造调用
    • 关联成员: RecoverWorldDataScreen()
  • Screen

    • 引用位置: 参数
  • CreateWorldScreen

    • 引用位置: 参数
  • EditWorldScreen

    • 引用位置: 方法调用
    • 关联成员: EditWorldScreen.conditionallyMakeBackupAndShowToast()
  • FileFixerProgressScreen

    • 引用位置: 构造调用
    • 关联成员: FileFixerProgressScreen()
  • InitialWorldCreationOptions

    • 引用位置: 构造调用
    • 关联成员: InitialWorldCreationOptions()
  • WorldCreationContext

    • 引用位置: 构造调用/返回值
    • 关联成员: WorldCreationContext()
  • DownloadedPackSource

    • 引用位置: 参数
  • HolderLookup

    • 引用位置: 参数
  • LayeredRegistryAccess

    • 引用位置: 参数
  • NbtUtils

    • 引用位置: 方法调用
    • 关联成员: NbtUtils.getDataVersion()
  • Component

    • 引用位置: 方法调用
    • 关联成员: Component.literal(), Component.translatable()
  • RegistryLayer

    • 引用位置: 参数
  • ReloadableServerResources

    • 引用位置: 参数
  • WorldLoader

    • 引用位置: 参数/方法调用/构造调用
    • 关联成员: InitConfig(), PackConfig(), WorldLoader.InitConfig(), WorldLoader.PackConfig(), WorldLoader.load()
  • WorldStem

    • 引用位置: 参数/构造调用/返回值
    • 关联成员: WorldStem()
  • PackRepository

    • 引用位置: 参数
  • ServerPacksSource

    • 引用位置: 方法调用
    • 关联成员: ServerPacksSource.createPackRepository()
  • MemoryReserve

    • 引用位置: 方法调用
    • 关联成员: MemoryReserve.release()
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.backgroundExecutor(), Util.getMillis()
  • DataFixers

    • 引用位置: 方法调用
    • 关联成员: DataFixers.getDataFixer(), DataFixers.getFileFixer()
  • UpgradeProgress

    • 引用位置: 参数/构造调用
    • 关联成员: UpgradeProgress()
  • ResolvableProfile

    • 引用位置: 参数/返回值
  • LevelSettings

    • 引用位置: 参数/返回值
  • GameRuleMap

    • 引用位置: 方法调用
    • 关联成员: GameRuleMap.of()
  • GameRules

    • 引用位置: 参数
  • WorldDimensions

    • 引用位置: 参数/构造调用
    • 关联成员: WorldDimensions()
  • WorldGenSettings

    • 引用位置: 构造调用
    • 关联成员: WorldGenSettings()
  • WorldOptions

    • 引用位置: 参数
  • LevelDataAndDimensions

    • 引用位置: 参数/方法调用/构造调用
    • 关联成员: LevelDataAndDimensions.WorldDataAndGenSettings(), WorldDataAndGenSettings()
  • LevelStorageSource

    • 引用位置: 参数/字段/方法调用/返回值
    • 关联成员: LevelStorageSource.getLevelDataAndDimensions(), LevelStorageSource.getPackConfig(), LevelStorageSource.readExistingSavedData()
  • LevelSummary

    • 引用位置: 参数
  • PrimaryLevelData

    • 引用位置: 构造调用
    • 关联成员: PrimaryLevelData()