Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c59ed3ccf | ||
|
|
43d8d96608 | ||
|
|
26a6a7d883 | ||
|
|
2e9c237367 | ||
|
|
99d2816ea7 | ||
|
|
7c3853b0e6 | ||
|
|
53aecf38e0 | ||
|
|
41fab0a781 | ||
|
|
3df35aa373 | ||
|
|
543eaa4f66 | ||
|
|
3a851b7f1a | ||
|
|
089ae1e313 | ||
|
|
bfe5802d02 |
No files matched your search
@@ -40,6 +40,8 @@ import org.jackhuang.hmcl.upgrade.UpdateHandler;
|
||||
public final class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("java.net.useSystemProxies", "true");
|
||||
|
||||
checkJavaFX();
|
||||
checkDirectoryPath();
|
||||
checkDSTRootCAX3();
|
||||
|
||||
@@ -65,6 +65,8 @@ public final class LauncherHelper {
|
||||
if (account == null)
|
||||
throw new IllegalArgumentException("No account");
|
||||
|
||||
Logging.LOG.info("Launching game version: " + selectedVersion);
|
||||
|
||||
GameRepository repository = profile.getRepository();
|
||||
|
||||
Version version = repository.getResolvedVersion(selectedVersion);
|
||||
@@ -388,10 +390,13 @@ public final class LauncherHelper {
|
||||
logs.removeFirst();
|
||||
|
||||
if (setting.isShowLogs()) {
|
||||
Lang.invoke(() -> {
|
||||
try {
|
||||
latch.await();
|
||||
logWindow.waitForLoaded();
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
|
||||
Platform.runLater(() -> logWindow.logLine(log, level));
|
||||
}
|
||||
|
||||
@@ -88,8 +88,6 @@ public class Theme {
|
||||
}
|
||||
|
||||
return new String[]{
|
||||
Theme.class.getResource("/css/jfoenix-fonts.css").toExternalForm(),
|
||||
Theme.class.getResource("/css/jfoenix-design.css").toExternalForm(),
|
||||
css,
|
||||
Theme.class.getResource("/assets/css/root.css").toExternalForm()
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@ import javafx.scene.layout.BorderPane;
|
||||
|
||||
import org.jackhuang.hmcl.mod.ModInfo;
|
||||
import org.jackhuang.hmcl.setting.Theme;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
@@ -54,7 +56,14 @@ public final class ModItem extends BorderPane {
|
||||
setStyle("-fx-background-radius: 2; -fx-background-color: white; -fx-padding: 8;");
|
||||
JFXDepthManager.setDepth(this, 1);
|
||||
modItem.setTitle(info.getFileName());
|
||||
modItem.setSubtitle(info.getName() + ", " + i18n("archive.version") + ": " + info.getVersion() + ", " + i18n("archive.game_version") + ": " + info.getGameVersion() + ", " + i18n("archive.author") + ": " + info.getAuthors());
|
||||
StringBuilder message = new StringBuilder(info.getName());
|
||||
if (StringUtils.isNotBlank(info.getVersion()))
|
||||
message.append(", ").append(i18n("archive.version")).append(": ").append(info.getVersion());
|
||||
if (StringUtils.isNotBlank(info.getGameVersion()))
|
||||
message.append(", ").append(i18n("archive.game_version")).append(": ").append(info.getGameVersion());
|
||||
if (StringUtils.isNotBlank(info.getAuthors()))
|
||||
message.append(", ").append(i18n("archive.author")).append(": ").append(info.getAuthors());
|
||||
modItem.setSubtitle(message.toString());
|
||||
chkEnabled.setSelected(info.isActive());
|
||||
chkEnabled.selectedProperty().addListener((a, b, newValue) ->
|
||||
info.activeProperty().set(newValue));
|
||||
|
||||
@@ -103,7 +103,7 @@ public final class SettingsPage extends StackPane implements DecoratorPage {
|
||||
@FXML
|
||||
private StackPane themeColorPickerContainer;
|
||||
@FXML
|
||||
private JFXCheckBox chkEnableProxy;
|
||||
private JFXCheckBox chkDisableProxy;
|
||||
@FXML
|
||||
private JFXRadioButton chkProxyHttp;
|
||||
@FXML
|
||||
@@ -160,10 +160,12 @@ public final class SettingsPage extends StackPane implements DecoratorPage {
|
||||
txtProxyUsername.textProperty().bindBidirectional(config().proxyUserProperty());
|
||||
txtProxyPassword.textProperty().bindBidirectional(config().proxyPassProperty());
|
||||
|
||||
proxyPane.disableProperty().bind(chkEnableProxy.selectedProperty().not());
|
||||
proxyPane.disableProperty().bind(chkDisableProxy.selectedProperty());
|
||||
authPane.disableProperty().bind(chkProxyAuthentication.selectedProperty().not());
|
||||
|
||||
chkEnableProxy.selectedProperty().bindBidirectional(config().hasProxyProperty());
|
||||
chkDisableProxy.setSelected(!config().hasProxy());
|
||||
chkDisableProxy.selectedProperty().addListener(o -> config().setHasProxy(!chkDisableProxy.isSelected()));
|
||||
config().hasProxyProperty().addListener(o -> chkDisableProxy.setSelected(!config().hasProxy()));
|
||||
chkProxyAuthentication.selectedProperty().bindBidirectional(config().hasProxyAuthProperty());
|
||||
|
||||
selectedProxyType = new SimpleObjectProperty<Proxy.Type>(Proxy.Type.HTTP) {
|
||||
|
||||
@@ -147,7 +147,7 @@ public final class VersionPage extends StackPane implements DecoratorPage {
|
||||
sub = "saves";
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
return;
|
||||
}
|
||||
FXUtils.openFolder(new File(profile.getRepository().getRunDirectory(version), sub));
|
||||
}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/*
|
||||
* Apply google Roboto font to all UI components
|
||||
* #5264AE
|
||||
*/
|
||||
|
||||
.root {
|
||||
-fx-base-font-family: "微软雅黑", "Microsoft YaHei", "Roboto";
|
||||
-fx-font-family: -fx-base-font-family;
|
||||
}
|
||||
|
||||
.disabled Label {
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
<ComponentList title="%settings.launcher.proxy"> <!-- proxy -->
|
||||
<VBox spacing="10">
|
||||
<JFXCheckBox fx:id="chkEnableProxy" text="%settings.launcher.proxy.enable" />
|
||||
<JFXCheckBox fx:id="chkDisableProxy" text="%settings.launcher.proxy.disable" />
|
||||
<VBox fx:id="proxyPane" style="-fx-padding: 0 0 0 30;">
|
||||
<HBox>
|
||||
<JFXRadioButton fx:id="chkProxyHttp" text="%settings.launcher.proxy.http" />
|
||||
|
||||
@@ -293,7 +293,7 @@ settings.launcher.language=Language
|
||||
settings.launcher.log_font=Log Font
|
||||
settings.launcher.proxy=Proxy
|
||||
settings.launcher.proxy.authentication=Proxy Authentication
|
||||
settings.launcher.proxy.enable=Enable Proxy
|
||||
settings.launcher.proxy.disable=Use system proxies
|
||||
settings.launcher.proxy.host=Host
|
||||
settings.launcher.proxy.http=HTTP
|
||||
settings.launcher.proxy.password=Password
|
||||
|
||||
@@ -293,7 +293,7 @@ settings.launcher.language=語言
|
||||
settings.launcher.log_font=日誌字體
|
||||
settings.launcher.proxy=代理
|
||||
settings.launcher.proxy.authentication=身份驗證
|
||||
settings.launcher.proxy.enable=启用代理
|
||||
settings.launcher.proxy.disable=使用系統代理
|
||||
settings.launcher.proxy.host=主機
|
||||
settings.launcher.proxy.http=HTTP
|
||||
settings.launcher.proxy.password=密碼
|
||||
|
||||
@@ -293,7 +293,7 @@ settings.launcher.language=语言
|
||||
settings.launcher.log_font=日志字体
|
||||
settings.launcher.proxy=代理
|
||||
settings.launcher.proxy.authentication=身份验证
|
||||
settings.launcher.proxy.enable=启用代理
|
||||
settings.launcher.proxy.disable=使用系统代理
|
||||
settings.launcher.proxy.host=主机
|
||||
settings.launcher.proxy.http=HTTP
|
||||
settings.launcher.proxy.password=密码
|
||||
|
||||
@@ -45,12 +45,4 @@ public class ProcessStoppedEvent extends Event {
|
||||
public ManagedProcess getProcess() {
|
||||
return process;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("source", source)
|
||||
.append("process", process)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -151,8 +151,9 @@ public class Version implements Comparable<Version>, Validation {
|
||||
}
|
||||
|
||||
protected Version resolve(VersionProvider provider, Set<String> resolvedSoFar) throws VersionNotFoundException {
|
||||
if (inheritsFrom == null)
|
||||
return this;
|
||||
if (inheritsFrom == null) {
|
||||
return this.jar == null ? this.setJar(id) : this;
|
||||
}
|
||||
|
||||
// To maximize the compatibility.
|
||||
if (!resolvedSoFar.add(id)) {
|
||||
|
||||
@@ -258,7 +258,7 @@ public class DefaultLauncher extends Launcher {
|
||||
File nativeFolder = Files.createTempDirectory("minecraft").toFile();
|
||||
|
||||
// To guarantee that when failed to generate launch command line, we will not call pre-launch command
|
||||
List<String> rawCommandLine = generateCommandLine(nativeFolder, true).asList();
|
||||
List<String> rawCommandLine = generateCommandLine(nativeFolder, isEnablingLoggingInfo()).asList();
|
||||
|
||||
decompressNatives(nativeFolder);
|
||||
|
||||
@@ -316,14 +316,17 @@ public class DefaultLauncher extends Launcher {
|
||||
throw new PermissionException();
|
||||
}
|
||||
|
||||
protected boolean isEnablingLoggingInfo() {
|
||||
return version.getLogging() != null && version.getLogging().containsKey(DownloadType.CLIENT)
|
||||
&& !"net.minecraft.launchwrapper.Launch".equals(version.getMainClass());
|
||||
}
|
||||
|
||||
private void startMonitors(ManagedProcess managedProcess, ProcessListener processListener) {
|
||||
startMonitors(managedProcess, processListener, true);
|
||||
}
|
||||
|
||||
private void startMonitors(ManagedProcess managedProcess, ProcessListener processListener, boolean isDaemon) {
|
||||
boolean enablesLoggingInfo = version.getLogging() != null && version.getLogging().containsKey(DownloadType.CLIENT)
|
||||
&& !"net.minecraft.launchwrapper.Launch".equals(version.getMainClass());
|
||||
if (enablesLoggingInfo)
|
||||
if (isEnablingLoggingInfo())
|
||||
startMonitorsWithLoggingInfo(managedProcess, processListener, isDaemon);
|
||||
else
|
||||
startMonitorsWithoutLoggingInfo(managedProcess, processListener, isDaemon);
|
||||
|
||||
@@ -152,14 +152,20 @@ public final class ModInfo implements Comparable<ModInfo> {
|
||||
try {
|
||||
return ForgeModMetadata.fromFile(modFile);
|
||||
} catch (Exception ignore) {
|
||||
description = "May be Forge mod";
|
||||
}
|
||||
|
||||
try {
|
||||
return RiftModMetadata.fromFile(modFile);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
|
||||
description = "";
|
||||
break;
|
||||
case "litemod":
|
||||
try {
|
||||
return LiteModMetadata.fromFile(modFile);
|
||||
} catch (Exception ignore) {
|
||||
description = "May be LiteLoader mod";
|
||||
description = "LiteLoader Mod";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.mod;
|
||||
|
||||
import org.jackhuang.hmcl.util.CompressingUtils;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -268,7 +269,7 @@ public final class MultiMCInstanceConfiguration {
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modpackFile.toPath())) {
|
||||
Path root = Files.list(fs.getPath("/")).filter(Files::isDirectory).findAny()
|
||||
.orElseThrow(() -> new IOException("Not a valid MultiMC modpack"));
|
||||
String name = root.normalize().getFileName().toString();
|
||||
String name = StringUtils.removeSuffix(root.normalize().getFileName().toString(), "/");
|
||||
|
||||
Path instancePath = root.resolve("instance.cfg");
|
||||
if (Files.notExists(instancePath))
|
||||
|
||||
@@ -120,7 +120,7 @@ public final class MultiMCModpackInstallTask extends Task {
|
||||
|
||||
if (Files.exists(patches))
|
||||
for (Path patchJson : Files.newDirectoryStream(patches)) {
|
||||
if (patchJson.endsWith(".json")) {
|
||||
if (patchJson.toString().endsWith(".json")) {
|
||||
MultiMCInstancePatch patch = Constants.GSON.fromJson(IOUtils.readFullyAsString(Files.newInputStream(patchJson)), MultiMCInstancePatch.class);
|
||||
List<String> newArguments = new LinkedList<>();
|
||||
for (String arg : patch.getTweakers()) {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2018 huangyuhui <[email protected]>
|
||||
*
|
||||
* 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 {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.mod;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Immutable
|
||||
public final class RiftModMetadata {
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final List<String> authors;
|
||||
|
||||
public RiftModMetadata() {
|
||||
this("", "", Collections.emptyList());
|
||||
}
|
||||
|
||||
public RiftModMetadata(String id, String name, List<String> authors) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.authors = authors;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<String> getAuthors() {
|
||||
return authors;
|
||||
}
|
||||
|
||||
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException {
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
|
||||
Path mcmod = fs.getPath("riftmod.json");
|
||||
if (Files.notExists(mcmod))
|
||||
throw new IOException("File " + modFile + " is not a Forge mod.");
|
||||
RiftModMetadata metadata = JsonUtils.fromNonNullJson(IOUtils.readFullyAsString(Files.newInputStream(mcmod)), RiftModMetadata.class);
|
||||
String authors = metadata.getAuthors() == null ? "" : String.join(", ", metadata.getAuthors());
|
||||
return new ModInfo(modFile, metadata.getName(), "",
|
||||
authors, "", "", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,12 @@ public final class CommandBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsing will ignore your manual escaping
|
||||
*
|
||||
* @param args commands
|
||||
* @return this
|
||||
*/
|
||||
public CommandBuilder add(String... args) {
|
||||
for (String s : args)
|
||||
raw.add(new Item(s, true));
|
||||
@@ -89,35 +95,27 @@ public final class CommandBuilder {
|
||||
}
|
||||
|
||||
private static String parseWindows(String s) {
|
||||
if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0)
|
||||
if (s.charAt(0) != '"') {
|
||||
// The argument has not been quoted, add quotes.
|
||||
return '"' + s.replace("\\", "\\\\").replace("\"", "\"\"") + '"';
|
||||
} else if (s.endsWith("\"")) {
|
||||
// The argument has already been quoted.
|
||||
return s;
|
||||
} else {
|
||||
// Unmatched quote for the argument.
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
String escape = " \t\"^&<>|";
|
||||
if (StringUtils.containsOne(s, escape.toCharArray()))
|
||||
// The argument has not been quoted, add quotes.
|
||||
return '"' + s
|
||||
.replace("\\", "\\\\")
|
||||
.replace("\"", "\"\"")
|
||||
+ '"';
|
||||
else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
private static String parseBash(String s) {
|
||||
if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0)
|
||||
if (s.charAt(0) != '"') {
|
||||
// The argument has not been quoted, add quotes.
|
||||
return '"' + s.replace("\"", "\\\"") + '"';
|
||||
} else if (s.endsWith("\"")) {
|
||||
// The argument has already been quoted.
|
||||
return s;
|
||||
} else {
|
||||
// Unmatched quote for the argument.
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
else
|
||||
String escaping = " \t\"!#$&'()*,;<=>?[\\]^`{|}~";
|
||||
String escaped = "\"$&`";
|
||||
if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0 || StringUtils.containsOne(s, escaping.toCharArray())) {
|
||||
// The argument has not been quoted, add quotes.
|
||||
for (char ch : escaped.toCharArray())
|
||||
s = s.replace("" + ch, "\\" + ch);
|
||||
return '"' + s + '"';
|
||||
} else
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.zip.ZipError;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
/**
|
||||
* Utilities of compressing
|
||||
@@ -66,7 +68,12 @@ public final class CompressingUtils {
|
||||
env.put("encoding", encoding);
|
||||
if (useTempFile)
|
||||
env.put("useTempFile", true);
|
||||
return ZIPFS_PROVIDER.newFileSystem(zipFile, env);
|
||||
try {
|
||||
return ZIPFS_PROVIDER.newFileSystem(zipFile, env);
|
||||
} catch (ZipError error) {
|
||||
// Since Java 8 throws ZipError stupidly
|
||||
throw new ZipException(error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -176,6 +176,13 @@ public final class StringUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean containsOne(String pattern, char... targets) {
|
||||
for (char target : targets)
|
||||
if (pattern.toLowerCase().indexOf(Character.toLowerCase(target)) >= 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<String> tokenize(String str) {
|
||||
if (str == null)
|
||||
return new LinkedList<>();
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user