2025-11-24 22:52:51 +03:00

327 lines
18 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService
* com.mojang.datafixers.DataFixer
* com.mojang.logging.LogUtils
* com.mojang.serialization.Dynamic
* com.mojang.serialization.Lifecycle
* joptsimple.AbstractOptionSpec
* joptsimple.ArgumentAcceptingOptionSpec
* joptsimple.NonOptionArgumentSpec
* joptsimple.OptionParser
* joptsimple.OptionSet
* joptsimple.OptionSpec
* joptsimple.OptionSpecBuilder
* joptsimple.ValueConverter
* joptsimple.util.PathConverter
* joptsimple.util.PathProperties
* org.jspecify.annotations.Nullable
* org.slf4j.Logger
*/
package net.minecraft.server;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import com.mojang.datafixers.DataFixer;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.Lifecycle;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.Proxy;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BooleanSupplier;
import joptsimple.AbstractOptionSpec;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.NonOptionArgumentSpec;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;
import joptsimple.OptionSpecBuilder;
import joptsimple.ValueConverter;
import joptsimple.util.PathConverter;
import joptsimple.util.PathProperties;
import net.minecraft.CrashReport;
import net.minecraft.DefaultUncaughtExceptionHandler;
import net.minecraft.SharedConstants;
import net.minecraft.SuppressForbidden;
import net.minecraft.commands.Commands;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.NbtException;
import net.minecraft.nbt.ReportedNbtException;
import net.minecraft.network.chat.Component;
import net.minecraft.server.Bootstrap;
import net.minecraft.server.Eula;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.Services;
import net.minecraft.server.WorldLoader;
import net.minecraft.server.WorldStem;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.dedicated.DedicatedServerProperties;
import net.minecraft.server.dedicated.DedicatedServerSettings;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.server.packs.repository.ServerPacksSource;
import net.minecraft.util.Mth;
import net.minecraft.util.Util;
import net.minecraft.util.datafix.DataFixers;
import net.minecraft.util.profiling.jfr.Environment;
import net.minecraft.util.profiling.jfr.JvmProfiler;
import net.minecraft.util.worldupdate.WorldUpgrader;
import net.minecraft.world.flag.FeatureFlags;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.WorldDataConfiguration;
import net.minecraft.world.level.chunk.storage.RegionFileVersion;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.gamerules.GameRules;
import net.minecraft.world.level.levelgen.WorldDimensions;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.levelgen.presets.WorldPresets;
import net.minecraft.world.level.storage.LevelDataAndDimensions;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.LevelSummary;
import net.minecraft.world.level.storage.PrimaryLevelData;
import net.minecraft.world.level.storage.WorldData;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
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();
OptionSpecBuilder nogui = parser.accepts("nogui");
OptionSpecBuilder initSettings = parser.accepts("initSettings", "Initializes 'server.properties' and 'eula.txt', then quits");
OptionSpecBuilder demo = parser.accepts("demo");
OptionSpecBuilder bonusChest = parser.accepts("bonusChest");
OptionSpecBuilder forceUpgrade = parser.accepts("forceUpgrade");
OptionSpecBuilder eraseCache = parser.accepts("eraseCache");
OptionSpecBuilder recreateRegionFiles = parser.accepts("recreateRegionFiles");
OptionSpecBuilder safeMode = parser.accepts("safeMode", "Loads level with vanilla datapack only");
AbstractOptionSpec help = parser.accepts("help").forHelp();
ArgumentAcceptingOptionSpec universe = parser.accepts("universe").withRequiredArg().defaultsTo((Object)".", (Object[])new String[0]);
ArgumentAcceptingOptionSpec worldName = parser.accepts("world").withRequiredArg();
ArgumentAcceptingOptionSpec port = parser.accepts("port").withRequiredArg().ofType(Integer.class).defaultsTo((Object)-1, (Object[])new Integer[0]);
ArgumentAcceptingOptionSpec serverId = parser.accepts("serverId").withRequiredArg();
OptionSpecBuilder jfrProfilingOption = parser.accepts("jfrProfile");
ArgumentAcceptingOptionSpec pidFile = parser.accepts("pidFile").withRequiredArg().withValuesConvertedBy((ValueConverter)new PathConverter(new PathProperties[0]));
NonOptionArgumentSpec nonOptions = parser.nonOptions();
try {
WorldStem worldStem;
Dynamic<?> loadedDataTag;
OptionSet options = parser.parse(args);
if (options.has((OptionSpec)help)) {
parser.printHelpOn((OutputStream)System.err);
return;
}
Path pidFilePath = (Path)options.valueOf((OptionSpec)pidFile);
if (pidFilePath != null) {
Main.writePidFile(pidFilePath);
}
CrashReport.preload();
if (options.has((OptionSpec)jfrProfilingOption)) {
JvmProfiler.INSTANCE.start(Environment.SERVER);
}
Bootstrap.bootStrap();
Bootstrap.validate();
Util.startTimerHackThread();
Path settingsFile = Paths.get("server.properties", new String[0]);
DedicatedServerSettings settings = new DedicatedServerSettings(settingsFile);
settings.forceSave();
RegionFileVersion.configure(settings.getProperties().regionFileComression);
Path eulaFile = Paths.get("eula.txt", new String[0]);
Eula eula = new Eula(eulaFile);
if (options.has((OptionSpec)initSettings)) {
LOGGER.info("Initialized '{}' and '{}'", (Object)settingsFile.toAbsolutePath(), (Object)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((String)options.valueOf((OptionSpec)universe));
Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), universePath);
String levelName = Optional.ofNullable((String)options.valueOf((OptionSpec)worldName)).orElse(settings.getProperties().levelName);
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(universePath.toPath());
LevelStorageSource.LevelStorageAccess access = levelStorageSource.validateAndCreateAccess(levelName);
if (access.hasWorldData()) {
LevelSummary summary;
try {
loadedDataTag = access.getDataTag();
summary = access.getSummary(loadedDataTag);
}
catch (IOException | NbtException | ReportedNbtException e) {
LevelStorageSource.LevelDirectory levelDirectory = access.getLevelDirectory();
LOGGER.warn("Failed to load world data from {}", (Object)levelDirectory.dataFile(), (Object)e);
LOGGER.info("Attempting to use fallback");
try {
loadedDataTag = access.getDataTagFallback();
summary = access.getSummary(loadedDataTag);
}
catch (IOException | NbtException | ReportedNbtException ex) {
LOGGER.error("Failed to load world data from {}", (Object)levelDirectory.oldDataFile(), (Object)ex);
LOGGER.error("Failed to load world data from {} and {}. World files may be corrupted. Shutting down.", (Object)levelDirectory.dataFile(), (Object)levelDirectory.oldDataFile());
return;
}
access.restoreLevelDataFromOld();
}
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;
}
} else {
loadedDataTag = null;
}
Dynamic<?> levelDataTag = loadedDataTag;
boolean safeModeEnabled = options.has((OptionSpec)safeMode);
if (safeModeEnabled) {
LOGGER.warn("Safe mode active, only vanilla datapack will be loaded");
}
PackRepository packRepository = ServerPacksSource.createPackRepository(access);
try {
WorldLoader.InitConfig worldLoadConfig = Main.loadOrCreateConfig(settings.getProperties(), levelDataTag, safeModeEnabled, packRepository);
worldStem = (WorldStem)Util.blockUntilDone(arg_0 -> Main.lambda$main$1(worldLoadConfig, levelDataTag, settings, options, (OptionSpec)demo, (OptionSpec)bonusChest, arg_0)).get();
}
catch (Exception e) {
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)e);
return;
}
RegistryAccess.Frozen registryHolder = worldStem.registries().compositeAccess();
WorldData data = worldStem.worldData();
boolean recreateRegionFilesValue = options.has((OptionSpec)recreateRegionFiles);
if (options.has((OptionSpec)forceUpgrade) || recreateRegionFilesValue) {
Main.forceUpgrade(access, data, DataFixers.getDataFixer(), options.has((OptionSpec)eraseCache), () -> true, registryHolder, recreateRegionFilesValue);
}
access.saveDataTag(registryHolder, data);
final DedicatedServer dedicatedServer = MinecraftServer.spin(arg_0 -> Main.lambda$main$3(access, packRepository, worldStem, settings, services, options, (OptionSpec)port, (OptionSpec)demo, (OptionSpec)serverId, (OptionSpec)nogui, (OptionSpec)nonOptions, arg_0));
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 t) {
LOGGER.error(LogUtils.FATAL_MARKER, "Failed to start the minecraft server", t);
}
}
private static WorldLoader.DataLoadOutput<WorldData> createNewWorldData(DedicatedServerSettings settings, WorldLoader.DataLoadContext context, Registry<LevelStem> datapackDimensions, boolean demoMode, boolean bonusChest) {
WorldDimensions dimensions;
WorldOptions worldOptions;
LevelSettings createLevelSettings;
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(), properties.hardcore, properties.difficulty.get(), false, new GameRules(context.dataConfiguration().enabledFeatures()), 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());
return new WorldLoader.DataLoadOutput<WorldData>(new PrimaryLevelData(createLevelSettings, worldOptions, finalDimensions.specialWorldProperty(), lifecycle), finalDimensions.dimensionsRegistryAccess());
}
private static void writePidFile(Path path) {
try {
long pid = ProcessHandle.current().pid();
Files.writeString(path, (CharSequence)Long.toString(pid), new OpenOption[0]);
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private static WorldLoader.InitConfig loadOrCreateConfig(DedicatedServerProperties properties, @Nullable Dynamic<?> levelDataTag, boolean safeModeEnabled, PackRepository packRepository) {
WorldDataConfiguration dataConfigToUse;
boolean initMode;
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, WorldData worldData, DataFixer fixerUpper, boolean eraseCache, BooleanSupplier isRunning, RegistryAccess registryAccess, boolean recreateRegionFiles) {
LOGGER.info("Forcing world upgrade!");
try (WorldUpgrader upgrader = new WorldUpgrader(storageSource, fixerUpper, worldData, registryAccess, eraseCache, recreateRegionFiles);){
Component lastStatus = null;
while (!upgrader.isFinished()) {
int totalChunks;
Component status = upgrader.getStatus();
if (lastStatus != status) {
lastStatus = status;
LOGGER.info(upgrader.getStatus().getString());
}
if ((totalChunks = upgrader.getTotalChunks()) > 0) {
int done = upgrader.getConverted() + upgrader.getSkipped();
LOGGER.info("{}% completed ({} / {} chunks)...", new Object[]{Mth.floor((float)done / (float)totalChunks * 100.0f), done, totalChunks});
}
if (!isRunning.getAsBoolean()) {
upgrader.cancel();
continue;
}
try {
Thread.sleep(1000L);
}
catch (InterruptedException interruptedException) {}
}
}
}
private static /* synthetic */ DedicatedServer lambda$main$3(LevelStorageSource.LevelStorageAccess access, PackRepository packRepository, WorldStem worldStem, DedicatedServerSettings settings, Services services, OptionSet options, OptionSpec port, OptionSpec demo, OptionSpec serverId, OptionSpec nogui, OptionSpec nonOptions, Thread thread) {
boolean gui;
DedicatedServer server = new DedicatedServer(thread, access, packRepository, worldStem, settings, DataFixers.getDataFixer(), services);
server.setPort((Integer)options.valueOf(port));
server.setDemo(options.has(demo));
server.setId((String)options.valueOf(serverId));
boolean bl = gui = !options.has(nogui) && !options.valuesOf(nonOptions).contains("nogui");
if (gui && !GraphicsEnvironment.isHeadless()) {
server.showGui();
}
return server;
}
private static /* synthetic */ CompletableFuture lambda$main$1(WorldLoader.InitConfig worldLoadConfig, Dynamic levelDataTag, DedicatedServerSettings settings, OptionSet options, OptionSpec demo, OptionSpec bonusChest, Executor executor) {
return WorldLoader.load(worldLoadConfig, context -> {
HolderLookup.RegistryLookup datapackDimensions = context.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM);
if (levelDataTag != null) {
LevelDataAndDimensions worldData = LevelStorageSource.getLevelDataAndDimensions(levelDataTag, context.dataConfiguration(), (Registry<LevelStem>)datapackDimensions, context.datapackWorldgen());
return new WorldLoader.DataLoadOutput<WorldData>(worldData.worldData(), worldData.dimensions().dimensionsRegistryAccess());
}
LOGGER.info("No existing world data, creating new world");
return Main.createNewWorldData(settings, context, (Registry<LevelStem>)datapackDimensions, options.has(demo), options.has(bonusChest));
}, WorldStem::new, Util.backgroundExecutor(), executor);
}
}