/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.base.Stopwatch * com.google.common.base.Ticker * com.mojang.jtracy.TracyClient * com.mojang.logging.LogUtils * com.mojang.util.UndashedUuid * joptsimple.ArgumentAcceptingOptionSpec * joptsimple.NonOptionArgumentSpec * joptsimple.OptionParser * joptsimple.OptionSet * joptsimple.OptionSpec * joptsimple.OptionSpecBuilder * org.apache.commons.lang3.StringEscapeUtils * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.client.main; import com.google.common.base.Stopwatch; import com.google.common.base.Ticker; import com.mojang.blaze3d.TracyBootstrap; import com.mojang.blaze3d.platform.DisplayData; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.jtracy.TracyClient; import com.mojang.logging.LogUtils; import com.mojang.util.UndashedUuid; import java.io.File; import java.net.Authenticator; import java.net.InetSocketAddress; import java.net.PasswordAuthentication; import java.net.Proxy; import java.util.List; import java.util.Optional; import java.util.OptionalInt; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; import joptsimple.ArgumentAcceptingOptionSpec; import joptsimple.NonOptionArgumentSpec; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; import joptsimple.OptionSpecBuilder; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.DefaultUncaughtExceptionHandler; import net.minecraft.Optionull; import net.minecraft.SharedConstants; import net.minecraft.client.ClientBootstrap; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraft.client.main.GameConfig; import net.minecraft.client.main.SilentInitException; import net.minecraft.client.server.IntegratedServer; import net.minecraft.client.telemetry.TelemetryProperty; import net.minecraft.client.telemetry.events.GameLoadTimesEvent; import net.minecraft.core.UUIDUtil; import net.minecraft.server.Bootstrap; import net.minecraft.util.NativeModuleLister; import net.minecraft.util.Util; import net.minecraft.util.datafix.DataFixTypes; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.profiling.jfr.Environment; import net.minecraft.util.profiling.jfr.JvmProfiler; import org.apache.commons.lang3.StringEscapeUtils; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class Main { /* * WARNING - Removed try catching itself - possible behaviour change. */ public static void main(String[] args) { GameConfig gameConfig; Logger logger; OptionParser parser = new OptionParser(); parser.allowsUnrecognizedOptions(); parser.accepts("demo"); parser.accepts("disableMultiplayer"); parser.accepts("disableChat"); parser.accepts("fullscreen"); parser.accepts("checkGlErrors"); OptionSpecBuilder renderDebugLabelsOption = parser.accepts("renderDebugLabels"); OptionSpecBuilder jfrProfilingOption = parser.accepts("jfrProfile"); OptionSpecBuilder tracyProfilingOption = parser.accepts("tracy"); OptionSpecBuilder tracyNoImageOption = parser.accepts("tracyNoImages"); ArgumentAcceptingOptionSpec quickPlayPathOption = parser.accepts("quickPlayPath").withRequiredArg(); ArgumentAcceptingOptionSpec quickPlaySingleplayerOption = parser.accepts("quickPlaySingleplayer").withOptionalArg(); ArgumentAcceptingOptionSpec quickPlayMultiplayerOption = parser.accepts("quickPlayMultiplayer").withRequiredArg(); ArgumentAcceptingOptionSpec quickPlayRealmsOption = parser.accepts("quickPlayRealms").withRequiredArg(); ArgumentAcceptingOptionSpec gameDirOption = parser.accepts("gameDir").withRequiredArg().ofType(File.class).defaultsTo((Object)new File("."), (Object[])new File[0]); ArgumentAcceptingOptionSpec assetsDirOption = parser.accepts("assetsDir").withRequiredArg().ofType(File.class); ArgumentAcceptingOptionSpec resourcePackDirOption = parser.accepts("resourcePackDir").withRequiredArg().ofType(File.class); ArgumentAcceptingOptionSpec proxyHostOption = parser.accepts("proxyHost").withRequiredArg(); ArgumentAcceptingOptionSpec proxyPortOption = parser.accepts("proxyPort").withRequiredArg().defaultsTo((Object)"8080", (Object[])new String[0]).ofType(Integer.class); ArgumentAcceptingOptionSpec proxyUserOption = parser.accepts("proxyUser").withRequiredArg(); ArgumentAcceptingOptionSpec proxyPassOption = parser.accepts("proxyPass").withRequiredArg(); ArgumentAcceptingOptionSpec usernameOption = parser.accepts("username").withRequiredArg().defaultsTo((Object)("Player" + System.currentTimeMillis() % 1000L), (Object[])new String[0]); OptionSpecBuilder offlineDeveloperMode = parser.accepts("offlineDeveloperMode"); ArgumentAcceptingOptionSpec uuidOption = parser.accepts("uuid").withRequiredArg(); ArgumentAcceptingOptionSpec xuidOption = parser.accepts("xuid").withOptionalArg().defaultsTo((Object)"", (Object[])new String[0]); ArgumentAcceptingOptionSpec clientIdOption = parser.accepts("clientId").withOptionalArg().defaultsTo((Object)"", (Object[])new String[0]); ArgumentAcceptingOptionSpec accessTokenOption = parser.accepts("accessToken").withRequiredArg().required(); ArgumentAcceptingOptionSpec versionOption = parser.accepts("version").withRequiredArg().required(); ArgumentAcceptingOptionSpec widthOption = parser.accepts("width").withRequiredArg().ofType(Integer.class).defaultsTo((Object)854, (Object[])new Integer[0]); ArgumentAcceptingOptionSpec heightOption = parser.accepts("height").withRequiredArg().ofType(Integer.class).defaultsTo((Object)480, (Object[])new Integer[0]); ArgumentAcceptingOptionSpec fullscreenWidthOption = parser.accepts("fullscreenWidth").withRequiredArg().ofType(Integer.class); ArgumentAcceptingOptionSpec fullscreenHeightOption = parser.accepts("fullscreenHeight").withRequiredArg().ofType(Integer.class); ArgumentAcceptingOptionSpec assetIndexOption = parser.accepts("assetIndex").withRequiredArg(); ArgumentAcceptingOptionSpec versionTypeString = parser.accepts("versionType").withRequiredArg().defaultsTo((Object)"release", (Object[])new String[0]); NonOptionArgumentSpec nonOption = parser.nonOptions(); OptionSet optionSet = parser.parse(args); File gameDir = (File)Main.parseArgument(optionSet, gameDirOption); String launchedVersion = (String)Main.parseArgument(optionSet, versionOption); String stage = "Pre-bootstrap"; try { if (optionSet.has((OptionSpec)jfrProfilingOption)) { JvmProfiler.INSTANCE.start(Environment.CLIENT); } if (optionSet.has((OptionSpec)tracyProfilingOption)) { TracyBootstrap.setup(); } Stopwatch totalTimePreClassLoadTimer = Stopwatch.createStarted((Ticker)Ticker.systemTicker()); Stopwatch preWindowPreClassLoadTimer = Stopwatch.createStarted((Ticker)Ticker.systemTicker()); GameLoadTimesEvent.INSTANCE.beginStep(TelemetryProperty.LOAD_TIME_TOTAL_TIME_MS, totalTimePreClassLoadTimer); GameLoadTimesEvent.INSTANCE.beginStep(TelemetryProperty.LOAD_TIME_PRE_WINDOW_MS, preWindowPreClassLoadTimer); SharedConstants.tryDetectVersion(); TracyClient.reportAppInfo((String)("Minecraft Java Edition " + SharedConstants.getCurrentVersion().name())); CompletableFuture dataFixerOptimization = DataFixers.optimize(DataFixTypes.TYPES_FOR_LEVEL_LIST); CrashReport.preload(); logger = LogUtils.getLogger(); stage = "Bootstrap"; Bootstrap.bootStrap(); ClientBootstrap.bootstrap(); GameLoadTimesEvent.INSTANCE.setBootstrapTime(Bootstrap.bootstrapDuration.get()); Bootstrap.validate(); stage = "Argument parsing"; List leftoverArgs = optionSet.valuesOf((OptionSpec)nonOption); if (!leftoverArgs.isEmpty()) { logger.info("Completely ignored arguments: {}", (Object)leftoverArgs); } String hostName = (String)Main.parseArgument(optionSet, proxyHostOption); Proxy proxy = Proxy.NO_PROXY; if (hostName != null) { try { proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(hostName, (int)((Integer)Main.parseArgument(optionSet, proxyPortOption)))); } catch (Exception exception) { // empty catch block } } final String proxyUser = (String)Main.parseArgument(optionSet, proxyUserOption); final String proxyPass = (String)Main.parseArgument(optionSet, proxyPassOption); if (!proxy.equals(Proxy.NO_PROXY) && Main.stringHasValue(proxyUser) && Main.stringHasValue(proxyPass)) { Authenticator.setDefault(new Authenticator(){ @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(proxyUser, proxyPass.toCharArray()); } }); } int width = (Integer)Main.parseArgument(optionSet, widthOption); int height = (Integer)Main.parseArgument(optionSet, heightOption); OptionalInt fullscreenWidth = Main.ofNullable((Integer)Main.parseArgument(optionSet, fullscreenWidthOption)); OptionalInt fullscreenHeight = Main.ofNullable((Integer)Main.parseArgument(optionSet, fullscreenHeightOption)); boolean isFullscreen = optionSet.has("fullscreen"); boolean isDemo = optionSet.has("demo"); boolean disableMultiplayer = optionSet.has("disableMultiplayer"); boolean disableChat = optionSet.has("disableChat"); boolean captureTracyImages = !optionSet.has((OptionSpec)tracyNoImageOption); boolean renderDebugLabels = optionSet.has((OptionSpec)renderDebugLabelsOption); String versionType = (String)Main.parseArgument(optionSet, versionTypeString); File assetsDir = optionSet.has((OptionSpec)assetsDirOption) ? (File)Main.parseArgument(optionSet, assetsDirOption) : new File(gameDir, "assets/"); File resourcePackDir = optionSet.has((OptionSpec)resourcePackDirOption) ? (File)Main.parseArgument(optionSet, resourcePackDirOption) : new File(gameDir, "resourcepacks/"); UUID uuid = Main.hasValidUuid((OptionSpec)uuidOption, optionSet, logger) ? UndashedUuid.fromStringLenient((String)((String)uuidOption.value(optionSet))) : UUIDUtil.createOfflinePlayerUUID((String)usernameOption.value(optionSet)); String assetIndex = optionSet.has((OptionSpec)assetIndexOption) ? (String)assetIndexOption.value(optionSet) : null; String xuid = (String)optionSet.valueOf((OptionSpec)xuidOption); String clientId = (String)optionSet.valueOf((OptionSpec)clientIdOption); String quickPlayLogPath = (String)Main.parseArgument(optionSet, quickPlayPathOption); GameConfig.QuickPlayVariant quickPlayVariant = Main.getQuickPlayVariant(optionSet, (OptionSpec)quickPlaySingleplayerOption, (OptionSpec)quickPlayMultiplayerOption, (OptionSpec)quickPlayRealmsOption); User user = new User((String)usernameOption.value(optionSet), uuid, (String)accessTokenOption.value(optionSet), Main.emptyStringToEmptyOptional(xuid), Main.emptyStringToEmptyOptional(clientId)); gameConfig = new GameConfig(new GameConfig.UserData(user, proxy), new DisplayData(width, height, fullscreenWidth, fullscreenHeight, isFullscreen), new GameConfig.FolderData(gameDir, resourcePackDir, assetsDir, assetIndex), new GameConfig.GameData(isDemo, launchedVersion, versionType, disableMultiplayer, disableChat, captureTracyImages, renderDebugLabels, optionSet.has((OptionSpec)offlineDeveloperMode)), new GameConfig.QuickPlayData(quickPlayLogPath, quickPlayVariant)); Util.startTimerHackThread(); dataFixerOptimization.join(); } catch (Throwable t) { CrashReport report = CrashReport.forThrowable(t, stage); CrashReportCategory initialization = report.addCategory("Initialization"); NativeModuleLister.addCrashSection(initialization); Minecraft.fillReport(null, null, launchedVersion, null, report); Minecraft.crash(null, gameDir, report); return; } Thread shutdownThread = new Thread("Client Shutdown Thread"){ @Override public void run() { Minecraft instance = Minecraft.getInstance(); if (instance == null) { return; } IntegratedServer server = instance.getSingleplayerServer(); if (server != null) { server.halt(true); } } }; shutdownThread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(logger)); Runtime.getRuntime().addShutdownHook(shutdownThread); Minecraft newMinecraft = null; try { Thread.currentThread().setName("Render thread"); RenderSystem.initRenderThread(); newMinecraft = new Minecraft(gameConfig); } catch (SilentInitException e) { Util.shutdownExecutors(); logger.warn("Failed to create window: ", (Throwable)e); return; } catch (Throwable t) { CrashReport report = CrashReport.forThrowable(t, "Initializing game"); CrashReportCategory initialization = report.addCategory("Initialization"); NativeModuleLister.addCrashSection(initialization); Minecraft.fillReport(newMinecraft, null, gameConfig.game.launchVersion, null, report); Minecraft.crash(newMinecraft, gameConfig.location.gameDirectory, report); return; } Minecraft minecraft = newMinecraft; minecraft.run(); try { minecraft.stop(); } finally { minecraft.destroy(); } } private static GameConfig.QuickPlayVariant getQuickPlayVariant(OptionSet optionSet, OptionSpec quickPlaySingleplayerOption, OptionSpec quickPlayMultiplayerOption, OptionSpec quickPlayRealmsOption) { long enabledOptions = Stream.of(quickPlaySingleplayerOption, quickPlayMultiplayerOption, quickPlayRealmsOption).filter(arg_0 -> ((OptionSet)optionSet).has(arg_0)).count(); if (enabledOptions == 0L) { return GameConfig.QuickPlayVariant.DISABLED; } if (enabledOptions > 1L) { throw new IllegalArgumentException("Only one quick play option can be specified"); } if (optionSet.has(quickPlaySingleplayerOption)) { String worldId = Main.unescapeJavaArgument(Main.parseArgument(optionSet, quickPlaySingleplayerOption)); return new GameConfig.QuickPlaySinglePlayerData(worldId); } if (optionSet.has(quickPlayMultiplayerOption)) { String serverAddress = Main.unescapeJavaArgument(Main.parseArgument(optionSet, quickPlayMultiplayerOption)); return Optionull.mapOrDefault(serverAddress, GameConfig.QuickPlayMultiplayerData::new, GameConfig.QuickPlayVariant.DISABLED); } if (optionSet.has(quickPlayRealmsOption)) { String realmId = Main.unescapeJavaArgument(Main.parseArgument(optionSet, quickPlayRealmsOption)); return Optionull.mapOrDefault(realmId, GameConfig.QuickPlayRealmsData::new, GameConfig.QuickPlayVariant.DISABLED); } return GameConfig.QuickPlayVariant.DISABLED; } private static @Nullable String unescapeJavaArgument(@Nullable String arg) { if (arg == null) { return null; } return StringEscapeUtils.unescapeJava((String)arg); } private static Optional emptyStringToEmptyOptional(String xuid) { return xuid.isEmpty() ? Optional.empty() : Optional.of(xuid); } private static OptionalInt ofNullable(@Nullable Integer value) { return value != null ? OptionalInt.of(value) : OptionalInt.empty(); } private static @Nullable T parseArgument(OptionSet optionSet, OptionSpec optionSpec) { try { return (T)optionSet.valueOf(optionSpec); } catch (Throwable t) { ArgumentAcceptingOptionSpec options; List defaultValues; if (optionSpec instanceof ArgumentAcceptingOptionSpec && !(defaultValues = (options = (ArgumentAcceptingOptionSpec)optionSpec).defaultValues()).isEmpty()) { return (T)defaultValues.get(0); } throw t; } } private static boolean stringHasValue(@Nullable String string) { return string != null && !string.isEmpty(); } private static boolean hasValidUuid(OptionSpec uuidOption, OptionSet optionSet, Logger logger) { return optionSet.has(uuidOption) && Main.isUuidValid(uuidOption, optionSet, logger); } private static boolean isUuidValid(OptionSpec uuidOption, OptionSet optionSet, Logger logger) { try { UndashedUuid.fromStringLenient((String)((String)uuidOption.value(optionSet))); } catch (IllegalArgumentException e) { logger.warn("Invalid UUID: '{}", uuidOption.value(optionSet)); return false; } return true; } static { System.setProperty("java.awt.headless", "true"); } }