feat: env vars for pre-launch command and post-exit command.

This commit is contained in:
huanghongxun
2021-09-19 02:44:51 +08:00
parent 5b02393c79
commit c0f82b1ae7
4 changed files with 87 additions and 14 deletions

View File

@@ -307,7 +307,8 @@ public class HMCLGameRepository extends DefaultGameRepository {
.setFullscreen(vs.isFullscreen()) .setFullscreen(vs.isFullscreen())
.setServerIp(vs.getServerIp()) .setServerIp(vs.getServerIp())
.setWrapper(vs.getWrapper()) .setWrapper(vs.getWrapper())
.setPrecalledCommand(vs.getPreLaunchCommand()) .setPreLaunchCommand(vs.getPreLaunchCommand())
.setPostExitCommand(vs.getPostExitCommand())
.setNoGeneratedJVMArgs(vs.isNoJVMArgs()) .setNoGeneratedJVMArgs(vs.isNoJVMArgs())
.setNativesDirType(vs.getNativesDirType()) .setNativesDirType(vs.getNativesDirType())
.setNativesDir(vs.getNativesDir()) .setNativesDir(vs.getNativesDir())

View File

@@ -269,6 +269,24 @@ public final class VersionSetting implements Cloneable {
preLaunchCommandProperty.set(preLaunchCommand); preLaunchCommandProperty.set(preLaunchCommand);
} }
private final StringProperty postExitCommand = new SimpleStringProperty(this, "postExitCommand", "");
public StringProperty postExitCommandProperty() {
return postExitCommand;
}
/**
* The command that will be executed after game exits.
* Operating system relevant.
*/
public String getPostExitCommand() {
return postExitCommand.get();
}
public void setPostExitCommand(String postExitCommand) {
this.postExitCommand.set(postExitCommand);
}
// options // options
private final StringProperty javaArgsProperty = new SimpleStringProperty(this, "javaArgs", ""); private final StringProperty javaArgsProperty = new SimpleStringProperty(this, "javaArgs", "");
@@ -602,6 +620,7 @@ public final class VersionSetting implements Cloneable {
minMemoryProperty.addListener(listener); minMemoryProperty.addListener(listener);
autoMemory.addListener(listener); autoMemory.addListener(listener);
preLaunchCommandProperty.addListener(listener); preLaunchCommandProperty.addListener(listener);
postExitCommand.addListener(listener);
javaArgsProperty.addListener(listener); javaArgsProperty.addListener(listener);
minecraftArgsProperty.addListener(listener); minecraftArgsProperty.addListener(listener);
noJVMArgsProperty.addListener(listener); noJVMArgsProperty.addListener(listener);
@@ -636,6 +655,7 @@ public final class VersionSetting implements Cloneable {
versionSetting.setMinMemory(getMinMemory()); versionSetting.setMinMemory(getMinMemory());
versionSetting.setAutoMemory(isAutoMemory()); versionSetting.setAutoMemory(isAutoMemory());
versionSetting.setPreLaunchCommand(getPreLaunchCommand()); versionSetting.setPreLaunchCommand(getPreLaunchCommand());
versionSetting.setPostExitCommand(getPostExitCommand());
versionSetting.setJavaArgs(getJavaArgs()); versionSetting.setJavaArgs(getJavaArgs());
versionSetting.setMinecraftArgs(getMinecraftArgs()); versionSetting.setMinecraftArgs(getMinecraftArgs());
versionSetting.setNoJVMArgs(isNoJVMArgs()); versionSetting.setNoJVMArgs(isNoJVMArgs());
@@ -673,6 +693,7 @@ public final class VersionSetting implements Cloneable {
obj.addProperty("height", src.getHeight()); obj.addProperty("height", src.getHeight());
obj.addProperty("javaDir", src.getJavaDir()); obj.addProperty("javaDir", src.getJavaDir());
obj.addProperty("precalledCommand", src.getPreLaunchCommand()); obj.addProperty("precalledCommand", src.getPreLaunchCommand());
obj.addProperty("postExitCommand", src.getPostExitCommand());
obj.addProperty("serverIp", src.getServerIp()); obj.addProperty("serverIp", src.getServerIp());
obj.addProperty("java", src.getJava()); obj.addProperty("java", src.getJava());
obj.addProperty("wrapper", src.getWrapper()); obj.addProperty("wrapper", src.getWrapper());

View File

@@ -53,6 +53,7 @@ public class LaunchOptions implements Serializable {
private String proxyPass; private String proxyPass;
private boolean noGeneratedJVMArgs; private boolean noGeneratedJVMArgs;
private String preLaunchCommand; private String preLaunchCommand;
private String postExitCommand;
private NativesDirectoryType nativesDirType; private NativesDirectoryType nativesDirType;
private String nativesDir; private String nativesDir;
private ProcessPriority processPriority = ProcessPriority.NORMAL; private ProcessPriority processPriority = ProcessPriority.NORMAL;
@@ -199,12 +200,19 @@ public class LaunchOptions implements Serializable {
} }
/** /**
* Called command line before launching the game. * Command called before game launches.
*/ */
public String getPreLaunchCommand() { public String getPreLaunchCommand() {
return preLaunchCommand; return preLaunchCommand;
} }
/**
* Command called after game exits.
*/
public String getPostExitCommand() {
return postExitCommand;
}
/** /**
* 0 - ./minecraft/versions/<version>/natives * 0 - ./minecraft/versions/<version>/natives
* 1 - custom natives directory * 1 - custom natives directory
@@ -500,8 +508,13 @@ public class LaunchOptions implements Serializable {
return this; return this;
} }
public Builder setPrecalledCommand(String precalledCommand) { public Builder setPreLaunchCommand(String preLaunchCommand) {
options.preLaunchCommand = precalledCommand; options.preLaunchCommand = preLaunchCommand;
return this;
}
public Builder setPostExitCommand(String postExitCommand) {
options.postExitCommand = postExitCommand;
return this; return this;
} }

View File

@@ -18,6 +18,7 @@
package org.jackhuang.hmcl.launch; package org.jackhuang.hmcl.launch;
import org.jackhuang.hmcl.auth.AuthInfo; import org.jackhuang.hmcl.auth.AuthInfo;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.Argument; import org.jackhuang.hmcl.game.Argument;
import org.jackhuang.hmcl.game.Arguments; import org.jackhuang.hmcl.game.Arguments;
import org.jackhuang.hmcl.game.GameRepository; import org.jackhuang.hmcl.game.GameRepository;
@@ -374,16 +375,9 @@ public class DefaultLauncher extends Launcher {
File runDirectory = repository.getRunDirectory(version.getId()); File runDirectory = repository.getRunDirectory(version.getId());
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) { if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
String versionName = Optional.ofNullable(options.getVersionName()).orElse(version.getId()); ProcessBuilder builder = new ProcessBuilder(StringUtils.tokenize(options.getPreLaunchCommand())).directory(runDirectory);
String preLaunchCommand = options.getPreLaunchCommand() builder.environment().putAll(getEnvVars());
.replace("$INST_NAME", versionName) builder.start().waitFor();
.replace("$INST_ID", versionName)
.replace("$INST_DIR", repository.getVersionRoot(version.getId()).getAbsolutePath())
.replace("$INST_MC_DIR", repository.getRunDirectory(version.getId()).getAbsolutePath())
.replace("$INST_JAVA", options.getJava().getBinary().toString());
new ProcessBuilder(StringUtils.tokenize(preLaunchCommand))
.directory(runDirectory).start().waitFor();
} }
Process process; Process process;
@@ -394,6 +388,7 @@ public class DefaultLauncher extends Launcher {
} }
String appdata = options.getGameDir().getAbsoluteFile().getParent(); String appdata = options.getGameDir().getAbsoluteFile().getParent();
if (appdata != null) builder.environment().put("APPDATA", appdata); if (appdata != null) builder.environment().put("APPDATA", appdata);
builder.environment().putAll(getEnvVars());
process = builder.start(); process = builder.start();
} catch (IOException e) { } catch (IOException e) {
throw new ProcessCreationException(e); throw new ProcessCreationException(e);
@@ -405,6 +400,31 @@ public class DefaultLauncher extends Launcher {
return p; return p;
} }
private Map<String, String> getEnvVars() {
String versionName = Optional.ofNullable(options.getVersionName()).orElse(version.getId());
Map<String, String> env = new HashMap<>();
env.put("INST_NAME", versionName);
env.put("INST_ID", versionName);
env.put("INST_DIR", repository.getVersionRoot(version.getId()).getAbsolutePath());
env.put("INST_MC_DIR", repository.getRunDirectory(version.getId()).getAbsolutePath());
env.put("INST_JAVA", options.getJava().getBinary().toString());
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
if (analyzer.has(LibraryAnalyzer.LibraryType.FORGE)) {
env.put("INST_FORGE", "1");
}
if (analyzer.has(LibraryAnalyzer.LibraryType.LITELOADER)) {
env.put("INST_LITELOADER", "1");
}
if (analyzer.has(LibraryAnalyzer.LibraryType.FABRIC)) {
env.put("INST_FABRIC", "1");
}
if (analyzer.has(LibraryAnalyzer.LibraryType.OPTIFINE)) {
env.put("INST_OPTIFINE", "1");
}
return env;
}
@Override @Override
public void makeLaunchScript(File scriptFile) throws IOException { public void makeLaunchScript(File scriptFile) throws IOException {
boolean isWindows = OperatingSystem.WINDOWS == OperatingSystem.CURRENT_OS; boolean isWindows = OperatingSystem.WINDOWS == OperatingSystem.CURRENT_OS;
@@ -432,12 +452,20 @@ public class DefaultLauncher extends Launcher {
writer.write("@echo off"); writer.write("@echo off");
writer.newLine(); writer.newLine();
writer.write("set APPDATA=" + options.getGameDir().getAbsoluteFile().getParent()); writer.write("set APPDATA=" + options.getGameDir().getAbsoluteFile().getParent());
for (Map.Entry<String, String> entry : getEnvVars().entrySet()) {
writer.write("set " + entry.getKey() + "=" + entry.getValue());
writer.newLine();
}
writer.newLine(); writer.newLine();
writer.write(new CommandBuilder().add("cd", "/D", repository.getRunDirectory(version.getId()).getAbsolutePath()).toString()); writer.write(new CommandBuilder().add("cd", "/D", repository.getRunDirectory(version.getId()).getAbsolutePath()).toString());
writer.newLine(); writer.newLine();
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX || OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) { } else if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX || OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
writer.write("#!/usr/bin/env bash"); writer.write("#!/usr/bin/env bash");
writer.newLine(); writer.newLine();
for (Map.Entry<String, String> entry : getEnvVars().entrySet()) {
writer.write("export " + entry.getKey() + "=" + entry.getValue());
writer.newLine();
}
writer.write(new CommandBuilder().add("cd", repository.getRunDirectory(version.getId()).getAbsolutePath()).toString()); writer.write(new CommandBuilder().add("cd", repository.getRunDirectory(version.getId()).getAbsolutePath()).toString());
writer.newLine(); writer.newLine();
} }
@@ -446,6 +474,16 @@ public class DefaultLauncher extends Launcher {
writer.newLine(); writer.newLine();
} }
writer.write(generateCommandLine(nativeFolder).toString()); writer.write(generateCommandLine(nativeFolder).toString());
writer.newLine();
if (StringUtils.isNotBlank(options.getPostExitCommand())) {
writer.write(options.getPostExitCommand());
writer.newLine();
}
if (isWindows) {
writer.write("pause");
writer.newLine();
}
} }
if (!scriptFile.setExecutable(true)) if (!scriptFile.setExecutable(true))
throw new PermissionException(); throw new PermissionException();