优化游戏代理参数设置 (#5273)

This commit is contained in:
Glavo
2026-01-21 20:40:28 +08:00
committed by GitHub
parent 0a0476b6d3
commit 8aecbe89f9
4 changed files with 145 additions and 94 deletions

View File

@@ -46,6 +46,7 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.net.Proxy;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.InvalidPathException; import java.nio.file.InvalidPathException;
import java.nio.file.Path; import java.nio.file.Path;
@@ -421,6 +422,7 @@ public final class HMCLGameRepository extends DefaultGameRepository {
.setHeight(vs.getHeight()) .setHeight(vs.getHeight())
.setFullscreen(vs.isFullscreen()) .setFullscreen(vs.isFullscreen())
.setWrapper(vs.getWrapper()) .setWrapper(vs.getWrapper())
.setProxyOption(getProxyOption())
.setPreLaunchCommand(vs.getPreLaunchCommand()) .setPreLaunchCommand(vs.getPreLaunchCommand())
.setPostExitCommand(vs.getPostExitCommand()) .setPostExitCommand(vs.getPostExitCommand())
.setNoGeneratedJVMArgs(vs.isNoJVMArgs()) .setNoGeneratedJVMArgs(vs.isNoJVMArgs())
@@ -440,17 +442,6 @@ public final class HMCLGameRepository extends DefaultGameRepository {
builder.setQuickPlayOption(new QuickPlayOption.MultiPlayer(vs.getServerIp())); builder.setQuickPlayOption(new QuickPlayOption.MultiPlayer(vs.getServerIp()));
} }
if (config().hasProxy()) {
builder.setProxyType(config().getProxyType());
builder.setProxyHost(config().getProxyHost());
builder.setProxyPort(config().getProxyPort());
if (config().hasProxyAuth()) {
builder.setProxyUser(config().getProxyUser());
builder.setProxyPass(config().getProxyPass());
}
}
Path json = getModpackConfiguration(version); Path json = getModpackConfiguration(version);
if (Files.exists(json)) { if (Files.exists(json)) {
try { try {
@@ -560,4 +551,39 @@ public final class HMCLGameRepository extends DefaultGameRepository {
return minimum; return minimum;
} }
} }
public static ProxyOption getProxyOption() {
if (!config().hasProxy() || config().getProxyType() == null) {
return ProxyOption.Default.INSTANCE;
}
return switch (config().getProxyType()) {
case DIRECT -> ProxyOption.Direct.INSTANCE;
case HTTP, SOCKS -> {
String proxyHost = config().getProxyHost();
int proxyPort = config().getProxyPort();
if (StringUtils.isBlank(proxyHost) || proxyPort < 0 || proxyPort > 0xFFFF) {
yield ProxyOption.Default.INSTANCE;
}
String proxyUser = config().getProxyUser();
String proxyPass = config().getProxyPass();
if (StringUtils.isBlank(proxyUser)) {
proxyUser = null;
proxyPass = null;
} else if (proxyPass == null) {
proxyPass = "";
}
if (config().getProxyType() == Proxy.Type.HTTP) {
yield new ProxyOption.Http(proxyHost, proxyPort, proxyUser, proxyPass);
} else {
yield new ProxyOption.Socks(proxyHost, proxyPort, proxyUser, proxyPass);
}
}
default -> ProxyOption.Default.INSTANCE;
};
}
} }

View File

@@ -21,7 +21,6 @@ import org.jackhuang.hmcl.java.JavaRuntime;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.Serializable; import java.io.Serializable;
import java.net.Proxy;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
@@ -49,11 +48,7 @@ public class LaunchOptions implements Serializable {
private boolean fullscreen; private boolean fullscreen;
private QuickPlayOption quickPlayOption; private QuickPlayOption quickPlayOption;
private String wrapper; private String wrapper;
private Proxy.Type proxyType; private ProxyOption proxyOption;
private String proxyHost;
private int proxyPort;
private String proxyUser;
private String proxyPass;
private boolean noGeneratedJVMArgs; private boolean noGeneratedJVMArgs;
private boolean noGeneratedOptimizingJVMArgs; private boolean noGeneratedOptimizingJVMArgs;
private String preLaunchCommand; private String preLaunchCommand;
@@ -195,30 +190,8 @@ public class LaunchOptions implements Serializable {
return wrapper; return wrapper;
} }
public Proxy.Type getProxyType() { public ProxyOption getProxyOption() {
return proxyType; return proxyOption;
}
public String getProxyHost() {
return proxyHost;
}
public int getProxyPort() {
return proxyPort;
}
/**
* The user name of the proxy, optional.
*/
public String getProxyUser() {
return proxyUser;
}
/**
* The password of the proxy, optional
*/
public String getProxyPass() {
return proxyPass;
} }
/** /**
@@ -422,28 +395,8 @@ public class LaunchOptions implements Serializable {
return this; return this;
} }
public Builder setProxyType(Proxy.Type proxyType) { public Builder setProxyOption(ProxyOption proxyOption) {
options.proxyType = proxyType; options.proxyOption = proxyOption;
return this;
}
public Builder setProxyHost(String proxyHost) {
options.proxyHost = proxyHost;
return this;
}
public Builder setProxyPort(int proxyPort) {
options.proxyPort = proxyPort;
return this;
}
public Builder setProxyUser(String proxyUser) {
options.proxyUser = proxyUser;
return this;
}
public Builder setProxyPass(String proxyPass) {
options.proxyPass = proxyPass;
return this; return this;
} }

View File

@@ -0,0 +1,63 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/// @author Glavo
public sealed interface ProxyOption {
final class Direct implements ProxyOption {
public static final Direct INSTANCE = new Direct();
private Direct() {
}
}
final class Default implements ProxyOption {
public static final Default INSTANCE = new Default();
private Default() {
}
}
record Http(@NotNull String host, int port, @Nullable String username,
@Nullable String password) implements ProxyOption {
public Http {
if (StringUtils.isBlank(host)) {
throw new IllegalArgumentException("Host cannot be blank");
}
if (port < 0 || port > 0xFFFF) {
throw new IllegalArgumentException("Illegal port: " + port);
}
}
}
record Socks(@NotNull String host, int port, @Nullable String username,
@Nullable String password) implements ProxyOption {
public Socks {
if (StringUtils.isBlank(host)) {
throw new IllegalArgumentException("Host cannot be blank");
}
if (port < 0 || port > 0xFFFF) {
throw new IllegalArgumentException("Illegal port: " + port);
}
}
}
}

View File

@@ -30,7 +30,6 @@ import org.jackhuang.hmcl.util.platform.*;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import java.io.*; import java.io.*;
import java.net.Proxy;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
@@ -170,22 +169,36 @@ public class DefaultLauncher extends Launcher {
if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS) if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS)
res.addDefault("-Duser.home=", options.getGameDir().toAbsolutePath().getParent().toString()); res.addDefault("-Duser.home=", options.getGameDir().toAbsolutePath().getParent().toString());
Proxy.Type proxyType = options.getProxyType(); boolean addProxyOptions = res.noneMatch(arg ->
if (proxyType == null) { arg.startsWith("-Djava.net.useSystemProxies=")
res.addDefault("-Djava.net.useSystemProxies=", "true"); || arg.startsWith("-Dhttp.proxy")
} else { || arg.startsWith("-Dhttps.proxy")
String proxyHost = options.getProxyHost(); || arg.startsWith("-DsocksProxy")
int proxyPort = options.getProxyPort(); || arg.startsWith("-Djava.net.socks.")
);
if (StringUtils.isNotBlank(proxyHost) && proxyPort >= 0 && proxyPort <= 0xFFFF) { if (addProxyOptions) {
if (proxyType == Proxy.Type.HTTP) { if (options.getProxyOption() == null || options.getProxyOption() == ProxyOption.Default.INSTANCE) {
res.addDefault("-Dhttp.proxyHost=", proxyHost); res.add("-Djava.net.useSystemProxies=", "true");
res.addDefault("-Dhttp.proxyPort=", String.valueOf(proxyPort)); } else if (options.getProxyOption() instanceof ProxyOption.Http httpProxy) {
res.addDefault("-Dhttps.proxyHost=", proxyHost); res.add("-Dhttp.proxyHost=" + httpProxy.host());
res.addDefault("-Dhttps.proxyPort=", String.valueOf(proxyPort)); res.add("-Dhttp.proxyPort=" + httpProxy.port());
} else if (proxyType == Proxy.Type.SOCKS) { res.add("-Dhttps.proxyHost=" + httpProxy.host());
res.addDefault("-DsocksProxyHost=", proxyHost); res.add("-Dhttps.proxyPort=" + httpProxy.port());
res.addDefault("-DsocksProxyPort=", String.valueOf(proxyPort));
if (StringUtils.isNotBlank(httpProxy.username())) {
res.add("-Dhttp.proxyUser=" + httpProxy.username());
res.add("-Dhttp.proxyPassword=" + Objects.requireNonNullElse(httpProxy.password(), ""));
res.add("-Dhttps.proxyUser=" + httpProxy.username());
res.add("-Dhttps.proxyPassword=" + Objects.requireNonNullElse(httpProxy.password(), ""));
}
} else if (options.getProxyOption() instanceof ProxyOption.Socks socksProxy) {
res.add("-DsocksProxyHost=" + socksProxy.host());
res.add("-DsocksProxyPort=" + socksProxy.port());
if (StringUtils.isNotBlank(socksProxy.username())) {
res.add("-Djava.net.socks.username=" + socksProxy.username());
res.add("-Djava.net.socks.password=" + Objects.requireNonNullElse(socksProxy.password(), ""));
} }
} }
} }
@@ -334,21 +347,17 @@ public class DefaultLauncher extends Launcher {
if (options.isFullscreen()) if (options.isFullscreen())
res.add("--fullscreen"); res.add("--fullscreen");
if (options.getProxyType() == Proxy.Type.SOCKS) { // https://github.com/HMCL-dev/HMCL/issues/774
String proxyHost = options.getProxyHost(); if (options.getProxyOption() instanceof ProxyOption.Socks socksProxy) {
int proxyPort = options.getProxyPort();
if (StringUtils.isNotBlank(proxyHost) && proxyPort >= 0 && proxyPort <= 0xFFFF) {
res.add("--proxyHost"); res.add("--proxyHost");
res.add(proxyHost); res.add(socksProxy.host());
res.add("--proxyPort"); res.add("--proxyPort");
res.add(String.valueOf(proxyPort)); res.add(String.valueOf(socksProxy.port()));
if (StringUtils.isNotBlank(options.getProxyUser()) && StringUtils.isNotBlank(options.getProxyPass())) { if (StringUtils.isNotBlank(socksProxy.username())) {
res.add("--proxyUser"); res.add("--proxyUser");
res.add(options.getProxyUser()); res.add(socksProxy.username());
res.add("--proxyPass"); res.add("--proxyPass");
res.add(options.getProxyPass()); res.add(Objects.requireNonNullElse(socksProxy.password(), ""));
}
} }
} }