Compare commits

..
13 Commits
22 changed files with 156 additions and 62 deletions

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<>();
BIN
View File
Binary file not shown.