mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-09 11:55:52 -04:00
parent
f223d2bc41
commit
e0805fc25f
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hello Minecraft! Launcher
|
|
||||||
* Copyright (C) 2022 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.ui.construct;
|
|
||||||
|
|
||||||
import com.jfoenix.validation.base.ValidatorBase;
|
|
||||||
import javafx.beans.NamedArg;
|
|
||||||
import javafx.scene.control.TextInputControl;
|
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
|
||||||
|
|
||||||
public class ServerAddressValidator extends ValidatorBase {
|
|
||||||
private final boolean nullable;
|
|
||||||
|
|
||||||
public ServerAddressValidator() {
|
|
||||||
this(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerAddressValidator(@NamedArg("nullable") boolean nullable) {
|
|
||||||
this(i18n("input.url"), nullable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerAddressValidator(@NamedArg("message") String message, @NamedArg("nullable") boolean nullable) {
|
|
||||||
super(message);
|
|
||||||
this.nullable = nullable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void eval() {
|
|
||||||
if (srcControl.get() instanceof TextInputControl) {
|
|
||||||
evalTextInputField();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern PATTERN = Pattern.compile("[-a-zA-Z0-9@:%._+~#=]{1,256}(:\\d+)?");
|
|
||||||
|
|
||||||
private void evalTextInputField() {
|
|
||||||
TextInputControl textField = ((TextInputControl) srcControl.get());
|
|
||||||
|
|
||||||
if (StringUtils.isBlank(textField.getText()))
|
|
||||||
hasErrors.set(!nullable);
|
|
||||||
else
|
|
||||||
hasErrors.set(!PATTERN.matcher(textField.getText()).matches());
|
|
||||||
}
|
|
||||||
}
|
|
@ -45,6 +45,8 @@ import org.jackhuang.hmcl.ui.construct.*;
|
|||||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
import org.jackhuang.hmcl.util.Pair;
|
import org.jackhuang.hmcl.util.Pair;
|
||||||
|
import org.jackhuang.hmcl.util.ServerAddress;
|
||||||
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
||||||
import org.jackhuang.hmcl.util.javafx.PropertyUtils;
|
import org.jackhuang.hmcl.util.javafx.PropertyUtils;
|
||||||
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
|
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
|
||||||
@ -451,6 +453,16 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
|
|
||||||
txtServerIP = new JFXTextField();
|
txtServerIP = new JFXTextField();
|
||||||
txtServerIP.setPromptText(i18n("settings.advanced.server_ip.prompt"));
|
txtServerIP.setPromptText(i18n("settings.advanced.server_ip.prompt"));
|
||||||
|
Validator.addTo(txtServerIP).accept(str -> {
|
||||||
|
if (StringUtils.isBlank(str))
|
||||||
|
return true;
|
||||||
|
try {
|
||||||
|
ServerAddress.parse(str);
|
||||||
|
return true;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
FXUtils.setLimitWidth(txtServerIP, 300);
|
FXUtils.setLimitWidth(txtServerIP, 300);
|
||||||
serverPane.addRow(0, new Label(i18n("settings.advanced.server_ip")), txtServerIP);
|
serverPane.addRow(0, new Label(i18n("settings.advanced.server_ip")), txtServerIP);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import org.jackhuang.hmcl.auth.AuthInfo;
|
|||||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||||
import org.jackhuang.hmcl.game.*;
|
import org.jackhuang.hmcl.game.*;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
|
import org.jackhuang.hmcl.util.ServerAddress;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
|
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
@ -295,15 +296,21 @@ public class DefaultLauncher extends Launcher {
|
|||||||
res.addAll(Arguments.parseArguments(argumentsFromAuthInfo.getGame(), configuration, features));
|
res.addAll(Arguments.parseArguments(argumentsFromAuthInfo.getGame(), configuration, features));
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(options.getServerIp())) {
|
if (StringUtils.isNotBlank(options.getServerIp())) {
|
||||||
String[] args = options.getServerIp().split(":");
|
String address = options.getServerIp();
|
||||||
if (GameVersionNumber.asGameVersion(gameVersion).compareTo("1.20") < 0) {
|
|
||||||
res.add("--server");
|
try {
|
||||||
res.add(args[0]);
|
ServerAddress parsed = ServerAddress.parse(address);
|
||||||
res.add("--port");
|
if (GameVersionNumber.asGameVersion(gameVersion).compareTo("1.20") < 0) {
|
||||||
res.add(args.length > 1 ? args[1] : "25565");
|
res.add("--server");
|
||||||
} else {
|
res.add(parsed.getHost());
|
||||||
res.add("--quickPlayMultiplayer");
|
res.add("--port");
|
||||||
res.add(args[0] + ":" + (args.length > 1 ? args[1] : "25565"));
|
res.add(parsed.getPort() >= 0 ? String.valueOf(parsed.getPort()) : "25565");
|
||||||
|
} else {
|
||||||
|
res.add("--quickPlayMultiplayer");
|
||||||
|
res.add(parsed.getPort() < 0 ? address + ":25565" : address);
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOG.warning("Invalid server address: " + address, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2025 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.util;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Glavo
|
||||||
|
*/
|
||||||
|
public final class ServerAddress {
|
||||||
|
|
||||||
|
private static final int UNKNOWN_PORT = -1;
|
||||||
|
|
||||||
|
private static IllegalArgumentException illegalAddress(String address) {
|
||||||
|
return new IllegalArgumentException("Invalid server address: " + address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalArgumentException if the address is not a valid server address
|
||||||
|
*/
|
||||||
|
public static @NotNull ServerAddress parse(@NotNull String address) {
|
||||||
|
Objects.requireNonNull(address);
|
||||||
|
|
||||||
|
if (!address.startsWith("[")) {
|
||||||
|
int colonPos = address.indexOf(':');
|
||||||
|
if (colonPos >= 0) {
|
||||||
|
if (colonPos == address.length() - 1)
|
||||||
|
throw illegalAddress(address);
|
||||||
|
|
||||||
|
String host = address.substring(0, colonPos);
|
||||||
|
int port;
|
||||||
|
try {
|
||||||
|
port = Integer.parseInt(address.substring(colonPos + 1));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw illegalAddress(address);
|
||||||
|
}
|
||||||
|
if (port < 0 || port > 0xFFFF)
|
||||||
|
throw illegalAddress(address);
|
||||||
|
return new ServerAddress(host, port);
|
||||||
|
} else {
|
||||||
|
return new ServerAddress(address);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Parse IPv6 address
|
||||||
|
int colonIndex = address.indexOf(':');
|
||||||
|
int closeBracketIndex = address.lastIndexOf(']');
|
||||||
|
|
||||||
|
if (colonIndex < 0 || closeBracketIndex < colonIndex)
|
||||||
|
throw illegalAddress(address);
|
||||||
|
|
||||||
|
String host = address.substring(1, closeBracketIndex);
|
||||||
|
if (closeBracketIndex == address.length() - 1)
|
||||||
|
return new ServerAddress(host);
|
||||||
|
|
||||||
|
if (address.length() < closeBracketIndex + 3 || address.charAt(closeBracketIndex + 1) != ':')
|
||||||
|
throw illegalAddress(address);
|
||||||
|
|
||||||
|
int port;
|
||||||
|
try {
|
||||||
|
port = Integer.parseInt(address.substring(closeBracketIndex + 2));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw illegalAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port < 0 || port > 0xFFFF)
|
||||||
|
throw illegalAddress(address);
|
||||||
|
|
||||||
|
return new ServerAddress(host, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String host;
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
public ServerAddress(@NotNull String host) {
|
||||||
|
this(host, UNKNOWN_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerAddress(@NotNull String host, int port) {
|
||||||
|
this.host = Objects.requireNonNull(host);
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof ServerAddress)) return false;
|
||||||
|
ServerAddress that = (ServerAddress) o;
|
||||||
|
return port == that.port && Objects.equals(host, that.host);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("ServerAddress[host='%s', port=%d]", host, port);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2025 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.util;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Glavo
|
||||||
|
*/
|
||||||
|
public final class ServerAddressTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParse() {
|
||||||
|
assertEquals(new ServerAddress("example.com"), ServerAddress.parse("example.com"));
|
||||||
|
assertEquals(new ServerAddress("example.com", 25565), ServerAddress.parse("example.com:25565"));
|
||||||
|
|
||||||
|
assertEquals(new ServerAddress("127.0.0.0"), ServerAddress.parse("127.0.0.0"));
|
||||||
|
assertEquals(new ServerAddress("127.0.0.0", 0), ServerAddress.parse("127.0.0.0:0"));
|
||||||
|
assertEquals(new ServerAddress("127.0.0.0", 12345), ServerAddress.parse("127.0.0.0:12345"));
|
||||||
|
|
||||||
|
assertEquals(new ServerAddress("::1"), ServerAddress.parse("[::1]"));
|
||||||
|
assertEquals(new ServerAddress("::1", 0), ServerAddress.parse("[::1]:0"));
|
||||||
|
assertEquals(new ServerAddress("::1", 12345), ServerAddress.parse("[::1]:12345"));
|
||||||
|
assertEquals(new ServerAddress("2001:db8::1"), ServerAddress.parse("[2001:db8::1]"));
|
||||||
|
assertEquals(new ServerAddress("2001:db8::1", 0), ServerAddress.parse("[2001:db8::1]:0"));
|
||||||
|
assertEquals(new ServerAddress("2001:db8::1", 12345), ServerAddress.parse("[2001:db8::1]:12345"));
|
||||||
|
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("["));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[]]"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[]:0"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[::1]:"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[::1]|"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[::1]|0"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[::1]:a"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[::1]:65536"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[::1]:-1"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[ ]:-1"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("[-]:-1"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("example.com:"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("example.com:a"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("example.com:65536"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ServerAddress.parse("example.com:-1"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user