package net.minecraft.client.main; import com.google.common.base.Stopwatch; import com.google.common.base.Ticker; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.mojang.authlib.properties.PropertyMap; import com.mojang.authlib.properties.PropertyMap.Serializer; 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 joptsimple.ArgumentAcceptingOptionSpec; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.DefaultUncaughtExceptionHandler; import net.minecraft.SharedConstants; import net.minecraft.Util; import net.minecraft.client.ClientBootstrap; import net.minecraft.client.Minecraft; import net.minecraft.client.User; import net.minecraft.client.User.Type; 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.obfuscate.DontObfuscate; import net.minecraft.server.Bootstrap; import net.minecraft.util.GsonHelper; import net.minecraft.util.NativeModuleLister; import net.minecraft.util.datafix.DataFixTypes; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.profiling.jfr.JvmProfiler; import org.apache.commons.lang3.StringEscapeUtils; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @Environment(EnvType.CLIENT) public class Main { @DontObfuscate public static void main(String[] strings) { OptionParser optionParser = new OptionParser(); optionParser.allowsUnrecognizedOptions(); optionParser.accepts("demo"); optionParser.accepts("disableMultiplayer"); optionParser.accepts("disableChat"); optionParser.accepts("fullscreen"); optionParser.accepts("checkGlErrors"); OptionSpec optionSpec = optionParser.accepts("renderDebugLabels"); OptionSpec optionSpec2 = optionParser.accepts("jfrProfile"); OptionSpec optionSpec3 = optionParser.accepts("tracy"); OptionSpec optionSpec4 = optionParser.accepts("tracyNoImages"); OptionSpec optionSpec5 = optionParser.accepts("quickPlayPath").withRequiredArg(); OptionSpec optionSpec6 = optionParser.accepts("quickPlaySingleplayer").withRequiredArg(); OptionSpec optionSpec7 = optionParser.accepts("quickPlayMultiplayer").withRequiredArg(); OptionSpec optionSpec8 = optionParser.accepts("quickPlayRealms").withRequiredArg(); OptionSpec optionSpec9 = optionParser.accepts("gameDir").withRequiredArg().ofType(File.class).defaultsTo(new File(".")); OptionSpec optionSpec10 = optionParser.accepts("assetsDir").withRequiredArg().ofType(File.class); OptionSpec optionSpec11 = optionParser.accepts("resourcePackDir").withRequiredArg().ofType(File.class); OptionSpec optionSpec12 = optionParser.accepts("proxyHost").withRequiredArg(); OptionSpec optionSpec13 = optionParser.accepts("proxyPort").withRequiredArg().defaultsTo("8080").ofType(Integer.class); OptionSpec optionSpec14 = optionParser.accepts("proxyUser").withRequiredArg(); OptionSpec optionSpec15 = optionParser.accepts("proxyPass").withRequiredArg(); OptionSpec optionSpec16 = optionParser.accepts("username").withRequiredArg().defaultsTo("Player" + System.currentTimeMillis() % 1000L); OptionSpec optionSpec17 = optionParser.accepts("uuid").withRequiredArg(); OptionSpec optionSpec18 = optionParser.accepts("xuid").withOptionalArg().defaultsTo(""); OptionSpec optionSpec19 = optionParser.accepts("clientId").withOptionalArg().defaultsTo(""); OptionSpec optionSpec20 = optionParser.accepts("accessToken").withRequiredArg().required(); OptionSpec optionSpec21 = optionParser.accepts("version").withRequiredArg().required(); OptionSpec optionSpec22 = optionParser.accepts("width").withRequiredArg().ofType(Integer.class).defaultsTo(854); OptionSpec optionSpec23 = optionParser.accepts("height").withRequiredArg().ofType(Integer.class).defaultsTo(480); OptionSpec optionSpec24 = optionParser.accepts("fullscreenWidth").withRequiredArg().ofType(Integer.class); OptionSpec optionSpec25 = optionParser.accepts("fullscreenHeight").withRequiredArg().ofType(Integer.class); OptionSpec optionSpec26 = optionParser.accepts("userProperties").withRequiredArg().defaultsTo("{}"); OptionSpec optionSpec27 = optionParser.accepts("profileProperties").withRequiredArg().defaultsTo("{}"); OptionSpec optionSpec28 = optionParser.accepts("assetIndex").withRequiredArg(); OptionSpec optionSpec29 = optionParser.accepts("userType").withRequiredArg().defaultsTo("legacy"); OptionSpec optionSpec30 = optionParser.accepts("versionType").withRequiredArg().defaultsTo("release"); OptionSpec optionSpec31 = optionParser.nonOptions(); OptionSet optionSet = optionParser.parse(strings); File file = parseArgument(optionSet, optionSpec9); String string = parseArgument(optionSet, optionSpec21); String string2 = "Pre-bootstrap"; Logger logger; GameConfig gameConfig; try { if (optionSet.has(optionSpec2)) { JvmProfiler.INSTANCE.start(net.minecraft.util.profiling.jfr.Environment.CLIENT); } if (optionSet.has(optionSpec3)) { TracyBootstrap.setup(); } Stopwatch stopwatch = Stopwatch.createStarted(Ticker.systemTicker()); Stopwatch stopwatch2 = Stopwatch.createStarted(Ticker.systemTicker()); GameLoadTimesEvent.INSTANCE.beginStep(TelemetryProperty.LOAD_TIME_TOTAL_TIME_MS, stopwatch); GameLoadTimesEvent.INSTANCE.beginStep(TelemetryProperty.LOAD_TIME_PRE_WINDOW_MS, stopwatch2); SharedConstants.tryDetectVersion(); TracyClient.reportAppInfo("Minecraft Java Edition " + SharedConstants.getCurrentVersion().getName()); CompletableFuture completableFuture = DataFixers.optimize(DataFixTypes.TYPES_FOR_LEVEL_LIST); CrashReport.preload(); logger = LogUtils.getLogger(); string2 = "Bootstrap"; Bootstrap.bootStrap(); ClientBootstrap.bootstrap(); GameLoadTimesEvent.INSTANCE.setBootstrapTime(Bootstrap.bootstrapDuration.get()); Bootstrap.validate(); string2 = "Argument parsing"; List list = optionSet.valuesOf(optionSpec31); if (!list.isEmpty()) { logger.info("Completely ignored arguments: {}", list); } String string3 = optionSpec29.value(optionSet); Type type = Type.byName(string3); if (type == null) { logger.warn("Unrecognized user type: {}", string3); } String string4 = parseArgument(optionSet, optionSpec12); Proxy proxy = Proxy.NO_PROXY; if (string4 != null) { try { proxy = new Proxy(java.net.Proxy.Type.SOCKS, new InetSocketAddress(string4, parseArgument(optionSet, optionSpec13))); } catch (Exception var83) { } } final String string5 = parseArgument(optionSet, optionSpec14); final String string6 = parseArgument(optionSet, optionSpec15); if (!proxy.equals(Proxy.NO_PROXY) && stringHasValue(string5) && stringHasValue(string6)) { Authenticator.setDefault(new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(string5, string6.toCharArray()); } }); } int i = parseArgument(optionSet, optionSpec22); int j = parseArgument(optionSet, optionSpec23); OptionalInt optionalInt = ofNullable(parseArgument(optionSet, optionSpec24)); OptionalInt optionalInt2 = ofNullable(parseArgument(optionSet, optionSpec25)); boolean bl = optionSet.has("fullscreen"); boolean bl2 = optionSet.has("demo"); boolean bl3 = optionSet.has("disableMultiplayer"); boolean bl4 = optionSet.has("disableChat"); boolean bl5 = !optionSet.has(optionSpec4); boolean bl6 = optionSet.has(optionSpec); Gson gson = new GsonBuilder().registerTypeAdapter(PropertyMap.class, new Serializer()).create(); PropertyMap propertyMap = GsonHelper.fromJson(gson, parseArgument(optionSet, optionSpec26), PropertyMap.class); PropertyMap propertyMap2 = GsonHelper.fromJson(gson, parseArgument(optionSet, optionSpec27), PropertyMap.class); String string7 = parseArgument(optionSet, optionSpec30); File file2 = optionSet.has(optionSpec10) ? parseArgument(optionSet, optionSpec10) : new File(file, "assets/"); File file3 = optionSet.has(optionSpec11) ? parseArgument(optionSet, optionSpec11) : new File(file, "resourcepacks/"); UUID uUID = hasValidUuid(optionSpec17, optionSet, logger) ? UndashedUuid.fromStringLenient(optionSpec17.value(optionSet)) : UUIDUtil.createOfflinePlayerUUID(optionSpec16.value(optionSet)); String string8 = optionSet.has(optionSpec28) ? optionSpec28.value(optionSet) : null; String string9 = optionSet.valueOf(optionSpec18); String string10 = optionSet.valueOf(optionSpec19); String string11 = parseArgument(optionSet, optionSpec5); String string12 = unescapeJavaArgument(parseArgument(optionSet, optionSpec6)); String string13 = unescapeJavaArgument(parseArgument(optionSet, optionSpec7)); String string14 = unescapeJavaArgument(parseArgument(optionSet, optionSpec8)); User user = new User( optionSpec16.value(optionSet), uUID, optionSpec20.value(optionSet), emptyStringToEmptyOptional(string9), emptyStringToEmptyOptional(string10), type ); gameConfig = new GameConfig( new GameConfig.UserData(user, propertyMap, propertyMap2, proxy), new DisplayData(i, j, optionalInt, optionalInt2, bl), new GameConfig.FolderData(file, file3, file2, string8), new GameConfig.GameData(bl2, string, string7, bl3, bl4, bl5, bl6), new GameConfig.QuickPlayData(string11, string12, string13, string14) ); Util.startTimerHackThread(); completableFuture.join(); } catch (Throwable var84) { CrashReport crashReport = CrashReport.forThrowable(var84, string2); CrashReportCategory crashReportCategory = crashReport.addCategory("Initialization"); NativeModuleLister.addCrashSection(crashReportCategory); Minecraft.fillReport(null, null, string, null, crashReport); Minecraft.crash(null, file, crashReport); return; } Thread thread = new Thread("Client Shutdown Thread") { public void run() { Minecraft minecraft = Minecraft.getInstance(); if (minecraft != null) { IntegratedServer integratedServer = minecraft.getSingleplayerServer(); if (integratedServer != null) { integratedServer.halt(true); } } } }; thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(logger)); Runtime.getRuntime().addShutdownHook(thread); Minecraft minecraft = null; try { Thread.currentThread().setName("Render thread"); RenderSystem.initRenderThread(); minecraft = new Minecraft(gameConfig); } catch (SilentInitException var81) { Util.shutdownExecutors(); logger.warn("Failed to create window: ", (Throwable)var81); return; } catch (Throwable var82) { CrashReport crashReport2 = CrashReport.forThrowable(var82, "Initializing game"); CrashReportCategory crashReportCategory2 = crashReport2.addCategory("Initialization"); NativeModuleLister.addCrashSection(crashReportCategory2); Minecraft.fillReport(minecraft, null, gameConfig.game.launchVersion, null, crashReport2); Minecraft.crash(minecraft, gameConfig.location.gameDirectory, crashReport2); return; } Minecraft minecraft2 = minecraft; minecraft.run(); try { minecraft2.stop(); } finally { minecraft.destroy(); } } @Nullable private static String unescapeJavaArgument(@Nullable String arg) { return arg == null ? null : StringEscapeUtils.unescapeJava(arg); } private static Optional emptyStringToEmptyOptional(String input) { return input.isEmpty() ? Optional.empty() : Optional.of(input); } private static OptionalInt ofNullable(@Nullable Integer value) { return value != null ? OptionalInt.of(value) : OptionalInt.empty(); } /** * Gets the value of a specified command-line parameter from an OptionSet. If it doesn't exist, it returns the default value for the parameter. */ @Nullable private static T parseArgument(OptionSet set, OptionSpec option) { try { return set.valueOf(option); } catch (Throwable var5) { if (option instanceof ArgumentAcceptingOptionSpec argumentAcceptingOptionSpec) { List list = argumentAcceptingOptionSpec.defaultValues(); if (!list.isEmpty()) { return (T)list.get(0); } } throw var5; } } /** * Returns {@code true} if the given string is neither null nor empty. */ private static boolean stringHasValue(@Nullable String str) { return str != null && !str.isEmpty(); } private static boolean hasValidUuid(OptionSpec uuidOption, OptionSet options, Logger logger) { return options.has(uuidOption) && isUuidValid(uuidOption, options, logger); } private static boolean isUuidValid(OptionSpec uuidOption, OptionSet optionSet, Logger logger) { try { UndashedUuid.fromStringLenient(uuidOption.value(optionSet)); return true; } catch (IllegalArgumentException var4) { logger.warn("Invalid UUID: '{}", uuidOption.value(optionSet)); return false; } } static { System.setProperty("java.awt.headless", "true"); } }