Compare commits

..
Author SHA1 Message Date
Burning_TNT af3719403d Support #3000: Support neoforge.mods.toml (#3031)
* Support #3000

* Fix #2371

* Rename references.

* Code cleanup.
2024-05-15 22:24:48 +08:00
Liyan Zhao e0764d6f0c support java from homebrew (#3035)
* fix: support java from homebrew

* fix: support java from homebrew

* fix: add ~/Library/Java/JavaVirtualMachine
2024-05-14 00:15:07 +08:00
zkitefly 908f47f75e Update Copyright (#3010) 2024-05-13 23:45:46 +08:00
Glavo a3af719087 支持自动下载 Java 21 (#3045) 2024-05-13 23:41:23 +08:00
zkitefly 7f13d6646b Update ExitWaiter.java (#3042) 2024-05-12 20:36:21 +08:00
Kieran Moy e8b4c38451 Add cinnamon desktop support (#3017) 2024-05-07 23:40:18 +08:00
Glavo 38ba6802a0 Bump Hub Mirror Action to 1.4 (#3034) 2024-05-07 23:36:28 +08:00
Glavo 381eead7b6 将 1.20.5 和 1.20.6 添加至 versions.txt (#3008)
* 更新 versions.txt

* update
2024-05-07 23:27:22 +08:00
3gf8jv4dv df953e5ea7 Fix NeoForge 2x icon not working (#2994) 2024-04-17 22:00:28 +08:00
Glavo 2fd2954a06 更新指向 XZ 主页的链接 (#2990) 2024-04-15 05:37:04 +08:00
Glavo a8bb5c1570 修复导入部分整合包失败的问题 (#2989)
* 修复导入部分整合包失败的问题

* update

* update
2024-04-15 04:02:24 +08:00
zkitefly a33377d1f2 add macos_failed_to_find_service_port_for_display (#2797)
* add macos_failed_to_find_service_port_for_display

日志来自 HMCL KOOK

* updata i18n

* Update I18N_zh.properties
2024-04-15 02:38:59 +08:00
zkiteflyandGlavo e515542add 还原 MCBBS 的鸣谢 (#2958)
* Update AboutPage.java

* update

---------

Co-authored-by: Glavo <zjx001202@gmail.com>
2024-04-15 02:35:20 +08:00
zkitefly 48b6bd4ea1 add NEOFORGE_FOREST_OPTIFINE (#2976)
* add NEOFORGE_FOREST_OPTIFINE

* fix
2024-04-15 02:10:02 +08:00
Liyan Zhao 9cf23f69a6 Fix Microsoft authentication (#2986)
* fix: microsoft login #2979

* fix: typo
2024-04-15 02:07:47 +08:00
Glavo 4104ca082d 修复日志文件夹不存在时无法将日志写入文件的问题 (#2984) 2024-04-11 19:43:18 +08:00
Glavo 32f8ffad46 修复整合包下载失败提示窗标题未正确格式化的问题 (#2980)
* 修复 i18n 问题

* update

* update
2024-04-08 21:49:54 +08:00
Glavo a5e04a7b81 将 24w14potato 添加至 versions.txt (#2962)
* 将 24w14potato 添加至 versions.txt

* Update test
2024-04-02 13:55:52 +08:00
Glavo 57018bef47 重新实现日志记录 (#2951)
* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update
2024-03-28 12:16:52 +08:00
Glavo 0b65431044 清理残余 MCBBS 相关内容 (#2953)
* 清理残余 MCBBS 相关内容

* update
2024-03-25 21:44:27 +08:00
Glavo 991729b684 支持从当前路径加载字体 (#2950) 2024-03-24 19:59:38 +08:00
MythandGlavo 1605eb1775 fix: add locale to avoid wrong yggdrasil server name (#2521)
* fix: add locale to avoid wrong yggdrasil server name

* update

---------

Co-authored-by: Glavo <zjx001202@gmail.com>
2024-03-23 14:19:16 +08:00
Glavo 94ccee0b76 优化 I18n (#2948)
* update

* update

* update

* update

* update
2024-03-23 14:11:52 +08:00
Glavo 8b94fe5b0b 更新模组和整合包信息 (#2947)
* update

* update
2024-03-23 11:31:09 +08:00
Glavo abec1abcff 更新默认皮肤 (#2943)
* 更新默认皮肤

* update

* update

* update

* update

* update

* update
2024-03-22 16:09:25 +08:00
Glavo 127938fa38 支持更多格式的版本图标 (#2942) 2024-03-21 20:01:21 +08:00
Glavo 1187ae4f04 Fix #2938: 修复 DefaultLauncher 会多次添加包装命令的问题 (#2939) 2024-03-16 11:08:17 +08:00
Glavo 8efdc536ee Fix #2934: 修复无法读取远古版本版本号的问题 (#2936)
* update

* update
2024-03-15 20:57:45 +08:00
Glavo 78f080b6cc Fix #2784: 离线账户选择 Steve/Alex 皮肤时强制使用本地 Yggdrasil 服务器 (#2933) 2024-03-15 13:39:50 +08:00
Glavo cc8bcfd924 Fix i18n (#2931)
* Fix i18n

* update
2024-03-15 12:56:29 +08:00
Glavo 806ca3f64a 更新 Modrinth 翻译 (#2929)
* update

* update

* update

* update

* update

* update
2024-03-15 12:24:43 +08:00
lyuxc_ 4a16fa13ee Update ModpackInfoPage.java (#2928) 2024-03-14 21:23:06 +08:00
180 changed files with 16111 additions and 7589 deletions

No files matched your search

+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Mirror GitHub to Gitee
uses: Yikun/hub-mirror-action@v1.3
uses: Yikun/hub-mirror-action@v1.4
with:
src: github/HMCL-dev
dst: gitee/huanghongxun
+1 -1
View File
@@ -118,7 +118,7 @@ tasks.getByName<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("sha
manifest {
attributes(
"Created-By" to "Copyright(c) 2013-2023 huangyuhui.",
"Created-By" to "Copyright(c) 2013-2024 huangyuhui.",
"Main-Class" to "org.jackhuang.hmcl.Main",
"Multi-Release" to "true",
"Implementation-Version" to project.version,
+3 -33
View File
@@ -27,7 +27,7 @@ S = ';'
MOD_SEPARATOR = ','
CURSEFORGE_PATTERN1 = re.compile(
r'^/minecraft/(mc-mods|modpacks|customization|mc-addons|customization/configuration)/+(?P<modid>[\w-]+)(/(.*?))?$')
r'^/(minecraft|Minecraft|minecraft-bedrock)/(mc-mods|modpacks|customization|mc-addons|texture-packs|customization/configuration|addons)/+(?P<modid>[\w-]+)(/(.*?))?$')
CURSEFORGE_PATTERN2 = re.compile(
r'^/projects/(?P<modid>[\w-]+)(/(.*?))?$')
CURSEFORGE_PATTERN3 = re.compile(
@@ -58,30 +58,6 @@ def parseMcmod(url):
return match.group('modid')
return ''
MCBBS_HTML_PATTERN = re.compile(r'/+thread-(?P<modid>\d+)-(\d+)-(\d+).html')
MCBBS_PHP_PATTERN = re.compile(r'')
def parseMcbbs(url):
res = urlparse(url)
if res.scheme not in ['http', 'https']:
return ''
if res.netloc != 'www.mcbbs.net':
return ''
match = MCBBS_HTML_PATTERN.match(res.path)
if match:
return match.group('modid')
query = parse_qs(res.query)
if res.path == '/forum.php':
if 'mod' in query and 'tid' in query and query['mod'] == ['viewthread']:
return query['tid']
return ''
skip = [
'Minecraft',
'The Building Game'
@@ -111,12 +87,11 @@ if __name__ == '__main__':
exit(1)
black_lists = [
'Master Chef'
'Wood Converter'
]
curseforge_id = ''
mcmod_id = ''
mcbbs_id = ''
links = mod['links']['list']
if 'curseforge' in links and links['curseforge'] and sub_name not in black_lists and chinese_name not in black_lists:
for link in links['curseforge']:
@@ -131,11 +106,6 @@ if __name__ == '__main__':
if mcmod_id == '':
print('Error mcmod ' + chinese_name)
exit(1)
if 'mcbbs' in links and links['mcbbs']:
mcbbs_id = parseMcbbs(links['mcbbs'][0]['url'])
if mcbbs_id == '':
print('Error mcbbs ' + chinese_name)
exit(1)
mod_id = []
if 'modid' in mod and 'list' in mod['modid']:
@@ -148,6 +118,6 @@ if __name__ == '__main__':
mod_ids = MOD_SEPARATOR.join([str(id) for id in mod_id])
outfile.write(
f'{curseforge_id}{S}{mcmod_id}{S}{mcbbs_id}{S}{mod_ids}{S}{chinese_name}{S}{sub_name}{S}{abbr}\n')
f'{curseforge_id}{S}{mcmod_id}{S}{mod_ids}{S}{chinese_name}{S}{sub_name}{S}{abbr}\n')
print('Success!')
@@ -12,14 +12,10 @@ import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jetbrains.annotations.Nullable;
public class SkinCanvas extends Group {
public static final Image ALEX = FXUtils.newBuiltinImage("/assets/img/skin/alex.png");
public static final Image STEVE = FXUtils.newBuiltinImage("/assets/img/skin/steve.png");
public static final SkinCube ALEX_LARM = new SkinCube(3, 12, 4, 14F / 64F, 16F / 64F, 32F / 64F, 48F / 64F, 0F, true);
public static final SkinCube ALEX_RARM = new SkinCube(3, 12, 4, 14F / 64F, 16F / 64F, 40F / 64F, 16F / 64F, 0F, true);
@@ -152,10 +148,6 @@ public class SkinCanvas extends Group {
capeGroup.setVisible(hasCape);
}
public SkinCanvas(double preW, double preH) {
this(STEVE, preW, preH, true);
}
public SkinCanvas(Image skin, double preW, double preH, boolean msaa) {
this.skin = skin;
this.preW = preW;
@@ -25,9 +25,6 @@ import javafx.scene.control.ButtonType;
import javafx.scene.input.Clipboard;
import javafx.scene.input.DataFormat;
import javafx.stage.Stage;
import org.jackhuang.hmcl.auth.offline.Skin;
import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.setting.ConfigHolder;
import org.jackhuang.hmcl.setting.SambaException;
import org.jackhuang.hmcl.task.AsyncTaskExecutor;
@@ -53,13 +50,10 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.stream.Stream;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class Launcher extends Application {
@@ -71,14 +65,12 @@ public final class Launcher extends Application {
CookieHandler.setDefault(COOKIE_MANAGER);
register();
LOG.info("JavaFX Version: " + System.getProperty("javafx.runtime.version"));
try {
Object pipeline = Class.forName("com.sun.prism.GraphicsPipeline").getMethod("getPipeline").invoke(null);
LOG.info("Prism pipeline: " + (pipeline == null ? "null" : pipeline.getClass().getName()));
} catch (Throwable e) {
LOG.log(Level.WARNING, "Failed to get prism pipeline", e);
LOG.warning("Failed to get prism pipeline", e);
}
try {
@@ -87,7 +79,7 @@ public final class Launcher extends Application {
} catch (SambaException ignored) {
Main.showWarningAndContinue(i18n("fatal.samba"));
} catch (IOException e) {
LOG.log(Level.SEVERE, "Failed to load config", e);
LOG.error("Failed to load config", e);
checkConfigInTempDir();
checkConfigOwner();
Main.showErrorAndExit(i18n("fatal.config_loading_failure", ConfigHolder.configLocation().getParent()));
@@ -128,45 +120,6 @@ public final class Launcher extends Application {
}
}
private static void register() {
Skin.registerDefaultSkinLoader((type) -> {
switch (type) {
case ALEX:
return Skin.class.getResourceAsStream("/assets/img/skin/alex.png");
case ARI:
return Skin.class.getResourceAsStream("/assets/img/skin/ari.png");
case EFE:
return Skin.class.getResourceAsStream("/assets/img/skin/efe.png");
case KAI:
return Skin.class.getResourceAsStream("/assets/img/skin/kai.png");
case MAKENA:
return Skin.class.getResourceAsStream("/assets/img/skin/makena.png");
case NOOR:
return Skin.class.getResourceAsStream("/assets/img/skin/noor.png");
case STEVE:
return Skin.class.getResourceAsStream("/assets/img/skin/steve.png");
case SUNNY:
return Skin.class.getResourceAsStream("/assets/img/skin/sunny.png");
case ZURI:
return Skin.class.getResourceAsStream("/assets/img/skin/zuri.png");
default:
return null;
}
});
RemoteMod.registerEmptyRemoteMod(new RemoteMod("", "", i18n("mods.broken_dependency.title"), i18n("mods.broken_dependency.desc"), new ArrayList<>(), "", "/assets/img/icon@8x.png", new RemoteMod.IMod() {
@Override
public List<RemoteMod> loadDependencies(RemoteModRepository modRepository) throws IOException {
throw new IOException();
}
@Override
public Stream<RemoteMod.Version> loadVersions(RemoteModRepository modRepository) throws IOException {
throw new IOException();
}
}));
}
private static ButtonType showAlert(AlertType alertType, String contentText, ButtonType... buttons) {
return new Alert(alertType, contentText, buttons).showAndWait().orElse(null);
}
@@ -211,7 +164,7 @@ public final class Launcher extends Application {
private static void checkConfigInTempDir() {
if (ConfigHolder.isNewlyCreated() && isConfigInTempDir()
&& showAlert(AlertType.WARNING, i18n("fatal.config_in_temp_dir"), ButtonType.YES, ButtonType.NO) == ButtonType.NO) {
System.exit(0);
Main.exit(0);
}
}
@@ -224,7 +177,7 @@ public final class Launcher extends Application {
try {
owner = Files.getOwner(ConfigHolder.configLocation()).getName();
} catch (IOException ioe) {
LOG.log(Level.WARNING, "Failed to get file owner", ioe);
LOG.warning("Failed to get file owner", ioe);
return;
}
@@ -249,17 +202,18 @@ public final class Launcher extends Application {
Clipboard.getSystemClipboard()
.setContent(Collections.singletonMap(DataFormat.PLAIN_TEXT, command));
}
System.exit(1);
Main.exit(1);
}
@Override
public void stop() throws Exception {
super.stop();
Controllers.onApplicationStop();
LOG.shutdown();
}
public static void main(String[] args) {
if (UpdateHandler.processArguments(args)) {
LOG.shutdown();
return;
}
@@ -277,6 +231,7 @@ public final class Launcher extends Application {
LOG.info("Current Directory: " + System.getProperty("user.dir"));
LOG.info("HMCL Directory: " + Metadata.HMCL_DIRECTORY);
LOG.info("HMCL Jar Path: " + Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found"));
LOG.info("HMCL Log File: " + Lang.requireNonNullElse(LOG.getLogFile(), "In Memory"));
LOG.info("Memory: " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "MB");
LOG.info("Physical memory: " + OperatingSystem.TOTAL_MEMORY + " MB");
LOG.info("Metaspace: " + ManagementFactory.getMemoryPoolMXBeans().stream()
+16 -13
View File
@@ -21,7 +21,6 @@ import javafx.application.Platform;
import javafx.scene.control.Alert;
import org.jackhuang.hmcl.ui.AwtUtils;
import org.jackhuang.hmcl.util.FractureiserDetector;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.SelfDependencyPatcher;
import org.jackhuang.hmcl.ui.SwingUtils;
import org.jackhuang.hmcl.util.platform.JavaVersion;
@@ -43,10 +42,9 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Collections;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class Main {
@@ -59,6 +57,8 @@ public final class Main {
System.getProperties().putIfAbsent("javafx.autoproxy.disable", "true");
System.getProperties().putIfAbsent("http.agent", "HMCL/" + Metadata.VERSION);
LOG.start(Metadata.HMCL_DIRECTORY.resolve("logs"));
checkDirectoryPath();
if (JavaVersion.CURRENT_JAVA.getParsedVersion() < 9)
@@ -68,8 +68,6 @@ public final class Main {
if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX)
initIcon();
Logging.start(Metadata.HMCL_DIRECTORY.resolve("logs"));
checkJavaFX();
verifyJavaFX();
detectFractureiser();
@@ -77,6 +75,11 @@ public final class Main {
Launcher.main(args);
}
public static void exit(int exitCode) {
LOG.shutdown();
System.exit(exitCode);
}
private static void initIcon() {
java.awt.Image image = java.awt.Toolkit.getDefaultToolkit().getImage(Main.class.getResource("/assets/img/icon@8x.png"));
AwtUtils.setAppleIcon(image);
@@ -93,7 +96,7 @@ public final class Main {
private static void detectFractureiser() {
if (FractureiserDetector.detect()) {
LOG.log(Level.SEVERE, "Detected that this computer is infected by fractureiser");
LOG.error("Detected that this computer is infected by fractureiser");
showErrorAndExit(i18n("fatal.fractureiser"));
}
}
@@ -102,14 +105,14 @@ public final class Main {
try {
SelfDependencyPatcher.patch();
} catch (SelfDependencyPatcher.PatchException e) {
LOG.log(Level.SEVERE, "unable to patch JVM", e);
LOG.error("unable to patch JVM", e);
showErrorAndExit(i18n("fatal.javafx.missing"));
} catch (SelfDependencyPatcher.IncompatibleVersionException e) {
LOG.log(Level.SEVERE, "unable to patch JVM", e);
LOG.error("unable to patch JVM", e);
showErrorAndExit(i18n("fatal.javafx.incompatible"));
} catch (CancellationException e) {
LOG.log(Level.SEVERE, "User cancels downloading JavaFX", e);
System.exit(0);
LOG.error("User cancels downloading JavaFX", e);
exit(0);
}
}
@@ -136,13 +139,13 @@ public final class Main {
try {
if (Platform.isFxApplicationThread()) {
new Alert(Alert.AlertType.ERROR, message).showAndWait();
System.exit(1);
exit(1);
}
} catch (Throwable ignored) {
}
SwingUtils.showErrorDialog(message);
System.exit(1);
exit(1);
}
/**
@@ -192,7 +195,7 @@ public final class Main {
LOG.info("Added Lets Encrypt root certificates as additional trust");
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException |
KeyManagementException e) {
LOG.log(Level.SEVERE, "Failed to load lets encrypt certificate. Expect problems", e);
LOG.error("Failed to load lets encrypt certificate. Expect problems", e);
}
}
}
@@ -1,7 +1,6 @@
package org.jackhuang.hmcl.countly;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
@@ -13,6 +12,7 @@ import java.util.Map;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class CrashReport {
@@ -59,7 +59,7 @@ public class CrashReport {
pair("_ram_current", getMemoryAvailable()),
pair("_ram_total", Runtime.getRuntime().maxMemory() / BYTES_IN_MB),
pair("_error", stackTrace),
pair("_logs", Logging.getLogs()),
pair("_logs", LOG.getLogs()),
pair("_name", throwable.getLocalizedMessage()),
pair("_nonfatal", nonFatal)
);
@@ -21,7 +21,6 @@ import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.auth.AuthInfo;
import org.jackhuang.hmcl.launch.DefaultLauncher;
import org.jackhuang.hmcl.launch.ProcessListener;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.i18n.I18n;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.platform.ManagedProcess;
@@ -29,9 +28,9 @@ import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/**
* @author huangyuhui
@@ -72,7 +71,7 @@ public final class HMCLGameLauncher extends DefaultLauncher {
}
}
if (I18n.getCurrentLocale().getLocale() != Locale.CHINA) {
if (!I18n.isUseChinese()) {
return;
}
@@ -97,7 +96,7 @@ public final class HMCLGameLauncher extends DefaultLauncher {
try {
FileUtils.writeText(optionsFile, String.format("lang:%s\n", lang));
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Unable to generate options.txt", e);
LOG.warning("Unable to generate options.txt", e);
}
}
}
@@ -50,12 +50,11 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
public class HMCLGameRepository extends DefaultGameRepository {
@@ -124,7 +123,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
if (!file.exists() && !versions.isEmpty())
FileUtils.writeText(file, PROFILE);
} catch (IOException ex) {
LOG.log(Level.WARNING, "Unable to create launcher_profiles.json, Forge/LiteLoader installer will not work.", ex);
LOG.warning("Unable to create launcher_profiles.json, Forge/LiteLoader installer will not work.", ex);
}
// https://github.com/HMCL-dev/HMCL/issues/938
@@ -259,8 +258,50 @@ public class HMCLGameRepository extends DefaultGameRepository {
return vs;
}
public File getVersionIconFile(String id) {
return new File(getVersionRoot(id), "icon.png");
public Optional<File> getVersionIconFile(String id) {
File root = getVersionRoot(id);
File iconFile = new File(root, "icon.png");
if (iconFile.exists()) {
return Optional.of(iconFile);
}
iconFile = new File(root, "icon.jpg");
if (iconFile.exists()) {
return Optional.of(iconFile);
}
iconFile = new File(root, "icon.bmp");
if (iconFile.exists()) {
return Optional.of(iconFile);
}
iconFile = new File(root, "icon.gif");
if (iconFile.exists()) {
return Optional.of(iconFile);
}
return Optional.empty();
}
public void setVersionIconFile(String id, File iconFile) throws IOException {
String ext = FileUtils.getExtension(iconFile).toLowerCase(Locale.ROOT);
if (!ext.equals("png") && !ext.equals("jpg") && !ext.equals("bmp") && !ext.equals("gif")) {
throw new IllegalArgumentException("Unsupported icon file: " + ext);
}
deleteIconFile(id);
FileUtils.copyFile(iconFile, new File(getVersionRoot(id), "icon." + ext));
}
public void deleteIconFile(String id) {
File root = getVersionRoot(id);
new File(root, "icon.png").delete();
new File(root, "icon.jpg").delete();
new File(root, "icon.bmp").delete();
new File(root, "icon.gif").delete();
}
public Image getVersionIconImage(String id) {
@@ -272,12 +313,12 @@ public class HMCLGameRepository extends DefaultGameRepository {
if (iconType == VersionIconType.DEFAULT) {
Version version = getVersion(id).resolve(this);
File iconFile = getVersionIconFile(id);
if (iconFile.exists()) {
try (InputStream inputStream = new FileInputStream(iconFile)) {
Optional<File> iconFile = getVersionIconFile(id);
if (iconFile.isPresent()) {
try (InputStream inputStream = new FileInputStream(iconFile.get())) {
return new Image(inputStream);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to load version icon of " + id, e);
LOG.warning("Failed to load version icon of " + id, e);
}
}
@@ -316,7 +357,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
FileUtils.writeText(file, GSON.toJson(localVersionSettings.get(id)));
return true;
} catch (IOException e) {
LOG.log(Level.SEVERE, "Unable to save version setting of " + id, e);
LOG.error("Unable to save version setting of " + id, e);
return false;
}
}
@@ -60,13 +60,12 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.Lang.resolveException;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -112,7 +111,7 @@ public final class LauncherHelper {
public void launch() {
FXUtils.checkFxUserThread();
Logging.LOG.info("Launching game version: " + selectedVersion);
LOG.info("Launching game version: " + selectedVersion);
Controllers.dialog(launchingStepsPane);
launch0();
@@ -333,7 +332,8 @@ public final class LauncherHelper {
}
private static Task<JavaVersion> checkGameState(Profile profile, VersionSetting setting, Version version) {
GameVersionNumber gameVersion = GameVersionNumber.asGameVersion(profile.getRepository().getGameVersion(version));
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version, profile.getRepository().getGameVersion(version).orElse(null));
GameVersionNumber gameVersion = GameVersionNumber.asGameVersion(analyzer.getVersion(LibraryAnalyzer.LibraryType.MINECRAFT));
if (setting.isNotCheckJVM()) {
return Task.composeAsync(() -> setting.getJavaVersion(gameVersion, version))
@@ -354,7 +354,9 @@ public final class LauncherHelper {
if (org.jackhuang.hmcl.util.platform.Platform.isCompatibleWithX86Java()) {
JavaVersionConstraint.VersionRanges range = JavaVersionConstraint.findSuitableJavaVersionRange(gameVersion, version);
if (range.getMandatory().contains(VersionNumber.asVersion("17.0.1"))) {
if (range.getMandatory().contains(VersionNumber.asVersion("21.0.3"))) {
targetJavaVersion = GameJavaVersion.JAVA_21;
} else if (range.getMandatory().contains(VersionNumber.asVersion("17.0.1"))) {
targetJavaVersion = GameJavaVersion.JAVA_17;
} else if (range.getMandatory().contains(VersionNumber.asVersion("16.0.1"))) {
targetJavaVersion = GameJavaVersion.JAVA_16;
@@ -388,7 +390,7 @@ public final class LauncherHelper {
future.complete(downloadedJavaVersion);
})
.exceptionally(throwable -> {
LOG.log(Level.WARNING, "Failed to download java", throwable);
LOG.warning("Failed to download java", throwable);
Controllers.confirm(i18n("launch.failed.no_accepted_java"), i18n("message.warning"), MessageType.WARNING, continueAction, () -> {
future.completeExceptionally(new CancellationException("No accepted java"));
});
@@ -417,7 +419,6 @@ public final class LauncherHelper {
JavaVersionConstraint violatedMandatoryConstraint = null;
List<JavaVersionConstraint> violatedSuggestedConstraints = null;
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version, gameVersion.toString());
for (JavaVersionConstraint constraint : JavaVersionConstraint.ALL) {
if (constraint.appliesToVersion(gameVersion, version, javaVersion, analyzer)) {
if (!constraint.checkJava(gameVersion, version, javaVersion)) {
@@ -452,7 +453,7 @@ public final class LauncherHelper {
future.complete(downloadedJavaVersion);
}, Schedulers.javafx())
.whenCompleteAsync((result, throwable) -> {
LOG.log(Level.WARNING, "Failed to download java", throwable);
LOG.warning("Failed to download java", throwable);
breakAction.run();
}, Schedulers.javafx());
return Task.fromCompletableFuture(future);
@@ -466,6 +467,11 @@ public final class LauncherHelper {
() -> FXUtils.openLink(OPENJDK_DOWNLOAD_LINK), null);
breakAction.run();
return Task.fromCompletableFuture(future);
case VANILLA_JAVA_21:
Controllers.confirm(i18n("launch.advice.require_newer_java_version", gameVersion.toString(), 21), i18n("message.warning"),
() -> FXUtils.openLink(OPENJDK_DOWNLOAD_LINK), null);
breakAction.run();
return Task.fromCompletableFuture(future);
case VANILLA_JAVA_8:
Controllers.dialog(i18n("launch.advice.java8_1_13"), i18n("message.error"), MessageType.ERROR, breakAction);
return Task.fromCompletableFuture(future);
@@ -605,7 +611,7 @@ public final class LauncherHelper {
.thenAcceptAsync(future::complete)
.exceptionally(throwable -> {
Throwable resolvedException = resolveException(throwable);
LOG.log(Level.WARNING, "Failed to download java", throwable);
LOG.warning("Failed to download java", throwable);
if (!(resolvedException instanceof CancellationException)) {
Controllers.dialog(DownloadProviders.localizeErrorMessage(resolvedException), i18n("install.failed"));
}
@@ -644,11 +650,11 @@ public final class LauncherHelper {
try {
return Task.completed(account.logIn());
} catch (CredentialExpiredException e) {
LOG.log(Level.INFO, "Credential has expired", e);
LOG.info("Credential has expired", e);
return Task.completed(DialogController.logIn(account));
} catch (AuthenticationException e) {
LOG.log(Level.WARNING, "Authentication failed, try skipping refresh", e);
LOG.warning("Authentication failed, try skipping refresh", e);
CompletableFuture<Task<AuthInfo>> future = new CompletableFuture<>();
runInFX(() -> {
@@ -27,10 +27,9 @@ import org.jackhuang.hmcl.util.StringUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Stream;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public abstract class LocalizedRemoteModRepository implements RemoteModRepository {
private static final int CONTAIN_CHINESE_WEIGHT = 10;
@@ -69,7 +68,7 @@ public abstract class LocalizedRemoteModRepository implements RemoteModRepositor
SearchResult searchResult = getBackedRemoteModRepository().search(gameVersion, category, pageOffset, pageSize, String.join(" ", englishSearchFiltersSet), getBackedRemoteModRepositorySortOrder(), sortOrder);
for (Iterator<RemoteMod> iterator = searchResult.getUnsortedResults().iterator(); iterator.hasNext(); ) {
if (chineseIndex > englishIndex) {
LOG.log(Level.WARNING, "Too many search results! Are the backed remote mod repository broken? Or are the API broken?");
LOG.warning("Too many search results! Are the backed remote mod repository broken? Or are the API broken?");
continue;
}
@@ -17,7 +17,7 @@
*/
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.logging.Logger;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.Zipper;
@@ -35,9 +35,8 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public final class LogExporter {
private LogExporter() {
@@ -70,9 +69,9 @@ public final class LogExporter {
processLogs(runDirectory, "*.log", "runDirectory", zipper);
processLogs(runDirectory.resolve("crash-reports"), "*.txt", "crash-reports", zipper);
zipper.putTextFile(Logging.getLogs(), "hmcl.log");
zipper.putTextFile(LOG.getLogs(), "hmcl.log");
zipper.putTextFile(logs, "minecraft.log");
zipper.putTextFile(Logging.filterForbiddenToken(launchScript), OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "launch.bat" : "launch.sh");
zipper.putTextFile(Logger.filterForbiddenToken(launchScript), OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "launch.bat" : "launch.sh");
for (String id : versions) {
Path versionJson = baseDirectory.resolve("versions").resolve(id).resolve(id + ".json");
@@ -95,16 +94,16 @@ public final class LogExporter {
FileTime time = Files.readAttributes(file, BasicFileAttributes.class).lastModifiedTime();
if (time.toMillis() >= processStartTime) {
try {
String crashLog = Logging.filterForbiddenToken(FileUtils.readText(file, OperatingSystem.NATIVE_CHARSET));
String crashLog = Logger.filterForbiddenToken(FileUtils.readText(file, OperatingSystem.NATIVE_CHARSET));
zipper.putTextFile(crashLog, file.getFileName().toString());
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to read log file: " + file, e);
LOG.warning("Failed to read log file: " + file, e);
}
}
}
}
} catch (Throwable e) {
LOG.log(Level.WARNING, "Failed to find any log on " + logDirectory, e);
LOG.warning("Failed to find any log on " + logDirectory, e);
}
}
}
@@ -23,7 +23,6 @@ import org.jackhuang.hmcl.auth.OAuth;
import org.jackhuang.hmcl.event.Event;
import org.jackhuang.hmcl.event.EventManager;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.io.JarUtils;
@@ -34,10 +33,10 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class OAuthServer extends NanoHTTPD implements OAuth.Session {
@@ -80,7 +79,7 @@ public final class OAuthServer extends NanoHTTPD implements OAuth.Session {
try {
session.parseBody(files);
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Failed to read post data", e);
LOG.warning("Failed to read post data", e);
return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, MIME_HTML, "");
} catch (ResponseException re) {
return newFixedLengthResponse(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
@@ -97,7 +96,7 @@ public final class OAuthServer extends NanoHTTPD implements OAuth.Session {
idToken = query.get("id_token");
future.complete(query.get("code"));
} else {
Logging.LOG.warning("Error: " + parameters);
LOG.warning("Error: " + parameters);
future.completeExceptionally(new AuthenticationException("failed to authenticate"));
}
@@ -106,7 +105,7 @@ public final class OAuthServer extends NanoHTTPD implements OAuth.Session {
html = IOUtils.readFullyAsString(OAuthServer.class.getResourceAsStream("/assets/microsoft_auth.html"))
.replace("%close-page%", i18n("account.methods.microsoft.close_page"));
} catch (IOException e) {
Logging.LOG.log(Level.SEVERE, "Failed to load html");
LOG.error("Failed to load html", e);
return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, MIME_HTML, "");
}
thread(() -> {
@@ -114,7 +113,7 @@ public final class OAuthServer extends NanoHTTPD implements OAuth.Session {
Thread.sleep(1000);
stop();
} catch (InterruptedException e) {
Logging.LOG.log(Level.SEVERE, "Failed to sleep for 1 second");
LOG.error("Failed to sleep for 1 second");
}
});
return newFixedLengthResponse(Response.Status.OK, "text/html; charset=UTF-8", html);
@@ -52,13 +52,12 @@ import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static java.util.Objects.requireNonNull;
import static org.jackhuang.hmcl.util.Lang.threadPool;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/**
* @author yushijinhun
@@ -116,7 +115,7 @@ public final class TexturesLoader {
} catch (Exception e) {
if (Files.isRegularFile(file)) {
// concurrency conflict?
LOG.log(Level.WARNING, "Failed to download texture " + texture.getUrl() + ", but the file is available", e);
LOG.warning("Failed to download texture " + texture.getUrl() + ", but the file is available", e);
} else {
throw new IOException("Failed to download texture " + texture.getUrl());
}
@@ -140,30 +139,42 @@ public final class TexturesLoader {
// ====
// ==== Skins ====
private final static Map<TextureModel, LoadedTexture> DEFAULT_SKINS = new EnumMap<>(TextureModel.class);
private static final String[] DEFAULT_SKINS = {"alex", "ari", "efe", "kai", "makena", "noor", "steve", "sunny", "zuri"};
static {
loadDefaultSkin("/assets/img/skin/steve.png", TextureModel.STEVE);
loadDefaultSkin("/assets/img/skin/alex.png", TextureModel.ALEX);
public static Image getDefaultSkinImage() {
return FXUtils.newBuiltinImage("/assets/img/skin/wide/steve.png");
}
private static void loadDefaultSkin(String path, TextureModel model) {
DEFAULT_SKINS.put(model, new LoadedTexture(FXUtils.newBuiltinImage(path), singletonMap("model", model.modelName)));
public static LoadedTexture getDefaultSkin(UUID uuid) {
int idx = Math.floorMod(uuid.hashCode(), DEFAULT_SKINS.length * 2);
TextureModel model;
Image skin;
if (idx < DEFAULT_SKINS.length) {
model = TextureModel.SLIM;
skin = FXUtils.newBuiltinImage("/assets/img/skin/slim/" + DEFAULT_SKINS[idx] + ".png");
} else {
model = TextureModel.WIDE;
skin = FXUtils.newBuiltinImage("/assets/img/skin/wide/" + DEFAULT_SKINS[idx - DEFAULT_SKINS.length] + ".png");
}
return new LoadedTexture(skin, singletonMap("model", model.modelName));
}
public static LoadedTexture getDefaultSkin(TextureModel model) {
return DEFAULT_SKINS.get(model);
public static TextureModel getDefaultModel(UUID uuid) {
return TextureModel.WIDE.modelName.equals(getDefaultSkin(uuid).getMetadata().get("model"))
? TextureModel.WIDE
: TextureModel.SLIM;
}
public static ObjectBinding<LoadedTexture> skinBinding(YggdrasilService service, UUID uuid) {
LoadedTexture uuidFallback = getDefaultSkin(TextureModel.detectUUID(uuid));
LoadedTexture uuidFallback = getDefaultSkin(uuid);
return BindingMapping.of(service.getProfileRepository().binding(uuid))
.map(profile -> profile
.flatMap(it -> {
try {
return YggdrasilService.getTextures(it);
} catch (ServerResponseMalformedException e) {
LOG.log(Level.WARNING, "Failed to parse texture payload", e);
LOG.warning("Failed to parse texture payload", e);
return Optional.empty();
}
})
@@ -176,7 +187,7 @@ public final class TexturesLoader {
try {
return loadTexture(texture);
} catch (Throwable e) {
LOG.log(Level.WARNING, "Failed to load texture " + texture.getUrl() + ", using fallback texture", e);
LOG.warning("Failed to load texture " + texture.getUrl() + ", using fallback texture", e);
return uuidFallback;
}
}, POOL);
@@ -187,7 +198,7 @@ public final class TexturesLoader {
}
public static ObservableValue<LoadedTexture> skinBinding(Account account) {
LoadedTexture uuidFallback = getDefaultSkin(TextureModel.detectUUID(account.getUUID()));
LoadedTexture uuidFallback = getDefaultSkin(account.getUUID());
if (account instanceof OfflineAccount) {
OfflineAccount offlineAccount = (OfflineAccount) account;
@@ -200,7 +211,7 @@ public final class TexturesLoader {
if (skin != null) {
skin.load(username).setExecutor(POOL).whenComplete(Schedulers.javafx(), (result, exception) -> {
if (exception != null) {
LOG.log(Level.WARNING, "Failed to load texture", exception);
LOG.warning("Failed to load texture", exception);
} else if (result != null && result.getSkin() != null && result.getSkin().getImage() != null) {
Map<String, String> metadata;
if (result.getModel() != null) {
@@ -231,7 +242,7 @@ public final class TexturesLoader {
try {
return loadTexture(texture);
} catch (Throwable e) {
LOG.log(Level.WARNING, "Failed to load texture " + texture.getUrl() + ", using fallback texture", e);
LOG.warning("Failed to load texture " + texture.getUrl() + ", using fallback texture", e);
return uuidFallback;
}
}, POOL);
@@ -348,7 +359,7 @@ public final class TexturesLoader {
fxAvatarBinding(canvas, skinBinding(account));
else {
unbindAvatar(canvas);
drawAvatar(canvas, getDefaultSkin(TextureModel.detectUUID(account.getUUID())).image);
drawAvatar(canvas, getDefaultSkin(account.getUUID()).image);
}
}
@@ -47,7 +47,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.logging.Level;
import static java.util.stream.Collectors.toList;
import static javafx.collections.FXCollections.observableArrayList;
@@ -55,7 +54,7 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
import static org.jackhuang.hmcl.util.Lang.immutableListOf;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -72,7 +71,7 @@ public final class Accounts {
try {
((AuthlibInjectorDownloader) AUTHLIB_INJECTOR_DOWNLOADER).checkUpdate();
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to check update for authlib-injector", e);
LOG.warning("Failed to check update for authlib-injector", e);
}
});
}
@@ -178,7 +177,7 @@ public final class Accounts {
Config.CONFIG_GSON.fromJson(reader, new TypeToken<List<Map<Object, Object>>>() {
}.getType()));
} catch (Throwable e) {
LOG.log(Level.WARNING, "Failed to load global accounts", e);
LOG.warning("Failed to load global accounts", e);
}
}
@@ -190,7 +189,7 @@ public final class Accounts {
FileUtils.saveSafely(globalAccountsFile, json);
}
} catch (IOException e) {
LOG.log(Level.SEVERE, "Failed to save global accounts", e);
LOG.error("Failed to save global accounts", e);
}
}
});
@@ -209,7 +208,7 @@ public final class Accounts {
try {
return factory.fromStorage(storage);
} catch (Exception e) {
LOG.log(Level.WARNING, "Failed to load account: " + storage, e);
LOG.warning("Failed to load account: " + storage, e);
return null;
}
}
@@ -321,7 +320,7 @@ public final class Accounts {
try {
finalSelected.logIn();
} catch (Throwable e) {
LOG.log(Level.WARNING, "Failed to log " + finalSelected + " in", e);
LOG.warning("Failed to log " + finalSelected + " in", e);
}
});
}
@@ -335,7 +334,7 @@ public final class Accounts {
try {
server.fetchMetadataResponse();
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to fetch authlib-injector server metdata: " + server, e);
LOG.warning("Failed to fetch authlib-injector server metdata: " + server, e);
}
});
}
@@ -34,10 +34,9 @@ import java.nio.file.Paths;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Level;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public final class AuthlibInjectorServers implements Validation {
@@ -77,7 +76,7 @@ public final class AuthlibInjectorServers implements Validation {
String content = FileUtils.readText(configLocation);
configInstance = JsonUtils.GSON.fromJson(content, AuthlibInjectorServers.class);
} catch (IOException | JsonParseException e) {
LOG.log(Level.WARNING, "Malformed authlib-injectors.json", e);
LOG.warning("Malformed authlib-injectors.json", e);
return;
}
@@ -29,9 +29,8 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.IOException;
import java.nio.file.*;
import java.util.Locale;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public final class ConfigHolder {
@@ -81,7 +80,7 @@ public final class ConfigHolder {
configLocation = locateConfig();
LOG.log(Level.INFO, "Config location: " + configLocation);
LOG.info("Config location: " + configLocation);
configInstance = loadConfig();
configInstance.addListener(source -> markConfigDirty());
@@ -91,6 +90,7 @@ public final class ConfigHolder {
Locale.setDefault(config().getLocalization().getLocale());
I18n.setLocale(configInstance.getLocalization());
LOG.setLogRetention(globalConfig().getLogRetention());
Settings.init();
if (newlyCreated) {
@@ -101,7 +101,7 @@ public final class ConfigHolder {
try {
Files.setAttribute(configLocation, "dos:hidden", true);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to set hidden attribute of " + configLocation, e);
LOG.warning("Failed to set hidden attribute of " + configLocation, e);
}
}
}
@@ -161,7 +161,7 @@ public final class ConfigHolder {
ownerChanged = true;
}
} catch (IOException e1) {
LOG.log(Level.WARNING, "Failed to get owner");
LOG.warning("Failed to get owner");
}
try {
String content = FileUtils.readText(configLocation);
@@ -173,7 +173,7 @@ public final class ConfigHolder {
return deserialized;
}
} catch (JsonParseException e) {
LOG.log(Level.WARNING, "Malformed config.", e);
LOG.warning("Malformed config.", e);
}
}
@@ -186,7 +186,7 @@ public final class ConfigHolder {
try {
writeToConfig(content);
} catch (IOException e) {
LOG.log(Level.SEVERE, "Failed to save config", e);
LOG.error("Failed to save config", e);
}
});
@@ -218,7 +218,7 @@ public final class ConfigHolder {
return deserialized;
}
} catch (JsonParseException e) {
LOG.log(Level.WARNING, "Malformed config.", e);
LOG.warning("Malformed config.", e);
}
}
@@ -230,7 +230,7 @@ public final class ConfigHolder {
try {
writeToGlobalConfig(content);
} catch (IOException e) {
LOG.log(Level.SEVERE, "Failed to save config", e);
LOG.error("Failed to save config", e);
}
});
@@ -23,10 +23,9 @@ import org.jackhuang.hmcl.util.StringUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
final class ConfigUpgrader {
private ConfigUpgrader() {
@@ -48,12 +47,12 @@ final class ConfigUpgrader {
}
if (configVersion > CURRENT_VERSION) {
LOG.log(Level.WARNING, String.format("Current HMCL only support the configuration version up to %d. However, the version now is %d.", CURRENT_VERSION, configVersion));
LOG.warning(String.format("Current HMCL only support the configuration version up to %d. However, the version now is %d.", CURRENT_VERSION, configVersion));
deserialized.setConfigVersion(CURRENT_VERSION);
return;
}
LOG.log(Level.INFO, String.format("Updating configuration from %d to %d.", configVersion, CURRENT_VERSION));
LOG.info(String.format("Updating configuration from %d to %d.", configVersion, CURRENT_VERSION));
Map<?, ?> rawJson = Collections.unmodifiableMap(new Gson().<Map<?, ?>>fromJson(rawContent, Map.class));
if (configVersion < 1) {
@@ -49,6 +49,8 @@ public final class GlobalConfig implements Cloneable, Observable {
private final IntegerProperty platformPromptVersion = new SimpleIntegerProperty();
private final IntegerProperty logRetention = new SimpleIntegerProperty();
private final Map<String, Object> unknownFields = new HashMap<>();
private final transient ObservableHelper helper = new ObservableHelper(this);
@@ -100,10 +102,23 @@ public final class GlobalConfig implements Cloneable, Observable {
this.platformPromptVersion.set(platformPromptVersion);
}
public int getLogRetention() {
return logRetention.get();
}
public IntegerProperty logRetentionProperty() {
return logRetention;
}
public void setLogRetention(int logRetention) {
this.logRetention.set(logRetention);
}
public static final class Serializer implements JsonSerializer<GlobalConfig>, JsonDeserializer<GlobalConfig> {
private static final Set<String> knownFields = new HashSet<>(Arrays.asList(
"agreementVersion",
"platformPromptVersion"
"platformPromptVersion",
"logRetention"
));
@Override
@@ -115,6 +130,7 @@ public final class GlobalConfig implements Cloneable, Observable {
JsonObject jsonObject = new JsonObject();
jsonObject.add("agreementVersion", context.serialize(src.getAgreementVersion()));
jsonObject.add("platformPromptVersion", context.serialize(src.getPlatformPromptVersion()));
jsonObject.add("logRetention", context.serialize(src.getLogRetention()));
for (Map.Entry<String, Object> entry : src.unknownFields.entrySet()) {
jsonObject.add(entry.getKey(), context.serialize(entry.getValue()));
}
@@ -131,6 +147,7 @@ public final class GlobalConfig implements Cloneable, Observable {
GlobalConfig config = new GlobalConfig();
config.setAgreementVersion(Optional.ofNullable(obj.get("agreementVersion")).map(JsonElement::getAsInt).orElse(0));
config.setPlatformPromptVersion(Optional.ofNullable(obj.get("platformPromptVersion")).map(JsonElement::getAsInt).orElse(0));
config.setLogRetention(Optional.ofNullable(obj.get("logRetention")).map(JsonElement::getAsInt).orElse(20));
for (Map.Entry<String, JsonElement> entry : obj.entrySet()) {
if (!knownFields.contains(entry.getKey())) {
@@ -29,7 +29,7 @@ import java.net.Proxy;
import java.net.Proxy.Type;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public final class ProxyManager {
private ProxyManager() {
@@ -23,23 +23,27 @@ import com.google.gson.stream.JsonWriter;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.IOUtils;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
@JsonAdapter(Theme.TypeAdapter.class)
public class Theme {
@@ -82,6 +86,30 @@ public class Theme {
return cssCharset;
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static Optional<Font> font;
private static Optional<Font> tryLoadFont() {
//noinspection OptionalAssignedToNull
if (font != null) {
return font;
}
Path path = Paths.get("font.ttf");
if (!Files.isRegularFile(path)) {
path = Paths.get("font.otf");
}
if (Files.isRegularFile(path)) {
try {
return font = Optional.ofNullable(Font.loadFont(path.toAbsolutePath().toUri().toURL().toExternalForm(), 0));
} catch (MalformedURLException ignored) {
}
}
return font = Optional.empty();
}
public static Theme getTheme() {
Theme theme = config().getTheme();
return theme == null ? BLUE : theme;
@@ -121,9 +149,24 @@ public class Theme {
String css = "/assets/css/blue.css";
String fontFamily = System.getProperty("hmcl.font.override", overrideFontFamily);
String fontStyle = null;
if (fontFamily == null) {
Optional<Font> font = tryLoadFont();
if (font.isPresent()) {
fontFamily = font.get().getFamily();
fontStyle = font.get().getStyle();
}
}
if (fontFamily != null || !this.color.equalsIgnoreCase(BLUE.color)) {
Color textFill = getForegroundColor();
String fontCss = "";
if (fontFamily != null) {
fontCss = "-fx-font-family: \"" + fontFamily + "\";";
if (fontStyle != null && !fontStyle.isEmpty())
fontCss += " -fx-font-style: \"" + fontStyle + "\";";
}
try {
File temp = File.createTempFile("hmcl", ".css");
String themeText = IOUtils.readFullyAsString(Theme.class.getResourceAsStream("/assets/css/custom.css"))
@@ -134,12 +177,12 @@ public class Theme {
.replace("%base-rippler-color%", String.format("rgba(%d, %d, %d, 0.3)", (int) Math.ceil(paint.getRed() * 256), (int) Math.ceil(paint.getGreen() * 256), (int) Math.ceil(paint.getBlue() * 256)))
.replace("%disabled-font-color%", String.format("rgba(%d, %d, %d, 0.7)", (int) Math.ceil(textFill.getRed() * 256), (int) Math.ceil(textFill.getGreen() * 256), (int) Math.ceil(textFill.getBlue() * 256)))
.replace("%font-color%", getColorDisplayName(getForegroundColor()))
.replace("%font%", Optional.ofNullable(fontFamily).map(f -> "-fx-font-family: \"" + f + "\";").orElse(""));
.replace("%font%", fontCss);
FileUtils.writeText(temp, themeText, getCssCharset());
temp.deleteOnExit();
css = temp.toURI().toString();
} catch (IOException | NullPointerException e) {
Logging.LOG.log(Level.SEVERE, "Unable to create theme stylesheet. Fallback to blue theme.", e);
LOG.error("Unable to create theme stylesheet. Fallback to blue theme.", e);
}
}
@@ -61,6 +61,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import static org.jackhuang.hmcl.setting.ConfigHolder.*;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class Controllers {
@@ -165,7 +166,7 @@ public final class Controllers {
}
public static void initialize(Stage stage) {
Logging.LOG.info("Start initializing application");
LOG.info("Start initializing application");
Controllers.stage = stage;
@@ -298,7 +299,7 @@ public final class Controllers {
});
JFXButton noButton = new JFXButton(i18n("launcher.agreement.decline"));
noButton.getStyleClass().add("dialog-cancel");
noButton.setOnAction(e -> System.exit(1));
noButton.setOnAction(e -> javafx.application.Platform.exit());
agreementPane.setActions(agreementLink, yesButton, noButton);
Controllers.dialog(agreementPane);
}
@@ -72,7 +72,7 @@ public class CrashWindow extends Stage {
FXUtils.setIcon(this);
setTitle(i18n("message.error"));
setOnCloseRequest(e -> System.exit(1));
setOnCloseRequest(e -> javafx.application.Platform.exit());
}
}
@@ -55,7 +55,6 @@ import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
import org.jackhuang.hmcl.ui.construct.JFXHyperlink;
import org.jackhuang.hmcl.util.Holder;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.ResourceNotFoundError;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.javafx.ExtendedProperties;
@@ -88,12 +87,11 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class FXUtils {
@@ -110,7 +108,7 @@ public final class FXUtils {
try {
Files.deleteIfExists(entry.getValue());
} catch (IOException e) {
LOG.log(Level.WARNING, String.format("Failed to delete cache file %s.", entry.getValue()), e);
LOG.warning(String.format("Failed to delete cache file %s.", entry.getValue()), e);
}
remoteImageCache.remove(entry.getKey());
}
@@ -337,7 +335,7 @@ public final class FXUtils {
Tooltip.class.getMethod("setHideDelay", Duration.class).invoke(tooltip, new Duration(closeDelay));
} catch (ReflectiveOperationException e2) {
e.addSuppressed(e2);
Logging.LOG.log(Level.SEVERE, "Cannot install tooltip", e);
LOG.error("Cannot install tooltip", e);
}
Tooltip.install(node, tooltip);
}
@@ -370,7 +368,7 @@ public final class FXUtils {
public static void openFolder(File file) {
if (!FileUtils.makeDirectory(file)) {
LOG.log(Level.SEVERE, "Unable to make directory " + file);
LOG.error("Unable to make directory " + file);
return;
}
@@ -397,7 +395,7 @@ public final class FXUtils {
else
LOG.warning("Open " + path + " failed with code " + exitCode);
} catch (Throwable e) {
LOG.log(Level.WARNING, "Unable to open " + path + " by executing " + openCommand, e);
LOG.warning("Unable to open " + path + " by executing " + openCommand, e);
}
}
@@ -405,7 +403,7 @@ public final class FXUtils {
try {
java.awt.Desktop.getDesktop().open(file);
} catch (Throwable e) {
LOG.log(Level.SEVERE, "Unable to open " + path + " by java.awt.Desktop.getDesktop()::open", e);
LOG.error("Unable to open " + path + " by java.awt.Desktop.getDesktop()::open", e);
}
});
}
@@ -432,7 +430,7 @@ public final class FXUtils {
else
LOG.warning("Show " + path + " in explorer failed with code " + exitCode);
} catch (Throwable e) {
LOG.log(Level.WARNING, "Unable to show " + path + " in explorer", e);
LOG.warning("Unable to show " + path + " in explorer", e);
}
// Fallback to open folder
@@ -469,7 +467,7 @@ public final class FXUtils {
Runtime.getRuntime().exec(new String[]{"rundll32.exe", "url.dll,FileProtocolHandler", link});
return;
} catch (Throwable e) {
LOG.log(Level.WARNING, "An exception occurred while calling rundll32", e);
LOG.warning("An exception occurred while calling rundll32", e);
}
}
if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) {
@@ -481,7 +479,7 @@ public final class FXUtils {
}
} catch (Throwable ignored) {
}
Logging.LOG.log(Level.WARNING, "No known browser found");
LOG.warning("No known browser found");
}
}
try {
@@ -491,9 +489,9 @@ public final class FXUtils {
try {
Runtime.getRuntime().exec(new String[]{"/usr/bin/open", link});
} catch (IOException ex) {
Logging.LOG.log(Level.WARNING, "Unable to open link: " + link, ex);
LOG.warning("Unable to open link: " + link, ex);
}
Logging.LOG.log(Level.WARNING, "Failed to open link: " + link, e);
LOG.warning("Failed to open link: " + link, e);
}
});
}
@@ -509,7 +507,7 @@ public final class FXUtils {
stage.setTitle(title);
stage.showAndWait();
} catch (NoClassDefFoundError | UnsatisfiedLinkError e) {
LOG.log(Level.WARNING, "WebView is missing or initialization failed, use JEditorPane replaced", e);
LOG.warning("WebView is missing or initialization failed, use JEditorPane replaced", e);
SwingUtils.initLookAndFeel();
SwingUtilities.invokeLater(() -> {
@@ -761,7 +759,7 @@ public final class FXUtils {
try (InputStream inputStream = Files.newInputStream(currentPath)) {
return new Image(inputStream, requestedWidth, requestedHeight, preserveRatio, smooth);
} catch (IOException e) {
LOG.log(Level.WARNING, "An exception encountered while reading data from cached image file.", e);
LOG.warning("An exception encountered while reading data from cached image file.", e);
}
}
@@ -771,7 +769,7 @@ public final class FXUtils {
try {
Files.deleteIfExists(currentPath);
} catch (IOException e) {
LOG.log(Level.WARNING, "An exception encountered while deleting broken cached image file.", e);
LOG.warning("An exception encountered while deleting broken cached image file.", e);
}
}
@@ -968,7 +966,7 @@ public final class FXUtils {
}
return texts;
} catch (SAXException | ParserConfigurationException | IOException e) {
LOG.log(Level.WARNING, "Failed to parse xml", e);
LOG.warning("Failed to parse xml", e);
return Collections.singletonList(new Text(segment));
}
}
@@ -44,7 +44,7 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.logging.Logger;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
@@ -61,14 +61,13 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -132,7 +131,7 @@ public class GameCrashWindow extends Stage {
try {
crashReport = CrashReportAnalyzer.findCrashReport(rawLog);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to read crash report", e);
LOG.warning("Failed to read crash report", e);
}
if (crashReport == null) {
crashReport = CrashReportAnalyzer.extractCrashReport(rawLog);
@@ -149,7 +148,7 @@ public class GameCrashWindow extends Stage {
try {
log = FileUtils.readText(latestLog);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to read logs/latest.log", e);
LOG.warning("Failed to read logs/latest.log", e);
return pair(new HashSet<CrashReportAnalyzer.Result>(), new HashSet<String>());
}
@@ -158,7 +157,7 @@ public class GameCrashWindow extends Stage {
loading.set(false);
if (exception != null) {
LOG.log(Level.WARNING, "Failed to analyze crash report", exception);
LOG.warning("Failed to analyze crash report", exception);
reasonTextFlow.getChildren().setAll(FXUtils.parseSegment(i18n("game.crash.reason.unknown"), Controllers::onHyperlinkAction));
} else {
EnumMap<CrashReportAnalyzer.Rule, CrashReportAnalyzer.Result> results = new EnumMap<>(CrashReportAnalyzer.Rule.class);
@@ -172,7 +171,7 @@ public class GameCrashWindow extends Stage {
List<Node> segments = new ArrayList<>(FXUtils.parseSegment(i18n("game.crash.feedback"), Controllers::onHyperlinkAction));
LOG.log(Level.INFO, "Number of reasons: " + results.size());
LOG.info("Number of reasons: " + results.size());
if (results.size() > 1) {
segments.add(new Text("\n"));
segments.addAll(FXUtils.parseSegment(i18n("game.crash.reason.multiple"), Controllers::onHyperlinkAction));
@@ -203,8 +202,9 @@ public class GameCrashWindow extends Stage {
case TWILIGHT_FOREST_OPTIFINE:
case PERFORMANT_FOREST_OPTIFINE:
case JADE_FOREST_OPTIFINE:
case NEOFORGE_FOREST_OPTIFINE:
message = i18n("game.crash.reason.mod", "OptiFine");
LOG.log(Level.INFO, "Crash cause: " + result.getRule() + ": " + i18n("game.crash.reason.mod", "OptiFine"));
LOG.info("Crash cause: " + result.getRule() + ": " + i18n("game.crash.reason.mod", "OptiFine"));
break;
default:
message = i18n("game.crash.reason." + result.getRule().name().toLowerCase(Locale.ROOT),
@@ -212,17 +212,17 @@ public class GameCrashWindow extends Stage {
.toArray());
break;
}
LOG.log(Level.INFO, "Crash cause: " + result.getRule() + ": " + message);
LOG.info("Crash cause: " + result.getRule() + ": " + message);
segments.addAll(FXUtils.parseSegment(message, Controllers::onHyperlinkAction));
segments.add(new Text("\n\n"));
}
if (results.isEmpty()) {
if (!keywords.isEmpty()) {
reasonTextFlow.getChildren().setAll(new Text(i18n("game.crash.reason.stacktrace", String.join(", ", keywords))));
LOG.log(Level.INFO, "Crash reason unknown, but some log keywords have been found: " + String.join(", ", keywords));
LOG.info("Crash reason unknown, but some log keywords have been found: " + String.join(", ", keywords));
} else {
reasonTextFlow.getChildren().setAll(FXUtils.parseSegment(i18n("game.crash.reason.unknown"), Controllers::onHyperlinkAction));
LOG.log(Level.INFO, "Crash reason unknown");
LOG.info("Crash reason unknown");
}
} else {
feedbackTextFlow.setVisible(false);
@@ -264,7 +264,7 @@ public class GameCrashWindow extends Stage {
private void showLogWindow() {
LogWindow logWindow = new LogWindow(managedProcess);
logWindow.logLine(Logging.filterForbiddenToken("Command: " + new CommandBuilder().addAll(managedProcess.getCommands())), Log4jLevel.INFO);
logWindow.logLine(Logger.filterForbiddenToken("Command: " + new CommandBuilder().addAll(managedProcess.getCommands())), Log4jLevel.INFO);
if (managedProcess.getClasspath() != null)
logWindow.logLine("ClassPath: " + managedProcess.getClasspath(), Log4jLevel.INFO);
for (Map.Entry<String, Log4jLevel> entry : logs)
@@ -287,7 +287,7 @@ public class GameCrashWindow extends Stage {
FXUtils.showFileInExplorer(logFile);
alert = new Alert(Alert.AlertType.INFORMATION, i18n("settings.launcher.launcher_log.export.success", logFile));
} else {
LOG.log(Level.WARNING, "Failed to export game crash info", exception);
LOG.warning("Failed to export game crash info", exception);
alert = new Alert(Alert.AlertType.WARNING, i18n("settings.launcher.launcher_log.export.failed") + "\n" + StringUtils.getStackTrace(exception));
}
@@ -55,13 +55,12 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.StringUtils.parseEscapeSequence;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -210,7 +209,7 @@ public final class LogWindow extends Stage {
try {
Files.write(logFile, logs.stream().map(x -> x.log).collect(Collectors.toList()));
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to export logs", e);
LOG.warning("Failed to export logs", e);
return;
}
@@ -238,7 +237,7 @@ public final class LogWindow extends Stage {
FXUtils.showFileInExplorer(dumpFile);
}
} catch (Throwable e) {
LOG.log(Level.WARNING, "Failed to create minecraft jstack dump", e);
LOG.warning("Failed to create minecraft jstack dump", e);
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, i18n("logwindow.export_dump.dependency_ok.button"));
@@ -27,11 +27,10 @@ import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
import org.jackhuang.hmcl.upgrade.RemoteVersion;
import java.util.logging.Level;
import static org.jackhuang.hmcl.Metadata.CHANGELOG_URL;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class UpgradeDialog extends JFXDialogLayout {
@@ -56,7 +55,7 @@ public class UpgradeDialog extends JFXDialogLayout {
});
setBody(webView);
} catch (NoClassDefFoundError | UnsatisfiedLinkError e) {
LOG.log(Level.WARNING, "WebView is missing or initialization failed", e);
LOG.warning("WebView is missing or initialization failed", e);
FXUtils.openLink(url);
}
}
@@ -27,7 +27,6 @@ import javafx.scene.control.Tooltip;
import org.jackhuang.hmcl.auth.Account;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
import org.jackhuang.hmcl.auth.yggdrasil.TextureModel;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
import org.jackhuang.hmcl.game.TexturesLoader;
import org.jackhuang.hmcl.setting.Accounts;
@@ -58,7 +57,7 @@ public class AccountAdvancedListItem extends AdvancedListItem {
tooltip.setText(i18n("account.create"));
TexturesLoader.unbindAvatar(canvas);
TexturesLoader.drawAvatar(canvas, TexturesLoader.getDefaultSkin(TextureModel.STEVE).getImage());
TexturesLoader.drawAvatar(canvas, TexturesLoader.getDefaultSkinImage());
} else {
titleProperty().bind(BindingMapping.of(account, Account::getCharacter));
@@ -54,11 +54,10 @@ import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import static java.util.Collections.emptySet;
import static javafx.beans.binding.Bindings.createBooleanBinding;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class AccountListItem extends RadioButton {
@@ -109,11 +108,11 @@ public class AccountListItem extends RadioButton {
} catch (CancellationException e1) {
// ignore cancellation
} catch (Exception e1) {
LOG.log(Level.WARNING, "Failed to refresh " + account + " with password", e1);
LOG.warning("Failed to refresh " + account + " with password", e1);
throw e1;
}
} catch (AuthenticationException e) {
LOG.log(Level.WARNING, "Failed to refresh " + account + " with token", e);
LOG.warning("Failed to refresh " + account + " with token", e);
throw e;
}
});
@@ -44,10 +44,9 @@ import org.jackhuang.hmcl.util.javafx.BindingMapping;
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
import java.net.URI;
import java.util.logging.Level;
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor;
@@ -137,7 +136,7 @@ public class AccountListPage extends DecoratorAnimatedPage implements DecoratorP
try {
host = URI.create(server.getUrl()).getHost();
} catch (IllegalArgumentException e) {
LOG.log(Level.WARNING, "Unparsable authlib-injector server url " + server.getUrl(), e);
LOG.warning("Unparsable authlib-injector server url " + server.getUrl(), e);
}
item.subtitleProperty().set(host);
Tooltip tooltip = new Tooltip();
@@ -35,11 +35,10 @@ import org.jackhuang.hmcl.util.io.NetworkUtils;
import javax.net.ssl.SSLException;
import java.io.IOException;
import java.util.logging.Level;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class AddAuthlibInjectorServerPane extends TransitionPane implements DialogAware {
@@ -201,7 +200,7 @@ public final class AddAuthlibInjectorServerPane extends TransitionPane implement
this.setContent(confirmServerPane, ContainerAnimations.SWIPE_LEFT.getAnimationProducer());
} else {
LOG.log(Level.WARNING, "Failed to resolve auth server: " + url, exception);
LOG.warning("Failed to resolve auth server: " + url, exception);
lblCreationWarning.setText(resolveFetchExceptionMessage(exception));
}
}).start();
@@ -36,10 +36,9 @@ import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
import org.jackhuang.hmcl.ui.construct.RequiredValidator;
import java.util.function.Consumer;
import java.util.logging.Level;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class ClassicAccountLoginDialog extends StackPane {
@@ -109,7 +108,7 @@ public class ClassicAccountLoginDialog extends StackPane {
fireEvent(new DialogCloseEvent());
progressBar.setVisible(false);
}, e -> {
LOG.log(Level.INFO, "Failed to login with password: " + oldAccount, e);
LOG.info("Failed to login with password: " + oldAccount, e);
if (e instanceof NoSelectedCharacterException) {
fireEvent(new DialogCloseEvent());
} else {
@@ -21,9 +21,8 @@ import org.jackhuang.hmcl.ui.construct.JFXHyperlink;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import java.util.function.Consumer;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class OAuthAccountLoginDialog extends DialogPane {
@@ -96,7 +95,7 @@ public class OAuthAccountLoginDialog extends DialogPane {
success.accept(authInfo);
onSuccess();
} else {
LOG.log(Level.INFO, "Failed to login when credentials expired: " + account, exception);
LOG.info("Failed to login when credentials expired: " + account, exception);
onFailure(Accounts.localizeErrorMessage(exception));
}
}).start();
@@ -25,7 +25,6 @@ import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.input.DragEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.*;
@@ -35,6 +34,7 @@ import moe.mickey.minecraft.skin.fx.animation.SkinAniWavingArms;
import org.jackhuang.hmcl.auth.offline.OfflineAccount;
import org.jackhuang.hmcl.auth.offline.Skin;
import org.jackhuang.hmcl.auth.yggdrasil.TextureModel;
import org.jackhuang.hmcl.game.TexturesLoader;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
@@ -42,11 +42,11 @@ import org.jackhuang.hmcl.ui.construct.*;
import java.io.File;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.UUID;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class OfflineAccountSkinPane extends StackPane {
@@ -71,7 +71,7 @@ public class OfflineAccountSkinPane extends StackPane {
BorderPane pane = new BorderPane();
SkinCanvas canvas = new SkinCanvas(SkinCanvas.STEVE, 300, 300, true);
SkinCanvas canvas = new SkinCanvas(TexturesLoader.getDefaultSkinImage(), 300, 300, true);
StackPane canvasPane = new StackPane(canvas);
canvasPane.setPrefWidth(300);
canvasPane.setPrefHeight(300);
@@ -116,11 +116,11 @@ public class OfflineAccountSkinPane extends StackPane {
));
modelCombobox.setConverter(stringConverter(model -> i18n("account.skin.model." + model.modelName)));
modelCombobox.getItems().setAll(TextureModel.STEVE, TextureModel.ALEX);
modelCombobox.getItems().setAll(TextureModel.WIDE, TextureModel.SLIM);
if (account.getSkin() == null) {
skinItem.setSelectedData(Skin.Type.DEFAULT);
modelCombobox.setValue(TextureModel.STEVE);
modelCombobox.setValue(TextureModel.WIDE);
} else {
skinItem.setSelectedData(account.getSkin().getType());
cslApiField.setText(account.getSkin().getCslApi());
@@ -133,16 +133,21 @@ public class OfflineAccountSkinPane extends StackPane {
getSkin().load(account.getUsername())
.whenComplete(Schedulers.javafx(), (result, exception) -> {
if (exception != null) {
LOG.log(Level.WARNING, "Failed to load skin", exception);
LOG.warning("Failed to load skin", exception);
Controllers.showToast(i18n("message.failed"));
} else {
UUID uuid = this.account.getUUID();
if (result == null || result.getSkin() == null && result.getCape() == null) {
canvas.updateSkin(getDefaultTexture(), isDefaultSlim(), null);
canvas.updateSkin(
TexturesLoader.getDefaultSkin(uuid).getImage(),
TexturesLoader.getDefaultModel(uuid) == TextureModel.SLIM,
null
);
return;
}
canvas.updateSkin(
result.getSkin() != null ? result.getSkin().getImage() : getDefaultTexture(),
result.getModel() == TextureModel.ALEX,
result.getSkin() != null ? result.getSkin().getImage() : TexturesLoader.getDefaultSkin(uuid).getImage(),
result.getModel() == TextureModel.SLIM,
result.getCape() != null ? result.getCape().getImage() : null);
}
}).start();
@@ -198,17 +203,4 @@ public class OfflineAccountSkinPane extends StackPane {
private Skin getSkin() {
return new Skin(skinItem.getSelectedData(), cslApiField.getText(), modelCombobox.getValue(), skinSelector.getValue(), capeSelector.getValue());
}
private boolean isDefaultSlim() {
return TextureModel.detectUUID(account.getUUID()) == TextureModel.ALEX;
}
private Image getDefaultTexture() {
if (isDefaultSlim()) {
return SkinCanvas.ALEX;
} else {
return SkinCanvas.STEVE;
}
}
}
@@ -31,11 +31,11 @@ import org.jackhuang.hmcl.ui.animation.AnimationProducer;
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.ui.wizard.Navigation;
import org.jackhuang.hmcl.util.Logging;
import java.util.Optional;
import java.util.Stack;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class Navigator extends TransitionPane {
private static final String PROPERTY_DIALOG_CLOSE_HANDLER = Navigator.class.getName() + ".closeListener";
@@ -65,7 +65,7 @@ public class Navigator extends TransitionPane {
if (from == node)
return;
Logging.LOG.info("Navigate to " + node);
LOG.info("Navigate to " + node);
stack.push(node);
backable.set(canGoBack());
@@ -104,11 +104,11 @@ public class Navigator extends TransitionPane {
if (stack.peek() != from) {
// Allow page to be closed multiple times.
Logging.LOG.log(Level.INFO, "Closing already closed page: " + from, new Throwable());
LOG.info("Closing already closed page: " + from, new Throwable());
return;
}
Logging.LOG.info("Closed page " + from);
LOG.info("Closed page " + from);
Node poppedNode = stack.pop();
NavigationEvent exited = new NavigationEvent(this, poppedNode, Navigation.NavigationDirection.PREVIOUS, NavigationEvent.EXITED);
@@ -19,11 +19,12 @@ package org.jackhuang.hmcl.ui.construct;
import javafx.scene.Node;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.util.Logging;
import java.util.Optional;
import java.util.Stack;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class StackContainerPane extends StackPane {
private final Stack<Node> stack = new Stack<>();
@@ -39,7 +40,7 @@ public class StackContainerPane extends StackPane {
stack.push(node);
getChildren().setAll(node);
Logging.LOG.info(this + " " + stack);
LOG.info(this + " " + stack);
}
public void pop(Node node) {
@@ -49,7 +50,7 @@ public class StackContainerPane extends StackPane {
else
getChildren().setAll(stack.peek());
Logging.LOG.info(this + " " + stack + ", removed: " + flag + ", object: " + node);
LOG.info(this + " " + stack + ", removed: " + flag + ", object: " + node);
}
public boolean isEmpty() {
@@ -62,15 +62,13 @@ import java.util.Locale;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.stream.Stream;
import static java.util.logging.Level.WARNING;
import static java.util.stream.Collectors.toList;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.io.FileUtils.getExtension;
public class DecoratorController {
@@ -186,7 +184,7 @@ public class DecoratorController {
}
}
} catch (Exception e) {
LOG.log(WARNING, "Couldn't load background image", e);
LOG.warning("Couldn't load background image", e);
}
}
break;
@@ -234,7 +232,7 @@ public class DecoratorController {
})
.collect(toList());
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to list files in ./bg", e);
LOG.warning("Failed to list files in ./bg", e);
return Optional.empty();
}
@@ -263,12 +261,12 @@ public class DecoratorController {
try {
img = new Image(url);
} catch (IllegalArgumentException e) {
LOG.log(WARNING, "Couldn't load background image", e);
LOG.warning("Couldn't load background image", e);
return Optional.empty();
}
if (img.getException() != null) {
LOG.log(WARNING, "Couldn't load background image", img.getException());
LOG.warning("Couldn't load background image", img.getException());
return Optional.empty();
}
@@ -42,10 +42,9 @@ import java.io.File;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class LocalModpackPage extends ModpackPage {
@@ -121,7 +120,7 @@ public final class LocalModpackPage extends ModpackPage {
controller.getSettings().put(MODPACK_MANUALLY_CREATED, true);
} else if (exception != null) {
LOG.log(Level.WARNING, "Failed to read modpack manifest", exception);
LOG.warning("Failed to read modpack manifest", exception);
Controllers.dialog(i18n("modpack.task.install.error"), i18n("message.error"), MessageDialogPane.MessageType.ERROR);
Platform.runLater(controller::onEnd);
} else {
@@ -57,11 +57,10 @@ import org.jackhuang.hmcl.util.Holder;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.ui.ToolbarListPageSkin.wrap;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.formatDateTime;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -232,7 +231,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
}
});
} else {
LOG.log(Level.WARNING, "Failed to fetch versions list", exception);
LOG.warning("Failed to fetch versions list", exception);
Platform.runLater(() -> {
if (versionList != currentVersionList) return;
root.setContent(failedPane, ContainerAnimations.FADE.getAnimationProducer());
@@ -179,7 +179,7 @@ public final class ModpackInfoPage extends Control implements WizardPage {
if (skinnable.controller.getSettings().get(MODPACK_TYPE) == MODPACK_TYPE_SERVER) {
Hyperlink hyperlink = new Hyperlink(i18n("modpack.wizard.step.initialization.server"));
hyperlink.setOnMouseClicked(e -> {
FXUtils.openLink("https://docs.hmcl.net/modpack/serverpack.htm");
FXUtils.openLink("https://docs.hmcl.net/modpack/serverpack.html");
});
borderPane.setTop(hyperlink);
} else {
@@ -109,6 +109,11 @@ public class AboutPage extends StackPane {
mcmod.setSubtitle(i18n("about.thanks_to.mcmod.statement"));
mcmod.setExternalLink("https://www.mcmod.cn/");
IconedTwoLineListItem mcbbs = new IconedTwoLineListItem();
mcbbs.setImage(FXUtils.newBuiltinImage("/assets/img/chest.png"));
mcbbs.setTitle(i18n("about.thanks_to.mcbbs"));
mcbbs.setSubtitle(i18n("about.thanks_to.mcbbs.statement"));
IconedTwoLineListItem contributors = new IconedTwoLineListItem();
contributors.setImage(FXUtils.newBuiltinImage("/assets/img/github.png"));
contributors.setTitle(i18n("about.thanks_to.contributors"));
@@ -121,7 +126,7 @@ public class AboutPage extends StackPane {
users.setSubtitle(i18n("about.thanks_to.users.statement"));
users.setExternalLink("https://docs.hmcl.net/groups.html");
thanks.getContent().setAll(yushijinhun, bangbang93, glavo, zekerzhayard, zkitefly, burningtnt, mcmod, shulkerSakura, gamerteam, redLnn, contributors, users);
thanks.getContent().setAll(yushijinhun, bangbang93, glavo, zekerzhayard, zkitefly, burningtnt, mcmod, mcbbs, shulkerSakura, gamerteam, redLnn, contributors, users);
}
ComponentList dep = new ComponentList();
@@ -144,7 +149,7 @@ public class AboutPage extends StackPane {
IconedTwoLineListItem xz = new IconedTwoLineListItem();
xz.setTitle("XZ for Java");
xz.setSubtitle("Lasse Collin, Igor Pavlov, and/or Brett Okken.\nPublic Domain.");
xz.setExternalLink("https://xz.tukaani.org/xz-for-java/");
xz.setExternalLink("https://tukaani.org/xz/java.html");
IconedTwoLineListItem fxgson = new IconedTwoLineListItem();
fxgson.setTitle("fx-gson");
@@ -54,12 +54,11 @@ import java.time.Instant;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
@@ -102,7 +101,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
try {
Controllers.navigate(new NBTEditorPage(file));
} catch (Throwable e) {
LOG.log(Level.WARNING, "Fail to open nbt file", e);
LOG.warning("Fail to open nbt file", e);
Controllers.dialog(i18n("nbt.open.failed") + "\n\n" + StringUtils.getStackTrace(e),
i18n("message.error"), MessageDialogPane.MessageType.ERROR);
}
@@ -31,24 +31,23 @@ import org.jackhuang.hmcl.upgrade.RemoteVersion;
import org.jackhuang.hmcl.upgrade.UpdateChannel;
import org.jackhuang.hmcl.upgrade.UpdateChecker;
import org.jackhuang.hmcl.upgrade.UpdateHandler;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.i18n.Locales;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.logging.Level;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor;
@@ -130,11 +129,11 @@ public final class SettingsPage extends SettingsView {
Path logFile = Paths.get("hmcl-exported-logs-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")) + ".log").toAbsolutePath();
LOG.info("Exporting logs to " + logFile);
try {
Files.write(logFile, Logging.getRawLogs());
try (OutputStream output = Files.newOutputStream(logFile)) {
LOG.exportLogs(output);
} catch (IOException e) {
Platform.runLater(() -> Controllers.dialog(i18n("settings.launcher.launcher_log.export.failed") + "\n" + StringUtils.getStackTrace(e), null, MessageType.ERROR));
LOG.log(Level.WARNING, "Failed to export logs", e);
LOG.warning("Failed to export logs", e);
return;
}
@@ -177,7 +177,7 @@ public abstract class SettingsView extends StackPane {
languagePane.setLeft(left);
cboLanguage = new JFXComboBox<>();
cboLanguage.setConverter(stringConverter(locale -> locale.getName(I18n.getCurrentLocale().getResourceBundle())));
cboLanguage.setConverter(stringConverter(I18n::getName));
FXUtils.setLimitWidth(cboLanguage, 300);
languagePane.setRight(cboLanguage);
@@ -18,10 +18,9 @@ import org.jackhuang.hmcl.util.StringUtils;
import java.io.*;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class NBTEditorPage extends BorderPane implements DecoratorPage {
@@ -53,7 +52,7 @@ public class NBTEditorPage extends BorderPane implements DecoratorPage {
try {
save();
} catch (IOException ex) {
LOG.log(Level.WARNING, "Failed to save NBT file", ex);
LOG.warning("Failed to save NBT file", ex);
Controllers.dialog(i18n("nbt.save.failed") + "\n\n" + StringUtils.getStackTrace(ex));
}
});
@@ -73,7 +72,7 @@ public class NBTEditorPage extends BorderPane implements DecoratorPage {
}, Schedulers.javafx())
.handleAsync((result, e) -> {
if (e != null) {
LOG.log(Level.WARNING, "Fail to open nbt file", e);
LOG.warning("Fail to open nbt file", e);
Controllers.dialog(i18n("nbt.open.failed") + "\n\n" + StringUtils.getStackTrace(e), null, MessageDialogPane.MessageType.WARNING, cancelButton::fire);
}
return null;
@@ -29,7 +29,6 @@ import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.ListPageBase;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
@@ -38,8 +37,8 @@ import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class DatapackListPage extends ListPageBase<DatapackListPageSkin.DatapackInfoObject> implements DecoratorPage {
@@ -71,7 +70,7 @@ public class DatapackListPage extends ListPageBase<DatapackListPageSkin.Datapack
zip.loadFromZip();
zip.installTo(worldDir);
} catch (IOException | IllegalArgumentException e) {
Logging.LOG.log(Level.WARNING, "Unable to parse datapack file " + datapack, e);
LOG.warning("Unable to parse datapack file " + datapack, e);
}
}
@@ -117,7 +116,7 @@ public class DatapackListPage extends ListPageBase<DatapackListPageSkin.Datapack
datapack.deletePack(pack);
} catch (IOException e) {
// Fail to remove mods if the game is running or the datapack is absent.
Logging.LOG.warning("Failed to delete datapack " + pack);
LOG.warning("Failed to delete datapack " + pack);
}
});
}
@@ -477,7 +477,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
protected void updateControl(RemoteMod dataItem, boolean empty) {
if (empty) return;
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(getSkinnable().repository.getType()).getModByCurseForgeId(dataItem.getSlug());
content.setTitle(mod != null && I18n.getCurrentLocale().getLocale() == Locale.CHINA ? mod.getDisplayName() : dataItem.getTitle());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : dataItem.getTitle());
content.setSubtitle(dataItem.getDescription());
content.getTags().setAll(dataItem.getCategories().stream()
.map(category -> getSkinnable().getLocalizedCategory(category))
@@ -240,7 +240,7 @@ public class DownloadPage extends Control implements DecoratorPage {
TwoLineListItem content = new TwoLineListItem();
HBox.setHgrow(content, Priority.ALWAYS);
ModTranslations.Mod mod = getSkinnable().translations.getModByCurseForgeId(getSkinnable().addon.getSlug());
content.setTitle(mod != null && I18n.getCurrentLocale().getLocale() == Locale.CHINA ? mod.getDisplayName() : getSkinnable().addon.getTitle());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : getSkinnable().addon.getTitle());
content.setSubtitle(getSkinnable().addon.getDescription());
content.getTags().setAll(getSkinnable().addon.getCategories().stream()
.map(category -> getSkinnable().page.getLocalizedCategory(category))
@@ -253,14 +253,6 @@ public class DownloadPage extends Control implements DecoratorPage {
descriptionPane.getChildren().add(openMcmodButton);
openMcmodButton.setMinWidth(Region.USE_PREF_SIZE);
runInFX(() -> FXUtils.installFastTooltip(openMcmodButton, i18n("mods.mcmod")));
// if (StringUtils.isNotBlank(getSkinnable().mod.getMcbbs())) {
// JFXHyperlink openMcbbsButton = new JFXHyperlink(i18n("mods.mcbbs"));
// openMcbbsButton.setExternalLink(ModManager.getMcbbsUrl(getSkinnable().mod.getMcbbs()));
// descriptionPane.getChildren().add(openMcbbsButton);
// openMcbbsButton.setMinWidth(Region.USE_PREF_SIZE);
// runInFX(() -> FXUtils.installFastTooltip(openMcbbsButton, i18n("mods.mcbbs")));
// }
}
JFXHyperlink openUrlButton = new JFXHyperlink(control.page.getLocalizedOfficialPage());
@@ -352,15 +344,21 @@ public class DownloadPage extends Control implements DecoratorPage {
container.setOnMouseClicked(e -> Controllers.navigate(new DownloadPage(page, addon, version, callback)));
getChildren().setAll(container);
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(page.repository.getType()).getModByCurseForgeId(addon.getSlug());
content.setTitle(mod != null && I18n.getCurrentLocale().getLocale() == Locale.CHINA ? mod.getDisplayName() : addon.getTitle());
content.setSubtitle(addon.getDescription());
content.getTags().setAll(addon.getCategories().stream()
.map(page::getLocalizedCategory)
.collect(Collectors.toList()));
if (addon != RemoteMod.BROKEN) {
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(page.repository.getType()).getModByCurseForgeId(addon.getSlug());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : addon.getTitle());
content.setSubtitle(addon.getDescription());
content.getTags().setAll(addon.getCategories().stream()
.map(page::getLocalizedCategory)
.collect(Collectors.toList()));
if (StringUtils.isNotBlank(addon.getIconUrl())) {
imageView.setImage(FXUtils.newRemoteImage(addon.getIconUrl(), 40, 40, true, true, true));
if (StringUtils.isNotBlank(addon.getIconUrl())) {
imageView.setImage(FXUtils.newRemoteImage(addon.getIconUrl(), 40, 40, true, true, true));
}
} else {
content.setTitle(i18n("mods.broken_dependency.title"));
content.setSubtitle(i18n("mods.broken_dependency.desc"));
imageView.setImage(FXUtils.newBuiltinImage("/assets/img/icon@8x.png", 40, 40, true, true));
}
}
}
@@ -35,12 +35,11 @@ import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.MINECRAFT;
import static org.jackhuang.hmcl.util.Lang.handleUncaught;
import static org.jackhuang.hmcl.util.Lang.threadPool;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class GameItem extends Control {
@@ -84,7 +83,7 @@ public class GameItem extends Control {
if (config == null) return;
tag.set(config.getVersion());
} catch (IOException | JsonParseException e) {
LOG.log(Level.WARNING, "Failed to read modpack configuration from " + version, e);
LOG.warning("Failed to read modpack configuration from " + version, e);
}
}, Platform::runLater)
.exceptionally(handleUncaught);
@@ -36,7 +36,6 @@ import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.ListPageBase;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.PageAware;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.TaskCancellationAction;
import org.jackhuang.hmcl.util.io.FileUtils;
@@ -45,10 +44,10 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObject> implements VersionPage.VersionLoadable, PageAware {
@@ -65,7 +64,7 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
try {
modManager.addMod(it.toPath());
} catch (IOException | IllegalArgumentException e) {
Logging.LOG.log(Level.WARNING, "Unable to parse mod file " + it, e);
LOG.warning("Unable to parse mod file " + it, e);
}
});
loadMods(modManager);
@@ -135,7 +134,7 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
modManager.addMod(file.toPath());
succeeded.add(file.getName());
} catch (Exception e) {
Logging.LOG.log(Level.WARNING, "Unable to add mod " + file, e);
LOG.warning("Unable to add mod " + file, e);
failed.add(file.getName());
// Actually addMod will not throw exceptions because FileChooser has already filtered files.
@@ -61,14 +61,13 @@ import java.nio.file.Path;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.ui.ToolbarListPageSkin.createToolbarButton2;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.StringUtils.isNotBlank;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -218,7 +217,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
Pattern pattern = Pattern.compile(queryString.substring("regex:".length()));
predicate = s -> pattern.matcher(s).find();
} catch (Throwable e) {
LOG.log(Level.WARNING, "Illegal regular expression", e);
LOG.warning("Illegal regular expression", e);
return;
}
} else {
@@ -391,15 +390,6 @@ class ModListPageSkin extends SkinBase<ModListPage> {
getActions().add(officialPageButton);
}
// if (modInfo.getMod() != null && StringUtils.isNotBlank(modInfo.getMod().getMcbbs())) {
// JFXHyperlink mcbbsButton = new JFXHyperlink(i18n("mods.mcbbs"));
// mcbbsButton.setOnAction(e -> {
// fireEvent(new DialogCloseEvent());
// FXUtils.openLink(ModManager.getMcbbsUrl(modInfo.getMod().getMcbbs()));
// });
// getActions().add(mcbbsButton);
// }
if (modInfo.getMod() == null || StringUtils.isBlank(modInfo.getMod().getMcmod())) {
JFXHyperlink searchButton = new JFXHyperlink(i18n("mods.mcmod.search"));
searchButton.setOnAction(e -> {
@@ -490,10 +480,8 @@ class ModListPageSkin extends SkinBase<ModListPage> {
content.getTags().add(i18n("install.installer.quilt"));
break;
}
if (dataItem.getMod() != null) {
if (I18n.getCurrentLocale().getLocale() == Locale.CHINA) {
content.getTags().add(dataItem.getMod().getDisplayName());
}
if (dataItem.getMod() != null && I18n.isUseChinese()) {
content.getTags().add(dataItem.getMod().getDisplayName());
}
content.setSubtitle(dataItem.getSubtitle());
if (booleanProperty != null) {
@@ -24,10 +24,9 @@ import org.jackhuang.hmcl.util.io.IOUtils;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
/**
@@ -127,7 +126,7 @@ public enum ModTranslations {
mods = Arrays.stream(modData.split("\n")).filter(line -> !line.startsWith("#")).map(Mod::new).collect(Collectors.toList());
return true;
} catch (Exception e) {
LOG.log(Level.WARNING, "Failed to load " + resourceName, e);
LOG.warning("Failed to load " + resourceName, e);
return false;
}
}
@@ -198,10 +197,9 @@ public enum ModTranslations {
return true;
}
public static class Mod {
public static final class Mod {
private final String curseforge;
private final String mcmod;
private final String mcbbs;
private final List<String> modIds;
private final String name;
private final String subname;
@@ -209,23 +207,21 @@ public enum ModTranslations {
public Mod(String line) {
String[] items = line.split(";", -1);
if (items.length != 7) {
throw new IllegalArgumentException("Illegal mod data line, 7 items expected " + line);
if (items.length != 6) {
throw new IllegalArgumentException("Illegal mod data line, 6 items expected " + line);
}
curseforge = items[0];
mcmod = items[1];
mcbbs = items[2];
modIds = Collections.unmodifiableList(Arrays.asList(items[3].split(",")));
name = items[4];
subname = items[5];
abbr = items[6];
modIds = Collections.unmodifiableList(Arrays.asList(items[2].split(",")));
name = items[3];
subname = items[4];
abbr = items[5];
}
public Mod(String curseforge, String mcmod, String mcbbs, List<String> modIds, String name, String subname, String abbr) {
public Mod(String curseforge, String mcmod, List<String> modIds, String name, String subname, String abbr) {
this.curseforge = curseforge;
this.mcmod = mcmod;
this.mcbbs = mcbbs;
this.modIds = modIds;
this.name = name;
this.subname = subname;
@@ -252,10 +248,6 @@ public enum ModTranslations {
return mcmod;
}
public String getMcbbs() {
return mcbbs;
}
public List<String> getModIds() {
return modIds;
}
@@ -21,7 +21,11 @@ import org.jackhuang.hmcl.game.LocalizedRemoteModRepository;
import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository;
import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository;
import org.jackhuang.hmcl.util.i18n.I18n;
import java.util.MissingResourceException;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class ResourcePackDownloadListPage extends DownloadListPage {
@@ -66,10 +70,18 @@ public class ResourcePackDownloadListPage extends DownloadListPage {
@Override
protected String getLocalizedCategory(String category) {
String key;
if ("mods.modrinth".equals(downloadSource.get())) {
return i18n("modrinth.category." + category);
key = "modrinth.category." + category;
} else {
return i18n("curse.category." + category);
key = "curse.category." + category;
}
try {
return I18n.getResourceBundle().getString(key);
} catch (MissingResourceException e) {
LOG.warning("Cannot find key " + key + " in resource bundle", e);
return category;
}
}
@@ -31,13 +31,11 @@ import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.DialogPane;
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class VersionIconDialog extends DialogPane {
@@ -74,20 +72,19 @@ public class VersionIconDialog extends DialogPane {
private void exploreIcon() {
FileChooser chooser = new FileChooser();
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("extension.png"), "*.png"));
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("extension.png"), "*.png", "*.jpg", "*.bmp", "*.gif"));
File selectedFile = chooser.showOpenDialog(Controllers.getStage());
if (selectedFile != null) {
File iconFile = profile.getRepository().getVersionIconFile(versionId);
try {
FileUtils.copyFile(selectedFile, iconFile);
profile.getRepository().setVersionIconFile(versionId, selectedFile);
if (vs != null) {
vs.setVersionIcon(VersionIconType.DEFAULT);
}
onAccept();
} catch (IOException e) {
Logging.LOG.log(Level.SEVERE, "Failed to copy icon file from " + selectedFile + " to " + iconFile, e);
} catch (IOException | IllegalArgumentException e) {
LOG.error("Failed to set icon file: " + selectedFile, e);
}
}
}
@@ -48,7 +48,6 @@ import org.jackhuang.hmcl.util.platform.JavaVersion;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -642,9 +641,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
if (versionId == null)
return;
File iconFile = profile.getRepository().getVersionIconFile(versionId);
if (iconFile.exists())
iconFile.delete();
profile.getRepository().deleteIconFile(versionId);
VersionSetting localVersionSetting = profile.getRepository().getLocalVersionSettingOrCreate(versionId);
if (localVersionSetting != null) {
localVersionSetting.setVersionIcon(VersionIconType.DEFAULT);
@@ -41,7 +41,6 @@ import org.jackhuang.hmcl.ui.construct.PromptDialogPane;
import org.jackhuang.hmcl.ui.construct.Validator;
import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider;
import org.jackhuang.hmcl.ui.export.ExportWizardProvider;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.TaskCancellationAction;
import org.jackhuang.hmcl.util.io.FileUtils;
@@ -55,8 +54,8 @@ import java.nio.file.Path;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class Versions {
@@ -84,7 +83,7 @@ public final class Versions {
} catch (IOException e) {
Controllers.dialog(
i18n("install.failed.downloading.detail", file.getFile().getUrl()) + "\n" + StringUtils.getStackTrace(e),
i18n("download.failed"), MessageDialogPane.MessageType.ERROR);
i18n("download.failed.no_code", file.getFile().getUrl()), MessageDialogPane.MessageType.ERROR);
return;
}
Controllers.taskDialog(
@@ -97,7 +96,7 @@ public final class Versions {
} else {
Controllers.dialog(
i18n("install.failed.downloading.detail", file.getFile().getUrl()) + "\n" + StringUtils.getStackTrace(e),
i18n("download.failed"), MessageDialogPane.MessageType.ERROR);
i18n("download.failed.no_code", file.getFile().getUrl()), MessageDialogPane.MessageType.ERROR);
}
}).executor(true),
i18n("message.downloading"),
@@ -184,7 +183,7 @@ public final class Versions {
try {
profile.getRepository().clean(id);
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Unable to clean game directory", e);
LOG.warning("Unable to clean game directory", e);
}
}
@@ -27,9 +27,8 @@ import java.text.DecimalFormat;
import java.time.Instant;
import java.util.Arrays;
import java.util.Locale;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.formatDateTime;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -421,7 +420,7 @@ public final class WorldInfoPage extends StackPane implements DecoratorPage {
try {
this.world.writeLevelDat(levelDat);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to save level.dat of world " + world.getWorldName(), e);
LOG.warning("Failed to save level.dat of world " + world.getWorldName(), e);
}
}
@@ -28,7 +28,6 @@ import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.*;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
@@ -39,10 +38,10 @@ import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class WorldListPage extends ListPageBase<WorldListItem> implements VersionPage.VersionLoadable {
@@ -139,7 +138,7 @@ public class WorldListPage extends ListPageBase<WorldListItem> implements Versio
}).start();
}, world.getWorldName());
}, e -> {
Logging.LOG.log(Level.WARNING, "Unable to parse world file " + zipFile, e);
LOG.warning("Unable to parse world file " + zipFile, e);
Controllers.dialog(i18n("world.import.invalid"));
}).start();
}
@@ -19,10 +19,11 @@ package org.jackhuang.hmcl.ui.wizard;
import javafx.scene.Node;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.Logging;
import java.util.*;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class WizardController implements Navigation {
private final WizardDisplayer displayer;
private WizardProvider provider = null;
@@ -71,7 +72,7 @@ public class WizardController implements Navigation {
displayer.onStart();
Logging.LOG.info("Navigating to " + page + ", pages: " + pages);
LOG.info("Navigating to " + page + ", pages: " + pages);
displayer.navigateTo(page, NavigationDirection.START);
}
@@ -90,7 +91,7 @@ public class WizardController implements Navigation {
if (page instanceof WizardPage)
((WizardPage) page).onNavigate(settings);
Logging.LOG.info("Navigating to " + page + ", pages: " + pages);
LOG.info("Navigating to " + page + ", pages: " + pages);
displayer.navigateTo(page, NavigationDirection.NEXT);
}
@@ -113,7 +114,7 @@ public class WizardController implements Navigation {
if (prevPage instanceof WizardPage)
((WizardPage) prevPage).onNavigate(settings);
Logging.LOG.info("Navigating to " + prevPage + ", pages: " + pages);
LOG.info("Navigating to " + prevPage + ", pages: " + pages);
displayer.navigateTo(prevPage, NavigationDirection.PREVIOUS);
}
@@ -31,12 +31,11 @@ import java.security.spec.X509EncodedKeySpec;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/**
* A class that checks the integrity of HMCL.
@@ -132,7 +131,7 @@ public final class IntegrityChecker {
LOG.info("Successfully verified current JAR");
selfVerified = true;
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to verify myself, is the JAR corrupt?", e);
LOG.warning("Failed to verify myself, is the JAR corrupt?", e);
selfVerified = false;
}
@@ -27,11 +27,10 @@ import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.io.IOException;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
public final class UpdateChecker {
@@ -112,7 +111,7 @@ public final class UpdateChecker {
result = checkUpdate(channel);
LOG.info("Latest version (" + channel + ") is " + result);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to check for update", e);
LOG.warning("Failed to check for update", e);
}
RemoteVersion finalResult = result;
@@ -42,13 +42,12 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.jackhuang.hmcl.ui.FXUtils.checkFxUserThread;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class UpdateHandler {
@@ -66,7 +65,7 @@ public final class UpdateHandler {
try {
performMigration();
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to perform migration", e);
LOG.warning("Failed to perform migration", e);
SwingUtils.showErrorDialog(i18n("fatal.apply_update_failure", Metadata.PUBLISH_URL) + "\n" + StringUtils.getStackTrace(e));
}
return true;
@@ -81,7 +80,7 @@ public final class UpdateHandler {
try {
applyUpdate(Paths.get(args[1]));
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to apply update", e);
LOG.warning("Failed to apply update", e);
SwingUtils.showErrorDialog(i18n("fatal.apply_update_failure", Metadata.PUBLISH_URL) + "\n" + StringUtils.getStackTrace(e));
}
return true;
@@ -108,7 +107,7 @@ public final class UpdateHandler {
try {
downloaded = Files.createTempFile("hmcl-update-", ".jar");
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to create temp file", e);
LOG.warning("Failed to create temp file", e);
return;
}
@@ -127,15 +126,15 @@ public final class UpdateHandler {
}
requestUpdate(downloaded, getCurrentLocation());
System.exit(0);
Main.exit(0);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to update to " + version, e);
LOG.warning("Failed to update to " + version, e);
Platform.runLater(() -> Controllers.dialog(StringUtils.getStackTrace(e), i18n("update.failed"), MessageType.ERROR));
}
} else {
Exception e = executor.getException();
LOG.log(Level.WARNING, "Failed to update to " + version, e);
LOG.warning("Failed to update to " + version, e);
if (e instanceof CancellationException) {
Platform.runLater(() -> Controllers.showToast(i18n("message.cancelled")));
} else {
@@ -162,7 +161,7 @@ public final class UpdateHandler {
Files.move(target, newFilename.get());
target = newFilename.get();
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to move target", e);
LOG.warning("Failed to move target", e);
}
}
@@ -273,7 +272,7 @@ public final class UpdateHandler {
LOG.info("Successfully broke the force update feature");
}
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to break the force update feature", e);
LOG.warning("Failed to break the force update feature", e);
} catch (JsonParseException e) {
hmclVersionJson.toFile().delete();
}
@@ -29,9 +29,8 @@ import org.jackhuang.hmcl.util.io.NetworkUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -67,14 +66,14 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler {
if (s.contains(entry.getKey())) {
if (StringUtils.isNotBlank(entry.getValue())) {
String info = entry.getValue();
LOG.severe(info);
LOG.error(info);
try {
Alert alert = new Alert(AlertType.INFORMATION, info);
alert.setTitle(i18n("message.info"));
alert.setHeaderText(i18n("message.info"));
alert.showAndWait();
} catch (Throwable t) {
LOG.log(Level.SEVERE, "Unable to show message", t);
LOG.error("Unable to show message", t);
}
}
return false;
@@ -90,14 +89,14 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOG.log(Level.SEVERE, "Uncaught exception in thread " + t.getName(), e);
LOG.error("Uncaught exception in thread " + t.getName(), e);
try {
CrashReport report = new CrashReport(t, e);
if (!report.shouldBeReport())
return;
LOG.log(Level.SEVERE, report.getDisplayText());
LOG.error(report.getDisplayText());
Platform.runLater(() -> {
if (checkThrowable(e)) {
if (showCrashWindow) {
@@ -109,8 +108,10 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler {
}
});
} catch (Throwable handlingException) {
LOG.log(Level.SEVERE, "Unable to handle uncaught exception", handlingException);
LOG.error("Unable to handle uncaught exception", handlingException);
}
LOG.shutdown();
}
private void reportToServer(CrashReport crashReport) {
@@ -118,13 +119,13 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler {
HashMap<String, String> map = new HashMap<>();
map.put("crash_report", crashReport.getDisplayText());
map.put("version", Metadata.VERSION);
map.put("log", Logging.getLogs());
map.put("log", LOG.getLogs());
try {
String response = NetworkUtils.doPost(NetworkUtils.toURL("https://hmcl.huangyuhui.net/hmcl/crash.php"), map);
if (StringUtils.isNotBlank(response))
LOG.log(Level.SEVERE, "Crash server response: " + response);
LOG.error("Crash server response: " + response);
} catch (IOException ex) {
LOG.log(Level.SEVERE, "Unable to post HMCL server.", ex);
LOG.error("Unable to post HMCL server.", ex);
}
});
t.setDaemon(true);
@@ -20,7 +20,7 @@ package org.jackhuang.hmcl.util;
import java.nio.file.Path;
import java.util.Set;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/**
* Utility for Adding JavaFX to module path.
@@ -15,10 +15,9 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public final class NativePatcher {
private NativePatcher() {
@@ -37,7 +36,7 @@ public final class NativePatcher {
return natives.getOrDefault(p.toString(), Collections.emptyMap());
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to load native library list", e);
LOG.warning("Failed to load native library list", e);
return Collections.emptyMap();
}
});
@@ -43,6 +43,7 @@ package org.jackhuang.hmcl.util;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.Main;
import org.jackhuang.hmcl.ui.SwingUtils;
import org.jackhuang.hmcl.util.io.ChecksumMismatchException;
import org.jackhuang.hmcl.util.io.IOUtils;
@@ -62,12 +63,11 @@ import java.util.List;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toSet;
import static org.jackhuang.hmcl.Metadata.HMCL_DIRECTORY;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.platform.JavaVersion.CURRENT_JAVA;
@@ -121,7 +121,7 @@ public final class SelfDependencyPatcher {
Class.forName("netscape.javascript.JSObject", false, classLoader);
Class.forName("org.w3c.dom.html.HTMLDocument", false, classLoader);
} catch (Throwable e) {
LOG.log(Level.WARNING, "Disable javafx.web because JRE is incomplete", e);
LOG.warning("Disable javafx.web because JRE is incomplete", e);
dependencies.removeIf(it -> "javafx.web".equals(it.module) || "javafx.media".equals(it.module));
}
@@ -250,7 +250,7 @@ public final class SelfDependencyPatcher {
}
} else {
LOG.info("User choose not to download JavaFX");
System.exit(0);
Main.exit(0);
}
throw new AssertionError();
}
@@ -20,13 +20,11 @@ package org.jackhuang.hmcl.util.i18n;
import org.jackhuang.hmcl.util.i18n.Locales.SupportedLocale;
import java.time.Instant;
import java.util.Arrays;
import java.util.IllegalFormatException;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public final class I18n {
@@ -34,26 +32,34 @@ public final class I18n {
}
private static volatile SupportedLocale locale = Locales.DEFAULT;
private static volatile ResourceBundle resourceBundle = locale.getResourceBundle();
private static volatile DateTimeFormatter dateTimeFormatter;
public static void setLocale(SupportedLocale locale) {
I18n.locale = locale;
resourceBundle = locale.getResourceBundle();
dateTimeFormatter = null;
}
public static SupportedLocale getCurrentLocale() {
return locale;
public static boolean isUseChinese() {
return locale.getLocale() == Locale.CHINA;
}
public static ResourceBundle getResourceBundle() {
return getCurrentLocale().getResourceBundle();
return resourceBundle;
}
public static String getName(SupportedLocale locale) {
return locale == Locales.DEFAULT ? resourceBundle.getString("lang.default") : locale.getResourceBundle().getString("lang");
}
public static String i18n(String key, Object... formatArgs) {
try {
return String.format(getResourceBundle().getString(key), formatArgs);
} catch (MissingResourceException e) {
LOG.log(Level.SEVERE, "Cannot find key " + key + " in resource bundle", e);
LOG.error("Cannot find key " + key + " in resource bundle", e);
} catch (IllegalFormatException e) {
LOG.log(Level.SEVERE, "Illegal format string, key=" + key + ", args=" + Arrays.toString(formatArgs), e);
LOG.error("Illegal format string, key=" + key + ", args=" + Arrays.toString(formatArgs), e);
}
return key + Arrays.toString(formatArgs);
@@ -63,13 +69,18 @@ public final class I18n {
try {
return getResourceBundle().getString(key);
} catch (MissingResourceException e) {
LOG.log(Level.SEVERE, "Cannot find key " + key + " in resource bundle", e);
LOG.error("Cannot find key " + key + " in resource bundle", e);
return key;
}
}
public static String formatDateTime(Instant instant) {
return getCurrentLocale().getDateTimeFormatter().format(instant);
DateTimeFormatter formatter = dateTimeFormatter;
if (formatter == null) {
formatter = dateTimeFormatter = DateTimeFormatter.ofPattern(getResourceBundle().getString("world.time")).withZone(ZoneId.systemDefault());
}
return formatter.format(instant);
}
public static boolean hasKey(String key) {
@@ -24,8 +24,6 @@ import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.platform.JavaVersion;
import java.io.IOException;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
@@ -34,7 +32,7 @@ public final class Locales {
private Locales() {
}
public static final SupportedLocale DEFAULT = new SupportedLocale(Locale.getDefault(), "lang.default");
public static final SupportedLocale DEFAULT = new SupportedLocale(Locale.getDefault());
/**
* English
@@ -102,23 +100,10 @@ public final class Locales {
@JsonAdapter(SupportedLocale.TypeAdapter.class)
public static final class SupportedLocale {
private final Locale locale;
private final String name;
private final ResourceBundle resourceBundle;
private DateTimeFormatter dateTimeFormatter;
private ResourceBundle resourceBundle;
SupportedLocale(Locale locale) {
this(locale, null);
}
SupportedLocale(Locale locale, String name) {
this.locale = locale;
this.name = name;
if (JavaVersion.CURRENT_JAVA.getParsedVersion() == JavaVersion.JAVA_8) {
resourceBundle = ResourceBundle.getBundle("assets.lang.I18N", locale, UTF8Control.INSTANCE);
} else {
// UTF-8 is supported in Java 9+
resourceBundle = ResourceBundle.getBundle("assets.lang.I18N", locale);
}
}
public Locale getLocale() {
@@ -126,20 +111,22 @@ public final class Locales {
}
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
ResourceBundle bundle = resourceBundle;
public DateTimeFormatter getDateTimeFormatter() {
if (dateTimeFormatter == null) {
dateTimeFormatter = DateTimeFormatter.ofPattern(resourceBundle.getString("world.time")).withZone(ZoneId.systemDefault());
if (resourceBundle == null) {
if (this != DEFAULT && this.locale == DEFAULT.locale) {
bundle = DEFAULT.getResourceBundle();
} else if (JavaVersion.CURRENT_JAVA.getParsedVersion() < 9) {
bundle = ResourceBundle.getBundle("assets.lang.I18N", locale, UTF8Control.INSTANCE);
} else {
// Java 9+ uses UTF-8 as the default encoding for resource bundles
bundle = ResourceBundle.getBundle("assets.lang.I18N", locale);
}
resourceBundle = bundle;
}
return dateTimeFormatter;
}
public String getName(ResourceBundle newResourceBundle) {
if (name == null) return resourceBundle.getString("lang");
else return newResourceBundle.getString(name);
return bundle;
}
public static final class TypeAdapter extends com.google.gson.TypeAdapter<SupportedLocale> {
@@ -0,0 +1,23 @@
package org.jackhuang.hmcl.util.logging;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* @author Glavo
*/
final class CallerFinder {
private static final StackWalker WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
private static final String PACKAGE_PREFIX = CallerFinder.class.getPackageName() + ".";
private static final Predicate<StackWalker.StackFrame> PREDICATE = stackFrame -> !stackFrame.getClassName().startsWith(PACKAGE_PREFIX);
private static final Function<Stream<StackWalker.StackFrame>, Optional<StackWalker.StackFrame>> FUNCTION = stream -> stream.filter(PREDICATE).findFirst();
static String getCaller() {
return WALKER.walk(FUNCTION).map(it -> it.getClassName() + "." + it.getMethodName()).orElse(null);
}
private CallerFinder() {
}
}
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 947 B

@@ -38,7 +38,7 @@ about.thanks_to.glavo.statement=Responsible for maintaining HMCL.
about.thanks_to.zekerzhayard.statement=Contribute a lot of technical support to HMCL.
about.thanks_to.zkitefly.statement=Responsible for maintaining documentation of HMCL.
about.thanks_to.mcbbs=MCBBS (Minecraft Chinese Forum)
about.thanks_to.mcbbs.statement=For providing mcbbs.net download mirror for Mainland China users.
about.thanks_to.mcbbs.statement=or providing mcbbs.net download mirror for Mainland China users.
about.thanks_to.mcmod=mcmod.cn
about.thanks_to.mcmod.statement=For providing Chinese translations and wiki for various mods.
about.thanks_to.red_lnn.statement=For providing the default background image.
@@ -143,8 +143,8 @@ account.portable=Portable Account
account.skin=Skin
account.skin.file=Skin File
account.skin.model=Model
account.skin.model.default=Classic (Steve)
account.skin.model.slim=Slim (Alex)
account.skin.model.default=Classic
account.skin.model.slim=Slim
account.skin.type.csl_api=Blessing Skin
account.skin.type.csl_api.location=Address
account.skin.type.csl_api.location.hint=CustomSkinAPI URL
@@ -325,9 +325,9 @@ download.existing=The file cannot be saved because it already exists. You can us
download.external_link=Open Download Website
download.failed=Failed to download %1$s, response code: %2$d
download.failed.empty=No versions are available, please click here to go back.
download.failed.no_code=Failed to download %s
download.failed.refresh=Unable to fetch version list. Please click here to retry.
download.game=Game
download.provider.mcbbs=MCBBS (https://www.mcbbs.net/)
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=Mojang (OptiFine is provided by BMCLAPI)
download.provider.official=From Official Sources
@@ -478,6 +478,7 @@ If your computer has a discrete graphics card, you need to check whether the gam
If you are using your integrated graphics card, please notice that Minecraft 1.16.5 or older requires <a href="https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html">Java 1.8.0_51 or older</a> for Intel(R) Core(TM) 3000 processor series or earlier.\n\
\n\
Turning on the "Use OpenGL software renderer" option in the instance settings can also solve this problem, but when this option is turned on, the frame rate will be significantly reduced in the case of insufficient CPU performance. So it is only recommended to turn it on for debugging purposes or in case of emergency.
game.crash.reason.macos_failed_to_find_service_port_for_display=The current game cannot continue due to a failure to initialize the OpenGL window on the Apple silicon platform.\nFor this issue, HMCL does not have direct solutions at the moment. Please try opening any browser and going fullscreen, then return to HMCL, launch the game, and <b>quickly return to the browser page</b> before the game window pops up, wait for the game window to appear, and then switch back to the game window.
game.crash.reason.illegal_access_error=The game crashed because of some mod(s).\n\
\n\
If you know: %1$s, you can update or delete the mod(s) and then try again.
@@ -827,26 +828,39 @@ Keep in mind that you are not allowed to add mods and resource packs that are ex
modpack.wizard.step.initialization.server=Click here for more tutorials for making a server modpack that can be automatically updated.
modrinth.category.adventure=Adventure
modrinth.category.audio=Audio
modrinth.category.blocks=Blocks
modrinth.category.bukkit=Bukkit
modrinth.category.bungeecord=BungeeCord
modrinth.category.challenging=Challenging
modrinth.category.core-shaders=Core Shaders
modrinth.category.combat=Combat
modrinth.category.cursed=Cursed
modrinth.category.decoration=Decoration
modrinth.category.economy=Economy
modrinth.category.entities=Entities
modrinth.category.environment=Environment
modrinth.category.equipment=Equipment
modrinth.category.fabric=Fabric
modrinth.category.fonts=Fonts
modrinth.category.food=Food
modrinth.category.forge=Forge
modrinth.category.game-mechanics=Game Mechanics
modrinth.category.gui=GUI
modrinth.category.items=Items
modrinth.category.kitchen-sink=Kitchen-Sink
modrinth.category.library=Library
modrinth.category.lightweight=Lightweight
modrinth.category.liteloader=LiteLoader
modrinth.category.locale=Locale
modrinth.category.magic=Magic
modrinth.category.management=Management
modrinth.category.minecraft=Minecraft
modrinth.category.minigame=Minigame
modrinth.category.misc=Misc
modrinth.category.mobs=Mobs
modrinth.category.modded=Modded
modrinth.category.models=Models
modrinth.category.modloader=Modloader
modrinth.category.multiplayer=Multiplayer
modrinth.category.neoforge=NeoForge
@@ -855,19 +869,32 @@ modrinth.category.paper=Paper
modrinth.category.purpur=Purpur
modrinth.category.quests=Quests
modrinth.category.quilt=Quilt
modrinth.category.realistic=Realistic
modrinth.category.rift=Rift
modrinth.category.simplistic=Simplistic
modrinth.category.social=Social
modrinth.category.spigot=Spigot
modrinth.category.sponge=Sponge
modrinth.category.storage=Storage
modrinth.category.technology=Technology
modrinth.category.themed=Themed
modrinth.category.transportation=Transportation
modrinth.category.tweaks=Tweaks
modrinth.category.utility=Utility
modrinth.category.vanilla-like=Vanilla-like
modrinth.category.velocity=Velocity
modrinth.category.waterfall=Waterfall
modrinth.category.worldgen=Worldgen
modrinth.category.datapack=Datapack
modrinth.category.folia=Folia
modrinth.category.8x-=8x-
modrinth.category.16x=16x
modrinth.category.32x=32x
modrinth.category.48x=48x
modrinth.category.64x=64x
modrinth.category.128x=128x
modrinth.category.256x=256x
modrinth.category.512x+=512x+
mods=Mods
mods.add=Add Mods
@@ -36,8 +36,6 @@ about.thanks_to.gamerteam.statement=Por proporcionar la imagen de fondo por defe
about.thanks_to.glavo.statement=Aportar mucho apoyo técnico a HMCL.
about.thanks_to.zekerzhayard.statement=Aportar mucho apoyo técnico a HMCL.
about.thanks_to.zkitefly.statement=Aportar mucho apoyo técnico a HMCL.
about.thanks_to.mcbbs=MCBBS (Foro chino de Minecraft)
about.thanks_to.mcbbs.statement=Por proporcionar un espejo de descarga de mcbbs.net para los usuarios de China continental.
about.thanks_to.mcmod=mcmod.cn
about.thanks_to.mcmod.statement=Por facilitar las traducciones al chino y el wiki de varios mods.
about.thanks_to.red_lnn.statement=Por proporcionar la imagen de fondo por defecto.
@@ -125,8 +123,8 @@ account.password=Contraseña
account.skin=Skin
account.skin.file=Archivo de skin
account.skin.model=Modelo
account.skin.model.default=Clásico (Steve)
account.skin.model.slim=Delgado (Alex)
account.skin.model.default=Clásico
account.skin.model.slim=Delgado
account.skin.type.csl_api=Blessing skin
account.skin.type.csl_api.location=URL
account.skin.type.csl_api.location.hint=CustomSkinAPI URL
@@ -304,7 +302,6 @@ download.failed=Falló la descarga de %1$s, código de respuesta: %2$d
download.failed.empty=No hay versiones disponibles, por favor haga clic aquí para volver.
download.failed.refresh=No se ha podido obtener la lista de versiones. Por favor, haga clic aquí para volver a intentarlo.
download.game=Juego
download.provider.mcbbs=MCBBS (https://www.mcbbs.net/)
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=Mojang (OptiFine es proporcionado por BMCLAPI)
download.provider.official=De fuentes oficiales
@@ -416,6 +413,7 @@ Por favor, inténtelo de nuevo después de actualizar su controlador gráfico a
Si tu ordenador tiene una tarjeta gráfica discreta, tienes que comprobar si el juego utiliza gráficos integrados/núcleo. Si es así, inicie el launcher utilizando su tarjeta gráfica discreta. Si el problema persiste, probablemente debería considerar la posibilidad de adquirir una nueva tarjeta gráfica o un nuevo ordenador.\n\
\n\
Si utiliza su tarjeta gráfica integrada, tenga en cuenta que Minecraft 1.16.5 o anterior requiere <a href="https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html">Java 1.8.0_51 o más antiguo</a> para la serie de procesadores Intel(R) Core(TM) 3000 o anteriores.
game.crash.reason.macos_failed_to_find_service_port_for_display=El juego actual no puede continuar debido a un fallo al inicializar la ventana de OpenGL en la plataforma de Apple silicon.\nPara este problema, HMCL no tiene soluciones directas por el momento. Intente abrir cualquier navegador y ponerlo en pantalla completa, luego vuelva a HMCL, inicie el juego y <b>vuelva rápidamente a la página del navegador</b> antes de que aparezca la ventana del juego, espere a que aparezca la ventana del juego y luego vuelva a la ventana del juego.
game.crash.reason.illegal_access_error=El juego se bloquea por culpa de algún(os) mod(s).\n\
\n\
Si sabes: %1$s, puedes actualizar o eliminar los mods y volver a intentarlo.
@@ -34,8 +34,6 @@ about.thanks_to.gamerteam.statement=デフォルトの背景画像プロバイ
about.thanks_to.glavo.statement=HMCLに多くのテクニカルサポートを提供
about.thanks_to.zekerzhayard.statement=HMCLに多くのテクニカルサポートを提供
about.thanks_to.zkitefly.statement=HMCLに多くのテクニカルサポートを提供。
about.thanks_to.mcbbs=MCBBS
about.thanks_to.mcbbs.statement=MCBBSダウンロードソースプロバイダー。
about.thanks_to.mcmod=mcmod.cn
about.thanks_to.mcmod.statement=Mod中国語の名前翻訳プロバイダー。
about.thanks_to.red_lnn.statement=デフォルトの背景画像プロバイダー。
@@ -112,8 +110,8 @@ account.password=パスワード
account.skin=スキン
account.skin.file=スキンイメージファイル
account.skin.model=モデル
account.skin.model.default=Classic (Steve)
account.skin.model.slim=Slim (Alex)
account.skin.model.default=Classic
account.skin.model.slim=Slim
account.skin.type.csl_api=Blessing Skin
account.skin.type.csl_api.location=アドレス
account.skin.type.csl_api.location.hint=CustomSkinAPI
@@ -286,7 +284,6 @@ download.failed=%1$s のダウンロードに失敗しました、応答コー
download.failed.empty=候補者なし。戻るにはここをクリックしてください。
download.failed.refresh=バージョンリストをダウンロードできません。ここをクリックして再試行してください。
download.game=ゲームのダウンロード
download.provider.mcbbs=MCBBS(https://www.mcbbs.net/)
download.provider.bmclapi=BMCLAPI(ミラーソース)
download.provider.mojang=Mojang(OptiFineはBMCLAPIにより提供されます) 推奨
download.provider.official=公式ソースからロード
@@ -370,6 +367,7 @@ game.crash.reason.graphics_driver=現在、お使いのグラフィックカー
ゲームを起動する前に、グラフィックカードのドライバーを最新バージョンにアップグレードしてみてください。\n\
ディスクリートグラフィックカードを搭載している場合、統合型/コアグラフィックカードを使用してゲームが起動するかどうかを確認する必要があります。その場合、ディスクリートグラフィックカードを使用したゲームでHMCLを起動してみてください。それでも問題がある場合は、新しいグラフィックカードや新しいコンピュータの購入を検討する必要があるかもしれません。\n\
コアグラフィックカードが必要な場合は、お使いのパソコンのCPUがIntel(R) Core(TM) 3000シリーズ以上であることをご確認ください。その場合、Minecraft 1.16.5以前の場合は、ゲームに使用しているJavaバージョンを1.8.0_51以下にダウングレードするか、ディスクリートグラフィックカードを交換するか、または、新しい コンピュータを使用します。
game.crash.reason.macos_failed_to_find_service_port_for_display=現在のゲームは、Apple silicon プラットフォームでの OpenGL ウィンドウの初期化に失敗したため、続行できません。\nこの問題に対して、HMCL には直接的な解決策がありません。ブラウザを任意に開いてフルスクリーンにし、その後 HMCL に戻り、ゲームを起動し、ゲームウィンドウが表示される前<b>に素早くブラウザのページに戻ってください</b>。ゲームウィンドウが表示されたらゲームウィンドウに戻ってください。
game.crash.reason.illegal_access_error=一部のmodが原因でゲームがクラッシュしました。\n認識している場合:%1$s、modを更新または削除して、再試行してください。
game.crash.reason.install_mixinbootstrap=MixinBootstrapが見つからないため、現在のゲームを続行できません。\n<a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a>をインストールしてみてください。インストール後にクラッシュする場合は、モジュールのファイル名の前に英語の「! をモジュールのファイル名の前につけてみてください。
game.crash.reason.jdk_9=Javaのバージョンが高すぎるため、ゲームを実行できません。\nJava 8をダウンロードしてインストールし、ゲーム設定で新しくインストールしたJavaを選択する必要があります。
@@ -36,8 +36,6 @@ about.thanks_to.gamerteam.statement=За предоставление фонов
about.thanks_to.glavo.statement=Оказал большую техническую поддержку HMCL.
about.thanks_to.zekerzhayard.statement=Оказал большую техническую поддержку HMCL.
about.thanks_to.zkitefly.statement=Оказал большую техническую поддержку HMCL.
about.thanks_to.mcbbs=MCBBS (Minecraft Chinese Forum)
about.thanks_to.mcbbs.statement=За предоставление зеркала скачивания MCBBS.NET для пользователей Китая.
about.thanks_to.mcmod=mcmod.cn
about.thanks_to.mcmod.statement=За предоставление перевода на китайский и вики для различных модов.
about.thanks_to.red_lnn.statement=За предоставление фонового изображения.
@@ -120,8 +118,8 @@ account.password=Пароль
account.skin=Скин
account.skin.file=Файл скина
account.skin.model=Модель
account.skin.model.default=Классическая (Стив)
account.skin.model.slim=Стройная (Алекс)
account.skin.model.default=Классическая
account.skin.model.slim=Стройная
account.skin.type.csl_api=Blessing Skin
account.skin.type.csl_api.location=Адрес
account.skin.type.csl_api.location.hint=URL-адрес CustomSkinAPI
@@ -303,7 +301,6 @@ download.failed=Не удаётся скачать %1$s, код ответа\: %
download.failed.empty=Версий нет. Нажмите здесь, чтобы вернуться назад.
download.failed.refresh=Не удаётся получить список версий. Нажмите здесь, чтобы повторить попытку.
download.game=Игра
download.provider.mcbbs=MCBBS (https://www.mcbbs.net/)
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=Mojang (OptiFine is provided by BMCLAPI)
download.provider.official=Из официальных источников
@@ -389,6 +386,7 @@ game.crash.reason.graphics_driver=Игра вылетела из-за пробл
Обновите графический драйвер до последней версии.\n\
Если в вашем компьютере установлена дискретная видеокарта, необходимо проверить, использует ли игра интегрированную/ядер графику. Если это так, запустите HMCL и игру с использованием дискретной видеокарты. Если у вас по-прежнему возникают подобные проблемы, вы можете подумать о приобретении новой видеокарты или нового компьютера.\n\
Если же вы хотите продолжать использовать графическое ядро, проверьте, используете ли вы процессор Intel(R) Core(TM) 3000 series или более старый. Если это так, то для Minecraft 1.16.5 или более старой версии вам необходимо понизить версию Java до 1.8.0_51 или более старой версии, либо приобрести специальную видеокарту или новый компьютер.
game.crash.reason.macos_failed_to_find_service_port_for_display=Текущая игра не может быть запущена из-за сбоя инициализации OpenGL окна на платформе Apple silicon.\nДля этой проблемы у HMCL временно нет прямых решений. Попробуйте открыть любой браузер и перейти в полноэкранный режим, затем вернуться в HMCL, запустить игру и <b>быстро вернуться на страницу браузера</b> перед появлением игрового окна, дождаться появления игрового окна, а затем вернуться в игровое окно.
game.crash.reason.illegal_access_error=Игра вылетела из-за некоторых модов.\nЕсли вы узнаёте: %1$s, вы можете обновить или удалить мод и повторить попытку.
game.crash.reason.install_mixinbootstrap=Текущая игра не может быть запущена из-за отсутствия MixinBootstrap. \nДля решения проблемы вы можете попробовать установить <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a>. Если после установки произошел сбой, попробуйте добавить английский символ "!" перед именем файла модуля. перед именем файла модуля, чтобы попытаться решить проблему.
game.crash.reason.jdk_9=Невозможно запустить игру из-за того, что версия Java слишком высокая.\nНеобходимо скачать и установить Java 8 и вновь выбрать установленную Java в настройках игры.
@@ -36,7 +36,7 @@ about.thanks_to.glavo.statement=負責 HMCL 的日常維護
about.thanks_to.zekerzhayard.statement=為 HMCL 貢獻許多技術支持
about.thanks_to.zkitefly.statement=負責維護 HMCL 的文檔
about.thanks_to.mcbbs=MCBBS 我的世界中文論壇
about.thanks_to.mcbbs.statement=提供 MCBBS 下載地點
about.thanks_to.mcbbs.statement=提供 MCBBS 下載源 (現已停止服務)
about.thanks_to.mcmod=MC 百科
about.thanks_to.mcmod.statement=提供 Mod 中文名映射表與 Mod 百科
about.thanks_to.red_lnn.statement=提供預設背景圖
@@ -152,8 +152,8 @@ account.portable=便攜帳戶
account.skin=皮膚
account.skin.file=皮膚圖片檔案
account.skin.model=模型
account.skin.model.default=經典(Steve)
account.skin.model.slim=苗條(Alex)
account.skin.model.default=經典
account.skin.model.slim=苗條
account.skin.type.csl_api=Blessing Skin 伺服器
account.skin.type.csl_api.location=伺服器位址
account.skin.type.csl_api.location.hint=CustomSkinAPI 位址
@@ -334,9 +334,9 @@ download.existing=檔案已存在,無法保存。你可以選擇另存為將
download.external_link=打開下載網站
download.failed=下載失敗: %1$s,錯誤碼:%2$d
download.failed.empty=沒有能安裝的版本,按一下此處返回。
download.failed.no_code=下載失敗: %s
download.failed.refresh=載入版本列表失敗,按一下此處重試。
download.game=新遊戲
download.provider.mcbbs=我的世界中文論壇 (MCBBS, https://www.mcbbs.net/)
download.provider.bmclapi=BMCLAPI (bangbang93,https://bmclapi2.bangbang93.com/)
download.provider.mojang=官方伺服器 (OptiFine 自動安裝的下載來源是 BMCLAPI)
download.provider.official=儘量使用官方源(最新,但可能加載慢)
@@ -435,6 +435,7 @@ game.crash.reason.graphics_driver=當前遊戲因為你的顯示卡驅動存在
如果你的電腦存在獨立顯示卡,你需要檢查遊戲是否使用集成/核芯顯示卡啟動。如果是,請嘗試使用獨立顯示卡啟動 HMCL 與遊戲。如果仍有問題,你可能需要考慮換一個新顯示卡或新電腦。\n\
如果你確實需要使用核芯顯示卡,請檢查你的電腦的 CPU 是否是 Intel(R) Core(TM) 3000 系列或更舊的處理器,如果是,對於 Minecraft 1.16.5 及更舊版本,請你將遊戲所使用的 Java 版本降級至 1.8.0_51 及以下版本,否則你需要更換獨立顯示卡或新電腦。\n\
在版本設定中打開“使用 OpenGL 軟渲染器”選項也可以解决此問題,但打開此選項後在 CPU 效能不足的情况下幀數會顯著降低,僅推薦以調試為目的或應急時開啟。
game.crash.reason.macos_failed_to_find_service_port_for_display=當前遊戲因為 apple silicon 平台下初始化 opengl 窗口失敗,無法繼續運行。\n對於該問題,HMCL 暫無直接性的解決方案。請您嘗試任意打開一個瀏覽器並全屏,然後再回到 HMCL 啟動遊戲,在彈出遊戲窗口前<b>迅速切回瀏覽器頁面</b>,等待遊戲窗口出現後再切回遊戲窗口。
game.crash.reason.illegal_access_error=當前遊戲因為某些 Mod 的問題,無法繼續運行。\n如果你認識:%1$s,你可以更新或刪除對應 Mod 再試。
game.crash.reason.install_mixinbootstrap=當前遊戲因為缺失 MixinBootstrap,無法繼續運行。\n你可以嘗試安裝 <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> 解決該問題。若安裝後崩潰,嘗試在該模組的文件名前加入英文“!”嘗試解決。
game.crash.reason.jdk_9=當前遊戲因為 Java 版本過高,無法繼續運行。\n你需要下載安裝 Java 8,並在遊戲設置中將 Java 設置為 1.8 的版本。
@@ -511,7 +512,7 @@ install.installer.forge=Forge
install.installer.neoforge=NeoForge
install.installer.game=Minecraft
install.installer.incompatible=與 %s 不相容
install.installer.install=安裝%s
install.installer.install=安裝 %s
install.installer.install_offline=從本機檔案安裝或升級
install.installer.install_offline.extension=Forge/OptiFine 安裝器
install.installer.install_offline.tooltip=支援匯入已經下載好的 Forge/OptiFine 安裝器
@@ -703,26 +704,39 @@ modpack.wizard.step.initialization.warning=在製作模組包前,請您確認
modpack.wizard.step.initialization.server=點選此處查看有關伺服器自動更新模組包的製作教學
modrinth.category.adventure=冒險
modrinth.category.audio=聲音
modrinth.category.blocks=方塊
modrinth.category.bukkit=Bukkit
modrinth.category.bungeecord=BungeeCord
modrinth.category.challenging=高難度
modrinth.category.core-shaders=覈心著色器
modrinth.category.combat=戰鬥
modrinth.category.cursed=Cursed
modrinth.category.decoration=裝飾
modrinth.category.economy=經濟
modrinth.category.entities=實體
modrinth.category.environment=環境
modrinth.category.equipment=裝備
modrinth.category.fabric=Fabric
modrinth.category.fonts=字體
modrinth.category.food=食物
modrinth.category.forge=Forge
modrinth.category.game-mechanics=遊戲機制
modrinth.category.gui=GUI
modrinth.category.items=物品
modrinth.category.kitchen-sink=大雜燴
modrinth.category.library=支持庫
modrinth.category.lightweight=輕量
modrinth.category.liteloader=LiteLoader
modrinth.category.locale=在地化
modrinth.category.magic=魔法
modrinth.category.management=管理
modrinth.category.minecraft=Minecraft
modrinth.category.minigame=小遊戲
modrinth.category.misc=其他
modrinth.category.mobs=生物
modrinth.category.modded=Modded
modrinth.category.models=模型
modrinth.category.modloader=Modloader
modrinth.category.multiplayer=多人
modrinth.category.neoforge=NeoForge
@@ -731,14 +745,19 @@ modrinth.category.paper=Paper
modrinth.category.purpur=Purpur
modrinth.category.quests=任務
modrinth.category.quilt=Quilt
modrinth.category.realistic=寫實
modrinth.category.rift=Rift
modrinth.category.simplistic=簡單
modrinth.category.social=社交
modrinth.category.spigot=Spigot
modrinth.category.sponge=Sponge
modrinth.category.storage=儲存
modrinth.category.technology=科技
modrinth.category.themed=主題
modrinth.category.transportation=運輸
modrinth.category.tweaks=優化
modrinth.category.utility=實用
modrinth.category.vanilla-like=類原生
modrinth.category.velocity=Velocity
modrinth.category.waterfall=Waterfall
modrinth.category.worldgen=世界生成
@@ -36,7 +36,7 @@ about.thanks_to.glavo.statement=负责 HMCL 的日常维护
about.thanks_to.zekerzhayard.statement=为 HMCL 贡献许多技术支持
about.thanks_to.zkitefly.statement=负责维护 HMCL 的文档
about.thanks_to.mcbbs=MCBBS 我的世界中文论坛
about.thanks_to.mcbbs.statement=提供 MCBBS 下载源
about.thanks_to.mcbbs.statement=提供 MCBBS 下载源 (现已停止服务)
about.thanks_to.mcmod=MC 百科
about.thanks_to.mcmod.statement=提供模组中文名映射表与 Mod 百科
about.thanks_to.red_lnn.statement=提供默认背景图
@@ -153,8 +153,8 @@ account.portable=便携账户
account.skin=皮肤
account.skin.file=皮肤图片文件
account.skin.model=模型
account.skin.model.default=经典(Steve)
account.skin.model.slim=苗条(Alex)
account.skin.model.default=经典
account.skin.model.slim=苗条
account.skin.type.csl_api=Blessing Skin 服务器
account.skin.type.csl_api.location=服务器地址
account.skin.type.csl_api.location.hint=CustomSkinAPI 地址
@@ -335,9 +335,9 @@ download.existing=文件已存在,无法保存。你可以在模组选择栏
download.external_link=打开下载网站
download.failed=下载失败: %1$s,错误码:%2$d
download.failed.empty=[没有可供安装的版本,点击此处返回]
download.failed.no_code=下载失败: %s
download.failed.refresh=[加载版本列表失败,点击此处重试]
download.game=新游戏
download.provider.mcbbs=我的世界中文论坛 (MCBBS, https://www.mcbbs.net)
download.provider.bmclapi=BMCLAPI(bangbang93,https://bmclapi2.bangbang93.com)
download.provider.mojang=官方(OptiFine 自动安装使用 BMCLAPI 下载源)
download.provider.official=尽量使用官方源(最新,但可能加载慢)
@@ -428,6 +428,7 @@ game.crash.reason.graphics_driver=当前游戏因为显卡驱动问题而崩溃
- 如果你确实需要使用核芯显卡,请检查你的电脑的 CPU 是否是 Intel(R) Core(TM) 3000 系列或更旧的处理器,如果是,对于 Minecraft 1.16.5 及更旧版本,请你将游戏所使用的 Java 版本降级至 1.8.0_51 及以下版本 <a href="https://github.com/frekele/oracle-java/releases/8u51-b16">Java 1.8.0 历史版本</a> ,否则请跳过;\n\
- 在全局(特定)游戏设置,高级设置中打开“使用 OpenGL 软渲染器”(开启此选项后帧数会显著降低,仅推荐在以调试为目的或应急时开启)。\n\
如果仍有问题,你可能需要考虑换一张新显卡或一台新电脑。
game.crash.reason.macos_failed_to_find_service_port_for_display=当前游戏因为 Apple silicon 平台下初始化 OpenGL 窗口失败,无法继续运行。\n对于该问题,HMCL 暂无直接性的解决方案。请您尝试任意打开一个浏览器并全屏,然后再回到 HMCL 启动游戏,在弹出游戏窗口前<b>迅速切回浏览器页面</b>,等待游戏窗口出现后再切回游戏窗口。
game.crash.reason.illegal_access_error=当前游戏因为某些模组的问题,无法继续运行。\n如果你认识:%1$s,你可以更新或删除对应模组再试。
game.crash.reason.install_mixinbootstrap=当前游戏因为缺失 MixinBootstrap,无法继续运行。\n你可以尝试安装 <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> 解决该问题。若安装后崩溃,尝试在该模组的文件名前加入英文“!”尝试解决。
game.crash.reason.need_jdk11=当前游戏因为 Java 虚拟机版本不合适,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 11</a>,并在全局(特定)游戏设置中将 Java 设置为 11 开头的版本。
@@ -702,26 +703,39 @@ modpack.wizard.step.initialization.warning=在制作整合包前,请您确认
modpack.wizard.step.initialization.server=点击此处查看有关服务器自动更新整合包的制作教程
modrinth.category.adventure=冒险
modrinth.category.audio=声音
modrinth.category.blocks=方块
modrinth.category.bukkit=Bukkit
modrinth.category.bungeecord=BungeeCord
modrinth.category.challenging=高难度
modrinth.category.core-shaders=核心着色器
modrinth.category.combat=战斗
modrinth.category.cursed=Cursed
modrinth.category.decoration=装饰
modrinth.category.economy=经济
modrinth.category.entities=实体
modrinth.category.environment=环境
modrinth.category.equipment=装备
modrinth.category.fabric=Fabric
modrinth.category.fonts=字体
modrinth.category.food=食物
modrinth.category.forge=Forge
modrinth.category.game-mechanics=游戏机制
modrinth.category.gui=GUI
modrinth.category.items=物品
modrinth.category.kitchen-sink=大杂烩
modrinth.category.library=支持库
modrinth.category.lightweight=轻量
modrinth.category.liteloader=LiteLoader
modrinth.category.locale=本地化
modrinth.category.magic=魔法
modrinth.category.management=管理
modrinth.category.minecraft=Minecraft
modrinth.category.minigame=小游戏
modrinth.category.misc=其他
modrinth.category.mobs=生物
modrinth.category.modded=Modded
modrinth.category.models=模型
modrinth.category.modloader=Modloader
modrinth.category.multiplayer=多人
modrinth.category.neoforge=NeoForge
@@ -730,14 +744,19 @@ modrinth.category.paper=Paper
modrinth.category.purpur=Purpur
modrinth.category.quests=任务
modrinth.category.quilt=Quilt
modrinth.category.realistic=写实
modrinth.category.rift=Rift
modrinth.category.simplistic=简单
modrinth.category.social=社交
modrinth.category.spigot=Spigot
modrinth.category.sponge=Sponge
modrinth.category.storage=存储
modrinth.category.technology=科技
modrinth.category.themed=主题
modrinth.category.transportation=运输
modrinth.category.tweaks=优化
modrinth.category.utility=实用
modrinth.category.vanilla-like=类原生
modrinth.category.velocity=Velocity
modrinth.category.waterfall=Waterfall
modrinth.category.worldgen=世界生成
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -8,6 +8,7 @@ import moe.mickey.minecraft.skin.fx.SkinCanvas;
import moe.mickey.minecraft.skin.fx.SkinCanvasSupport;
import moe.mickey.minecraft.skin.fx.animation.SkinAniRunning;
import moe.mickey.minecraft.skin.fx.animation.SkinAniWavingArms;
import org.jackhuang.hmcl.game.TexturesLoader;
import java.util.function.Consumer;
@@ -16,7 +17,7 @@ public class Test extends Application {
public static final String TITLE = "FX - Minecraft skin preview";
public static SkinCanvas createSkinCanvas() {
SkinCanvas canvas = new SkinCanvas(SkinCanvas.STEVE, 400, 400, true);
SkinCanvas canvas = new SkinCanvas(TexturesLoader.getDefaultSkinImage(), 400, 400, true);
canvas.getAnimationPlayer().addSkinAnimation(new SkinAniWavingArms(100, 2000, 7.5, canvas), new SkinAniRunning(100, 100, 30, canvas));
FunctionHelper.alwaysB(Consumer<SkinCanvas>::accept, canvas, new SkinCanvasSupport.Mouse(.5), new SkinCanvasSupport.Drag(TITLE));
return canvas;
@@ -32,9 +32,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class AuthlibInjectorDownloader implements AuthlibInjectorArtifactProvider {
@@ -44,7 +43,7 @@ public class AuthlibInjectorDownloader implements AuthlibInjectorArtifactProvide
private final Supplier<DownloadProvider> downloadProvider;
/**
* @param artifactsDirectory where to save authlib-injector artifacts
* @param artifactLocation where to save authlib-injector artifacts
*/
public AuthlibInjectorDownloader(Path artifactLocation, Supplier<DownloadProvider> downloadProvider) {
this.artifactLocation = artifactLocation;
@@ -139,7 +138,7 @@ public class AuthlibInjectorDownloader implements AuthlibInjectorArtifactProvide
try {
return Optional.of(AuthlibInjectorArtifactInfo.from(path));
} catch (IOException e) {
LOG.log(Level.WARNING, "Bad authlib-injector artifact", e);
LOG.warning("Bad authlib-injector artifact", e);
return Optional.empty();
}
}
@@ -19,7 +19,7 @@ package org.jackhuang.hmcl.auth.authlibinjector;
import static java.util.Collections.emptyMap;
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import java.io.IOException;
import java.lang.reflect.Type;
@@ -29,7 +29,6 @@ import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
import org.jackhuang.hmcl.util.io.HttpRequest;
@@ -60,6 +59,7 @@ public class AuthlibInjectorServer implements Observable {
try {
url = addHttpsIfMissing(url);
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestProperty("Accept-Language", Locale.getDefault().toLanguageTag());
String ali = conn.getHeaderField("x-authlib-injector-api-location");
if (ali != null) {
@@ -68,6 +68,7 @@ public class AuthlibInjectorServer implements Observable {
conn.disconnect();
url = absoluteAli.toString();
conn = (HttpURLConnection) absoluteAli.openConnection();
conn.setRequestProperty("Accept-Language", Locale.getDefault().toLanguageTag());
}
}
@@ -252,7 +253,7 @@ public class AuthlibInjectorServer implements Observable {
try {
instance.setMetadataResponse(jsonObj.get("metadataResponse").getAsString(), jsonObj.get("metadataTimestamp").getAsLong());
} catch (JsonParseException e) {
LOG.log(Level.WARNING, "Ignoring malformed metadata response cache: " + jsonObj.get("metadataResponse"), e);
LOG.warning("Ignoring malformed metadata response cache: " + jsonObj.get("metadataResponse"), e);
}
}
return instance;
@@ -17,12 +17,11 @@
*/
package org.jackhuang.hmcl.auth.authlibinjector;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.logging.Level;
public class SimpleAuthlibInjectorArtifactProvider implements AuthlibInjectorArtifactProvider {
@@ -42,7 +41,7 @@ public class SimpleAuthlibInjectorArtifactProvider implements AuthlibInjectorArt
try {
return Optional.of(getArtifactInfo());
} catch (IOException e) {
LOG.log(Level.WARNING, "Bad authlib-injector artifact", e);
LOG.warning("Bad authlib-injector artifact", e);
return Optional.empty();
}
}
@@ -28,10 +28,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.logging.Level;
import static java.util.Objects.requireNonNull;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class MicrosoftAccount extends OAuthAccount {
@@ -142,7 +141,7 @@ public class MicrosoftAccount extends OAuthAccount {
try {
return YggdrasilService.getTextures(it);
} catch (ServerResponseMalformedException e) {
LOG.log(Level.WARNING, "Failed to parse texture payload", e);
LOG.warning("Failed to parse texture payload", e);
return Optional.empty();
}
}));
@@ -39,13 +39,12 @@ import java.net.URL;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.util.Objects.requireNonNull;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Lang.threadPool;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
public class MicrosoftService {
@@ -62,7 +61,7 @@ public class MicrosoftService {
this.profileRepository = new ObservableOptionalCache<>(uuid -> {
LOG.info("Fetching properties of " + uuid);
return getCompleteGameProfile(uuid);
}, (uuid, e) -> LOG.log(Level.WARNING, "Failed to fetch properties of " + uuid, e), POOL);
}, (uuid, e) -> LOG.warning("Failed to fetch properties of " + uuid, e), POOL);
}
public ObservableOptionalCache<UUID, CompleteGameProfile, AuthenticationException> getProfileRepository() {
@@ -97,7 +96,7 @@ public class MicrosoftService {
}
if (response.displayClaims == null || response.displayClaims.xui == null || response.displayClaims.xui.size() == 0 || !response.displayClaims.xui.get(0).containsKey("uhs")) {
LOG.log(Level.WARNING, "Unrecognized xbox authorization response " + GSON.toJson(response));
LOG.warning("Unrecognized xbox authorization response " + GSON.toJson(response));
throw new NoXuiException();
}
@@ -147,6 +146,16 @@ public class MicrosoftService {
long notAfter = minecraftResponse.expiresIn * 1000L + System.currentTimeMillis();
// Check MC ownership, this is necessary, see GitHub#2979
HttpURLConnection request = HttpRequest.GET("https://api.minecraftservices.com/entitlements/mcstore")
.authorization("Bearer " + minecraftResponse.accessToken)
.retry(5)
.accept("application/json").createConnection();
if (request.getResponseCode() != 200) {
throw new ResponseCodeException(new URL("https://api.minecraftservices.com/entitlements/mcstore"), request.getResponseCode());
}
// Get Minecraft Account UUID
MinecraftProfileResponse profileResponse = getMinecraftProfile(minecraftResponse.tokenType, minecraftResponse.accessToken);
handleErrorResponse(profileResponse);
@@ -18,7 +18,7 @@
package org.jackhuang.hmcl.auth.microsoft;
import org.jackhuang.hmcl.auth.AuthInfo;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.logging.Logger;
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
import java.util.Map;
@@ -45,7 +45,7 @@ public class MicrosoftSession {
this.user = user;
this.profile = profile;
if (accessToken != null) Logging.registerAccessToken(accessToken);
if (accessToken != null) Logger.registerAccessToken(accessToken);
}
public String getTokenType() {
@@ -25,7 +25,6 @@ import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorArtifactInfo;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorArtifactProvider;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorDownloadException;
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;
@@ -101,14 +100,7 @@ public class OfflineAccount extends Account {
}
protected boolean loadAuthlibInjector(Skin skin) {
if (skin == null) return false;
if (skin.getType() == Skin.Type.DEFAULT) return false;
TextureModel defaultModel = TextureModel.detectUUID(getUUID());
if (skin.getType() == Skin.Type.ALEX && defaultModel == TextureModel.ALEX ||
skin.getType() == Skin.Type.STEVE && defaultModel == TextureModel.STEVE) {
return false;
}
return true;
return skin != null && skin.getType() != Skin.Type.DEFAULT;
}
@Override
@@ -18,6 +18,7 @@
package org.jackhuang.hmcl.auth.offline;
import com.google.gson.annotations.SerializedName;
import javafx.scene.image.Image;
import org.jackhuang.hmcl.auth.yggdrasil.TextureModel;
import org.jackhuang.hmcl.task.FetchTask;
import org.jackhuang.hmcl.task.GetTask;
@@ -39,7 +40,6 @@ import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Lang.tryCast;
@@ -99,12 +99,6 @@ public class Skin {
}
}
private static Function<Type, InputStream> defaultSkinLoader = null;
public static void registerDefaultSkinLoader(Function<Type, InputStream> defaultSkinLoader0) {
defaultSkinLoader = defaultSkinLoader0;
}
private final Type type;
private final String cslApi;
private final TextureModel textureModel;
@@ -128,7 +122,7 @@ public class Skin {
}
public TextureModel getTextureModel() {
return textureModel == null ? TextureModel.STEVE : textureModel;
return textureModel == null ? TextureModel.WIDE : textureModel;
}
public String getLocalSkinPath() {
@@ -152,11 +146,14 @@ public class Skin {
case STEVE:
case SUNNY:
case ZURI:
if (defaultSkinLoader == null) {
return Task.supplyAsync(() -> null);
}
TextureModel model = type == Type.ALEX ? TextureModel.ALEX : TextureModel.STEVE;
return Task.supplyAsync(() -> new LoadedSkin(model, Texture.loadTexture(defaultSkinLoader.apply(type)), null));
TextureModel model = this.textureModel != null ? this.textureModel : type == Type.ALEX ? TextureModel.SLIM : TextureModel.WIDE;
String resource = (model == TextureModel.SLIM ? "/assets/img/skin/slim/" : "/assets/img/skin/wide/") + type.name().toLowerCase(Locale.ROOT) + ".png";
return Task.supplyAsync(() -> new LoadedSkin(
model,
Texture.loadTexture(new Image(resource)),
null
));
case LOCAL_FILE:
return Task.supplyAsync(() -> {
Texture skin = null, cape = null;
@@ -227,16 +224,7 @@ public class Skin {
String localSkinPath = tryCast(storage.get("localSkinPath"), String.class).orElse(null);
String localCapePath = tryCast(storage.get("localCapePath"), String.class).orElse(null);
TextureModel model;
if ("default".equals(textureModel)) {
model = TextureModel.STEVE;
} else if ("slim".equals(textureModel)) {
model = TextureModel.ALEX;
} else {
model = TextureModel.STEVE;
}
return new Skin(type, cslApi, model, localSkinPath, localCapePath);
return new Skin(type, cslApi, "slim".equals(textureModel) ? TextureModel.SLIM : TextureModel.WIDE, localSkinPath, localCapePath);
}
private static class FetchBytesTask extends FetchTask<InputStream> {
@@ -327,9 +315,9 @@ public class Skin {
@Nullable
public TextureModel getModel() {
if (textures != null && textures.slim != null) {
return TextureModel.ALEX;
return TextureModel.SLIM;
} else if (textures != null && textures.defaultSkin != null) {
return TextureModel.STEVE;
return TextureModel.WIDE;
} else {
return null;
}
@@ -351,9 +339,9 @@ public class Skin {
public String getHash() {
TextureModel model = getModel();
if (model == TextureModel.ALEX)
if (model == TextureModel.SLIM)
return getAlexModelHash();
else if (model == TextureModel.STEVE)
else if (model == TextureModel.WIDE)
return getSteveModelHash();
else
return null;
@@ -178,7 +178,7 @@ public class YggdrasilServer extends HttpServer {
public Object toCompleteResponse(String rootUrl) {
Map<String, Object> realTextures = new HashMap<>();
if (skin != null && skin.getSkin() != null) {
if (skin.getModel() == TextureModel.ALEX) {
if (skin.getModel() == TextureModel.SLIM) {
realTextures.put("SKIN", mapOf(
pair("url", rootUrl + "/textures/" + skin.getSkin().getHash()),
pair("metadata", mapOf(
@@ -17,27 +17,12 @@
*/
package org.jackhuang.hmcl.auth.yggdrasil;
import java.util.Map;
import java.util.UUID;
public enum TextureModel {
STEVE("default"), ALEX("slim");
WIDE("default"), SLIM("slim");
public final String modelName;
TextureModel(String modelName) {
this.modelName = modelName;
}
public static TextureModel detectModelName(Map<String, String> metadata) {
if (metadata != null && "slim".equals(metadata.get("model"))) {
return ALEX;
} else {
return STEVE;
}
}
public static TextureModel detectUUID(UUID uuid) {
return (uuid.hashCode() & 1) == 1 ? ALEX : STEVE;
}
}
@@ -24,10 +24,9 @@ import org.jackhuang.hmcl.util.javafx.BindingMapping;
import java.nio.file.Path;
import java.util.*;
import java.util.logging.Level;
import static java.util.Objects.requireNonNull;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public abstract class YggdrasilAccount extends ClassicAccount {
@@ -197,7 +196,7 @@ public abstract class YggdrasilAccount extends ClassicAccount {
try {
return YggdrasilService.getTextures(it);
} catch (ServerResponseMalformedException e) {
LOG.log(Level.WARNING, "Failed to parse texture payload", e);
LOG.warning("Failed to parse texture payload", e);
return Optional.empty();
}
}));
@@ -40,13 +40,12 @@ import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.unmodifiableList;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Lang.threadPool;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
public class YggdrasilService {
@@ -63,7 +62,7 @@ public class YggdrasilService {
LOG.info("Fetching properties of " + uuid + " from " + provider);
return getCompleteGameProfile(uuid);
},
(uuid, e) -> LOG.log(Level.WARNING, "Failed to fetch properties of " + uuid + " from " + provider, e),
(uuid, e) -> LOG.warning("Failed to fetch properties of " + uuid + " from " + provider, e),
POOL);
}
Loaded 100 of 180 files, more files were not shown because too many files have changed in this diff. Show more