Main.java

net.minecraft.server.Main

信息

  • 全限定名:net.minecraft.server.Main
  • 类型:public class
  • 包:net.minecraft.server
  • 源码路径:src/main/java/net/minecraft/server/Main.java
  • 起始行号:L62
  • 职责:

    TODO

字段/常量

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

      TODO

内部类/嵌套类型

构造器

方法

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

public static void main(String[] args) @ L65

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

参数:

  • args: String[]

说明:

TODO

private static WorldLoader.DataLoadOutput<LevelDataAndDimensions.WorldDataAndGenSettings> createNewWorldData(DedicatedServerSettings settings, WorldLoader.DataLoadContext context, Registry<LevelStem> datapackDimensions, boolean demoMode, boolean bonusChest) @ L231

  • 方法名:createNewWorldData
  • 源码定位:L231
  • 返回类型:WorldLoader.DataLoadOutput<LevelDataAndDimensions.WorldDataAndGenSettings>
  • 修饰符:private static

参数:

  • settings: DedicatedServerSettings
  • context: WorldLoader.DataLoadContext
  • datapackDimensions: Registry
  • demoMode: boolean
  • bonusChest: boolean

说明:

TODO

private static void writePidFile(Path path) @ L263

  • 方法名:writePidFile
  • 源码定位:L263
  • 返回类型:void
  • 修饰符:private static

参数:

  • path: Path

说明:

TODO

private static WorldLoader.InitConfig loadOrCreateConfig(DedicatedServerProperties properties, Dynamic<?> levelDataTag, boolean safeModeEnabled, PackRepository packRepository) @ L272

  • 方法名:loadOrCreateConfig
  • 源码定位:L272
  • 返回类型:WorldLoader.InitConfig
  • 修饰符:private static

参数:

  • properties: DedicatedServerProperties
  • levelDataTag: Dynamic<?>
  • safeModeEnabled: boolean
  • packRepository: PackRepository

说明:

TODO

private static void forceUpgrade(LevelStorageSource.LevelStorageAccess storageSource, DataFixer fixerUpper, boolean eraseCache, BooleanSupplier isRunning, RegistryAccess registryAccess, boolean recreateRegionFiles) @ L290

  • 方法名:forceUpgrade
  • 源码定位:L290
  • 返回类型:void
  • 修饰符:private static

参数:

  • storageSource: LevelStorageSource.LevelStorageAccess
  • fixerUpper: DataFixer
  • eraseCache: boolean
  • isRunning: BooleanSupplier
  • registryAccess: RegistryAccess
  • recreateRegionFiles: boolean

说明:

TODO

代码

public class Main {
    private static final Logger LOGGER = LogUtils.getLogger();
 
    @SuppressForbidden(reason = "System.out needed before bootstrap")
    public static void main(String[] args) {
        SharedConstants.tryDetectVersion();
        OptionParser parser = new OptionParser();
        OptionSpec<Void> nogui = parser.accepts("nogui");
        OptionSpec<Void> initSettings = parser.accepts("initSettings", "Initializes 'server.properties' and 'eula.txt', then quits");
        OptionSpec<Void> demo = parser.accepts("demo");
        OptionSpec<Void> bonusChest = parser.accepts("bonusChest");
        OptionSpec<Void> forceUpgrade = parser.accepts("forceUpgrade");
        OptionSpec<Void> eraseCache = parser.accepts("eraseCache");
        OptionSpec<Void> recreateRegionFiles = parser.accepts("recreateRegionFiles");
        OptionSpec<Void> safeMode = parser.accepts("safeMode", "Loads level with vanilla datapack only");
        OptionSpec<Void> help = parser.accepts("help").forHelp();
        OptionSpec<String> universe = parser.accepts("universe").withRequiredArg().defaultsTo(".");
        OptionSpec<String> worldName = parser.accepts("world").withRequiredArg();
        OptionSpec<Integer> port = parser.accepts("port").withRequiredArg().ofType(Integer.class).defaultsTo(-1);
        OptionSpec<String> serverId = parser.accepts("serverId").withRequiredArg();
        OptionSpec<Void> jfrProfilingOption = parser.accepts("jfrProfile");
        OptionSpec<Path> pidFile = parser.accepts("pidFile").withRequiredArg().withValuesConvertedBy(new PathConverter());
        OptionSpec<String> nonOptions = parser.nonOptions();
 
        try {
            OptionSet options = parser.parse(args);
            if (options.has(help)) {
                parser.printHelpOn(System.err);
                return;
            }
 
            Path pidFilePath = options.valueOf(pidFile);
            if (pidFilePath != null) {
                writePidFile(pidFilePath);
            }
 
            CrashReport.preload();
            if (options.has(jfrProfilingOption)) {
                JvmProfiler.INSTANCE.start(Environment.SERVER);
            }
 
            Bootstrap.bootStrap();
            Bootstrap.validate();
            Util.startTimerHackThread();
            Path settingsFile = Paths.get("server.properties");
            DedicatedServerSettings settings = new DedicatedServerSettings(settingsFile);
            settings.forceSave();
            RegionFileVersion.configure(settings.getProperties().regionFileComression);
            Path eulaFile = Paths.get("eula.txt");
            Eula eula = new Eula(eulaFile);
            if (options.has(initSettings)) {
                LOGGER.info("Initialized '{}' and '{}'", settingsFile.toAbsolutePath(), eulaFile.toAbsolutePath());
                return;
            }
 
            if (!eula.hasAgreedToEULA()) {
                LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
                return;
            }
 
            File universePath = new File(options.valueOf(universe));
            Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), universePath);
            String levelName = Optional.ofNullable(options.valueOf(worldName)).orElse(settings.getProperties().levelName);
            LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(universePath.toPath());
            LevelStorageSource.LevelStorageAccess access = levelStorageSource.validateAndCreateAccess(levelName);
            Dynamic<?> levelDataTag;
            if (access.hasWorldData()) {
                Dynamic<?> levelDataUnfixed;
                try {
                    levelDataUnfixed = access.getUnfixedDataTagWithFallback();
                } catch (NbtException | ReportedNbtException | IOException var39) {
                    LOGGER.error("Failed to load world data. World files may be corrupted. Shutting down.", (Throwable)var39);
                    return;
                }
 
                LevelSummary summary = access.fixAndGetSummaryFromTag(levelDataUnfixed);
                if (summary.requiresManualConversion()) {
                    LOGGER.info("This world must be opened in an older version (like 1.6.4) to be safely converted");
                    return;
                }
 
                if (!summary.isCompatible()) {
                    LOGGER.info("This world was created by an incompatible version.");
                    return;
                }
 
                levelDataTag = DataFixers.getFileFixer().fix(access, levelDataUnfixed, new UpgradeProgress());
            } else {
                levelDataTag = null;
            }
 
            boolean safeModeEnabled = options.has(safeMode);
            if (safeModeEnabled) {
                LOGGER.warn("Safe mode active, only vanilla datapack will be loaded");
            }
 
            PackRepository packRepository = ServerPacksSource.createPackRepository(access);
 
            WorldStem worldStem;
            try {
                WorldLoader.InitConfig worldLoadConfig = loadOrCreateConfig(settings.getProperties(), levelDataTag, safeModeEnabled, packRepository);
                worldStem = Util.<WorldStem>blockUntilDone(
                        executor -> WorldLoader.load(
                            worldLoadConfig,
                            context -> {
                                Registry<LevelStem> datapackDimensions = context.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM);
                                if (levelDataTag != null) {
                                    LevelDataAndDimensions worldData = LevelStorageSource.getLevelDataAndDimensions(
                                        access, levelDataTag, context.dataConfiguration(), datapackDimensions, context.datapackWorldgen()
                                    );
                                    return new WorldLoader.DataLoadOutput<>(
                                        worldData.worldDataAndGenSettings(), worldData.dimensions().dimensionsRegistryAccess()
                                    );
                                } else {
                                    LOGGER.info("No existing world data, creating new world");
                                    return createNewWorldData(settings, context, datapackDimensions, options.has(demo), options.has(bonusChest));
                                }
                            },
                            WorldStem::new,
                            Util.backgroundExecutor(),
                            executor
                        )
                    )
                    .get();
            } catch (Exception var38) {
                LOGGER.warn(
                    "Failed to load datapacks, can't proceed with server load. You can either fix your datapacks or reset to vanilla with --safeMode",
                    (Throwable)var38
                );
                return;
            }
 
            RegistryAccess.Frozen registryHolder = worldStem.registries().compositeAccess();
            WorldData data = worldStem.worldDataAndGenSettings().data();
            boolean recreateRegionFilesValue = options.has(recreateRegionFiles);
            if (options.has(forceUpgrade) || recreateRegionFilesValue) {
                forceUpgrade(access, DataFixers.getDataFixer(), options.has(eraseCache), () -> true, registryHolder, recreateRegionFilesValue);
            }
 
            access.saveDataTag(data);
            final DedicatedServer dedicatedServer = MinecraftServer.spin(
                thread -> {
                    DedicatedServer server = new DedicatedServer(
                        thread, access, packRepository, worldStem, Optional.empty(), settings, DataFixers.getDataFixer(), services
                    );
                    server.setPort(options.valueOf(port));
                    server.setDemo(options.has(demo));
                    server.setId(options.valueOf(serverId));
                    boolean gui = !options.has(nogui) && !options.valuesOf(nonOptions).contains("nogui");
                    if (gui && !GraphicsEnvironment.isHeadless()) {
                        server.showGui();
                    }
 
                    return server;
                }
            );
            Thread shutdownThread = new Thread("Server Shutdown Thread") {
                @Override
                public void run() {
                    dedicatedServer.halt(true);
                }
            };
            shutdownThread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER));
            Runtime.getRuntime().addShutdownHook(shutdownThread);
        } catch (Throwable var40) {
            LOGGER.error(LogUtils.FATAL_MARKER, "Failed to start the minecraft server", var40);
        }
    }
 
    private static WorldLoader.DataLoadOutput<LevelDataAndDimensions.WorldDataAndGenSettings> createNewWorldData(
        DedicatedServerSettings settings, WorldLoader.DataLoadContext context, Registry<LevelStem> datapackDimensions, boolean demoMode, boolean bonusChest
    ) {
        LevelSettings createLevelSettings;
        WorldOptions worldOptions;
        WorldDimensions dimensions;
        if (demoMode) {
            createLevelSettings = MinecraftServer.DEMO_SETTINGS;
            worldOptions = WorldOptions.DEMO_OPTIONS;
            dimensions = WorldPresets.createNormalWorldDimensions(context.datapackWorldgen());
        } else {
            DedicatedServerProperties properties = settings.getProperties();
            createLevelSettings = new LevelSettings(
                properties.levelName,
                properties.gameMode.get(),
                new LevelSettings.DifficultySettings(properties.difficulty.get(), properties.hardcore, false),
                false,
                context.dataConfiguration()
            );
            worldOptions = bonusChest ? properties.worldOptions.withBonusChest(true) : properties.worldOptions;
            dimensions = properties.createDimensions(context.datapackWorldgen());
        }
 
        WorldDimensions.Complete finalDimensions = dimensions.bake(datapackDimensions);
        Lifecycle lifecycle = finalDimensions.lifecycle().add(context.datapackWorldgen().allRegistriesLifecycle());
        PrimaryLevelData primaryLevelData = new PrimaryLevelData(createLevelSettings, finalDimensions.specialWorldProperty(), lifecycle);
        return new WorldLoader.DataLoadOutput<>(
            new LevelDataAndDimensions.WorldDataAndGenSettings(primaryLevelData, new WorldGenSettings(worldOptions, dimensions)),
            finalDimensions.dimensionsRegistryAccess()
        );
    }
 
    private static void writePidFile(Path path) {
        try {
            long pid = ProcessHandle.current().pid();
            Files.writeString(path, Long.toString(pid));
        } catch (IOException var3) {
            throw new UncheckedIOException(var3);
        }
    }
 
    private static WorldLoader.InitConfig loadOrCreateConfig(
        DedicatedServerProperties properties, @Nullable Dynamic<?> levelDataTag, boolean safeModeEnabled, PackRepository packRepository
    ) {
        boolean initMode;
        WorldDataConfiguration dataConfigToUse;
        if (levelDataTag != null) {
            WorldDataConfiguration storedConfiguration = LevelStorageSource.readDataConfig(levelDataTag);
            initMode = false;
            dataConfigToUse = storedConfiguration;
        } else {
            initMode = true;
            dataConfigToUse = new WorldDataConfiguration(properties.initialDataPackConfiguration, FeatureFlags.DEFAULT_FLAGS);
        }
 
        WorldLoader.PackConfig packConfig = new WorldLoader.PackConfig(packRepository, dataConfigToUse, safeModeEnabled, initMode);
        return new WorldLoader.InitConfig(packConfig, Commands.CommandSelection.DEDICATED, properties.functionPermissions);
    }
 
    private static void forceUpgrade(
        LevelStorageSource.LevelStorageAccess storageSource,
        DataFixer fixerUpper,
        boolean eraseCache,
        BooleanSupplier isRunning,
        RegistryAccess registryAccess,
        boolean recreateRegionFiles
    ) {
        LOGGER.info("Forcing world upgrade!");
 
        try (WorldUpgrader upgrader = new WorldUpgrader(storageSource, fixerUpper, registryAccess, eraseCache, recreateRegionFiles)) {
            Component lastStatus = null;
 
            while (!upgrader.isFinished()) {
                Component status = upgrader.getStatus();
                if (lastStatus != status) {
                    lastStatus = status;
                    LOGGER.info(upgrader.getStatus().getString());
                }
 
                int totalChunks = upgrader.getTotalChunks();
                if (totalChunks > 0) {
                    int done = upgrader.getConverted() + upgrader.getSkipped();
                    LOGGER.info("{}% completed ({} / {} chunks)...", Mth.floor((float)done / totalChunks * 100.0F), done, totalChunks);
                }
 
                if (!isRunning.getAsBoolean()) {
                    upgrader.cancel();
                } else {
                    try {
                        Thread.sleep(1000L);
                    } catch (InterruptedException var12) {
                    }
                }
            }
        }
    }
}

引用的其他类

  • CrashReport

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

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

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

    • 引用位置: 参数
  • RegistryAccess

    • 引用位置: 参数
  • Bootstrap

    • 引用位置: 方法调用
    • 关联成员: Bootstrap.bootStrap(), Bootstrap.validate()
  • Eula

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

    • 引用位置: 方法调用
    • 关联成员: MinecraftServer.spin()
  • Services

    • 引用位置: 方法调用
    • 关联成员: Services.create()
  • WorldLoader

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

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

    • 引用位置: 参数
  • DedicatedServerSettings

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

    • 引用位置: 参数
  • ServerPacksSource

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

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

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

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

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

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

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

    • 引用位置: 参数
  • LevelSettings

    • 引用位置: 方法调用/构造调用
    • 关联成员: DifficultySettings(), LevelSettings(), LevelSettings.DifficultySettings()
  • WorldDataConfiguration

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

    • 引用位置: 方法调用
    • 关联成员: RegionFileVersion.configure()
  • LevelStem

    • 引用位置: 参数
  • WorldGenSettings

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

    • 引用位置: 方法调用
    • 关联成员: WorldPresets.createNormalWorldDimensions()
  • LevelDataAndDimensions

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

    • 引用位置: 参数/方法调用
    • 关联成员: LevelStorageSource.createDefault(), LevelStorageSource.getLevelDataAndDimensions(), LevelStorageSource.readDataConfig()
  • PrimaryLevelData

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