From ee955d002c4913244cdafcfbe63acef49fae1066 Mon Sep 17 00:00:00 2001 From: Gravit Date: Wed, 20 Nov 2019 20:00:23 +0700 Subject: [PATCH] [FEATURE] New ClientProcessBuilder API --- .../client/ClientLauncherContext.java | 2 + .../launcher/client/ClientProcessBuilder.java | 152 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 Launcher/src/main/java/pro/gravit/launcher/client/ClientProcessBuilder.java diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherContext.java b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherContext.java index 51f78968..a618e529 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherContext.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncherContext.java @@ -12,6 +12,8 @@ public class ClientLauncherContext { public final List args = new LinkedList<>(); public String pathLauncher; public ProcessBuilder builder; + public Process process; public ClientProfile clientProfile; public PlayerProfile playerProfile; + public ClientLauncher.Params params; } diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientProcessBuilder.java b/Launcher/src/main/java/pro/gravit/launcher/client/ClientProcessBuilder.java new file mode 100644 index 00000000..cd4d9382 --- /dev/null +++ b/Launcher/src/main/java/pro/gravit/launcher/client/ClientProcessBuilder.java @@ -0,0 +1,152 @@ +package pro.gravit.launcher.client; + +import pro.gravit.launcher.ClientLauncherWrapper; +import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.guard.LauncherGuardManager; +import pro.gravit.launcher.hasher.HashedDir; +import pro.gravit.launcher.managers.ClientHookManager; +import pro.gravit.launcher.profiles.ClientProfile; +import pro.gravit.utils.helper.EnvHelper; +import pro.gravit.utils.helper.IOHelper; +import pro.gravit.utils.helper.JVMHelper; +import pro.gravit.utils.helper.LogHelper; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import static pro.gravit.launcher.client.ClientLauncher.checkJVMBitsAndVersion; + +public class ClientProcessBuilder { + private HashedDir assetHDir; + private HashedDir clientHDir; + private ClientProfile profile; + private ClientLauncher.Params params; + private Path nativesDir = IOHelper.toPath("natives"); + private Path resourcepacksDir = IOHelper.toPath("resourcepacks"); + private boolean pipeOutput = false; + private boolean clientLaunchStarting = false; + public interface ParamsWriter + { + void write(ClientLauncherContext context); + } + private ParamsWriter paramsWriter; + + private static final String MAGICAL_INTEL_OPTION = "-XX:HeapDumpPath=ThisTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump"; + + public ClientProcessBuilder setAssetHDir(HashedDir assetHDir) { + this.assetHDir = assetHDir; + return this; + } + + public ClientProcessBuilder setClientHDir(HashedDir clientHDir) { + this.clientHDir = clientHDir; + return this; + } + + public ClientProcessBuilder setProfile(ClientProfile profile) { + this.profile = profile; + return this; + } + + public ClientProcessBuilder setParams(ClientLauncher.Params params) { + this.params = params; + return this; + } + + public ClientProcessBuilder setNativesDir(Path nativesDir) { + this.nativesDir = nativesDir; + return this; + } + + public ClientProcessBuilder setResourcepacksDir(Path resourcepacksDir) { + this.resourcepacksDir = resourcepacksDir; + return this; + } + + public ClientProcessBuilder setPipeOutput(boolean pipeOutput) { + this.pipeOutput = pipeOutput; + return this; + } + + public ClientProcessBuilder setParamsWriter(ParamsWriter paramsWriter) { + this.paramsWriter = paramsWriter; + return this; + } + + public ClientLauncherContext build() throws IOException { + LogHelper.debug("Writing ClientLauncher params"); + ClientLauncherContext context = new ClientLauncherContext(); + clientLaunchStarting = true; + checkJVMBitsAndVersion(); + LogHelper.debug("Resolving JVM binary"); + Path javaBin = LauncherGuardManager.getGuardJavaBinPath(); + context.javaBin = javaBin; + context.clientProfile = profile; + context.playerProfile = params.pp; + context.args.add(javaBin.toString()); + context.args.add(MAGICAL_INTEL_OPTION); + context.params = params; + if(paramsWriter != null) paramsWriter.write(context); + if (params.ram > 0 && params.ram <= FunctionalBridge.getJVMTotalMemory()) { + context.args.add("-Xms" + params.ram + 'M'); + context.args.add("-Xmx" + params.ram + 'M'); + } + context.args.add(JVMHelper.jvmProperty(LogHelper.DEBUG_PROPERTY, Boolean.toString(LogHelper.isDebugEnabled()))); + context.args.add(JVMHelper.jvmProperty(LogHelper.STACKTRACE_PROPERTY, Boolean.toString(LogHelper.isStacktraceEnabled()))); + context.args.add(JVMHelper.jvmProperty(LogHelper.DEV_PROPERTY, Boolean.toString(LogHelper.isDevEnabled()))); + context.args.add(JVMHelper.jvmProperty(LogHelper.NO_JANSI_PROPERTY, "true")); // Отключаем JAnsi для нормального вывода в DEBUG окно + JVMHelper.addSystemPropertyToArgs(context.args, DirBridge.CUSTOMDIR_PROPERTY); + JVMHelper.addSystemPropertyToArgs(context.args, DirBridge.USE_CUSTOMDIR_PROPERTY); + JVMHelper.addSystemPropertyToArgs(context.args, DirBridge.USE_OPTDIR_PROPERTY); + if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) { + if (JVMHelper.OS_VERSION.startsWith("10.")) { + LogHelper.debug("MustDie 10 fix is applied"); + context.args.add(JVMHelper.jvmProperty("os.name", "Windows 10")); + context.args.add(JVMHelper.jvmProperty("os.version", "10.0")); + } + } + // Add classpath and main class + String pathLauncher = IOHelper.getCodeSource(ClientLauncher.class).toString(); + context.pathLauncher = pathLauncher; + Collections.addAll(context.args, ClientLauncherWrapper.MAGIC_ARG); + Collections.addAll(context.args, profile.getJvmArgs()); + profile.pushOptionalJvmArgs(context.args); + Collections.addAll(context.args, "-Djava.library.path=".concat(params.clientDir.resolve(nativesDir).toString())); // Add Native Path + Collections.addAll(context.args, "-javaagent:".concat(pathLauncher)); + ClientHookManager.clientLaunchHook.hook(context); + LauncherGuardManager.guard.addCustomParams(context); + Collections.addAll(context.args, ClientLauncher.class.getName()); + ClientHookManager.clientLaunchFinallyHook.hook(context); + + // Print commandline debug message + LogHelper.debug("Commandline: " + context.args); + + // Build client process + LogHelper.debug("Launching client instance"); + ProcessBuilder builder = new ProcessBuilder(context.args); + context.builder = builder; + LauncherGuardManager.guard.addCustomEnv(context); + //else + //builder.environment().put("CLASSPATH", classPathString.toString()); + EnvHelper.addEnv(builder); + builder.directory(params.clientDir.toFile()); + builder.inheritIO(); + if (pipeOutput) { + builder.redirectErrorStream(true); + builder.redirectOutput(ProcessBuilder.Redirect.PIPE); + } + List command = builder.command(); + // Let's rock! + ClientHookManager.preStartHook.hook(context, builder); + context.process = builder.start(); + if (builder.command() != command) { + LogHelper.error("Something strange cheating..."); + System.exit(100); + return null; + } + ClientHookManager.postStartHook.hook(context, builder); + return context; + } +}