fix(launch): should not patch offline account skin when generating launch script or stopping the launcher immediately after game launched.

This commit is contained in:
huanghongxun 2021-12-19 18:44:49 +08:00
parent 9514357391
commit e57cb0ce51
8 changed files with 103 additions and 46 deletions

View File

@ -328,7 +328,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
vs.setUsesGlobal(true);
}
public LaunchOptions getLaunchOptions(String version, JavaVersion javaVersion, File gameDir) {
public LaunchOptions getLaunchOptions(String version, JavaVersion javaVersion, File gameDir, boolean makeLaunchScript) {
VersionSetting vs = getVersionSetting(version);
LaunchOptions.Builder builder = new LaunchOptions.Builder()
@ -358,7 +358,8 @@ public class HMCLGameRepository extends DefaultGameRepository {
.setNativesDir(vs.getNativesDir())
.setProcessPriority(vs.getProcessPriority())
.setUseNativeGLFW(vs.isUseNativeGLFW())
.setUseNativeOpenAL(vs.isUseNativeOpenAL());
.setUseNativeOpenAL(vs.isUseNativeOpenAL())
.setDaemon(!makeLaunchScript && vs.getLauncherVisibility().isDaemon());
if (config().hasProxy()) {
builder.setProxy(ProxyManager.getProxy());
if (config().hasProxyAuth()) {

View File

@ -172,7 +172,7 @@ public final class LauncherHelper {
}
}).withStage("launch.state.logging_in"))
.thenComposeAsync(authInfo -> Task.supplyAsync(() -> {
LaunchOptions launchOptions = repository.getLaunchOptions(selectedVersion, javaVersionRef.get(), profile.getGameDir());
LaunchOptions launchOptions = repository.getLaunchOptions(selectedVersion, javaVersionRef.get(), profile.getGameDir(), scriptFile != null);
return new HMCLGameLauncher(
repository,
version,

View File

@ -43,5 +43,9 @@ public enum LauncherVisibility {
/**
* Hide the launcher and reopen it when game closes.
*/
HIDE_AND_REOPEN
HIDE_AND_REOPEN;
public boolean isDaemon() {
return this != CLOSE;
}
}

View File

@ -18,8 +18,10 @@
package org.jackhuang.hmcl.auth;
import org.jackhuang.hmcl.game.Arguments;
import org.jackhuang.hmcl.game.LaunchOptions;
import org.jackhuang.hmcl.util.Immutable;
import java.io.IOException;
import java.util.UUID;
/**
@ -27,26 +29,18 @@ import java.util.UUID;
* @author huangyuhui
*/
@Immutable
public final class AuthInfo implements AutoCloseable {
public class AuthInfo implements AutoCloseable {
private final String username;
private final UUID uuid;
private final String accessToken;
private final String userProperties;
private final Arguments arguments;
private final AutoCloseable closeable;
public AuthInfo(String username, UUID uuid, String accessToken, String userProperties) {
this(username, uuid, accessToken, userProperties, null, null);
}
public AuthInfo(String username, UUID uuid, String accessToken, String userProperties, Arguments arguments, AutoCloseable closeable) {
this.username = username;
this.uuid = uuid;
this.accessToken = accessToken;
this.userProperties = userProperties;
this.arguments = arguments;
this.closeable = closeable;
}
public String getUsername() {
@ -72,24 +66,14 @@ public final class AuthInfo implements AutoCloseable {
}
/**
* Called when launching game.
* @return null if no argument is specified
*/
public Arguments getArguments() {
return arguments;
}
public AuthInfo withArguments(Arguments arguments) {
return new AuthInfo(username, uuid, accessToken, userProperties, arguments, closeable);
}
public AuthInfo withCloseable(AutoCloseable closeable) {
return new AuthInfo(username, uuid, accessToken, userProperties, arguments, closeable);
public Arguments getLaunchArguments(LaunchOptions options) throws IOException {
return null;
}
@Override
public void close() throws Exception {
if (closeable != null) {
closeable.close();
}
}
}

View File

@ -26,6 +26,7 @@ import org.jackhuang.hmcl.auth.yggdrasil.TextureType;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilSession;
import org.jackhuang.hmcl.game.Arguments;
import org.jackhuang.hmcl.game.LaunchOptions;
import org.jackhuang.hmcl.util.ToStringBuilder;
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
import java.io.IOException;
@ -71,7 +72,7 @@ public class AuthlibInjectorAccount extends YggdrasilAccount {
Optional<String> prefetchedMeta = server.getMetadataResponse();
if (auth.isPresent() && artifact.isPresent() && prefetchedMeta.isPresent()) {
return Optional.of(auth.get().withArguments(generateArguments(artifact.get(), server, prefetchedMeta.get())));
return Optional.of(new AuthlibInjectorAuthInfo(auth.get(), artifact.get(), server, prefetchedMeta.get()));
} else {
return Optional.empty();
}
@ -112,14 +113,30 @@ public class AuthlibInjectorAccount extends YggdrasilAccount {
}
}
return auth.withArguments(generateArguments(artifact, server, prefetchedMeta));
return new AuthlibInjectorAuthInfo(auth, artifact, server, prefetchedMeta);
}
private static Arguments generateArguments(AuthlibInjectorArtifactInfo artifact, AuthlibInjectorServer server, String prefetchedMeta) {
return new Arguments().addJVMArguments(
"-javaagent:" + artifact.getLocation().toString() + "=" + server.getUrl(),
"-Dauthlibinjector.side=client",
"-Dauthlibinjector.yggdrasil.prefetched=" + Base64.getEncoder().encodeToString(prefetchedMeta.getBytes(UTF_8)));
private static class AuthlibInjectorAuthInfo extends AuthInfo {
private final AuthlibInjectorArtifactInfo artifact;
private final AuthlibInjectorServer server;
private final String prefetchedMeta;
public AuthlibInjectorAuthInfo(AuthInfo authInfo, AuthlibInjectorArtifactInfo artifact, AuthlibInjectorServer server, String prefetchedMeta) {
super(authInfo.getUsername(), authInfo.getUUID(), authInfo.getAccessToken(), authInfo.getUserProperties());
this.artifact = artifact;
this.server = server;
this.prefetchedMeta = prefetchedMeta;
}
@Override
public Arguments getLaunchArguments(LaunchOptions options) {
return new Arguments().addJVMArguments(
"-javaagent:" + artifact.getLocation().toString() + "=" + server.getUrl(),
"-Dauthlibinjector.side=client",
"-Dauthlibinjector.yggdrasil.prefetched=" + Base64.getEncoder().encodeToString(prefetchedMeta.getBytes(UTF_8)));
}
}
@Override

View File

@ -28,6 +28,7 @@ import org.jackhuang.hmcl.auth.yggdrasil.Texture;
import org.jackhuang.hmcl.auth.yggdrasil.TextureModel;
import org.jackhuang.hmcl.auth.yggdrasil.TextureType;
import org.jackhuang.hmcl.game.Arguments;
import org.jackhuang.hmcl.game.LaunchOptions;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.ToStringBuilder;
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
@ -129,15 +130,7 @@ public class OfflineAccount extends Account {
}
try {
YggdrasilServer server = new YggdrasilServer(0);
server.start();
server.addCharacter(new YggdrasilServer.Character(uuid, username, skin.load(username).run()));
return authInfo.withArguments(new Arguments().addJVMArguments(
"-javaagent:" + artifact.getLocation().toString() + "=" + "http://localhost:" + server.getListeningPort(),
"-Dauthlibinjector.side=client"
))
.withCloseable(server::stop);
return new OfflineAuthInfo(authInfo, artifact);
} catch (Exception e) {
throw new AuthenticationException(e);
}
@ -146,6 +139,46 @@ public class OfflineAccount extends Account {
}
}
private class OfflineAuthInfo extends AuthInfo {
private final AuthlibInjectorArtifactInfo artifact;
private YggdrasilServer server;
public OfflineAuthInfo(AuthInfo authInfo, AuthlibInjectorArtifactInfo artifact) {
super(authInfo.getUsername(), authInfo.getUUID(), authInfo.getAccessToken(), authInfo.getUserProperties());
this.artifact = artifact;
}
@Override
public Arguments getLaunchArguments(LaunchOptions options) throws IOException {
if (!options.isDaemon()) return null;
server = new YggdrasilServer(0);
server.start();
try {
server.addCharacter(new YggdrasilServer.Character(uuid, username, skin.load(username).run()));
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
}
return new Arguments().addJVMArguments(
"-javaagent:" + artifact.getLocation().toString() + "=" + "http://localhost:" + server.getListeningPort(),
"-Dauthlibinjector.side=client"
);
}
@Override
public void close() throws Exception {
super.close();
if (server != null)
server.stop();
}
}
@Override
public Optional<AuthInfo> playOffline() throws AuthenticationException {
return Optional.of(logIn());

View File

@ -59,6 +59,7 @@ public class LaunchOptions implements Serializable {
private ProcessPriority processPriority = ProcessPriority.NORMAL;
private boolean useNativeGLFW;
private boolean useNativeOpenAL;
private boolean daemon;
/**
* The game directory
@ -243,6 +244,13 @@ public class LaunchOptions implements Serializable {
return useNativeOpenAL;
}
/**
* Will launcher keeps alive after game launched or not.
*/
public boolean isDaemon() {
return daemon;
}
public static class Builder {
private final LaunchOptions options = new LaunchOptions();
@ -411,6 +419,10 @@ public class LaunchOptions implements Serializable {
return options.useNativeOpenAL;
}
public boolean isDaemon() {
return options.daemon;
}
public Builder setGameDir(File gameDir) {
options.gameDir = gameDir;
return this;
@ -543,5 +555,10 @@ public class LaunchOptions implements Serializable {
return this;
}
public Builder setDaemon(boolean daemon) {
options.daemon = daemon;
return this;
}
}
}

View File

@ -255,8 +255,9 @@ public class DefaultLauncher extends Launcher {
configuration.put("${natives_directory}", nativeFolderPath);
res.addAll(Arguments.parseArguments(version.getArguments().map(Arguments::getJvm).orElseGet(this::getDefaultJVMArguments), configuration));
if (authInfo.getArguments() != null && authInfo.getArguments().getJvm() != null && !authInfo.getArguments().getJvm().isEmpty())
res.addAll(Arguments.parseArguments(authInfo.getArguments().getJvm(), configuration));
Arguments argumentsFromAuthInfo = authInfo.getLaunchArguments(options);
if (argumentsFromAuthInfo != null && argumentsFromAuthInfo.getJvm() != null && !argumentsFromAuthInfo.getJvm().isEmpty())
res.addAll(Arguments.parseArguments(argumentsFromAuthInfo.getJvm(), configuration));
res.add(version.getMainClass());
@ -267,8 +268,8 @@ public class DefaultLauncher extends Launcher {
if (version.getMinecraftArguments().isPresent()) {
res.addAll(Arguments.parseArguments(this.getDefaultGameArguments(), configuration, features));
}
if (authInfo.getArguments() != null && authInfo.getArguments().getGame() != null && !authInfo.getArguments().getGame().isEmpty())
res.addAll(Arguments.parseArguments(authInfo.getArguments().getGame(), configuration, features));
if (argumentsFromAuthInfo != null && argumentsFromAuthInfo.getGame() != null && !argumentsFromAuthInfo.getGame().isEmpty())
res.addAll(Arguments.parseArguments(argumentsFromAuthInfo.getGame(), configuration, features));
if (StringUtils.isNotBlank(options.getServerIp())) {
String[] args = options.getServerIp().split(":");