Compare commits
52
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a230ef6b5 | ||
|
|
c12ae9fdf8 | ||
|
|
773ef4282c | ||
|
|
9edfe29659 | ||
|
|
5591d92e25 | ||
|
|
65bdb29e71 | ||
|
|
355df211db | ||
|
|
fa66549f53 | ||
|
|
6e48dbd6c6 | ||
|
|
e3c7278759 | ||
|
|
dd1829d8ca | ||
|
|
60ac16a3ea | ||
|
|
b400a9a3ef | ||
|
|
c7cc2d0733 | ||
|
|
861223e909 | ||
|
|
70ecbc734e | ||
|
|
2ca7e7c830 | ||
|
|
9a0db56ac3 | ||
|
|
c1ae5875ba | ||
|
|
1d0ae427bf | ||
|
|
3dde2d19e2 | ||
|
|
d5ec6d7b85 | ||
|
|
13856b71a0 | ||
|
|
c6658771ca | ||
|
|
406f36584d | ||
|
|
898750d058 | ||
|
|
09e9e934d3 | ||
|
|
3d170267b7 | ||
|
|
3ca7e3cf88 | ||
|
|
1378d1445a | ||
|
|
16d304dbb4 | ||
|
|
aff5db7759 | ||
|
|
0697aa9755 | ||
|
|
995d3bd4b9 | ||
|
|
3bf5204e79 | ||
|
|
0b1ce6e94a | ||
|
|
a66ccd7385 | ||
|
|
7a3f125802 | ||
|
|
4a8dcce3d4 | ||
|
|
adcc3eb43f | ||
|
|
8bbd1a7cf4 | ||
|
|
467ff26278 | ||
|
|
d6a267afa4 | ||
|
|
743e934436 | ||
|
|
f89ac2231a | ||
|
|
1877a18ebb | ||
|
|
c99f85d9d5 | ||
|
|
228942c60a | ||
|
|
fecd567eab | ||
|
|
602840519b | ||
|
|
959adf1075 | ||
|
|
422f681fe6 |
No files matched your search
@@ -54,12 +54,14 @@ jobs:
|
||||
echo "" >> RELEASE_NOTE
|
||||
echo "| File Name | SHA-256 Checksum |" >> RELEASE_NOTE
|
||||
echo "| --- | --- |" >> RELEASE_NOTE
|
||||
echo "| HMCL-$HMCL_VERSION.exe | $(cat HMCL-$HMCL_VERSION.exe.sha256) |" >> RELEASE_NOTE
|
||||
echo "| HMCL-$HMCL_VERSION.jar | $(cat HMCL-$HMCL_VERSION.jar.sha256) |" >> RELEASE_NOTE
|
||||
echo "| HMCL-$HMCL_VERSION.sh | $(cat HMCL-$HMCL_VERSION.sh.sha256) |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.exe]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.exe) | $(cat HMCL-$HMCL_VERSION.exe.sha256) |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.jar]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.jar) | $(cat HMCL-$HMCL_VERSION.jar.sha256) |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.sh]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.sh) | $(cat HMCL-$HMCL_VERSION.sh.sha256) |" >> RELEASE_NOTE
|
||||
env:
|
||||
GH_DOWNLOAD_BASE_URL: https://github.com/HMCL-dev/HMCL/releases/download
|
||||
- name: Create release
|
||||
if: ${{ env.continue == 'true' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: RELEASE_NOTE
|
||||
files: |
|
||||
@@ -69,6 +71,7 @@ jobs:
|
||||
target_commitish: ${{ env.HMCL_COMMIT_SHA }}
|
||||
name: ${{ env.HMCL_TAG_NAME }}
|
||||
tag_name: ${{ env.HMCL_TAG_NAME }}
|
||||
prerelease: ture
|
||||
stable-check-update:
|
||||
if: ${{ github.repository_owner == 'HMCL-dev' }}
|
||||
needs: dev-check-update
|
||||
@@ -118,12 +121,14 @@ jobs:
|
||||
echo "" >> RELEASE_NOTE
|
||||
echo "| File Name | SHA-256 Checksum |" >> RELEASE_NOTE
|
||||
echo "| --- | --- |" >> RELEASE_NOTE
|
||||
echo "| HMCL-$HMCL_VERSION.exe | $(cat HMCL-$HMCL_VERSION.exe.sha256) |" >> RELEASE_NOTE
|
||||
echo "| HMCL-$HMCL_VERSION.jar | $(cat HMCL-$HMCL_VERSION.jar.sha256) |" >> RELEASE_NOTE
|
||||
echo "| HMCL-$HMCL_VERSION.sh | $(cat HMCL-$HMCL_VERSION.sh.sha256) |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.exe]($GH_DOWNLOAD_BASE_URL/release-$HMCL_VERSION/HMCL-$HMCL_VERSION.exe) | $(cat HMCL-$HMCL_VERSION.exe.sha256) |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.jar]($GH_DOWNLOAD_BASE_URL/release-$HMCL_VERSION/HMCL-$HMCL_VERSION.jar) | $(cat HMCL-$HMCL_VERSION.jar.sha256) |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.sh]($GH_DOWNLOAD_BASE_URL/release-$HMCL_VERSION/HMCL-$HMCL_VERSION.sh) | $(cat HMCL-$HMCL_VERSION.sh.sha256) |" >> RELEASE_NOTE
|
||||
env:
|
||||
GH_DOWNLOAD_BASE_URL: https://github.com/HMCL-dev/HMCL/releases/download
|
||||
- name: Create release
|
||||
if: ${{ env.continue == 'true' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: RELEASE_NOTE
|
||||
files: |
|
||||
|
||||
+1
-19
@@ -25,7 +25,7 @@ val buildNumber = System.getenv("BUILD_NUMBER")?.toInt().let { number ->
|
||||
if (!shortCommit.isNullOrEmpty()) "$prefix-$shortCommit" else "SNAPSHOT"
|
||||
}
|
||||
}
|
||||
val versionRoot = System.getenv("VERSION_ROOT") ?: "3.5"
|
||||
val versionRoot = System.getenv("VERSION_ROOT") ?: "3.6"
|
||||
val versionType = System.getenv("VERSION_TYPE") ?: if (isOfficial) "nightly" else "unofficial"
|
||||
|
||||
val microsoftAuthId = System.getenv("MICROSOFT_AUTH_ID") ?: ""
|
||||
@@ -167,24 +167,6 @@ fun createExecutable(suffix: String, header: String) {
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
fun convertToBSS(resource: String) {
|
||||
doFirst {
|
||||
val cssFile = File(projectDir, "src/main/resources/$resource")
|
||||
val bssFile = File(projectDir, "build/compiled-resources/${resource.substring(0, resource.length - 4)}.bss")
|
||||
bssFile.parentFile.mkdirs()
|
||||
javaexec {
|
||||
classpath = sourceSets["main"].compileClasspath
|
||||
mainClass.set("com.sun.javafx.css.parser.Css2Bin")
|
||||
args(cssFile, bssFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
from("build/compiled-resources")
|
||||
|
||||
convertToBSS("assets/css/root.css")
|
||||
convertToBSS("assets/css/blue.css")
|
||||
|
||||
into("META-INF/versions/11") {
|
||||
from(sourceSets["java11"].output)
|
||||
}
|
||||
|
||||
@@ -36,10 +36,14 @@ import org.jackhuang.hmcl.mod.ModpackProvider;
|
||||
import org.jackhuang.hmcl.setting.*;
|
||||
import org.jackhuang.hmcl.task.*;
|
||||
import org.jackhuang.hmcl.ui.*;
|
||||
import org.jackhuang.hmcl.ui.construct.*;
|
||||
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
|
||||
import org.jackhuang.hmcl.ui.construct.PromptDialogPane;
|
||||
import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.ResponseCodeException;
|
||||
import org.jackhuang.hmcl.util.platform.*;
|
||||
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||
@@ -60,9 +64,10 @@ import static javafx.application.Platform.runLater;
|
||||
import static javafx.application.Platform.setImplicitExit;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.Lang.resolveException;
|
||||
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.Platform.*;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
import static org.jackhuang.hmcl.util.platform.Platform.SYSTEM_PLATFORM;
|
||||
import static org.jackhuang.hmcl.util.platform.Platform.isCompatibleWithX86Java;
|
||||
|
||||
public final class LauncherHelper {
|
||||
|
||||
@@ -178,6 +183,9 @@ public final class LauncherHelper {
|
||||
.thenComposeAsync(() -> logIn(account).withStage("launch.state.logging_in"))
|
||||
.thenComposeAsync(authInfo -> Task.supplyAsync(() -> {
|
||||
LaunchOptions launchOptions = repository.getLaunchOptions(selectedVersion, javaVersionRef.get(), profile.getGameDir(), javaAgents, scriptFile != null);
|
||||
|
||||
LOG.info("Here's the structure of game mod directory:\n" + FileUtils.printFileStructure(repository.getModManager(selectedVersion).getModsDirectory(), 10));
|
||||
|
||||
return new HMCLGameLauncher(
|
||||
repository,
|
||||
version.get(),
|
||||
@@ -522,6 +530,9 @@ public final class LauncherHelper {
|
||||
case MODDED_JAVA_17:
|
||||
suggestions.add(i18n("launch.advice.modded_java", 17, gameVersion));
|
||||
break;
|
||||
case MODDED_JAVA_21:
|
||||
suggestions.add(i18n("launch.advice.modded_java", 21, gameVersion));
|
||||
break;
|
||||
case VANILLA_JAVA_8_51:
|
||||
suggestions.add(i18n("launch.advice.java8_51_1_13"));
|
||||
break;
|
||||
|
||||
@@ -24,9 +24,8 @@ 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.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -36,11 +35,10 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Base64;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
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;
|
||||
@@ -58,34 +56,6 @@ public class Theme {
|
||||
Color.web("#B71C1C") // red
|
||||
};
|
||||
|
||||
private static Charset cssCharset;
|
||||
|
||||
private static Charset getCssCharset() {
|
||||
if (cssCharset != null)
|
||||
return cssCharset;
|
||||
|
||||
Charset defaultCharset = Charset.defaultCharset();
|
||||
if (defaultCharset != StandardCharsets.UTF_8) {
|
||||
// https://bugs.openjdk.org/browse/JDK-8279328
|
||||
// For JavaFX 17 or earlier, native encoding should be used
|
||||
String jfxVersion = System.getProperty("javafx.version");
|
||||
if (jfxVersion != null) {
|
||||
Matcher matcher = Pattern.compile("^(?<version>[0-9]+)").matcher(jfxVersion);
|
||||
if (matcher.find()) {
|
||||
int v = Lang.parseInt(matcher.group(), -1);
|
||||
if (v >= 18) {
|
||||
cssCharset = StandardCharsets.UTF_8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cssCharset == null)
|
||||
cssCharset = defaultCharset;
|
||||
|
||||
return cssCharset;
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
private static Optional<Font> font;
|
||||
|
||||
@@ -145,6 +115,14 @@ public class Theme {
|
||||
return isLight() ? Color.BLACK : Color.WHITE;
|
||||
}
|
||||
|
||||
private static String rgba(Color color, double opacity) {
|
||||
return String.format("rgba(%d, %d, %d, %.1f)",
|
||||
(int) Math.ceil(color.getRed() * 256),
|
||||
(int) Math.ceil(color.getGreen() * 256),
|
||||
(int) Math.ceil(color.getBlue() * 256),
|
||||
opacity);
|
||||
}
|
||||
|
||||
public String[] getStylesheets(String overrideFontFamily) {
|
||||
String css = "/assets/css/blue.css";
|
||||
|
||||
@@ -163,30 +141,44 @@ public class Theme {
|
||||
|
||||
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"))
|
||||
.replace("%base-color%", color)
|
||||
.replace("%base-red%", Integer.toString((int) Math.ceil(paint.getRed() * 256)))
|
||||
.replace("%base-green%", Integer.toString((int) Math.ceil(paint.getGreen() * 256)))
|
||||
.replace("%base-blue%", Integer.toString((int) Math.ceil(paint.getBlue() * 256)))
|
||||
.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%", fontCss);
|
||||
FileUtils.writeText(temp, themeText, getCssCharset());
|
||||
temp.deleteOnExit();
|
||||
css = temp.toURI().toString();
|
||||
} catch (IOException | NullPointerException e) {
|
||||
LOG.error("Unable to create theme stylesheet. Fallback to blue theme.", e);
|
||||
}
|
||||
StringBuilder themeBuilder = new StringBuilder(512);
|
||||
themeBuilder.append(".root {")
|
||||
.append("-fx-base-color:").append(color).append(';')
|
||||
.append("-fx-base-darker-color: derive(-fx-base-color, -10%);")
|
||||
.append("-fx-base-check-color: derive(-fx-base-color, 30%);")
|
||||
.append("-fx-rippler-color:").append(rgba(paint, 0.3)).append(';')
|
||||
.append("-fx-base-rippler-color: derive(").append(rgba(paint, 0.3)).append(", 100%);")
|
||||
.append("-fx-base-disabled-text-fill:").append(rgba(textFill, 0.7)).append(";")
|
||||
.append("-fx-base-text-fill:").append(getColorDisplayName(getForegroundColor())).append(";")
|
||||
.append("-theme-thumb:").append(rgba(paint, 0.7)).append(";");
|
||||
|
||||
if (fontFamily == null)
|
||||
// https://github.com/HMCL-dev/HMCL/pull/3423
|
||||
themeBuilder.append("-fx-font-family: -fx-base-font-family;");
|
||||
else
|
||||
themeBuilder.append("-fx-font-family:\"").append(fontFamily).append("\";");
|
||||
|
||||
if (fontStyle != null && !fontStyle.isEmpty())
|
||||
themeBuilder.append("-fx-font-style:\"").append(fontStyle).append("\";");
|
||||
|
||||
themeBuilder.append('}');
|
||||
|
||||
if (FXUtils.JAVAFX_MAJOR_VERSION >= 17)
|
||||
// JavaFX 17+ support loading stylesheets from data URIs
|
||||
// https://bugs.openjdk.org/browse/JDK-8267554
|
||||
css = "data:text/css;charset=UTF-8;base64," + Base64.getEncoder().encodeToString(themeBuilder.toString().getBytes(StandardCharsets.UTF_8));
|
||||
else
|
||||
try {
|
||||
File temp = File.createTempFile("hmcl", ".css");
|
||||
// For JavaFX 17 or earlier, CssParser uses the default charset
|
||||
// https://bugs.openjdk.org/browse/JDK-8279328
|
||||
FileUtils.writeText(temp, themeBuilder.toString(), Charset.defaultCharset());
|
||||
temp.deleteOnExit();
|
||||
css = temp.toURI().toString();
|
||||
} catch (IOException | NullPointerException e) {
|
||||
LOG.error("Unable to create theme stylesheet. Fallback to blue theme.", e);
|
||||
}
|
||||
}
|
||||
|
||||
return new String[]{css, "/assets/css/root.css"};
|
||||
@@ -235,7 +227,7 @@ public class Theme {
|
||||
}
|
||||
|
||||
public static String getColorDisplayName(Color c) {
|
||||
return c != null ? String.format("#%02x%02x%02x", Math.round(c.getRed() * 255.0D), Math.round(c.getGreen() * 255.0D), Math.round(c.getBlue() * 255.0D)).toUpperCase(Locale.ROOT) : null;
|
||||
return c != null ? String.format("#%02X%02X%02X", Math.round(c.getRed() * 255.0D), Math.round(c.getGreen() * 255.0D), Math.round(c.getBlue() * 255.0D)) : null;
|
||||
}
|
||||
|
||||
private static ObjectBinding<Color> FOREGROUND_FILL;
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.glavo.png.javafx.PNGJavaFXUtils;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||
import org.jackhuang.hmcl.util.Holder;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.ResourceNotFoundError;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
@@ -72,8 +73,6 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.*;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
@@ -85,6 +84,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
||||
@@ -96,6 +97,20 @@ public final class FXUtils {
|
||||
private FXUtils() {
|
||||
}
|
||||
|
||||
public static final int JAVAFX_MAJOR_VERSION;
|
||||
|
||||
static {
|
||||
String jfxVersion = System.getProperty("javafx.version");
|
||||
int majorVersion = -1;
|
||||
if (jfxVersion != null) {
|
||||
Matcher matcher = Pattern.compile("^(?<version>[0-9]+)").matcher(jfxVersion);
|
||||
if (matcher.find()) {
|
||||
majorVersion = Lang.parseInt(matcher.group(), -1);
|
||||
}
|
||||
}
|
||||
JAVAFX_MAJOR_VERSION = majorVersion;
|
||||
}
|
||||
|
||||
public static final String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace";
|
||||
|
||||
private static final Map<String, Image> builtinImageCache = new ConcurrentHashMap<>();
|
||||
@@ -298,8 +313,12 @@ public final class FXUtils {
|
||||
ScrollUtils.addSmoothScrolling(scrollPane);
|
||||
}
|
||||
|
||||
private static final Duration TOOLTIP_FAST_SHOW_DELAY = Duration.millis(50);
|
||||
private static final Duration TOOLTIP_SLOW_SHOW_DELAY = Duration.millis(500);
|
||||
private static final Duration TOOLTIP_SHOW_DURATION = Duration.millis(5000);
|
||||
|
||||
public static void installFastTooltip(Node node, Tooltip tooltip) {
|
||||
installTooltip(node, 50, 5000, 0, tooltip);
|
||||
runInFX(() -> TooltipInstaller.INSTALLER.installTooltip(node, TOOLTIP_FAST_SHOW_DELAY, TOOLTIP_SHOW_DURATION, Duration.ZERO, tooltip));
|
||||
}
|
||||
|
||||
public static void installFastTooltip(Node node, String tooltip) {
|
||||
@@ -307,39 +326,13 @@ public final class FXUtils {
|
||||
}
|
||||
|
||||
public static void installSlowTooltip(Node node, Tooltip tooltip) {
|
||||
installTooltip(node, 500, 5000, 0, tooltip);
|
||||
runInFX(() -> TooltipInstaller.INSTALLER.installTooltip(node, TOOLTIP_SLOW_SHOW_DELAY, TOOLTIP_SHOW_DURATION, Duration.ZERO, tooltip));
|
||||
}
|
||||
|
||||
public static void installSlowTooltip(Node node, String tooltip) {
|
||||
installSlowTooltip(node, new Tooltip(tooltip));
|
||||
}
|
||||
|
||||
public static void installTooltip(Node node, double openDelay, double visibleDelay, double closeDelay, Tooltip tooltip) {
|
||||
runInFX(() -> {
|
||||
try {
|
||||
// Java 8
|
||||
Class<?> behaviorClass = Class.forName("javafx.scene.control.Tooltip$TooltipBehavior");
|
||||
Constructor<?> behaviorConstructor = behaviorClass.getDeclaredConstructor(Duration.class, Duration.class, Duration.class, boolean.class);
|
||||
behaviorConstructor.setAccessible(true);
|
||||
Object behavior = behaviorConstructor.newInstance(new Duration(openDelay), new Duration(visibleDelay), new Duration(closeDelay), false);
|
||||
Method installMethod = behaviorClass.getDeclaredMethod("install", Node.class, Tooltip.class);
|
||||
installMethod.setAccessible(true);
|
||||
installMethod.invoke(behavior, node, tooltip);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
try {
|
||||
// Java 9
|
||||
Tooltip.class.getMethod("setShowDelay", Duration.class).invoke(tooltip, new Duration(openDelay));
|
||||
Tooltip.class.getMethod("setShowDuration", Duration.class).invoke(tooltip, new Duration(visibleDelay));
|
||||
Tooltip.class.getMethod("setHideDelay", Duration.class).invoke(tooltip, new Duration(closeDelay));
|
||||
} catch (ReflectiveOperationException e2) {
|
||||
e.addSuppressed(e2);
|
||||
LOG.error("Cannot install tooltip", e);
|
||||
}
|
||||
Tooltip.install(node, tooltip);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void playAnimation(Node node, String animationKey, Timeline timeline) {
|
||||
animationKey = "FXUTILS.ANIMATION." + animationKey;
|
||||
Object oldTimeline = node.getProperties().get(animationKey);
|
||||
|
||||
@@ -65,7 +65,6 @@ 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.Logger.LOG;
|
||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
@@ -387,13 +386,13 @@ public class GameCrashWindow extends Stage {
|
||||
gameDir.getStyleClass().setAll("two-line-item-second-large");
|
||||
gameDir.setTitle(i18n("game.directory"));
|
||||
gameDir.setSubtitle(launchOptions.getGameDir().getAbsolutePath());
|
||||
runInFX(() -> FXUtils.installFastTooltip(gameDir, i18n("game.directory")));
|
||||
FXUtils.installFastTooltip(gameDir, i18n("game.directory"));
|
||||
|
||||
TwoLineListItem javaDir = new TwoLineListItem();
|
||||
javaDir.getStyleClass().setAll("two-line-item-second-large");
|
||||
javaDir.setTitle(i18n("settings.game.java_directory"));
|
||||
javaDir.setSubtitle(launchOptions.getJava().getBinary().toAbsolutePath().toString());
|
||||
runInFX(() -> FXUtils.installFastTooltip(javaDir, i18n("settings.game.java_directory")));
|
||||
FXUtils.installFastTooltip(javaDir, i18n("settings.game.java_directory"));
|
||||
|
||||
Label reasonTitle = new Label(i18n("game.crash.reason"));
|
||||
reasonTitle.getStyleClass().add("two-line-item-second-large-title");
|
||||
@@ -424,7 +423,7 @@ public class GameCrashWindow extends Stage {
|
||||
|
||||
JFXButton helpButton = FXUtils.newRaisedButton(i18n("help"));
|
||||
helpButton.setOnAction(e -> FXUtils.openLink("https://docs.hmcl.net/help.html"));
|
||||
runInFX(() -> FXUtils.installFastTooltip(helpButton, i18n("logwindow.help")));
|
||||
FXUtils.installFastTooltip(helpButton, i18n("logwindow.help"));
|
||||
|
||||
|
||||
toolBar.setPadding(new Insets(8));
|
||||
|
||||
@@ -32,7 +32,7 @@ public enum SVG {
|
||||
CANCEL("M12 2C17.5 2 22 6.5 22 12S17.5 22 12 22 2 17.5 2 12 6.5 2 12 2M12 4C10.1 4 8.4 4.6 7.1 5.7L18.3 16.9C19.3 15.5 20 13.8 20 12C20 7.6 16.4 4 12 4M16.9 18.3L5.7 7.1C4.6 8.4 4 10.1 4 12C4 16.4 7.6 20 12 20C13.9 20 15.6 19.4 16.9 18.3Z"),
|
||||
CHAT("M20,2A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H6L2,22V4C2,2.89 2.9,2 4,2H20M4,4V17.17L5.17,16H20V4H4M6,7H18V9H6V7M6,11H15V13H6V11Z"),
|
||||
CLOSE("M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"),
|
||||
COPY("M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"),
|
||||
COPY("M15 16H7V6h8m.4-2H6.6A1.6 1.6 90 005 5.6V16.4a1.6 1.6 90 001.6 1.6h8.8A1.6 1.6 90 0017 16.4V5.6A1.6 1.6 90 0015.4 4M13 1H3.6A1.6 1.6 90 002 2.6V13h2V3H13V1Z"),
|
||||
DOTS_VERTICAL("M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z"),
|
||||
DOTS_HORIZONTAL("M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"),
|
||||
DELETE("M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"),
|
||||
@@ -59,6 +59,7 @@ public enum SVG {
|
||||
ALERT_OUTLINE("M12,2L1,21H23M12,6L19.53,19H4.47M11,10V14H13V10M11,16V18H13V16"),
|
||||
PLUS("M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z"),
|
||||
PLUS_CIRCLE_OUTLINE("M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z"),
|
||||
MINUS("M19 13H5V11H19V13Z"),
|
||||
IMPORT_ICON("M14,12L10,8V11H2V13H10V16M20,18V6C20,4.89 19.1,4 18,4H6A2,2 0 0,0 4,6V9H6V6H18V18H6V15H4V18A2,2 0 0,0 6,20H18A2,2 0 0,0 20,18Z"),
|
||||
EXPORT("M23,12L19,8V11H10V13H19V16M1,18V6C1,4.89 1.9,4 3,4H15A2,2 0 0,1 17,6V9H15V6H3V18H15V15H17V18A2,2 0 0,1 15,20H3A2,2 0 0,1 1,18Z"),
|
||||
OPEN_IN_NEW("M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z"),
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.util.Duration;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public class TooltipInstaller {
|
||||
public static final TooltipInstaller INSTALLER;
|
||||
|
||||
static {
|
||||
TooltipInstaller installer = null;
|
||||
|
||||
try {
|
||||
installer = new NewInstaller();
|
||||
} catch (Throwable e) {
|
||||
try {
|
||||
installer = new OldInstaller();
|
||||
} catch (Throwable e2) {
|
||||
e2.addSuppressed(e);
|
||||
LOG.warning("Failed to initialize TooltipInstaller", e2);
|
||||
}
|
||||
}
|
||||
|
||||
INSTALLER = installer != null ? installer : new TooltipInstaller();
|
||||
}
|
||||
|
||||
TooltipInstaller() {
|
||||
}
|
||||
|
||||
public void installTooltip(Node node, Duration showDelay, Duration showDuration, Duration hideDelay, Tooltip tooltip) {
|
||||
Tooltip.install(node, tooltip);
|
||||
}
|
||||
|
||||
// For Java 8
|
||||
private static final class OldInstaller extends TooltipInstaller {
|
||||
private static final Constructor<?> createTooltipBehavior;
|
||||
private static final Method installTooltipBehavior;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> behaviorClass = Class.forName("javafx.scene.control.Tooltip$TooltipBehavior");
|
||||
createTooltipBehavior = behaviorClass.getDeclaredConstructor(Duration.class, Duration.class, Duration.class, boolean.class);
|
||||
createTooltipBehavior.setAccessible(true);
|
||||
installTooltipBehavior = behaviorClass.getDeclaredMethod("install", Node.class, Tooltip.class);
|
||||
installTooltipBehavior.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installTooltip(Node node, Duration showDelay, Duration showDuration, Duration hideDelay, Tooltip tooltip) {
|
||||
try {
|
||||
Object behavior = createTooltipBehavior.newInstance(showDelay, showDuration, hideDelay, false);
|
||||
installTooltipBehavior.invoke(behavior, node, tooltip);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
LOG.warning("Failed to set tooltip show delay", e);
|
||||
Tooltip.install(node, tooltip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For Java 9+
|
||||
private static final class NewInstaller extends TooltipInstaller {
|
||||
private static final MethodHandle setTooltipShowDelay;
|
||||
private static final MethodHandle setTooltipShowDuration;
|
||||
private static final MethodHandle setTooltipHideDelay;
|
||||
|
||||
static {
|
||||
try {
|
||||
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
|
||||
MethodType methodType = MethodType.methodType(void.class, Duration.class);
|
||||
|
||||
setTooltipShowDelay = lookup.findVirtual(Tooltip.class, "setShowDelay", methodType);
|
||||
setTooltipShowDuration = lookup.findVirtual(Tooltip.class, "setShowDuration", methodType);
|
||||
setTooltipHideDelay = lookup.findVirtual(Tooltip.class, "setHideDelay", methodType);
|
||||
} catch (Exception e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installTooltip(Node node, Duration showDelay, Duration showDuration, Duration hideDelay, Tooltip tooltip) {
|
||||
try {
|
||||
setTooltipShowDelay.invokeExact(tooltip, showDelay);
|
||||
setTooltipShowDuration.invokeExact(tooltip, showDuration);
|
||||
setTooltipHideDelay.invokeExact(tooltip, hideDelay);
|
||||
} catch (Throwable e) {
|
||||
LOG.warning("Failed to set tooltip show delay", e);
|
||||
}
|
||||
|
||||
Tooltip.install(node, tooltip);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,10 +42,9 @@ import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
||||
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public class AccountListItemSkin extends SkinBase<AccountListItem> {
|
||||
public final class AccountListItemSkin extends SkinBase<AccountListItem> {
|
||||
|
||||
public AccountListItemSkin(AccountListItem skinnable) {
|
||||
super(skinnable);
|
||||
@@ -118,10 +117,10 @@ public class AccountListItemSkin extends SkinBase<AccountListItem> {
|
||||
btnMove.getStyleClass().add("toggle-icon4");
|
||||
if (skinnable.getAccount().isPortable()) {
|
||||
btnMove.setGraphic(SVG.EARTH.createIcon(Theme.blackFill(), -1, -1));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnMove, i18n("account.move_to_global")));
|
||||
FXUtils.installFastTooltip(btnMove, i18n("account.move_to_global"));
|
||||
} else {
|
||||
btnMove.setGraphic(SVG.EXPORT.createIcon(Theme.blackFill(), -1, -1));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnMove, i18n("account.move_to_portable")));
|
||||
FXUtils.installFastTooltip(btnMove, i18n("account.move_to_portable"));
|
||||
}
|
||||
spinnerMove.setContent(btnMove);
|
||||
right.getChildren().add(spinnerMove);
|
||||
@@ -143,7 +142,7 @@ public class AccountListItemSkin extends SkinBase<AccountListItem> {
|
||||
});
|
||||
btnRefresh.getStyleClass().add("toggle-icon4");
|
||||
btnRefresh.setGraphic(SVG.REFRESH.createIcon(Theme.blackFill(), -1, -1));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnRefresh, i18n("button.refresh")));
|
||||
FXUtils.installFastTooltip(btnRefresh, i18n("button.refresh"));
|
||||
spinnerRefresh.setContent(btnRefresh);
|
||||
right.getChildren().add(spinnerRefresh);
|
||||
|
||||
@@ -160,7 +159,7 @@ public class AccountListItemSkin extends SkinBase<AccountListItem> {
|
||||
});
|
||||
btnUpload.getStyleClass().add("toggle-icon4");
|
||||
btnUpload.setGraphic(SVG.HANGER.createIcon(Theme.blackFill(), -1, -1));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnUpload, i18n("account.skin.upload")));
|
||||
FXUtils.installFastTooltip(btnUpload, i18n("account.skin.upload"));
|
||||
spinnerUpload.managedProperty().bind(spinnerUpload.visibleProperty());
|
||||
spinnerUpload.visibleProperty().bind(skinnable.canUploadSkin());
|
||||
spinnerUpload.setContent(btnUpload);
|
||||
@@ -170,9 +169,10 @@ public class AccountListItemSkin extends SkinBase<AccountListItem> {
|
||||
JFXButton btnCopyUUID = new JFXButton();
|
||||
SpinnerPane spinnerCopyUUID = new SpinnerPane();
|
||||
spinnerCopyUUID.getStyleClass().add("small-spinner-pane");
|
||||
btnUpload.getStyleClass().add("toggle-icon4");
|
||||
btnCopyUUID.setOnAction(e -> FXUtils.copyText(skinnable.getAccount().getUUID().toString()));
|
||||
btnCopyUUID.setGraphic(SVG.COPY.createIcon(Theme.blackFill(), -1, -1));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnCopyUUID, i18n("account.copy_uuid")));
|
||||
FXUtils.installFastTooltip(btnCopyUUID, i18n("account.copy_uuid"));
|
||||
spinnerCopyUUID.setContent(btnCopyUUID);
|
||||
right.getChildren().add(spinnerCopyUUID);
|
||||
|
||||
@@ -180,8 +180,8 @@ public class AccountListItemSkin extends SkinBase<AccountListItem> {
|
||||
btnRemove.setOnAction(e -> Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"), skinnable::remove, null));
|
||||
btnRemove.getStyleClass().add("toggle-icon4");
|
||||
BorderPane.setAlignment(btnRemove, Pos.CENTER);
|
||||
btnRemove.setGraphic(SVG.DELETE.createIcon(Theme.blackFill(), -1, -1));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnRemove, i18n("button.delete")));
|
||||
btnRemove.setGraphic(SVG.DELETE_OUTLINE.createIcon(Theme.blackFill(), -1, -1));
|
||||
FXUtils.installFastTooltip(btnRemove, i18n("button.delete"));
|
||||
right.getChildren().add(btnRemove);
|
||||
root.setRight(right);
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ public final class AddAuthlibInjectorServerPane extends TransitionPane implement
|
||||
confirmServerPane.setActions(prevButton, cancelButton, finishButton);
|
||||
}
|
||||
|
||||
this.setContent(addServerPane, ContainerAnimations.NONE.getAnimationProducer());
|
||||
this.setContent(addServerPane, ContainerAnimations.NONE);
|
||||
|
||||
lblCreationWarning.maxWidthProperty().bind(((FlowPane) lblCreationWarning.getParent()).widthProperty());
|
||||
btnAddNext.disableProperty().bind(txtServerUrl.textProperty().isEmpty());
|
||||
@@ -198,7 +198,7 @@ public final class AddAuthlibInjectorServerPane extends TransitionPane implement
|
||||
|
||||
lblServerWarning.setVisible("http".equals(NetworkUtils.toURL(serverBeingAdded.getUrl()).getProtocol()));
|
||||
|
||||
this.setContent(confirmServerPane, ContainerAnimations.SWIPE_LEFT.getAnimationProducer());
|
||||
this.setContent(confirmServerPane, ContainerAnimations.SWIPE_LEFT);
|
||||
} else {
|
||||
LOG.warning("Failed to resolve auth server: " + url, exception);
|
||||
lblCreationWarning.setText(resolveFetchExceptionMessage(exception));
|
||||
@@ -208,7 +208,7 @@ public final class AddAuthlibInjectorServerPane extends TransitionPane implement
|
||||
}
|
||||
|
||||
private void onAddPrev() {
|
||||
this.setContent(addServerPane, ContainerAnimations.SWIPE_RIGHT.getAnimationProducer());
|
||||
this.setContent(addServerPane, ContainerAnimations.SWIPE_RIGHT);
|
||||
}
|
||||
|
||||
private void onAddFinish() {
|
||||
|
||||
@@ -317,7 +317,7 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
|
||||
JFXHyperlink deauthorizeLink = new JFXHyperlink(i18n("account.methods.microsoft.deauthorize"));
|
||||
deauthorizeLink.setExternalLink("https://account.live.com/consent/Edit?client_id=000000004C794E0A");
|
||||
JFXHyperlink forgotpasswordLink = new JFXHyperlink(i18n("account.methods.forgot_password"));
|
||||
forgotpasswordLink.setExternalLink("https://www.minecraft.net/password/forgot");
|
||||
forgotpasswordLink.setExternalLink("https://account.live.com/ResetPassword.aspx");
|
||||
JFXHyperlink createProfileLink = new JFXHyperlink(i18n("account.methods.microsoft.makegameidsettings"));
|
||||
createProfileLink.setExternalLink("https://www.minecraft.net/msaprofile/mygames/editprofile");
|
||||
box.getChildren().setAll(profileLink, birthLink, purchaseLink, deauthorizeLink, forgotpasswordLink, createProfileLink);
|
||||
@@ -510,7 +510,7 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
|
||||
|
||||
if (factory instanceof OfflineAccountFactory) {
|
||||
txtUsername.setPromptText(i18n("account.methods.offline.name.special_characters"));
|
||||
runInFX(() -> FXUtils.installFastTooltip(txtUsername, i18n("account.methods.offline.name.special_characters")));
|
||||
FXUtils.installFastTooltip(txtUsername, i18n("account.methods.offline.name.special_characters"));
|
||||
|
||||
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.microsoft.purchase"));
|
||||
purchaseLink.setExternalLink(YggdrasilService.PURCHASE_URL);
|
||||
|
||||
@@ -28,9 +28,9 @@ import javafx.scene.control.Label;
|
||||
import javafx.scene.input.DragEvent;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import javafx.scene.layout.*;
|
||||
import moe.mickey.minecraft.skin.fx.SkinCanvas;
|
||||
import moe.mickey.minecraft.skin.fx.animation.SkinAniRunning;
|
||||
import moe.mickey.minecraft.skin.fx.animation.SkinAniWavingArms;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinCanvas;
|
||||
import org.jackhuang.hmcl.ui.skin.animation.SkinAniRunning;
|
||||
import org.jackhuang.hmcl.ui.skin.animation.SkinAniWavingArms;
|
||||
import org.jackhuang.hmcl.auth.offline.OfflineAccount;
|
||||
import org.jackhuang.hmcl.auth.offline.Skin;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.TextureModel;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,165 +27,225 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public enum ContainerAnimations {
|
||||
NONE(c -> {
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getPreviousNode().setTranslateY(0);
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
}, c -> Collections.emptyList()),
|
||||
public enum ContainerAnimations implements AnimationProducer {
|
||||
NONE {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getPreviousNode().setTranslateY(0);
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A fade between the old and new view
|
||||
*/
|
||||
FADE(c -> {
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getPreviousNode().setTranslateY(0);
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(0);
|
||||
}, c ->
|
||||
Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
FADE {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getPreviousNode().setTranslateY(0);
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 1, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 0, Interpolator.EASE_BOTH)),
|
||||
new KeyFrame(c.getDuration(),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 1, Interpolator.EASE_BOTH)))),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 1, Interpolator.EASE_BOTH)));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A fade between the old and new view
|
||||
*/
|
||||
FADE_IN(c -> {
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(0);
|
||||
}, c ->
|
||||
Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
FADE_IN {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 0, FXUtils.SINE)),
|
||||
new KeyFrame(c.getDuration(),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 1, FXUtils.SINE)))),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 1, FXUtils.SINE)));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A fade between the old and new view
|
||||
*/
|
||||
FADE_OUT(c -> {
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
}, c ->
|
||||
Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
FADE_OUT {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 1, FXUtils.SINE)),
|
||||
new KeyFrame(c.getDuration(),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 0, FXUtils.SINE)))),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 0, FXUtils.SINE)));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* A zoom effect
|
||||
*/
|
||||
ZOOM_IN(c -> {
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getPreviousNode().setTranslateY(0);
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
}, c ->
|
||||
Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
ZOOM_IN {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getPreviousNode().setTranslateY(0);
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getPreviousNode().scaleXProperty(), 1, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().scaleYProperty(), 1, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 1, Interpolator.EASE_BOTH)),
|
||||
new KeyFrame(c.getDuration(),
|
||||
new KeyValue(c.getPreviousNode().scaleXProperty(), 4, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().scaleYProperty(), 4, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH)))),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH)));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* A zoom effect
|
||||
*/
|
||||
ZOOM_OUT(c -> {
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getPreviousNode().setTranslateY(0);
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
}, c ->
|
||||
(Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
ZOOM_OUT {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getPreviousNode().setTranslateY(0);
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(0);
|
||||
c.getCurrentNode().setTranslateY(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getPreviousNode().scaleXProperty(), 1, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().scaleYProperty(), 1, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 1, Interpolator.EASE_BOTH)),
|
||||
new KeyFrame(c.getDuration(),
|
||||
new KeyValue(c.getPreviousNode().scaleXProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().scaleYProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH))))),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH)));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* A swipe effect
|
||||
*/
|
||||
SWIPE_LEFT(c -> {
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(0);
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(c.getCurrentRoot().getWidth());
|
||||
}, c ->
|
||||
Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
SWIPE_LEFT {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(0);
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(c.getCurrentRoot().getWidth());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getCurrentNode().translateXProperty(), c.getCurrentRoot().getWidth(), Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH)),
|
||||
new KeyFrame(c.getDuration(),
|
||||
new KeyValue(c.getCurrentNode().translateXProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), -c.getCurrentRoot().getWidth(), Interpolator.EASE_BOTH)))),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), -c.getCurrentRoot().getWidth(), Interpolator.EASE_BOTH)));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A swipe effect
|
||||
*/
|
||||
SWIPE_RIGHT(c -> {
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(0);
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(-c.getCurrentRoot().getWidth());
|
||||
}, c ->
|
||||
Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
SWIPE_RIGHT {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(0);
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(-c.getCurrentRoot().getWidth());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getCurrentNode().translateXProperty(), -c.getCurrentRoot().getWidth(), Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH)),
|
||||
new KeyFrame(c.getDuration(),
|
||||
new KeyValue(c.getCurrentNode().translateXProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), c.getCurrentRoot().getWidth(), Interpolator.EASE_BOTH)))),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), c.getCurrentRoot().getWidth(), Interpolator.EASE_BOTH)));
|
||||
}
|
||||
},
|
||||
|
||||
SWIPE_LEFT_FADE_SHORT(c -> {
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(0);
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(c.getCurrentRoot().getWidth());
|
||||
}, c ->
|
||||
Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
SWIPE_LEFT_FADE_SHORT {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(0);
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(c.getCurrentRoot().getWidth());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getCurrentNode().translateXProperty(), 50, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 0, Interpolator.EASE_BOTH),
|
||||
@@ -194,19 +254,26 @@ public enum ContainerAnimations {
|
||||
new KeyValue(c.getCurrentNode().translateXProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), -50, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 1, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH)))),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH)));
|
||||
}
|
||||
},
|
||||
|
||||
SWIPE_RIGHT_FADE_SHORT(c -> {
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(0);
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(c.getCurrentRoot().getWidth());
|
||||
}, c ->
|
||||
Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
SWIPE_RIGHT_FADE_SHORT {
|
||||
@Override
|
||||
public void init(AnimationHandler c) {
|
||||
c.getPreviousNode().setScaleX(1);
|
||||
c.getPreviousNode().setScaleY(1);
|
||||
c.getPreviousNode().setOpacity(0);
|
||||
c.getPreviousNode().setTranslateX(0);
|
||||
c.getCurrentNode().setScaleX(1);
|
||||
c.getCurrentNode().setScaleY(1);
|
||||
c.getCurrentNode().setOpacity(1);
|
||||
c.getCurrentNode().setTranslateX(c.getCurrentRoot().getWidth());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler c) {
|
||||
return Arrays.asList(new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(c.getCurrentNode().translateXProperty(), -50, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 0, Interpolator.EASE_BOTH),
|
||||
@@ -215,38 +282,12 @@ public enum ContainerAnimations {
|
||||
new KeyValue(c.getCurrentNode().translateXProperty(), 0, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().translateXProperty(), 50, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getCurrentNode().opacityProperty(), 1, Interpolator.EASE_BOTH),
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH))));
|
||||
new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH)));
|
||||
}
|
||||
};
|
||||
|
||||
private final AnimationProducer animationProducer;
|
||||
private ContainerAnimations opposite;
|
||||
|
||||
ContainerAnimations(Consumer<AnimationHandler> init, Function<AnimationHandler, List<KeyFrame>> animationProducer) {
|
||||
this.animationProducer = new AnimationProducer() {
|
||||
@Override
|
||||
public void init(AnimationHandler handler) {
|
||||
init.accept(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyFrame> animate(AnimationHandler handler) {
|
||||
return animationProducer.apply(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable AnimationProducer opposite() {
|
||||
return opposite != null ? opposite.getAnimationProducer() : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public AnimationProducer getAnimationProducer() {
|
||||
return animationProducer;
|
||||
}
|
||||
|
||||
public ContainerAnimations getOpposite() {
|
||||
return opposite;
|
||||
}
|
||||
|
||||
static {
|
||||
NONE.opposite = NONE;
|
||||
FADE.opposite = FADE;
|
||||
@@ -257,4 +298,15 @@ public enum ContainerAnimations {
|
||||
ZOOM_IN.opposite = ZOOM_OUT;
|
||||
ZOOM_OUT.opposite = ZOOM_IN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void init(AnimationHandler handler);
|
||||
|
||||
@Override
|
||||
public abstract List<KeyFrame> animate(AnimationHandler handler);
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerAnimations opposite() {
|
||||
return opposite;
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,8 @@ public class FontComboBox extends JFXComboBox<String> {
|
||||
private boolean loaded = false;
|
||||
|
||||
public FontComboBox() {
|
||||
setMinWidth(260);
|
||||
|
||||
styleProperty().bind(Bindings.concat("-fx-font-family: \"", valueProperty(), "\""));
|
||||
|
||||
setCellFactory(listView -> new JFXListCell<String>() {
|
||||
|
||||
@@ -17,7 +17,6 @@ import javafx.scene.layout.Priority;
|
||||
import org.jackhuang.hmcl.setting.Theme;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.util.Lazy;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
public class IconedTwoLineListItem extends HBox {
|
||||
@@ -29,13 +28,8 @@ public class IconedTwoLineListItem extends HBox {
|
||||
|
||||
private final ImageView imageView = new ImageView();
|
||||
private final TwoLineListItem twoLineListItem = new TwoLineListItem();
|
||||
private final Lazy<JFXButton> externalLinkButton = new Lazy<>(() -> {
|
||||
JFXButton button = new JFXButton();
|
||||
button.getStyleClass().add("toggle-icon4");
|
||||
button.setGraphic(SVG.OPEN_IN_NEW.createIcon(Theme.blackFill(), -1, -1));
|
||||
button.setOnAction(e -> FXUtils.openLink(externalLink.get()));
|
||||
return button;
|
||||
});
|
||||
private JFXButton externalLinkButton;
|
||||
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private final InvalidationListener observer;
|
||||
|
||||
@@ -52,7 +46,7 @@ public class IconedTwoLineListItem extends HBox {
|
||||
getChildren().clear();
|
||||
if (image.get() != null) getChildren().add(imageView);
|
||||
getChildren().add(twoLineListItem);
|
||||
if (StringUtils.isNotBlank(externalLink.get())) getChildren().add(externalLinkButton.get());
|
||||
if (StringUtils.isNotBlank(externalLink.get())) getChildren().add(getExternalLinkButton());
|
||||
}, image, externalLink);
|
||||
}
|
||||
|
||||
@@ -111,4 +105,14 @@ public class IconedTwoLineListItem extends HBox {
|
||||
public ImageView getImageView() {
|
||||
return imageView;
|
||||
}
|
||||
|
||||
public JFXButton getExternalLinkButton() {
|
||||
if (externalLinkButton == null) {
|
||||
externalLinkButton = new JFXButton();
|
||||
externalLinkButton.getStyleClass().add("toggle-icon4");
|
||||
externalLinkButton.setGraphic(SVG.OPEN_IN_NEW.createIcon(Theme.blackFill(), -1, -1));
|
||||
externalLinkButton.setOnAction(e -> FXUtils.openLink(externalLink.get()));
|
||||
}
|
||||
return externalLinkButton;
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ public class Navigator extends TransitionPane {
|
||||
if (obj instanceof AnimationProducer) {
|
||||
setContent(node, (AnimationProducer) obj);
|
||||
} else {
|
||||
setContent(node, ContainerAnimations.NONE.getAnimationProducer());
|
||||
setContent(node, ContainerAnimations.NONE);
|
||||
}
|
||||
|
||||
NavigationEvent navigated = new NavigationEvent(this, node, Navigation.NavigationDirection.PREVIOUS, NavigationEvent.NAVIGATED);
|
||||
|
||||
@@ -146,12 +146,12 @@ public class SpinnerPane extends Control {
|
||||
|
||||
observer = FXUtils.observeWeak(() -> {
|
||||
if (getSkinnable().getFailedReason() != null) {
|
||||
root.setContent(failedPane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
root.setContent(failedPane, ContainerAnimations.FADE);
|
||||
failedReasonLabel.setText(getSkinnable().getFailedReason());
|
||||
} else if (getSkinnable().isLoading()) {
|
||||
root.setContent(topPane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
root.setContent(topPane, ContainerAnimations.FADE);
|
||||
} else {
|
||||
root.setContent(contentPane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
root.setContent(contentPane, ContainerAnimations.FADE);
|
||||
}
|
||||
}, getSkinnable().loadingProperty(), getSkinnable().failedReasonProperty());
|
||||
}
|
||||
|
||||
@@ -457,7 +457,7 @@ public class DecoratorController {
|
||||
public void startWizard(WizardProvider wizardProvider, String category) {
|
||||
FXUtils.checkFxUserThread();
|
||||
|
||||
navigator.navigate(new DecoratorWizardDisplayer(wizardProvider, category), ContainerAnimations.FADE.getAnimationProducer());
|
||||
navigator.navigate(new DecoratorWizardDisplayer(wizardProvider, category), ContainerAnimations.FADE);
|
||||
}
|
||||
|
||||
// ==== Authlib Injector DnD ====
|
||||
|
||||
@@ -18,10 +18,8 @@
|
||||
package org.jackhuang.hmcl.ui.decorator;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.svg.SVGGlyph;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.css.PseudoClass;
|
||||
import javafx.geometry.Bounds;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
@@ -44,13 +42,8 @@ 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.Lang;
|
||||
|
||||
public class DecoratorSkin extends SkinBase<Decorator> {
|
||||
private static final PseudoClass TRANSPARENT = PseudoClass.getPseudoClass("transparent");
|
||||
private static final SVGGlyph minus = Lang.apply(new SVGGlyph(0, "MINUS", "M804.571 420.571v109.714q0 22.857-16 38.857t-38.857 16h-694.857q-22.857 0-38.857-16t-16-38.857v-109.714q0-22.857 16-38.857t38.857-16h694.857q22.857 0 38.857 16t16 38.857z", Color.WHITE),
|
||||
glyph -> { glyph.setSize(12, 2); glyph.setTranslateY(4); });
|
||||
|
||||
private final StackPane root, parent;
|
||||
private final StackPane titleContainer;
|
||||
private final Stage primaryStage;
|
||||
@@ -69,8 +62,6 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
||||
|
||||
primaryStage = control.getPrimaryStage();
|
||||
|
||||
minus.fillProperty().bind(Theme.foregroundFillBinding());
|
||||
|
||||
Decorator skinnable = getSkinnable();
|
||||
root = new StackPane();
|
||||
root.getStyleClass().add("window");
|
||||
@@ -174,11 +165,11 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
||||
if (s.isAnimate()) {
|
||||
AnimationProducer animation;
|
||||
if (skinnable.getNavigationDirection() == Navigation.NavigationDirection.NEXT) {
|
||||
animation = ContainerAnimations.SWIPE_LEFT_FADE_SHORT.getAnimationProducer();
|
||||
animation = ContainerAnimations.SWIPE_LEFT_FADE_SHORT;
|
||||
} else if (skinnable.getNavigationDirection() == Navigation.NavigationDirection.PREVIOUS) {
|
||||
animation = ContainerAnimations.SWIPE_RIGHT_FADE_SHORT.getAnimationProducer();
|
||||
animation = ContainerAnimations.SWIPE_RIGHT_FADE_SHORT;
|
||||
} else {
|
||||
animation = ContainerAnimations.FADE.getAnimationProducer();
|
||||
animation = ContainerAnimations.FADE;
|
||||
}
|
||||
skinnable.setNavigationDirection(Navigation.NavigationDirection.START);
|
||||
navBarPane.setContent(node, animation);
|
||||
@@ -202,9 +193,7 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
||||
btnHelp.setOnAction(e -> FXUtils.openLink("https://docs.hmcl.net/help.html"));
|
||||
|
||||
JFXButton btnMin = new JFXButton();
|
||||
StackPane pane = new StackPane(minus);
|
||||
pane.setAlignment(Pos.CENTER);
|
||||
btnMin.setGraphic(pane);
|
||||
btnMin.setGraphic(SVG.MINUS.createIcon(Theme.foregroundFillBinding(), -1, -1));
|
||||
btnMin.getStyleClass().add("jfx-decorator-button");
|
||||
btnMin.setOnAction(e -> skinnable.minimize());
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public abstract class DecoratorTabPage extends DecoratorTransitionPage implement
|
||||
if (newValue.getNode() != null) {
|
||||
onNavigating(getCurrentPage());
|
||||
if (getCurrentPage() != null) getCurrentPage().fireEvent(new Navigator.NavigationEvent(null, getCurrentPage(), Navigation.NavigationDirection.NEXT, Navigator.NavigationEvent.NAVIGATING));
|
||||
navigate(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer());
|
||||
navigate(newValue.getNode(), ContainerAnimations.FADE);
|
||||
onNavigated(getCurrentPage());
|
||||
if (getCurrentPage() != null) getCurrentPage().fireEvent(new Navigator.NavigationEvent(null, getCurrentPage(), Navigation.NavigationDirection.NEXT, Navigator.NavigationEvent.NAVIGATED));
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class DecoratorWizardDisplayer extends DecoratorTransitionPage implements
|
||||
@Override
|
||||
public void navigateTo(Node page, Navigation.NavigationDirection nav) {
|
||||
displayer.navigateTo(page, nav);
|
||||
navigate(page, nav.getAnimation().getAnimationProducer());
|
||||
navigate(page, nav.getAnimation());
|
||||
|
||||
String prefix = category == null ? "" : category + " - ";
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage
|
||||
|
||||
tab.select(newGameTab);
|
||||
FXUtils.onChangeAndOperate(tab.getSelectionModel().selectedItemProperty(), newValue -> {
|
||||
transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer());
|
||||
transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE);
|
||||
});
|
||||
|
||||
{
|
||||
|
||||
@@ -178,7 +178,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
||||
btnRefresh.setGraphic(wrap(SVG.REFRESH.createIcon(Theme.blackFill(), -1, -1)));
|
||||
|
||||
Holder<RemoteVersionListCell> lastCell = new Holder<>();
|
||||
list.setCellFactory(listView -> new RemoteVersionListCell(lastCell));
|
||||
list.setCellFactory(listView -> new RemoteVersionListCell(lastCell, libraryId));
|
||||
|
||||
FXUtils.onClicked(list, () -> {
|
||||
if (list.getSelectionModel().getSelectedIndex() < 0)
|
||||
@@ -210,7 +210,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
||||
@Override
|
||||
public void refresh() {
|
||||
VersionList<?> currentVersionList = versionList;
|
||||
root.setContent(spinner, ContainerAnimations.FADE.getAnimationProducer());
|
||||
root.setContent(spinner, ContainerAnimations.FADE);
|
||||
executor = currentVersionList.refreshAsync(gameVersion).whenComplete((result, exception) -> {
|
||||
if (exception == null) {
|
||||
List<RemoteVersion> items = loadVersions();
|
||||
@@ -218,7 +218,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
||||
Platform.runLater(() -> {
|
||||
if (versionList != currentVersionList) return;
|
||||
if (currentVersionList.getVersions(gameVersion).isEmpty()) {
|
||||
root.setContent(emptyPane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
root.setContent(emptyPane, ContainerAnimations.FADE);
|
||||
} else {
|
||||
if (items.isEmpty()) {
|
||||
chkRelease.setSelected(true);
|
||||
@@ -227,14 +227,14 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
||||
} else {
|
||||
list.getItems().setAll(items);
|
||||
}
|
||||
root.setContent(center, ContainerAnimations.FADE.getAnimationProducer());
|
||||
root.setContent(center, ContainerAnimations.FADE);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
LOG.warning("Failed to fetch versions list", exception);
|
||||
Platform.runLater(() -> {
|
||||
if (versionList != currentVersionList) return;
|
||||
root.setContent(failedPane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
root.setContent(failedPane, ContainerAnimations.FADE);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -272,8 +272,12 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
||||
|
||||
private final Holder<RemoteVersionListCell> lastCell;
|
||||
|
||||
RemoteVersionListCell(Holder<RemoteVersionListCell> lastCell) {
|
||||
RemoteVersionListCell(Holder<RemoteVersionListCell> lastCell, String libraryId) {
|
||||
this.lastCell = lastCell;
|
||||
if ("game".equals(libraryId)) {
|
||||
content.getExternalLinkButton().setGraphic(SVG.EARTH.createIcon(Theme.blackFill(), -1, -1));
|
||||
FXUtils.installFastTooltip(content.getExternalLinkButton(), i18n("wiki.tooltip"));
|
||||
}
|
||||
|
||||
pane.getStyleClass().add("md-list-cell");
|
||||
StackPane.setMargin(content, new Insets(10, 16, 10, 16));
|
||||
@@ -307,14 +311,19 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
||||
case RELEASE:
|
||||
content.getTags().setAll(i18n("version.game.release"));
|
||||
content.setImage(VersionIconType.GRASS.getIcon());
|
||||
content.setExternalLink(i18n("wiki.version.game.release", remoteVersion.getGameVersion()));
|
||||
break;
|
||||
case SNAPSHOT:
|
||||
content.getTags().setAll(i18n("version.game.snapshot"));
|
||||
content.setImage(VersionIconType.COMMAND.getIcon());
|
||||
|
||||
|
||||
content.setExternalLink(i18n("wiki.version.game.snapshot", remoteVersion.getGameVersion()));
|
||||
break;
|
||||
default:
|
||||
content.getTags().setAll(i18n("version.game.old"));
|
||||
content.setImage(VersionIconType.CRAFT_TABLE.getIcon());
|
||||
content.setExternalLink(null);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -339,6 +348,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
||||
content.setSubtitle(remoteVersion.getGameVersion());
|
||||
else
|
||||
content.getTags().setAll(remoteVersion.getGameVersion());
|
||||
content.setExternalLink(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
@@ -116,7 +117,7 @@ public final class AboutPage extends StackPane {
|
||||
return componentList;
|
||||
}
|
||||
|
||||
try (Reader reader = new InputStreamReader(input)) {
|
||||
try (Reader reader = new InputStreamReader(input, StandardCharsets.UTF_8)) {
|
||||
JsonArray array = JsonUtils.GSON.fromJson(reader, JsonArray.class);
|
||||
|
||||
for (JsonElement element : array) {
|
||||
|
||||
@@ -66,7 +66,7 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor
|
||||
gameTab.initializeIfNeeded();
|
||||
gameTab.getNode().loadVersion(Profiles.getSelectedProfile(), null);
|
||||
FXUtils.onChangeAndOperate(tab.getSelectionModel().selectedItemProperty(), newValue -> {
|
||||
transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer());
|
||||
transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE);
|
||||
});
|
||||
|
||||
{
|
||||
|
||||
@@ -66,7 +66,6 @@ import java.util.stream.IntStream;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.SINE;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public final class MainPage extends StackPane implements DecoratorPage {
|
||||
@@ -116,7 +115,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
announcementBox.getChildren().add(announcementCard);
|
||||
|
||||
announcementPane = new TransitionPane();
|
||||
announcementPane.setContent(announcementBox, ContainerAnimations.NONE.getAnimationProducer());
|
||||
announcementPane.setContent(announcementBox, ContainerAnimations.NONE);
|
||||
|
||||
getChildren().add(announcementPane);
|
||||
}
|
||||
@@ -224,7 +223,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
StackPane.setAlignment(svg, Pos.CENTER_RIGHT);
|
||||
graphic.getChildren().setAll(svg);
|
||||
graphic.setTranslateX(12);
|
||||
runInFX(() -> FXUtils.installFastTooltip(menuButton, i18n("version.switch")));
|
||||
FXUtils.installFastTooltip(menuButton, i18n("version.switch"));
|
||||
menuButton.setGraphic(graphic);
|
||||
|
||||
launchPane.getChildren().setAll(launchButton, separator, menuButton);
|
||||
@@ -301,7 +300,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
public void hideAnnouncementPane() {
|
||||
if (announcementPane != null) {
|
||||
config().getShownTips().put(ANNOUNCEMENT, Metadata.VERSION);
|
||||
announcementPane.setContent(new StackPane(), ContainerAnimations.FADE.getAnimationProducer());
|
||||
announcementPane.setContent(new StackPane(), ContainerAnimations.FADE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
downloadItem.setActionButtonVisible(false);
|
||||
downloadItem.setTitle(i18n("download"));
|
||||
downloadItem.setOnAction(e -> Controllers.navigate(Controllers.getDownloadPage()));
|
||||
runInFX(() -> FXUtils.installFastTooltip(downloadItem, i18n("download.hint")));
|
||||
FXUtils.installFastTooltip(downloadItem, i18n("download.hint"));
|
||||
|
||||
// fifth item in left sidebar
|
||||
AdvancedListItem launcherSettingsItem = new AdvancedListItem();
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.event.Event;
|
||||
import javafx.event.EventHandler;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.animation.AnimationTimer;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.scene.*;
|
||||
import javafx.scene.image.Image;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.scene.shape.Mesh;
|
||||
import javafx.scene.shape.MeshView;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.PixelReader;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.scene.Group;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.animation.Transition;
|
||||
import javafx.beans.value.WritableValue;
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
package moe.mickey.minecraft.skin.fx.animation;
|
||||
package org.jackhuang.hmcl.ui.skin.animation;
|
||||
|
||||
import javafx.util.Duration;
|
||||
import moe.mickey.minecraft.skin.fx.FunctionHelper;
|
||||
import moe.mickey.minecraft.skin.fx.SkinAnimation;
|
||||
import moe.mickey.minecraft.skin.fx.SkinCanvas;
|
||||
import moe.mickey.minecraft.skin.fx.SkinTransition;
|
||||
import org.jackhuang.hmcl.ui.skin.FunctionHelper;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinAnimation;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinCanvas;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinTransition;
|
||||
|
||||
public final class SkinAniRunning extends SkinAnimation {
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
package moe.mickey.minecraft.skin.fx.animation;
|
||||
package org.jackhuang.hmcl.ui.skin.animation;
|
||||
|
||||
import javafx.util.Duration;
|
||||
import moe.mickey.minecraft.skin.fx.FunctionHelper;
|
||||
import moe.mickey.minecraft.skin.fx.SkinAnimation;
|
||||
import moe.mickey.minecraft.skin.fx.SkinCanvas;
|
||||
import moe.mickey.minecraft.skin.fx.SkinTransition;
|
||||
import org.jackhuang.hmcl.ui.skin.FunctionHelper;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinAnimation;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinCanvas;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinTransition;
|
||||
|
||||
public final class SkinAniWavingArms extends SkinAnimation {
|
||||
|
||||
@@ -64,7 +64,6 @@ import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor;
|
||||
@@ -302,7 +301,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
||||
lblGameVersion.visibleProperty().bind(hasVersion);
|
||||
gameVersionField.managedProperty().bind(hasVersion);
|
||||
gameVersionField.visibleProperty().bind(hasVersion);
|
||||
runInFX(() -> FXUtils.installFastTooltip(gameVersionField, i18n("search.enter")));
|
||||
FXUtils.installFastTooltip(gameVersionField, i18n("search.enter"));
|
||||
|
||||
FXUtils.onChangeAndOperate(getSkinnable().version, version -> {
|
||||
if (StringUtils.isNotBlank(version.getVersion())) {
|
||||
|
||||
@@ -62,7 +62,6 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public class DownloadPage extends Control implements DecoratorPage {
|
||||
@@ -241,14 +240,14 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
openMcmodButton.setExternalLink(getSkinnable().translations.getMcmodUrl(getSkinnable().mod));
|
||||
descriptionPane.getChildren().add(openMcmodButton);
|
||||
openMcmodButton.setMinWidth(Region.USE_PREF_SIZE);
|
||||
runInFX(() -> FXUtils.installFastTooltip(openMcmodButton, i18n("mods.mcmod")));
|
||||
FXUtils.installFastTooltip(openMcmodButton, i18n("mods.mcmod"));
|
||||
}
|
||||
|
||||
JFXHyperlink openUrlButton = new JFXHyperlink(control.page.getLocalizedOfficialPage());
|
||||
openUrlButton.setExternalLink(getSkinnable().addon.getPageUrl());
|
||||
descriptionPane.getChildren().add(openUrlButton);
|
||||
openUrlButton.setMinWidth(Region.USE_PREF_SIZE);
|
||||
runInFX(() -> FXUtils.installFastTooltip(openUrlButton, control.page.getLocalizedOfficialPage()));
|
||||
FXUtils.installFastTooltip(openUrlButton, control.page.getLocalizedOfficialPage());
|
||||
}
|
||||
|
||||
SpinnerPane spinnerPane = new SpinnerPane();
|
||||
@@ -346,7 +345,10 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
pane.getChildren().setAll(FXUtils.limitingSize(imageView, 40, 40), content);
|
||||
|
||||
RipplerContainer container = new RipplerContainer(pane);
|
||||
FXUtils.onClicked(container, () -> Controllers.navigate(new DownloadPage(page, addon, version, callback)));
|
||||
FXUtils.onClicked(container, () -> {
|
||||
fireEvent(new DialogCloseEvent());
|
||||
Controllers.navigate(new DownloadPage(page, addon, version, callback));
|
||||
});
|
||||
getChildren().setAll(container);
|
||||
|
||||
if (addon != RemoteMod.BROKEN) {
|
||||
@@ -505,7 +507,6 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
dependencies.put(dependency.getType(), list);
|
||||
}
|
||||
DependencyModItem dependencyModItem = new DependencyModItem(selfPage.page, dependency.load(), selfPage.version, selfPage.callback);
|
||||
FXUtils.onClicked(dependencyModItem, () -> fireEvent(new DialogCloseEvent()));
|
||||
dependencies.get(dependency.getType()).add(dependencyModItem);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hmcl.ui.versions;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.ImageView;
|
||||
import org.jackhuang.hmcl.event.Event;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
@@ -34,15 +33,13 @@ import java.util.function.Consumer;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public class GameAdvancedListItem extends AdvancedListItem {
|
||||
private final Tooltip tooltip;
|
||||
private final ImageView imageView;
|
||||
private final WeakListenerHolder holder = new WeakListenerHolder();
|
||||
private Profile profile;
|
||||
@SuppressWarnings("unused")
|
||||
private Consumer<Event> onVersionIconChangedListener;
|
||||
|
||||
public GameAdvancedListItem() {
|
||||
tooltip = new Tooltip();
|
||||
|
||||
Pair<Node, ImageView> view = createImageView(null);
|
||||
setLeftGraphic(view.getKey());
|
||||
imageView = view.getValue();
|
||||
@@ -63,17 +60,13 @@ public class GameAdvancedListItem extends AdvancedListItem {
|
||||
}
|
||||
if (version != null && Profiles.getSelectedProfile() != null &&
|
||||
Profiles.getSelectedProfile().getRepository().hasVersion(version)) {
|
||||
FXUtils.installFastTooltip(this, tooltip);
|
||||
setTitle(version);
|
||||
setSubtitle(null);
|
||||
setTitle(i18n("version.manage.manage"));
|
||||
setSubtitle(version);
|
||||
imageView.setImage(Profiles.getSelectedProfile().getRepository().getVersionIconImage(version));
|
||||
tooltip.setText(version);
|
||||
} else {
|
||||
Tooltip.uninstall(this,tooltip);
|
||||
setTitle(i18n("version.empty"));
|
||||
setSubtitle(i18n("version.empty.add"));
|
||||
imageView.setImage(VersionIconType.DEFAULT.getIcon());
|
||||
tooltip.setText("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ import org.jackhuang.hmcl.ui.construct.PopupMenu;
|
||||
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
||||
import org.jackhuang.hmcl.util.Lazy;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public class GameListItemSkin extends SkinBase<GameListItem> {
|
||||
@@ -82,7 +81,7 @@ public class GameListItemSkin extends SkinBase<GameListItem> {
|
||||
btnUpgrade.setOnAction(e -> skinnable.update());
|
||||
btnUpgrade.getStyleClass().add("toggle-icon4");
|
||||
btnUpgrade.setGraphic(FXUtils.limitingSize(SVG.UPDATE.createIcon(Theme.blackFill(), 24, 24), 24, 24));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnUpgrade, i18n("version.update")));
|
||||
FXUtils.installFastTooltip(btnUpgrade, i18n("version.update"));
|
||||
right.getChildren().add(btnUpgrade);
|
||||
}
|
||||
|
||||
@@ -92,7 +91,7 @@ public class GameListItemSkin extends SkinBase<GameListItem> {
|
||||
btnLaunch.getStyleClass().add("toggle-icon4");
|
||||
BorderPane.setAlignment(btnLaunch, Pos.CENTER);
|
||||
btnLaunch.setGraphic(FXUtils.limitingSize(SVG.ROCKET_LAUNCH_OUTLINE.createIcon(Theme.blackFill(), 24, 24), 24, 24));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnLaunch, i18n("version.launch.test")));
|
||||
FXUtils.installFastTooltip(btnLaunch, i18n("version.launch.test"));
|
||||
right.getChildren().add(btnLaunch);
|
||||
}
|
||||
|
||||
@@ -105,7 +104,7 @@ public class GameListItemSkin extends SkinBase<GameListItem> {
|
||||
btnManage.getStyleClass().add("toggle-icon4");
|
||||
BorderPane.setAlignment(btnManage, Pos.CENTER);
|
||||
btnManage.setGraphic(FXUtils.limitingSize(SVG.DOTS_VERTICAL.createIcon(Theme.blackFill(), 24, 24), 24, 24));
|
||||
runInFX(() -> FXUtils.installFastTooltip(btnManage, i18n("settings.game.management")));
|
||||
FXUtils.installFastTooltip(btnManage, i18n("settings.game.management"));
|
||||
right.getChildren().add(btnManage);
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
|
||||
})
|
||||
.whenComplete(Schedulers.javafx(), (result, exception) -> {
|
||||
if (exception != null || result == null) {
|
||||
Controllers.dialog("Failed to check updates", "failed", MessageDialogPane.MessageType.ERROR);
|
||||
Controllers.dialog(i18n("mods.check_updates.failed_check"), i18n("message.failed"), MessageDialogPane.MessageType.ERROR);
|
||||
} else if (result.isEmpty()) {
|
||||
Controllers.dialog(i18n("mods.check_updates.empty"));
|
||||
} else {
|
||||
|
||||
@@ -186,6 +186,14 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
||||
}
|
||||
});
|
||||
|
||||
listView.setOnContextMenuRequested(event -> {
|
||||
ModInfoObject selectedItem = listView.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem != null && listView.getSelectionModel().getSelectedItems().size() == 1) {
|
||||
listView.getSelectionModel().clearSelection();
|
||||
Controllers.dialog(new ModInfoDialog(selectedItem));
|
||||
}
|
||||
});
|
||||
|
||||
center.setContent(listView);
|
||||
root.getContent().add(center);
|
||||
}
|
||||
@@ -204,7 +212,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
||||
private void changeToolbar(HBox newToolbar) {
|
||||
Node oldToolbar = toolbarPane.getCurrentNode();
|
||||
if (newToolbar != oldToolbar) {
|
||||
toolbarPane.setContent(newToolbar, ContainerAnimations.FADE.getAnimationProducer());
|
||||
toolbarPane.setContent(newToolbar, ContainerAnimations.FADE);
|
||||
if (newToolbar == searchBar) {
|
||||
searchField.requestFocus();
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public class ModUpdatesPage extends BorderPane implements DecoratorPage {
|
||||
task.whenComplete(Schedulers.javafx(), exception -> {
|
||||
fireEvent(new PageCloseEvent());
|
||||
if (!task.getFailedMods().isEmpty()) {
|
||||
Controllers.dialog(i18n("mods.check_updates.failed") + "\n" +
|
||||
Controllers.dialog(i18n("mods.check_updates.failed_download") + "\n" +
|
||||
task.getFailedMods().stream().map(LocalModFile::getFileName).collect(Collectors.joining("\n")),
|
||||
i18n("install.failed"),
|
||||
MessageDialogPane.MessageType.ERROR);
|
||||
|
||||
@@ -78,7 +78,7 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage
|
||||
|
||||
tab.select(versionSettingsTab);
|
||||
FXUtils.onChangeAndOperate(tab.getSelectionModel().selectedItemProperty(), newValue -> {
|
||||
transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer());
|
||||
transitionPane.setContent(newValue.getNode(), ContainerAnimations.FADE);
|
||||
});
|
||||
|
||||
listenerHolder.add(EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).registerWeak(event -> checkSelectedVersion(), EventPriority.HIGHEST));
|
||||
|
||||
@@ -685,7 +685,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
version = null;
|
||||
} else {
|
||||
gameVersionNumber = GameVersionNumber.asGameVersion(repository.getGameVersion(versionId));
|
||||
version = repository.getVersion(versionId);
|
||||
version = repository.getResolvedVersion(versionId);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -83,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.no_code", file.getFile().getUrl()), MessageDialogPane.MessageType.ERROR);
|
||||
i18n("download.failed.no_code"), MessageDialogPane.MessageType.ERROR);
|
||||
return;
|
||||
}
|
||||
Controllers.taskDialog(
|
||||
@@ -96,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.no_code", file.getFile().getUrl()), MessageDialogPane.MessageType.ERROR);
|
||||
i18n("download.failed.no_code"), MessageDialogPane.MessageType.ERROR);
|
||||
}
|
||||
}).executor(true),
|
||||
i18n("message.downloading"),
|
||||
|
||||
@@ -39,16 +39,6 @@ public final class Locales {
|
||||
*/
|
||||
public static final SupportedLocale EN = new SupportedLocale(Locale.ROOT);
|
||||
|
||||
/**
|
||||
* Traditional Chinese
|
||||
*/
|
||||
public static final SupportedLocale ZH = new SupportedLocale(Locale.TRADITIONAL_CHINESE);
|
||||
|
||||
/**
|
||||
* Simplified Chinese
|
||||
*/
|
||||
public static final SupportedLocale ZH_CN = new SupportedLocale(Locale.SIMPLIFIED_CHINESE);
|
||||
|
||||
/**
|
||||
* Spanish
|
||||
*/
|
||||
@@ -64,23 +54,33 @@ public final class Locales {
|
||||
*/
|
||||
public static final SupportedLocale JA = new SupportedLocale(Locale.JAPANESE);
|
||||
|
||||
public static final List<SupportedLocale> LOCALES = Lang.immutableListOf(DEFAULT, EN, ZH_CN, ZH, ES, RU, JA);
|
||||
/**
|
||||
* Traditional Chinese
|
||||
*/
|
||||
public static final SupportedLocale ZH = new SupportedLocale(Locale.TRADITIONAL_CHINESE);
|
||||
|
||||
/**
|
||||
* Simplified Chinese
|
||||
*/
|
||||
public static final SupportedLocale ZH_CN = new SupportedLocale(Locale.SIMPLIFIED_CHINESE);
|
||||
|
||||
public static final List<SupportedLocale> LOCALES = Lang.immutableListOf(DEFAULT, EN, ES, JA, RU, ZH_CN, ZH);
|
||||
|
||||
public static SupportedLocale getLocaleByName(String name) {
|
||||
if (name == null) return DEFAULT;
|
||||
switch (name.toLowerCase(Locale.ROOT)) {
|
||||
case "en":
|
||||
return EN;
|
||||
case "es":
|
||||
return ES;
|
||||
case "ja":
|
||||
return JA;
|
||||
case "ru":
|
||||
return RU;
|
||||
case "zh":
|
||||
return ZH;
|
||||
case "zh_cn":
|
||||
return ZH_CN;
|
||||
case "es":
|
||||
return ES;
|
||||
case "ru":
|
||||
return RU;
|
||||
case "ja":
|
||||
return JA;
|
||||
default:
|
||||
return DEFAULT;
|
||||
}
|
||||
@@ -88,11 +88,11 @@ public final class Locales {
|
||||
|
||||
public static String getNameByLocale(SupportedLocale locale) {
|
||||
if (locale == EN) return "en";
|
||||
else if (locale == ZH) return "zh";
|
||||
else if (locale == ZH_CN) return "zh_CN";
|
||||
else if (locale == ES) return "es";
|
||||
else if (locale == RU) return "ru";
|
||||
else if (locale == JA) return "ja";
|
||||
else if (locale == ZH) return "zh";
|
||||
else if (locale == ZH_CN) return "zh_CN";
|
||||
else if (locale == DEFAULT) return "def";
|
||||
else throw new IllegalArgumentException("Unknown locale: " + locale);
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -24,5 +24,8 @@
|
||||
-fx-base-disabled-text-fill: rgba(256, 256, 256, 0.7);
|
||||
-fx-base-text-fill: white;
|
||||
|
||||
/* https://github.com/HMCL-dev/HMCL/pull/3423 */
|
||||
-fx-font-family: -fx-base-font-family;
|
||||
|
||||
-theme-thumb: rgba(92, 107, 192, 0.7);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
.root {
|
||||
-fx-base-color: %base-color%;
|
||||
-fx-base-darker-color: derive(-fx-base-color, -10%);
|
||||
-fx-base-check-color: derive(-fx-base-color, 30%);
|
||||
-fx-rippler-color: rgba(%base-red%, %base-green%, %base-blue%, 0.3);
|
||||
-fx-base-rippler-color: derive(%base-rippler-color%, 100%);
|
||||
-fx-base-disabled-text-fill: %disabled-font-color%;
|
||||
-fx-base-text-fill: %font-color%;
|
||||
|
||||
-theme-thumb: rgba(%base-red%, %base-green%, %base-blue%, 0.7);
|
||||
|
||||
%font%
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -23,25 +23,29 @@ about=Acerca de
|
||||
about.copyright=Copyright
|
||||
about.copyright.statement=Copyright © 2024 huangyuhui.
|
||||
about.author=Autor
|
||||
about.author.statement=@huanghongxun en bilibili
|
||||
about.author.statement=bilibili @huanghongxun
|
||||
about.claim=EULA
|
||||
about.claim.statement=Haz clic en este enlace para ver el texto completo.
|
||||
about.claim.statement=Haga clic en este enlace para ver el texto completo.
|
||||
about.dependency=Bibliotecas de terceros
|
||||
about.legal=Reconocimiento legal
|
||||
about.thanks_to=Gracias a
|
||||
about.thanks_to.bangbang93.statement=Por proporcionar la API de descarga de BMCLAPI, por favor considere hacer una donación.
|
||||
about.thanks_to.bangbang93.statement=Por proporcionar el espejo de descarga de BMCLAPI, por favor considere hacer una donación!
|
||||
about.thanks_to.burningtnt.statement=Aportar mucho apoyo técnico a HMCL.
|
||||
about.thanks_to.contributors=Todos los colaboradores en GitHub
|
||||
about.thanks_to.contributors.statement=Sin la impresionante comunidad de código abierto, Hello Minecraft! Launcher no habría llegado tan lejos.
|
||||
about.thanks_to.contributors.statement=Sin la impresionante comunidad de código abierto, HMCL no habría llegado tan lejos.
|
||||
about.thanks_to.gamerteam.statement=Por proporcionar la imagen de fondo por defecto.
|
||||
about.thanks_to.glavo.statement=Aportar mucho apoyo técnico a HMCL.
|
||||
about.thanks_to.glavo.statement=Responsable del mantenimiento de 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.mcmod=mcmod.cn
|
||||
about.thanks_to.mcmod.statement=Por facilitar las traducciones al chino y el wiki de varios mods.
|
||||
about.thanks_to.zkitefly.statement=Responsable del mantenimiento de la documentación de HMCL.
|
||||
about.thanks_to.mcbbs=MCBBS (Foro Chino Minecraft)
|
||||
about.thanks_to.mcbbs.statement=Por proporcionar el espejo de descarga de mcbbs.net para los usuarios de China continental. (Ya no disponible)
|
||||
about.thanks_to.mcmod=MCMod (mcmod.cn)
|
||||
about.thanks_to.mcmod.statement=Por proporcionar las traducciones al chino simplificado y la wiki de varios mods.
|
||||
about.thanks_to.red_lnn.statement=Por proporcionar la imagen de fondo por defecto.
|
||||
about.thanks_to.shulkersakura.statement=Por proporcionar el logotipo de HMCL.
|
||||
about.thanks_to.users=Miembros del grupo de usuarios de HMCL
|
||||
about.thanks_to.users.statement=Gracias por las donaciones, los informes de errores, etc.
|
||||
about.thanks_to.yushijinhun.statement=Por proporcionar soporte relacionado con authlib-injector.
|
||||
about.thanks_to.yushijinhun.statement=Por proporcionar el soporte relacionado con authlib-injector.
|
||||
about.open_source=Código abierto
|
||||
about.open_source.statement=GPL v3 (https://github.com/HMCL-dev/HMCL)
|
||||
|
||||
@@ -148,6 +152,7 @@ assets.index.malformed=Los archivos de índice de los activos descargados estaba
|
||||
button.cancel=Cancelar
|
||||
button.change_source=Cambiar fuente de descarga
|
||||
button.clear=Limpiar
|
||||
button.copy_and_exit=Copiar y salir
|
||||
button.delete=Borrar
|
||||
button.edit=Editar
|
||||
button.install=Instalar
|
||||
@@ -156,17 +161,21 @@ button.no=No
|
||||
button.ok=Aceptar
|
||||
button.refresh=Refrescar
|
||||
button.remove=Eliminar
|
||||
button.remove.confirm=¿Está seguro de querer eliminarlo definitivamente? Esta acción no se puede deshacer.
|
||||
button.remove.confirm=¿Estás seguro de que deseas eliminarlo de forma permanente? ¡Esta acción no se puede deshacer!
|
||||
button.retry=Reintentar
|
||||
button.save=Guardar
|
||||
button.save_as=Guardar como
|
||||
button.select_all=Seleccionar todo
|
||||
button.view=Vista
|
||||
button.yes=Sí
|
||||
|
||||
chat=Chat de grupo
|
||||
|
||||
color.recent=Recomendado
|
||||
color.custom=Color personalizado
|
||||
|
||||
crash.NoClassDefFound=Por favor, verifique la integridad de este software, o intente actualizar su versión de Java.
|
||||
crash.user_fault=El launcher se ha bloqueado debido a un entorno Java o de sistema corrupto. Por favor, asegúrese de que su Java o sistema operativo está instalado correctamente.
|
||||
crash.NoClassDefFound=Por favor, verifique la integridad de este software, o intente actualizar su Java.
|
||||
crash.user_fault=El lanzador se ha bloqueado debido a que Java o el entorno del sistema están dañados. Por favor, asegúrese de que su Java o sistema operativo está instalado correctamente.
|
||||
|
||||
curse.category.0=Todos
|
||||
|
||||
@@ -316,7 +325,7 @@ download.javafx.prepare=Preparando la descarga
|
||||
|
||||
exception.access_denied=HMCL no puede acceder al archivo %s, puede estar bloqueado por otro proceso.\n\
|
||||
\n\
|
||||
Para los usuarios de Windows, puede abrir el 'Monitor de Recursos' para comprobar si otro proceso lo está utilizando actualmente. Si es así, puede intentarlo de nuevo después de cerrar ese proceso.\
|
||||
Para los usuarios de Windows, puede abrir el 'Monitor de Recursos' para comprobar si otro proceso lo está utilizando actualmente. Si es así, puede intentarlo de nuevo después de cerrar ese proceso.\n\
|
||||
Si no es así, comprueba si tu cuenta tiene suficientes privilegios para acceder a él.
|
||||
exception.artifact_malformed=No se puede verificar la integridad de los archivos descargados .
|
||||
exception.ssl_handshake=No se puede establecer una conexión SSL debido a que faltan certificados SSL en la instalación actual de Java. Puede intentar ejecutar HMCL en otra versión de Java y luego volver a intentarlo.
|
||||
@@ -333,7 +342,7 @@ Por favor, intente cambiar a versiones de Java como Oracle Java 8 que tiene Java
|
||||
fatal.javafx.missing=No se encontró un entorno JavaFX.\n\
|
||||
Si está utilizando Java 11 o superior, por favor, descargue Oracle JRE 8 (java.com), o instale BellSoft Liberica Full JRE (bell-sw.com/pages/downloads).\n\
|
||||
O, si está utilizando distribuciones de OpenJDK, asegúrese de que tiene incluido OpenJFX.
|
||||
fatal.config_loading_failure=No se pueden cargar los archivos de configuración.\nPara macOS, intente colocar HMCL en un lugar con permiso que no sea "Escritorio", "Descargas" y "Documentos" y vuelva a intentarlo.
|
||||
fatal.config_loading_failure=No se pueden cargar los archivos de configuración.\nPara macOS, intente colocar HMCL en un lugar con permiso que no sea "Escritorio", "Descargas" y "Documentos" y vuelva a intentarlo.\n\
|
||||
¡Por favor, asegúrese de que "Hello Minecraft! Launcher" tiene acceso de lectura y escritura a "%s" y a los archivos que contiene.
|
||||
fatal.migration_requires_manual_reboot=Hello Minecraft! Launcher ha sido actualizado. Por favor, reinicie el launcher.
|
||||
fatal.apply_update_failure=Lo sentimos, pero Hello Minecraft! Launcher no puede actualizarse.\n\
|
||||
@@ -379,7 +388,7 @@ game.crash.reason.bootstrap_failed=El juego se ha bloqueado debido al mod %1$s.\
|
||||
\n\
|
||||
Puedes intentar borrarlo o actualizarlo.
|
||||
game.crash.reason.config=El juego se ha bloqueado porque un mod %1$s no puede analizar su archivo de configuración %2$s.
|
||||
game.crash.reason.debug_crash=El juego se ha bloqueado porque lo has activado manualmente.
|
||||
game.crash.reason.debug_crash=El juego se ha bloqueado porque lo has activado manualmente.\n\
|
||||
\n\
|
||||
Entonces, probablemente sabes por qué.
|
||||
game.crash.reason.mixin_apply_mod_failed=El juego se ha bloqueado porque Mixin no puede aplicar el mod %1$s, no se puede continuar.\n\
|
||||
@@ -436,7 +445,7 @@ game.crash.reason.loading_crashed_fabric=El juego se ha bloqueado debido al mod
|
||||
Puedes intentar borrarlo o actualizarlo.
|
||||
game.crash.reason.memory_exceeded=El juego se ha bloqueado debido a que se ha asignado demasiada memoria para un pequeño archivo de paginación.\n\
|
||||
\n\
|
||||
Puede intentar desactivar la opción de asignación automática de memoria en la configuración y ajustar el valor hasta que el juego se inicie.
|
||||
Puede intentar desactivar la opción de asignación automática de memoria en la configuración y ajustar el valor hasta que el juego se inicie.\n\
|
||||
También puede tratar de aumentar el tamaño del archivo de paginación en la configuración del sistema.
|
||||
game.crash.reason.mod=El juego se ha bloqueado debido al mod %1$s.\n\
|
||||
\n\
|
||||
@@ -475,22 +484,19 @@ game.crash.reason.mod_resolution_mod_version.any=%1$s (Cualquier versión)
|
||||
game.crash.reason.forge_repeat_installation=El juego actual no puede continuar ejecutándose debido a una instalación duplicada de Forge. <a href="https://github.com/HMCL-dev/HMCL/issues/1880">Este es un problema conocido</a>\nSe recomienda cargar los comentarios del registro en GitHub para que podamos encontrar más pistas y arreglar esta pregunta. \nActualmente puede ir a la instalación automática para desinstalar Forge y volver a instalarlo.
|
||||
game.crash.reason.optifine_repeat_installation=El juego actual no puede seguir ejecutándose debido a la instalación repetida de OptiFine. \nElimine OptiFine de la carpeta Mod o vaya a Gestión de juegos-Instalación automática para desinstalar OptiFine que se instala automáticamente.
|
||||
game.crash.reason.modmixin_failure=El juego actual no puede continuar ejecutándose debido a algunas fallas en la inyección de mods. \nEsto generalmente significa que el mod tiene un error o no es compatible con el entorno actual. \nPuede consultar el registro para ver si hay un mod incorrecto.
|
||||
game.crash.reason.file_or_content_verification_failed=El juego actual tiene un problema porque fallaron algunos archivos o la verificación de contenido. \nIntente eliminar esta versión (incluidas las modificaciones) y vuelva a descargarla, o intente usar un proxy cuando vuelva a descargar, etc.
|
||||
game.crash.reason.mod_repeat_installation=El juego actual tiene múltiples Mods idénticos instalados repetidamente, y cada Mod solo puede aparecer una vez. Elimina los Mods repetidos y luego inicia el juego.
|
||||
game.crash.reason.forge_error=Forge puede haber proporcionado un mensaje de error.\nPuede ver el registro y realizar las acciones correspondientes de acuerdo con la información de registro en el informe de errores.\nSi no ve un mensaje de error, puede consultar el informe de errores para saber cómo ocurrió el error.\n%1$s
|
||||
game.crash.reason.mod_solution0=El juego actual no puede seguir ejecutándose debido a algunos problemas de modificación.\nPuede consultar el registro para ver si hay un mod incorrecto.
|
||||
game.crash.reason.mod_profile_causes_game_crash=El juego actual no puede seguir ejecutándose debido a un problema con el perfil de mod.\nPuede consultar el registro del mod defectuoso y su archivo de configuración.
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution=Forge puede haber dado un mensaje de error.\nPuede ver el registro y realizar las acciones correspondientes de acuerdo con la información de registro en el informe de errores.\nSi no ve un mensaje de error, puede consultar el informe de errores para saber cómo ocurrió el error.
|
||||
game.crash.reason.mod_resolution0=El juego actual no puede seguir ejecutándose debido a algunos problemas de modificación.\nPuede consultar el registro para ver si hay un mod incorrecto.
|
||||
game.crash.reason.java_version_is_too_high=El juego actual se bloqueó porque la versión de Java es demasiado alta y no puede seguir ejecutándose.\nCambie a una versión anterior de Java en la pestaña Java Path de Configuración global del juego o Configuración específica del juego antes de iniciar el juego.\nSi no es así, puede descargarlo desde <a href="https://www.java.com/download/">java.com (Java8)</a> o <a href="https://bell-sw.com/pages/downloads/#downloads">BellSoft Liberica Full JRE (Java17)</a> y otras plataformas para descargar e instalar una (reinicie el iniciador después de la instalación).
|
||||
game.crash.reason.mod_name=El juego actual no puede continuar ejecutándose debido a un problema con el nombre del archivo mod. El nombre del archivo de\nMod solo debe usar mayúsculas y minúsculas (Aa ~ Zz), números (0 ~ 9), líneas horizontales (-), subrayado (_) y puntos (.) en toda la mitad del inglés.\n Por favor, vaya a la carpeta mod para agregar un carácter de Cumplimiento anterior a todos los nombres de archivo mod que no cumplan.
|
||||
game.crash.reason.incomplete_forge_installation=O jogo atual não pode continuar devido a uma instalação incompleta do Forge / NeoForge.\nDesinstale e reinstale o Forge / NeoForge em Configurações de versão - Instalação automática.
|
||||
game.crash.reason.modlauncher_8=El juego se ha bloqueado porque tu versión actual de Forge no es compatible con tu instalación de Java. Por favor, intente actualizar Forge, o intente utilizar Java 8u312/11.0.13/17.0.1 o versiones anteriores.\n\
|
||||
\n\
|
||||
8u312 y anteriores\:\n\
|
||||
https://oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html
|
||||
https://oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html\n\
|
||||
\n\
|
||||
11.0.13 y anteriores\:\n\
|
||||
https://oracle.com/java/technologies/javase/jdk11-archive-downloads.html
|
||||
https://oracle.com/java/technologies/javase/jdk11-archive-downloads.html\n\
|
||||
\n\
|
||||
17.0.1 y anteriores\:\n\
|
||||
https://oracle.com/java/technologies/javase/jdk17-archive-downloads.html
|
||||
@@ -499,21 +505,21 @@ game.crash.reason.no_class_def_found_error=El juego no puede ejecutarse debido a
|
||||
A su instancia de juego le falta %1$s, esto puede deberse a que falta un mod, a que hay un mod incompatible instalado o a que algunos archivos pueden estar dañados.\n\
|
||||
\n\
|
||||
Puede que tengas que reinstalar el juego y todos los mods o pedir ayuda a alguien.
|
||||
game.crash.reason.no_sethod_error=El juego no puede ejecutarse debido a un código incompleto.\n\
|
||||
game.crash.reason.no_such_method_error=El juego no puede ejecutarse debido a un código incompleto.\n\
|
||||
\n\
|
||||
Es posible que a su instancia de juego le falte un mod, que haya instalado un mod incompatible o que algunos archivos estén dañados.\n\
|
||||
\n\
|
||||
Puede que tengas que reinstalar el juego y todos los mods o pedir ayuda a alguien.
|
||||
game.crash.reason.opengl_not_supported=El juego se ha bloqueado porque OpenGL no es compatible con su controlador de gráficos.\n\
|
||||
\n\
|
||||
Si está transmitiendo el juego a través de Internet o utilizando un entorno de escritorio remoto, por favor, intente jugar el juego en su entorno local.
|
||||
Si está transmitiendo el juego a través de Internet o utilizando un entorno de escritorio remoto, por favor, intente jugar el juego en su entorno local.\n\
|
||||
O bien, puede intentar actualizar su controlador a la última versión y volver a intentarlo.\n\
|
||||
\n\
|
||||
Si tu ordenador tiene una tarjeta gráfica discreta, por favor, asegúrate de que el juego la está utilizando para el renderizado. Si el problema persiste, considera la posibilidad de adquirir una nueva tarjeta gráfica o un nuevo ordenador.
|
||||
game.crash.reason.openj9=El juego no puede ejecutarse en una máquina virtual OpenJ9. Por favor, cambia a una VM Java Hotspot en la configuración del juego y vuelve a ejecutar el juego. Si no tienes una, puedes descargar una en línea.
|
||||
game.crash.reason.out_of_memory=El juego se ha bloqueado porque se ha quedado sin memoria.\n\
|
||||
\n\
|
||||
Esto puede deberse a que no hay suficiente memoria disponible, o a que hay demasiados mods instalados. Puedes intentar solucionarlo aumentando la memoria asignada en la configuración del juego.
|
||||
Esto puede deberse a que no hay suficiente memoria disponible, o a que hay demasiados mods instalados. Puedes intentar solucionarlo aumentando la memoria asignada en la configuración del juego.\n\
|
||||
Si sigues encontrando estos problemas, es posible que necesites una mejor computadora.
|
||||
game.crash.reason.resolution_too_high=El juego se ha bloqueado porque estás utilizando un resource packs cuya resolución de textura es demasiado alta.\n\
|
||||
\n\
|
||||
@@ -538,11 +544,6 @@ game.crash.reason.unsatisfied_link_error=No se puede iniciar Minecraft porque fa
|
||||
Si ha modificado la configuración de la biblioteca nativa, por favor, asegúrese de que estas bibliotecas existen. O, por favor, intente iniciar de nuevo después de revertir a los valores predeterminados.\n\
|
||||
Si no lo ha hecho, por favor, compruebe si le faltan mods de dependencia.\n\
|
||||
De lo contrario, si usted cree que esto es causado por HMCL, por favor, comentarios a nosotros.
|
||||
game.crash.reason.failed_to_load_a_library=Failed to load a library.\n\
|
||||
\n\
|
||||
Si ha modificado la configuración de la biblioteca nativa, por favor, asegúrese de que estas bibliotecas existen. O, por favor, intente iniciar de nuevo después de revertir a los valores predeterminados.\n\
|
||||
Si no lo ha hecho, por favor, compruebe si le faltan mods de dependencia.\n\
|
||||
De lo contrario, si usted cree que esto es causado por HMCL, por favor, comentarios a nosotros.
|
||||
game.crash.title=Juego interrumpido
|
||||
game.directory=Ruta del juego
|
||||
game.version=Versión del juego
|
||||
@@ -597,6 +598,36 @@ install.new_game.malformed=Nombre no válido
|
||||
install.select=Seleccione una operación
|
||||
install.success=Instalado con éxito.
|
||||
|
||||
java.add=Añadir Java
|
||||
java.add.failed=Este Java no es válido o es incompatible con la plataforma actual.
|
||||
java.disable=Deshabilitar este Java
|
||||
java.disable.confirm=¿Está seguro de que desea desactivar este Java?
|
||||
java.disabled.management=Java desactivado
|
||||
java.disabled.management.remove=Eliminar este Java de la lista
|
||||
java.disabled.management.restore=Activar este Java
|
||||
java.download=Descargar Java
|
||||
java.download.load_list.failed=Error al cargar la lista de versiones
|
||||
java.download.more=Más distribuciones de Java
|
||||
java.download.prompt=Elija la versión de Java que desea descargar:
|
||||
java.download.distribution=Distribución
|
||||
java.download.version=Versión
|
||||
java.download.packageType=Tipo de paquete
|
||||
java.management=Gestión Java
|
||||
java.info.architecture=Arquitectura
|
||||
java.info.vendor=Proveedor
|
||||
java.info.version=Versión
|
||||
java.info.disco.distribution=Distribución
|
||||
java.install=Instalar Java
|
||||
java.install.archive=Fuente Path
|
||||
java.install.failed.exists=Este nombre ya tiene dueño
|
||||
java.install.failed.invalid=Este archivo no es un paquete de instalación de Java válido, por lo que no se puede instalar.
|
||||
java.install.failed.unsupported_platform=Este Java no es compatible con la plataforma actual, por lo que no puede instalarse.
|
||||
java.install.name=Nombre
|
||||
java.install.warning.invalid_character=Carácter ilegal en el nombre
|
||||
java.reveal=Revelar el directorio de Java
|
||||
java.uninstall=Desinstalar Java
|
||||
java.uninstall.confirm=¿Está seguro de que desea desinstalar este Java? ¡Esta acción no se puede deshacer!
|
||||
|
||||
lang=Español
|
||||
lang.default=Usar idioma del sistema
|
||||
|
||||
@@ -620,8 +651,6 @@ launch.advice.too_large_memory_for_32bit=Has asignado un tamaño de memoria mayo
|
||||
launch.advice.vanilla_linux_java_8=Minecraft 1.12.2 o inferior sólo admite Java 8 para la plataforma Linux x86-64, porque las versiones posteriores no pueden cargar las bibliotecas nativas de 32 bits como liblwjgl.so\n\
|
||||
\n\
|
||||
Por favor, descárguelo de java.com, o instale OpenJDK 8.
|
||||
launch.advice.vanilla_x86=Minecraft actualmente no proporciona soporte oficial para arquitecturas distintas de x86 o x86-64.\n\
|
||||
Puedes intentar descargar la librería nativa de tu plataforma y especificar su ruta, luego vuelve a intentarlo.
|
||||
launch.advice.vanilla_x86.translation=Minecraft no proporciona actualmente soporte oficial para arquitecturas distintas de x86 y x86-64.\n\
|
||||
Por favor, instale Java para x86-64 para jugar a Minecraft a través del entorno de traducción Rosetta, o descargue sus bibliotecas nativas correspondientes y especifique su ruta.
|
||||
launch.failed=No se puede ejecutar
|
||||
@@ -659,7 +688,7 @@ launcher.background.translucent=Translúcido
|
||||
launcher.cache_directory=Directorio de la caché
|
||||
launcher.cache_directory.clean=Borrar caché
|
||||
launcher.cache_directory.choose=Elegir el directorio de la caché
|
||||
launcher.cache_directory.default=Por defecto (%AppData%/.minecraft o ~/.minecraft)
|
||||
launcher.cache_directory.default=Por defecto (%APPDATA%/.minecraft o ~/.minecraft)
|
||||
launcher.cache_directory.disabled=Desactivado
|
||||
launcher.cache_directory.invalid=No se ha podido crear el directorio de la caché, volviendo a los valores por defecto.
|
||||
launcher.contact=Contacta con nosotros
|
||||
@@ -738,7 +767,6 @@ modpack.scan=Análisis del índice de modpacks
|
||||
modpack.task.install=Instalar Modpack
|
||||
modpack.task.install.error=No se ha podido identificar este modpack. Actualmente sólo soportamos los modpacks Curse, Modrinth, MultiMC y MCBBS.
|
||||
modpack.type.curse=Curse
|
||||
modpack.type.curse.tolerable_error=No se han podido descargar las dependencias, puedes intentar continuar la descarga ejecutando esta instancia del juego.
|
||||
modpack.type.curse.error=No se han podido descargar las dependencias de CurseForge, inténtalo de nuevo o utiliza una conexión proxy.
|
||||
modpack.type.curse.not_found=Algunas dependencias ya no están disponibles, por favor intenta instalar una versión más reciente del modpack.
|
||||
modpack.type.manual.warning=Este archivo contiene una copia completa de una instancia de Minecraft. La mayoría de las veces, sólo tienes que descomprimirlo y ejecutar el juego usando su launcher incorporado. Pero, HMCL todavía puede importarlo, sin garantía de su utilidad, ¿aún continúa?
|
||||
@@ -746,7 +774,7 @@ modpack.type.mcbbs=Tipo MCBBS
|
||||
modpack.type.mcbbs.export=Puede ser importado por ¡Hello Minecraft! Launcher
|
||||
modpack.type.modrinth=Modrinth
|
||||
modpack.type.multimc=MultiMC
|
||||
¡modpack.type.multimc.export=Puede ser importado por Hello Minecraft! Launcher y MultiMC
|
||||
modpack.type.multimc.export=Puede ser importado por Hello Minecraft! Launcher y MultiMC
|
||||
modpack.type.server=Actualización automática del modpack desde el servidor
|
||||
modpack.type.server.export=Permite al propietario del servidor actualizar la instancia del juego de forma remota
|
||||
modpack.type.server.malformed=Manifiesto de modpack inválido, por favor, consulte al creador del modpack del servidor para solucionar este problema.
|
||||
@@ -763,7 +791,7 @@ modpack.wizard.step.initialization.exported_version=Versión del juego a exporta
|
||||
modpack.wizard.step.initialization.force_update=Forzar la actualización del modpack a la última versión (necesitarás un servicio de alojamiento de archivos)
|
||||
modpack.wizard.step.initialization.include_launcher=Incluir el launcher
|
||||
modpack.wizard.step.initialization.save=Exportar a...
|
||||
modpack.wizard.step.initialization.warning=Antes de crear un modpack, por favor asegúrate de que el juego se ejecuta, y que es una versión de lanzamiento en lugar de una versión instantánea. El launcher guardará su configuración de descarga.
|
||||
modpack.wizard.step.initialization.warning=Antes de crear un modpack, por favor asegúrate de que el juego se ejecuta, y que es una versión de lanzamiento en lugar de una versión instantánea. El launcher guardará su configuración de descarga.\n\
|
||||
\n\
|
||||
Ten en cuenta que no se te permite añadir mods y resource packs que se digan explícitamente que no se pueden distribuir o poner en un modpack.
|
||||
modpack.wizard.step.initialization.server=Haga clic aquí para ver más tutoriales para hacer un modpack de servidor que se pueda actualizar automáticamente.
|
||||
@@ -802,7 +830,8 @@ mods.add.success=%s fue instalado con éxito.
|
||||
mods.category=Categoría
|
||||
mods.check_updates=Comprobar actualizaciones
|
||||
mods.check_updates.current_version=Versión actual
|
||||
mods.check_updates.failed=No se han podido descargar algunos de los archivos.
|
||||
mods.check_updates.failed_check=No se ha podido comprobar si hay actualizaciones.
|
||||
mods.check_updates.failed_download=No se han podido descargar algunos de los archivos.
|
||||
mods.check_updates.file=Archivo
|
||||
mods.check_updates.source=Fuente
|
||||
mods.check_updates.target_version=Versión de destino
|
||||
|
||||
@@ -18,31 +18,35 @@
|
||||
|
||||
# Contributors: zhixuan2333
|
||||
|
||||
about=About
|
||||
about=について
|
||||
about.copyright=著作権
|
||||
about.copyright.statement=Copyright © 2024 huangyuhui。
|
||||
about.author=Author
|
||||
about.author.statement=bilibili : @huanghongxun
|
||||
about.copyright.statement=Copyright © 2024 huangyuhui
|
||||
about.author=著者
|
||||
about.author.statement=bilibili @huanghongxun
|
||||
about.claim=EULA
|
||||
about.claim.statement=テキスト全体のリンクをクリックします。
|
||||
about.dependency=Dependencies
|
||||
about.claim.statement=全文はこのリンクをクリック
|
||||
about.dependency=依存関係
|
||||
about.legal=法的承認
|
||||
about.thanks_to=Thanks to
|
||||
about.thanks_to.bangbang93.statement=BMCLAPIダウンロードソースプロバイダー。
|
||||
about.thanks_to.contributors=問題、プルリクエストなどを介してこのプロジェクトに参加したすべての貢献者。
|
||||
about.thanks_to.contributors.statement=Hello Minecraftをサポートしてくれたオープンソースコミュニティに感謝します!ランチャー
|
||||
about.thanks_to.gamerteam.statement=デフォルトの背景画像プロバイダー。
|
||||
about.thanks_to.glavo.statement=HMCLに多くのテクニカルサポートを提供
|
||||
about.thanks_to=感謝します…
|
||||
about.thanks_to.bangbang93.statement=BMCLAPIダウンロードミラープロバイダー。寄付をご検討ください!
|
||||
about.thanks_to.burningtnt.statement=HMCLに多くのテクニカルサポートを提供
|
||||
about.thanks_to.contributors=GitHubのすべての貢献者
|
||||
about.thanks_to.contributors.statement=HMCLをサポートしてくれたオープンソースコミュニティに感謝する
|
||||
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.mcmod=mcmod.cn
|
||||
about.thanks_to.mcmod.statement=Mod中国語の名前翻訳プロバイダー。
|
||||
about.thanks_to.red_lnn.statement=デフォルトの背景画像プロバイダー。
|
||||
about.thanks_to.zkitefly.statement=HMCLドキュメントメンテナ
|
||||
about.thanks_to.mcbbs=MCBBS (Minecraft中国語フォーラム)
|
||||
about.thanks_to.mcbbs.statement=中国本土ユーザー向けのmcbbs.netダウンロードミラープロバイダー(もう利用できません)
|
||||
about.thanks_to.mcmod=MCMod (mcmod.cn)
|
||||
about.thanks_to.mcmod.statement=様々なMODの簡体字中国語名前翻訳とウィキを提供する
|
||||
about.thanks_to.red_lnn.statement=デフォルトの背景画像プロバイダー
|
||||
about.thanks_to.shulkersakura.statement=HMCLロゴプロバイダー
|
||||
about.thanks_to.users=HMCLユーザーグループのメンバー
|
||||
about.thanks_to.users.statement=寄付、バグレポートなどに感謝します。
|
||||
about.thanks_to.yushijinhun.statement=authlib-インジェクターのサポート
|
||||
about.thanks_to.users.statement=寄付、バグレポートなどに感謝します
|
||||
about.thanks_to.yushijinhun.statement=authlib-injector関連のサポートを提供する
|
||||
about.open_source=オープンソース
|
||||
about.open_source.statement=GPL v3(https://github.com/HMCL-dev/HMCL/)
|
||||
about.open_source.statement=GPL v3 (https://github.com/HMCL-dev/HMCL)
|
||||
|
||||
account=アカウント
|
||||
account.cape=マント
|
||||
@@ -136,6 +140,7 @@ assets.index.malformed=アセットインデックスの形式が正しくあり
|
||||
button.cancel=キャンセル
|
||||
button.change_source=ダウンロードソースの変更
|
||||
button.clear=クリア
|
||||
button.copy_and_exit=コピーして終了
|
||||
button.delete=削除
|
||||
button.edit=編集
|
||||
button.install=インストール
|
||||
@@ -144,19 +149,23 @@ button.no=いいえ
|
||||
button.ok=OK
|
||||
button.refresh=更新
|
||||
button.remove=削除
|
||||
button.remove.confirm=削除してもよろしいですか?この操作をロールバックすることはできません!
|
||||
button.remove.confirm=本当に完全に削除しますか?この操作は元に戻せません!
|
||||
button.retry=リトライ
|
||||
button.save=保存
|
||||
button.save_as=名前を付けて保存
|
||||
button.select_all=すべて選択
|
||||
button.view=読む
|
||||
button.yes=はい
|
||||
|
||||
chat=グループチャット
|
||||
|
||||
color.recent=推奨
|
||||
color.custom=カスタムカラー
|
||||
|
||||
crash.NoClassDefFound=「HelloMinecraft!Launcher」ソフトウェアが破損していないことを確認してください。
|
||||
crash.user_fault=OSまたはJava環境が正しくインストールされていない可能性があり、クラッシュする可能性があります。Javaランタイム環境またはコンピュータを確認してください。
|
||||
crash.NoClassDefFound=このソフトウェアの整合性を確認するか、Javaの更新をお試しください。
|
||||
crash.user_fault=JavaまたはOSの環境が壊れているため、ランチャーがクラッシュしました。JavaまたはOSが正しくインストールされているかご確認ください。
|
||||
|
||||
curse.category.0=すべて
|
||||
curse.category.0=全て
|
||||
|
||||
# https://addons-ecs.forgesvc.net/api/v2/category/section/4471
|
||||
curse.category.4474=Sci-Fi
|
||||
@@ -350,12 +359,9 @@ game.crash.reason.entity=エンティティが原因でゲームを実行でき
|
||||
game.crash.reason.fabric_version_0_12=Fabric 0.12以降は、現在インストールされているmodと互換性がありません。ファブリックを0.11.7にダウングレードする必要があります。
|
||||
game.crash.reason.fabric_warnings=Fabricはいくつかの警告を出します:\n%1$s
|
||||
game.crash.reason.modmixin_failure=mod インジェクションの失敗により、現在のゲームを続行できません。\nこれは通常、MOD にバグがあるか、現在の環境と互換性がないことを意味します。\n間違った mod のログを確認できます。
|
||||
game.crash.reason.file_or_content_verification_failed=一部のファイルまたはコンテンツの検証に失敗したため、現在のゲームに問題があります。\nこのバージョン (mod を含む) を削除して再ダウンロードするか、再ダウンロード時にプロキシを使用するなどしてください。
|
||||
game.crash.reason.mod_repeat_installation=現在のゲームには複数の同一の Mod が繰り返しインストールされており、各 Mod は 1 回しか表示できません。ゲームを開始する前に繰り返しの Mod を削除してください。
|
||||
game.crash.reason.forge_error=Forge がエラー メッセージを表示した可能性があります。 \nログを表示し、エラー レポートのログ情報に従って対応するアクションを実行できます。 \nエラー メッセージが表示されない場合は、エラー レポートをチェックして、エラーがどのように発生したかを知ることができます。\n%1$s
|
||||
game.crash.reason.mod_resolution0=mod の問題により、現在のゲームを続行できません。 \n間違った mod のログを確認できます。
|
||||
game.crash.reason.mod_profile_causes_game_crash=mod プロファイルに問題があるため、現在のゲームを続行できません。 \n障害のある mod とその構成ファイルのログを確認できます。
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution=Forge がエラー メッセージを表示した可能性があります。 \nログを表示し、エラー レポートのログ情報に従って対応するアクションを実行できます。 \nエラー メッセージが表示されない場合は、エラー レポートをチェックして、エラーがどのように発生したかを知ることができます。
|
||||
game.crash.reason.java_version_is_too_high=Java のバージョンが高すぎて実行を継続できないため、現在のゲームがクラッシュしました。 \nゲームを起動する前に、グローバル ゲーム設定またはゲーム固有の設定の Java パス タブで Java の以前のバージョンに切り替えてください。 \nそうでない場合は、<a href="https://www.java.com/download/">java.com (Java8)</a> または <a href="https://bell-sw.com/pages/downloads/#downloads">BellSoft Liberica Full JRE (Java17)</a> およびその他のプラットフォームをダウンロードしてインストールします (インストール後にランチャーを再起動します)。
|
||||
game.crash.reason.mod_name=現在のゲームはModファイル名の問題で続行できません。\nModファイル名は、英文の全半角の大文字と小文字(Aa ~ Zz)、数字(0 ~ 9)、横線(-)、アンダースコア(_)、点(.)のみを使用してください。\n上記のコンプライアンス文字をModフォルダに追加してください。
|
||||
game.crash.reason.incomplete_forge_installation=Forge / NeoForge のインストールが不完全なため、現在のゲームを続行できません。\nバージョン設定 - 自動インストールで Forge / NeoForge をアンインストールしてから再インストールしてください。
|
||||
@@ -400,7 +406,6 @@ game.crash.reason.stacktrace=不明。[ログ]ボタンをクリックすると
|
||||
game.crash.reason.too_old_java=Java仮想マシンのバージョンが低すぎるため、ゲームを実行できません。\nゲーム設定でJava仮想マシンの新しいバージョン(%1$s)に切り替えて、ゲームを再起動する必要があります。そうでない場合は、オンラインでダウンロードできます。
|
||||
game.crash.reason.unknown=不明。「ログ」ボタンをクリックすると詳細を確認できます。
|
||||
game.crash.reason.unsatisfied_link_error=必要なネイティブライブラリがないため、ゲームを実行できません。\n不足しているネイティブライブラリ:%1$s。\nゲーム設定でネイティブライブラリパスオプションを変更した場合は、元に戻すことをお勧めします。標準モードに切り替えます。\nすでに標準モードになっている場合は、不足しているネイティブライブラリがmodまたはゲームに属しているかどうかを確認してください。HMCLが原因であることが確実な場合は、フィードバックをお送りください。\nネイティブライブラリパスを本当にカスタマイズする必要がある場合は、ゲームに必要なすべてのネイティブライブラリをディレクトリに配置する必要があります。
|
||||
game.crash.reason.failed_to_load_a_library=ネイティブ ライブラリのロードに失敗したため、ゲームを実行できません。\nゲーム設定でネイティブライブラリパスオプションを変更した場合は、元に戻すことをお勧めします。標準モードに切り替えます。\nすでに標準モードになっている場合は、不足しているネイティブライブラリがmodまたはゲームに属しているかどうかを確認してください。HMCLが原因であることが確実な場合は、フィードバックをお送りください。\nネイティブライブラリパスを本当にカスタマイズする必要がある場合は、ゲームに必要なすべてのネイティブライブラリをディレクトリに配置する必要があります。
|
||||
game.crash.title=ゲームがクラッシュしました
|
||||
game.directory=ゲームディレクトリ
|
||||
game.version=ゲームバージョン
|
||||
@@ -455,6 +460,36 @@ install.new_game.malformed=無効な名前
|
||||
install.select=操作を選択します
|
||||
install.success=正常にインストールされました
|
||||
|
||||
java.add=Javaの追加
|
||||
java.add.failed=このJavaは無効であるか、現在のプラットフォームと互換性がない。
|
||||
java.disable=無効化
|
||||
java.disable.confirm=本当にこのJavaを無効にしますか?
|
||||
java.disabled.management=無効なJava
|
||||
java.disabled.management.remove=このJavaをリストから削除する
|
||||
java.disabled.management.restore=有効化
|
||||
java.download=Javaをダウンロード
|
||||
java.download.load_list.failed=バージョンリストの読み込みに失敗しました
|
||||
java.download.more=その他のJavaディストリビューション
|
||||
java.download.prompt=ダウンロードしたいJavaのバージョンを選択してください:
|
||||
java.download.distribution=配布の種類
|
||||
java.download.version=バージョン
|
||||
java.download.packageType=パッケージの種類
|
||||
java.management=Javaの管理
|
||||
java.info.architecture=アーキテクチャ
|
||||
java.info.vendor=発行元
|
||||
java.info.version=バージョン
|
||||
java.info.disco.distribution=配布の種類
|
||||
java.install=Javaのインストール
|
||||
java.install.archive=場所
|
||||
java.install.failed.exists=この名前はすでに使用されている
|
||||
java.install.failed.invalid=このアーカイブは有効なJavaインストール・パッケージではないため、インストールできません。
|
||||
java.install.failed.unsupported_platform=このJavaは現在のプラットフォームと互換性がないため、インストールできません。
|
||||
java.install.name=名前
|
||||
java.install.warning.invalid_character=名前に不正な文字が含まれています
|
||||
java.reveal=Javaディレクトリを表示する
|
||||
java.uninstall=このJavaをアンインストールする
|
||||
java.uninstall.confirm=本当にこのJavaをアンインストールしますか?この操作は元に戻せません!
|
||||
|
||||
lang=日本語
|
||||
lang.default=システム言語を使用する
|
||||
|
||||
@@ -467,8 +502,8 @@ launch.advice.forge2760_liteloader=Forge 2760以降はLiteLoaderと互換性が
|
||||
launch.advice.forge28_2_2_optifine=Forge28.2.2以降のバージョンはOptiFineと互換性がありません。Forgeを28.2.1以前のバージョンにダウングレードすることを検討してください。
|
||||
launch.advice.java8_1_13=Minecraft 1.13以降は、Java8以降でのみ実行できます。
|
||||
launch.advice.java8_51_1_13=Minecraft 1.13は、1.8.0_51より前のJava8でクラッシュする可能性があります。最新バージョンのJava8をインストールしてください。
|
||||
launch.advice.java9=Java9以降のバージョンのJavaでMinecraft1.12以前を起動することはできません。
|
||||
ゲームを高速化するには、launch.advice.newer_java=Java8をお勧めします。多くのMinecraft1.12以降、およびほとんどのModには、Java8が必要です。
|
||||
launch.advice.java9=Java9以降のバージョンのJavaでMinecraft1.12以前を起動することはできません。ゲームを高速化するには、Java8をお勧めします。
|
||||
launch.advice.newer_java=多くのMinecraft1.12以降、およびほとんどのModには、Java8が必要です。
|
||||
launch.advice.not_enough_space=割り当てたメモリが多すぎます。物理メモリサイズが%dMBであるため、ゲームがクラッシュする可能性があります。
|
||||
launch.advice.too_large_memory_for_32bit=32ビットJavaランタイム環境が原因で、割り当てたメモリが多すぎるため、ゲームがクラッシュする可能性があります。32ビットシステムの最大メモリ容量は1024MBです。
|
||||
launch.advice.vanilla_linux_java_8=Linux x86-64の場合、Minecraft1.12.2以下はJava8でのみ実行できます。\nJava9以降のバージョンでは、liblwjgl.soなどの32ビットネイティブライブラリをロードできません。
|
||||
@@ -506,7 +541,7 @@ launcher.background.translucent=半透明
|
||||
launcher.cache_directory=キャッシュ用のディレクトリ
|
||||
launcher.cache_directory.clean=クリアランス
|
||||
launcher.cache_directory.choose=キャッシュするディレクトリを選択します
|
||||
launcher.cache_directory.default=標準(%AppData%/.minecraft または ~/.minecraft)
|
||||
launcher.cache_directory.default=標準(%APPDATA%/.minecraft または ~/.minecraft)
|
||||
launcher.cache_directory.disabled=無効(常にゲームパスを使用する)
|
||||
launcher.cache_directory.invalid=無効なディレクトリ。デフォルト設定の復元。
|
||||
launcher.contact=お問い合わせ
|
||||
@@ -581,8 +616,6 @@ modpack.scan=このmodpackをスキャンしています
|
||||
modpack.task.install=Modpackのインポート
|
||||
modpack.task.install.error=このmodpackファイルは認識できません。CurseおよびMultiMCmodpackのみがサポートされています。
|
||||
modpack.type.curse=Curse
|
||||
modpack.type.curse.completion=Cursemodpackに関連するファイルをインストールします
|
||||
modpack.type.curse.tolerable_error=このmodpackのすべてのファイルのダウンロードを完了できません。対応するゲームバージョンを開始するときに、ダウンロードを再試行できます。ネットワークの問題により、数回再試行する場合があります。
|
||||
modpack.type.curse.error=このmodpackをインストールできません。再試行してください。
|
||||
modpack.type.curse.not_found=必要なリソースの一部が欠落しているため、ダウンロードできませんでした。最新バージョンまたは他のmodpackを検討してください。
|
||||
modpack.type.manual.warning=このmodpackをインポートする代わりに、おそらくこのmodpackファイルを直接解凍する必要があります。そして、バンドルされたランチャーを使用してゲームを起動します。このmodpackは、ランチャーによってエクスポートされるのではなく、.minecraftディレクトリを圧縮することによって手動で作成されます。HMCLはこのmodpackのインポートを試みることができます、続行しますか?
|
||||
@@ -632,7 +665,8 @@ mods.add.success=mods %s が正常に追加されました。
|
||||
mods.category=Category
|
||||
mods.check_updates=更新を確認
|
||||
mods.check_updates.current_version=Current
|
||||
mods.check_updates.failed=一部のファイルのダウンロードに失敗しました
|
||||
mods.check_updates.failed_check=更新のチェックに失敗しました
|
||||
mods.check_updates.failed_download=一部のファイルのダウンロードに失敗しました
|
||||
mods.check_updates.file=ファイル
|
||||
mods.check_updates.source=Source
|
||||
mods.check_updates.target_version=Target
|
||||
|
||||
@@ -22,22 +22,26 @@ about=О лаунчере
|
||||
about.copyright=Авторские права
|
||||
about.copyright.statement=Авторские права © 2024 huangyuhui.
|
||||
about.author=Автор
|
||||
about.author.statement=bilibili: @huanghongxun
|
||||
about.author.statement=bilibili @huanghongxun
|
||||
about.claim=EULA
|
||||
about.claim.statement=Кликните на ссылку, чтобы увидеть весь текст.
|
||||
about.dependency=Зависимости
|
||||
about.legal=Юридическое подтверждение
|
||||
about.thanks_to=Отдельная благодарность
|
||||
about.thanks_to.bangbang93.statement=За предоставление API скачивания BMCLAPI. Рассмотрите возможность пожертвования.
|
||||
about.thanks_to.bangbang93.statement=За предоставление зеркала загрузки BMCLAPI, пожалуйста, подумайте о пожертвовании!
|
||||
about.thanks_to.burningtnt.statement=Оказал большую техническую поддержку HMCL.
|
||||
about.thanks_to.contributors=Всем участникам на GitHub
|
||||
about.thanks_to.contributors.statement=Без потрясающего сообщества с открытым исходным кодом, Hello Minecraft! Launcher не смог бы добраться так далеко.
|
||||
about.thanks_to.contributors.statement=Без потрясающего сообщества с открытым исходным кодом, HMCL не смог бы добраться так далеко.
|
||||
about.thanks_to.gamerteam.statement=За предоставление фонового изображения.
|
||||
about.thanks_to.glavo.statement=Оказал большую техническую поддержку HMCL.
|
||||
about.thanks_to.glavo.statement=Отвечает за поддержание HMCL.
|
||||
about.thanks_to.zekerzhayard.statement=Оказал большую техническую поддержку HMCL.
|
||||
about.thanks_to.zkitefly.statement=Оказал большую техническую поддержку HMCL.
|
||||
about.thanks_to.mcmod=mcmod.cn
|
||||
about.thanks_to.mcmod.statement=За предоставление перевода на китайский и вики для различных модов.
|
||||
about.thanks_to.zkitefly.statement=Отвечает за поддержание документации HMCL.
|
||||
about.thanks_to.mcbbs=MCBBS (Китайский форум Minecraft)
|
||||
about.thanks_to.mcbbs.statement=За предоставление зеркала загрузки mcbbs.net для пользователей материкового Китая. (Больше недоступно)
|
||||
about.thanks_to.mcmod=MCMod (mcmod.cn)
|
||||
about.thanks_to.mcmod.statement=За предоставление упрощенного китайского перевода и вики для различных модов.
|
||||
about.thanks_to.red_lnn.statement=За предоставление фонового изображения.
|
||||
about.thanks_to.shulkersakura.statement=За предоставление логотипа для HMCL.
|
||||
about.thanks_to.users=Членам группы пользователей HMCL
|
||||
about.thanks_to.users.statement=Спасибо за пожертвования, отчёты об ошибках и так далее.
|
||||
about.thanks_to.yushijinhun.statement=За предоставление поддержки, связанной с authlib-injector.
|
||||
@@ -156,8 +160,11 @@ button.retry=Повторить снова
|
||||
button.save=Сохранить
|
||||
button.save_as=Сохранить как
|
||||
button.select_all=Выбрать все
|
||||
button.view=Просмотреть
|
||||
button.yes=Да
|
||||
|
||||
chat=Групповой чат
|
||||
|
||||
color.recent=Рекомендуемые
|
||||
color.custom=Пользовательский цвет
|
||||
|
||||
@@ -369,13 +376,10 @@ game.crash.reason.fabric_version_0_12=Fabric 0.12 (и выше) несовмес
|
||||
game.crash.reason.mixin_apply_mod_failed=Текущая игра не может продолжать работать из-за невозможности применения мода %1$s с помощью Mixin.\nВы можете попробовать удалить или обновить этот мод, чтобы решить проблему.
|
||||
game.crash.reason.fabric_warnings=Предупреждения от Fabric:\n%1$s
|
||||
game.crash.reason.modmixin_failure=Текущая игра не может продолжать работать из-за некоторых сбоев внедрения модов.\nОбычно это означает, что мод содержит ошибку или несовместим с текущей средой.\nВы можете проверить журнал на наличие неправильного мода.
|
||||
game.crash.reason.file_or_content_verification_failed=В текущей игре возникла проблема, поскольку не удалось проверить некоторые файлы или содержимое.\nПожалуйста, попробуйте удалить эту версию (включая моды) и загрузить заново, или попробуйте использовать прокси при повторной загрузке и т. д.
|
||||
game.crash.reason.mod_repeat_installation=В текущей игре неоднократно установлено несколько одинаковых модов, и каждый мод может появиться только один раз. Пожалуйста, удалите повторяющиеся моды перед запуском игры.
|
||||
game.crash.reason.need_jdk11=Текущая игра не может продолжать работать из-за неподходящей версии виртуальной машины Java.\nВам необходимо загрузить и установить Java 11, а также установить версию Java, начинающуюся с 11, в глобальных (конкретных) настройках игры.
|
||||
game.crash.reason.forge_error=Возможно, Forge предоставил сообщение об ошибке.\nВы можете просмотреть журнал и выполнить соответствующие действия в соответствии с информацией журнала в отчете об ошибках.\nЕсли вы не видите сообщения об ошибке, вы можете просмотреть отчет об ошибке, чтобы узнать, как она возникла.\n%1$s
|
||||
game.crash.reason.mod_resolution0=Текущая игра не может продолжать работать из-за некоторых проблем с модом.\nВы можете проверить журнал на наличие неправильного мода.
|
||||
game.crash.reason.mod_profile_causes_game_crash=Текущая игра не может продолжать работать из-за проблемы с профилем мода.\nВы можете проверить журнал на наличие неисправного мода и его конфигурационного файла.
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution=Forge мог выдать сообщение об ошибке.\nВы можете просмотреть журнал и выполнить соответствующие действия в соответствии с информацией журнала в отчете об ошибках.\nЕсли вы не видите сообщения об ошибке, вы можете просмотреть отчет об ошибке, чтобы узнать, как она возникла.
|
||||
game.crash.reason.java_version_is_too_high=Текущая игра аварийно завершилась из-за того, что версия Java слишком высока и не может продолжать работать.\nПеред запуском игры переключитесь на более раннюю версию Java на вкладке "Путь к Java" в глобальных настройках игры или в настройках игры.\nЕсли нет, вы можете загрузить его с <a href="https://www.java.com/download/">java.com (Java8)</a> или <a href="https://bell- sw.com/pages/downloads">BellSoft Liberica Full JRE (Java17)</a> и другие платформы, чтобы загрузить и установить ее (перезапустите программу запуска после установки).
|
||||
game.crash.reason.mod_name=Текущая игра не может продолжать работать из - за проблем с именем файла Mod. Имя файла\nMod должно быть использовано только в английском языке в полном углу с большими буквами (Aa ~ Zz), цифрами (0 ~ 9), горизонтальными линиями (-), подчеркнутыми (_) и точками (.) .\nПожалуйста, добавьте символ соответствия в папку Mod для всех несовместимых имен файлов Mod.
|
||||
game.crash.reason.incomplete_forge_installation=Текущая игра не может быть продолжена из-за незавершенной установки Forge / NeoForge.\nУдалите и переустановите Forge / NeoForge в настройках версии - Автоматическая установка.
|
||||
@@ -420,7 +424,6 @@ game.crash.reason.stacktrace=Неизвестно. Вы можете просм
|
||||
game.crash.reason.too_old_java=Невозможно запустить игру из-за того, что версия виртуальной машины Java слишком низкая.\nYou need to switch to a newer version (%1$s) of Java virtual machine in the game settings and restart the game. If not, you can download it online.
|
||||
game.crash.reason.unknown=Неизвестно. Вы можете просмотреть подробности, кликнув на кнопку «Журналы».
|
||||
game.crash.reason.unsatisfied_link_error=Невозможно запустить игру из-за того, что отсутствуют необходимые встроенные библиотеки.\nОтсутствующая нативная библиотека: %1$s.\nЕсли в настройках игры вы изменили параметр пути к нативной библиотеке, лучше переключиться обратно в стандартный режим.\nЕсли это уже стандартный режим, проверьте, принадлежит ли отсутствующая нативная библиотека моду или игре. Если вы уверены, что это произошло по вине HMCL, вы можете написать нам через обратную связь.\nЕсли вам действительно нужно настроить путь к нативным библиотекам, вы должны поместить в каталог все нативные библиотеки, которые требуются игре.
|
||||
game.crash.reason.failed_to_load_a_library=Не удалось запустить игру, так как не удалось загрузить встроенную библиотеку.\nЕсли в настройках игры вы изменили параметр пути к нативной библиотеке, лучше переключиться обратно в стандартный режим.\nЕсли это уже стандартный режим, проверьте, принадлежит ли отсутствующая нативная библиотека моду или игре. Если вы уверены, что это произошло по вине HMCL, вы можете написать нам через обратную связь.\nЕсли вам действительно нужно настроить путь к нативным библиотекам, вы должны поместить в каталог все нативные библиотеки, которые требуются игре.
|
||||
game.crash.title=Игра вылетела
|
||||
game.directory=Путь игры
|
||||
game.version=Версия игры
|
||||
@@ -475,6 +478,36 @@ install.new_game.malformed=Недопустимое имя
|
||||
install.select=Выберите операцию
|
||||
install.success=Успешно установлено.
|
||||
|
||||
java.add=Добавить Java
|
||||
java.add.failed=Этот Java недопустим или несовместим с текущей платформой.
|
||||
java.disable=Отключить Java
|
||||
java.disable.confirm=Вы уверены, что хотите отключить эту Java?
|
||||
java.disabled.management=Отключенная Java
|
||||
java.disabled.management.remove=Удалить эту Java из списка
|
||||
java.disabled.management.restore=Включить эту Java
|
||||
java.download=Скачать Java
|
||||
java.download.load_list.failed=Не удалось загрузить список версий
|
||||
java.download.more=Больше дистрибутивов Java
|
||||
java.download.prompt=Выберите версию Java, которую вы хотите загрузить:
|
||||
java.download.distribution=Дистрибуция
|
||||
java.download.version=Версия
|
||||
java.download.packageType=Тип упаковки
|
||||
java.management=Управление Java
|
||||
java.info.architecture=Архитектура
|
||||
java.info.vendor=Поставщик
|
||||
java.info.version=Версия
|
||||
java.info.disco.distribution=Дистрибуция
|
||||
java.install=Установите Java
|
||||
java.install.archive=Расположение
|
||||
java.install.failed.exists=Это имя уже используется
|
||||
java.install.failed.invalid=Этот архив не является допустимым установочным пакетом Java, поэтому его установка невозможна.
|
||||
java.install.failed.unsupported_platform=Эта Java несовместима с текущей платформой, поэтому ее невозможно установить.
|
||||
java.install.name=Название
|
||||
java.install.warning.invalid_character=Неправильный символ в названии
|
||||
java.reveal=Откройте каталог Java
|
||||
java.uninstall=Удалить Java
|
||||
java.uninstall.confirm=Вы уверены, что хотите удалить эту Java? Это действие нельзя отменить!
|
||||
|
||||
lang=Русский
|
||||
lang.default=Использовать язык системы
|
||||
|
||||
@@ -530,7 +563,7 @@ launcher.background.translucent=Полупрозрачный
|
||||
launcher.cache_directory=Папка с кэшем
|
||||
launcher.cache_directory.clean=Очистить кэш
|
||||
launcher.cache_directory.choose=Выберите папку для кэша
|
||||
launcher.cache_directory.default=По умолчанию (%AppData%/.minecraft или ~/.minecraft)
|
||||
launcher.cache_directory.default=По умолчанию (%APPDATA%/.minecraft или ~/.minecraft)
|
||||
launcher.cache_directory.disabled=Отключено
|
||||
launcher.cache_directory.invalid=Не удаётся создать папку для кэша, возвращаем к значению по умолчанию.
|
||||
launcher.contact=Связаться с нами
|
||||
@@ -606,8 +639,6 @@ modpack.scan=Разбор индекса модпака
|
||||
modpack.task.install=Установить модпак
|
||||
modpack.task.install.error=Не удаётся идентифицировать этот модпак. Поддерживаются только модпаки Curse, Modrinth, MultiMC и MCBBS.
|
||||
modpack.type.curse=Curse
|
||||
modpack.type.curse.completion=Установите файлы, связанные с модпаком Curse
|
||||
modpack.type.curse.tolerable_error=Мы не можем завершить скачивание всех файлов этого модпака. Вы можете повторить скачивание при запуске соответствующей версии игры. Вы можете повторить попытку несколько раз из-за проблем с сетью.
|
||||
modpack.type.curse.error=Невозможно установить этот модпак. Повторите ещё раз.
|
||||
modpack.type.curse.not_found=Некоторые из необходимых ресурсов отсутствуют и поэтому не могут быть загружены. Скачайте последнюю версию или другие модпаки.
|
||||
modpack.type.manual.warning=Возможно, вам нужно напрямую распаковать файл этого модпака, а не импортировать его. И запустите игру с помощью прилагаемого лаунчера. Этот модпак создаётся вручную путем сжатия директории .minecraft, а не экспортируется лаунчером. HMCL может попытаться импортировать этот модпак, продолжать?
|
||||
@@ -665,7 +696,8 @@ mods.add.success=%s был успешно установлен.
|
||||
mods.category=Категория
|
||||
mods.check_updates=Проверить обновления
|
||||
mods.check_updates.current_version=Текущая версия
|
||||
mods.check_updates.failed=Не удаётся скачать некоторые файлы.
|
||||
mods.check_updates.failed_check=Не удалось проверить обновления.
|
||||
mods.check_updates.failed_download=Не удаётся скачать некоторые файлы.
|
||||
mods.check_updates.file=Файл
|
||||
mods.check_updates.source=Источник
|
||||
mods.check_updates.target_version=Целевая версия
|
||||
@@ -712,7 +744,7 @@ world.import.failed=Не удаётся импортировать этот ми
|
||||
world.import.invalid=Не удаётся разобрать сохранение.
|
||||
world.info.title=Сведения о мире %s
|
||||
world.info.basic=Основные сведения
|
||||
world.info.allow_cheats=Разрешить читы
|
||||
world.info.allow_cheats=Разрешить команды/читы
|
||||
world.info.dimension.the_nether=Нижний мир
|
||||
world.info.dimension.the_end=Край
|
||||
world.info.difficulty=Сложность
|
||||
|
||||
@@ -65,7 +65,7 @@ account.failed.injector_download_failure=無法下載 authlib-injector,請檢
|
||||
account.failed.invalid_credentials=你的使用者名稱或密碼錯誤,或者登入次數過多被暫時禁止登入,請稍後再試。
|
||||
account.failed.invalid_password=密碼無效
|
||||
account.failed.invalid_token=請嘗試登出並重新輸入密碼登入。
|
||||
account.failed.migration=你的帳戶需要遷移至 Microsoft 帳戶。如果你已經遷移,你需要使用 Microsoft 方式登入遷移後的帳戶。
|
||||
account.failed.migration=你的帳戶需要遷移至 Microsoft 帳戶。如果你已經遷移,你需要使用遷移後的 Microsoft 帳戶登入。
|
||||
account.failed.no_character=該帳戶沒有角色。
|
||||
account.failed.server_disconnected=無法訪問登入伺服器,帳戶資訊重新整理失敗。\n\
|
||||
你可以選取「再次重新整理帳戶」重新嘗試。\n\
|
||||
@@ -98,11 +98,11 @@ account.copy_uuid=複製該帳戶的 UUID
|
||||
account.methods=登入方式
|
||||
account.methods.authlib_injector=authlib-injector 登入
|
||||
account.methods.microsoft=Microsoft 帳戶
|
||||
account.methods.microsoft.birth=如何修改帳戶出生日期
|
||||
account.methods.microsoft.deauthorize=解除帳戶授權
|
||||
account.methods.microsoft.birth=如何變更帳戶出生日期
|
||||
account.methods.microsoft.deauthorize=移除應用存取權
|
||||
account.methods.microsoft.close_page=已完成 Microsoft 帳戶授權,接下來啟動器還需要完成其餘登入步驟。你現在可以關閉本頁面了。
|
||||
account.methods.microsoft.error.add_family=由於你未滿 18 歲,你的帳戶必須被加入到家庭中才能登入遊戲。你也可以點擊上方連結更改你的帳戶的出生日期,使年齡滿 18 歲以上以繼續登入。
|
||||
account.methods.microsoft.error.add_family_probably=請檢查你的帳戶設定,如果你未滿 18 歲,你的帳戶必須被加入到家庭中才能登入遊戲。你也可以點擊上方連結更改你的帳戶的出生日期,使年齡滿 18 歲以上以繼續登入。
|
||||
account.methods.microsoft.error.add_family=由於你未滿 18 歲,你的帳戶必須被加入到家庭中才能登入遊戲。你也可以點擊上方「編輯帳戶配置檔」更改你的帳戶出生日期,使年齡滿 18 歲以上以繼續登入。
|
||||
account.methods.microsoft.error.add_family_probably=請檢查你的帳戶設定,如果你未滿 18 歲,你的帳戶必須被加入到家庭中才能登入遊戲。你也可以點擊上方「編輯帳戶配置檔」更改你的帳戶出生日期,使年齡滿 18 歲以上以繼續登入。
|
||||
account.methods.microsoft.error.country_unavailable=你所在的國家或地區不受 Xbox Live 的支援。
|
||||
account.methods.microsoft.error.missing_xbox_account=你的 Microsoft 帳戶尚未關聯 Xbox 帳戶,你必須先建立 Xbox 帳戶,才能登入遊戲。
|
||||
account.methods.microsoft.error.no_character=該帳戶未包含 Minecraft: Java 版購買記錄。\n若已購買,則可能未建立遊戲檔案,請點擊上方連結建立。
|
||||
@@ -112,17 +112,17 @@ account.methods.microsoft.logging_in=登入中……
|
||||
account.methods.microsoft.makegameidsettings=建立檔案 / 編輯檔案名稱
|
||||
account.methods.microsoft.hint=請點擊「登入」按鈕,稍後複製此處顯示的代碼,在打開的登入網頁中完成登入過程。\n\
|
||||
\n\
|
||||
如果登入 Microsoft 帳戶的令牌洩露,可點擊下方連結解除授權,然後等待令牌過期。\n\
|
||||
如果登入 Microsoft 帳戶的令牌洩露,可點擊下方「移除應用存取權」,然後等待令牌過期。\n\
|
||||
\n\
|
||||
如遇到問題,你可以點擊右上角幫助按鈕進行求助。
|
||||
account.methods.microsoft.manual=你的代碼為 <b>%1$s</b>,請點擊此處複製。\n\
|
||||
\n\
|
||||
點擊「登入」按鈕後,你應該在打開的登入網頁中完成登入過程。如果網頁沒有打開,你可以自行在瀏覽器中訪問 %2$s\n\
|
||||
\n\
|
||||
如果登入 Microsoft 帳戶的令牌洩露,可點擊下方連結解除授權,然後等待令牌過期。\n\
|
||||
如果登入 Microsoft 帳戶的令牌洩露,可點擊下方「移除應用存取權」,然後等待令牌過期。\n\
|
||||
\n\
|
||||
如遇到問題,你可以點擊右上角幫助按鈕進行求助。
|
||||
account.methods.microsoft.profile=帳戶設定頁
|
||||
account.methods.microsoft.profile=編輯帳戶配置檔
|
||||
account.methods.microsoft.purchase=購買 Minecraft
|
||||
account.methods.forgot_password=忘記密碼
|
||||
account.methods.microsoft.snapshot=你正在使用第三方提供的 HMCL,請下載官方版本進行登入。
|
||||
@@ -328,7 +328,7 @@ download.existing=檔案已存在,無法儲存。你可以將檔案儲存至
|
||||
download.external_link=打開下載網站
|
||||
download.failed=下載失敗:%1$s\n錯誤碼:%2$d
|
||||
download.failed.empty=沒有可供安裝的版本,按一下此處返回。
|
||||
download.failed.no_code=下載失敗:%s
|
||||
download.failed.no_code=下載失敗
|
||||
download.failed.refresh=載入版本清單失敗,按一下此處重試。
|
||||
download.game=新遊戲
|
||||
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
|
||||
@@ -608,7 +608,7 @@ launcher.background.translucent=半透明
|
||||
launcher.cache_directory=檔案下載快取目錄
|
||||
launcher.cache_directory.clean=清理
|
||||
launcher.cache_directory.choose=選取檔案下載快取目錄
|
||||
launcher.cache_directory.default=預設 ("%AppData%/.minecraft" 或 "~/.minecraft")
|
||||
launcher.cache_directory.default=預設 ("%APPDATA%/.minecraft" 或 "~/.minecraft")
|
||||
launcher.cache_directory.disabled=停用
|
||||
launcher.cache_directory.invalid=無法建立自訂的快取目錄,還原至預設設定
|
||||
launcher.contact=聯絡我們
|
||||
@@ -790,7 +790,8 @@ mods.channel.release=Release
|
||||
mods.check_updates=檢查模組更新
|
||||
mods.check_updates.current_version=目前版本
|
||||
mods.check_updates.empty=沒有需要更新的模組
|
||||
mods.check_updates.failed=部分檔案下載失敗
|
||||
mods.check_updates.failed_check=檢查更新失敗
|
||||
mods.check_updates.failed_download=部分檔案下載失敗
|
||||
mods.check_updates.file=檔案
|
||||
mods.check_updates.source=來源
|
||||
mods.check_updates.target_version=目標版本
|
||||
@@ -855,7 +856,7 @@ world.import.failed=無法匯入此世界: %s
|
||||
world.import.invalid=無法識別的存檔壓縮檔
|
||||
world.info.title=世界 [%s] - 世界資訊
|
||||
world.info.basic=基本資訊
|
||||
world.info.allow_cheats=允許指令
|
||||
world.info.allow_cheats=允許指令(作弊)
|
||||
world.info.dimension.the_nether=地獄
|
||||
world.info.dimension.the_end=末地
|
||||
world.info.difficulty=難易度
|
||||
@@ -1147,6 +1148,10 @@ version.manage.rename.fail=重新命名版本失敗,可能檔案被佔用或
|
||||
version.settings=遊戲設定
|
||||
version.update=更新模組包
|
||||
|
||||
wiki.tooltip=Minecraft Wiki 頁面
|
||||
wiki.version.game.release=https://zh.minecraft.wiki/w/Java版%s?variant=zh-tw
|
||||
wiki.version.game.snapshot=https://zh.minecraft.wiki/w/%s?variant=zh-tw
|
||||
|
||||
wizard.prev=< 上一步
|
||||
wizard.failed=失敗
|
||||
wizard.finish=完成
|
||||
|
||||
@@ -65,7 +65,7 @@ account.failed.injector_download_failure=无法下载 authlib-injector,可能
|
||||
account.failed.invalid_credentials=你的用户名或密码错误,或登录次数过多被暂时禁止登录,请稍后再试。
|
||||
account.failed.invalid_password=无效的密码
|
||||
account.failed.invalid_token=请尝试登出并重新输入密码登录
|
||||
account.failed.migration=你的账户需要迁移至微软账户。如果你已经迁移,你需要使用微软账户登录迁移后的账户。
|
||||
account.failed.migration=你的账户需要迁移至微软账户。如果你已经迁移,你需要使用迁移后的微软账户登录。
|
||||
account.failed.no_character=该账户没有角色
|
||||
account.failed.server_disconnected=无法访问登录服务器,账户信息刷新失败。\n\
|
||||
你可以选择“再次刷新账户”重新尝试。\n\
|
||||
@@ -99,11 +99,11 @@ account.copy_uuid=复制该账户的 UUID
|
||||
account.methods=登录方式
|
||||
account.methods.authlib_injector=外置登录 (authlib-injector)
|
||||
account.methods.microsoft=微软账户
|
||||
account.methods.microsoft.birth=如何修改账户出生日期
|
||||
account.methods.microsoft.birth=如何更改账户出生日期
|
||||
account.methods.microsoft.close_page=已完成微软账户授权,接下来启动器还需要完成其余登录步骤。你现在可以关闭本页面了。
|
||||
account.methods.microsoft.deauthorize=解除账户授权
|
||||
account.methods.microsoft.error.add_family=请点击上方“账户设置页”更改你的账户出生日期,使年龄满 18 岁以上,或将账户加入到家庭中。\n你可以点击右上角帮助按钮进行求助。
|
||||
account.methods.microsoft.error.add_family_probably=请点击上方“账户设置页”更改你的账户出生日期,使年龄满 18 岁以上,或将账户加入到家庭中。\n你可以点击右上角帮助按钮进行求助。
|
||||
account.methods.microsoft.error.add_family=请点击上方“编辑账户个人信息”更改你的账户出生日期,使年龄满 18 岁以上,或将账户加入到家庭中。\n你可以点击右上角帮助按钮进行求助。
|
||||
account.methods.microsoft.error.add_family_probably=请点击上方“编辑账户个人信息”更改你的账户出生日期,使年龄满 18 岁以上,或将账户加入到家庭中。\n你可以点击右上角帮助按钮进行求助。
|
||||
account.methods.microsoft.error.country_unavailable=你所在的国家或地区不受 Xbox Live 的支持。
|
||||
account.methods.microsoft.error.missing_xbox_account=请点击上方“创建档案”关联 Xbox 账户。\n你可以点击右上角帮助按钮进行求助。
|
||||
account.methods.microsoft.error.no_character=请确认你已经购买了 Minecraft: Java 版。\n若已购买,则可能未创建游戏档案,请点击上方“创建档案”以创建游戏档案。\n你可以点击右上角帮助按钮进行求助。
|
||||
@@ -116,8 +116,8 @@ account.methods.microsoft.hint=你需要按照以下步骤添加账户:\n\
|
||||
\ 2. 在弹出的网页中输入 HMCL 显示的代码,并点击“允许访问”;\n\
|
||||
\ 3. 按照网站的提示登录;\n\
|
||||
\ 4. 当网站提示“是否允许此应用访问你的信息?”时,请点击“接受”;\n\
|
||||
\ 5. 在网站提示“大功告成”后,只需等待账户完成添加即可。\n\
|
||||
若网站提示“出现错误”或账户添加失败时,请重新按照以上步骤重新添加。\n\
|
||||
\ 5. 在网站提示“大功告成”后,等待账户完成添加即可。\n\
|
||||
若网站提示“出现错误”或账户添加失败时,请按照以上步骤重新添加。\n\
|
||||
<b>若设备网络环境不佳,可能会导致网页加载缓慢甚至无法加载,请使用网络代理并重试。</b>\n\
|
||||
如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||
account.methods.microsoft.manual=你需要按照以下步骤添加:\n\
|
||||
@@ -125,12 +125,12 @@ account.methods.microsoft.manual=你需要按照以下步骤添加:\n\
|
||||
\ 2. 在弹出的网页中输入 <b>%1$s</b> (已自动复制),并点击“允许访问”;\n\
|
||||
\ 3. 按照网站的提示登录;\n\
|
||||
\ 4. 当网站提示“是否允许此应用访问你的信息?”时,请点击“接受”;\n\
|
||||
\ 5. 在网站提示“大功告成”后,只需等待账户完成添加即可。\n\
|
||||
\ 5. 在网站提示“大功告成”后,等待账户完成添加即可。\n\
|
||||
若网站未能显示,请手动在浏览器中打开:%2$s\n\
|
||||
若网站提示“出现错误”或账户添加失败时,请重新按照以上步骤重新添加。\n\
|
||||
若网站提示“出现错误”或账户添加失败时,请按照以上步骤重新添加。\n\
|
||||
<b>若设备网络环境不佳,可能会导致网页加载缓慢甚至无法加载,请使用网络代理并重试。</b>\n\
|
||||
如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||
account.methods.microsoft.profile=账户设置页
|
||||
account.methods.microsoft.profile=编辑账户个人信息
|
||||
account.methods.microsoft.purchase=购买 Minecraft
|
||||
account.methods.forgot_password=忘记密码
|
||||
account.methods.microsoft.snapshot=你正在使用第三方提供的 HMCL,请下载官方版本来登录微软账户。
|
||||
@@ -337,7 +337,7 @@ download.existing=文件已存在,无法保存。你可以将文件保存至
|
||||
download.external_link=打开下载网站
|
||||
download.failed=下载失败: %1$s,\n错误码:%2$d\n你可以点击右上角帮助按钮进行求助。
|
||||
download.failed.empty=[没有可供安装的版本,点击此处返回]\n(你可以点击右上角帮助按钮进行求助)
|
||||
download.failed.no_code=下载失败: %s
|
||||
download.failed.no_code=下载失败
|
||||
download.failed.refresh=[加载版本列表失败,点击此处重试]\n(你可以点击右上角帮助按钮进行求助)
|
||||
download.game=新游戏
|
||||
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com)
|
||||
@@ -434,7 +434,7 @@ game.crash.reason.jdk_9=当前游戏由于 Java 版本过高,无法继续运
|
||||
game.crash.reason.jvm_32bit=当前游戏由于内存分配过大,超过了 32 位 Java 内存限制,无法继续运行。\n如果你的电脑是 64 位系统,请下载安装并更换 64 位 Java。<a href="https://bell-sw.com/pages/downloads/#downloads">下载 Java</a>\n如果你的电脑是 32 位系统,你或许可以重新安装 64 位系统,或换一台新电脑。\n或者,你可以在“(全局/版本特定) 游戏设置 → 游戏内存”中关闭“自动分配内存”,并且把内存限制调节为 1024 MB 或以下。
|
||||
game.crash.reason.loading_crashed_forge=当前游戏由于模组“%1$s (%2$s)”错误,无法继续运行。\n你可以尝试删除或更新该模组以解决问题。
|
||||
game.crash.reason.loading_crashed_fabric=当前游戏由于模组“%1$s”错误,无法继续运行。\n你可以尝试删除或更新该模组以解决问题。
|
||||
game.crash.reason.memory_exceeded=当前游戏由于分配的内存过大,无法继续运行。\n该问题是由于系统页面文件太小导致的。\n你需要在全局(特定)游戏设置中关闭游戏内存的自动分配,并将游戏内存调低至游戏能正常启动为止。\n你还可以尝试将 虚拟内存 设置调整至「自动管理所有驱动器分页文件大小」,<a href="https://docs.hmcl.net/assets/img/hmcl/自动管理所有驱动器分页文件大小.webp">详情</a>。
|
||||
game.crash.reason.memory_exceeded=当前游戏由于分配的内存过大,无法继续运行。\n该问题是由于系统页面文件太小导致的。\n你需要在全局(特定)游戏设置中关闭游戏内存的自动分配,并将游戏内存调低至游戏能正常启动为止。\n你还可以尝试将虚拟内存设置调整为“自动管理所有驱动器分页文件大小”,<a href="https://docs.hmcl.net/assets/img/hmcl/自动管理所有驱动器分页文件大小.webp">详情</a>。
|
||||
game.crash.reason.mac_jdk_8u261=当前游戏由于你所使用的 Forge/OptiFine 与 Java 冲突而崩溃。\n请尝试更新 Forge/OptiFine,或使用 Java 8u251 及更早版本启动。
|
||||
game.crash.reason.mod=当前游戏由于“%1$s”的问题,无法继续运行。\n你可以更新或删除已经安装的“%1$s”再试。
|
||||
game.crash.reason.mod_resolution=当前游戏由于模组依赖问题,无法继续运行。Fabric 提供了如下信息:\n%1$s
|
||||
@@ -561,7 +561,7 @@ java.uninstall.confirm=你确定要卸载此 Java 吗?此操作无法撤销!
|
||||
lang=简体中文
|
||||
lang.default=跟随系统语言
|
||||
|
||||
launch.advice==%s 是否继续启动?
|
||||
launch.advice=%s 是否继续启动?
|
||||
launch.advice.multi=检测到以下问题:\n\n%s\n\n这些问题可能导致游戏无法正常启动或影响游戏体验,是否继续启动?\n你可以点击右上角帮助按钮进行求助。
|
||||
launch.advice.java.auto=当前选择的 Java 虚拟机版本不满足游戏要求。\n点击“是”即可由 HMCL 来自动选取合适的 Java 虚拟机版本。\n或者你可以在“(全局/版本特定) 游戏设置 → 游戏 Java”中选择一个合适的 Java 虚拟机版本。
|
||||
launch.advice.java.modded_java_7=Minecraft 1.7.2 及更低版本需要 Java 7 及更低版本。
|
||||
@@ -619,7 +619,7 @@ launcher.background.translucent=半透明
|
||||
launcher.cache_directory=文件下载缓存文件夹
|
||||
launcher.cache_directory.clean=清理缓存
|
||||
launcher.cache_directory.choose=选择文件下载缓存文件夹
|
||||
launcher.cache_directory.default=默认 ("%AppData%/.minecraft" 或 "~/.minecraft")
|
||||
launcher.cache_directory.default=默认 ("%APPDATA%/.minecraft" 或 "~/.minecraft")
|
||||
launcher.cache_directory.disabled=禁用 (总是使用游戏文件夹路径)
|
||||
launcher.cache_directory.invalid=无法创建自定义的缓存文件夹,恢复默认设置
|
||||
launcher.contact=联系我们
|
||||
@@ -801,7 +801,8 @@ mods.channel.release=稳定版本
|
||||
mods.check_updates=检查模组更新
|
||||
mods.check_updates.current_version=当前版本
|
||||
mods.check_updates.empty=没有需要更新的模组
|
||||
mods.check_updates.failed=部分文件下载失败
|
||||
mods.check_updates.failed_check=检查更新失败
|
||||
mods.check_updates.failed_download=部分文件下载失败
|
||||
mods.check_updates.file=文件
|
||||
mods.check_updates.source=来源
|
||||
mods.check_updates.target_version=目标版本
|
||||
@@ -867,7 +868,7 @@ world.import.failed=无法导入此世界:%s
|
||||
world.import.invalid=无法识别该存档压缩包
|
||||
world.info.title=世界 [%s] - 世界信息
|
||||
world.info.basic=基本信息
|
||||
world.info.allow_cheats=允许作弊
|
||||
world.info.allow_cheats=允许命令(作弊)
|
||||
world.info.dimension.the_nether=下界
|
||||
world.info.dimension.the_end=末地
|
||||
world.info.difficulty=难度
|
||||
@@ -944,17 +945,17 @@ settings.advanced.modify=编辑高级设置
|
||||
settings.advanced.title=高级设置 - %s
|
||||
settings.advanced.custom_commands=自定义命令
|
||||
settings.advanced.custom_commands.hint=自定义命令被调用时将包含如下的环境变量:\n\
|
||||
\ · $INST_NAME:版本名称;\n\
|
||||
\ · $INST_ID:版本名称;\n\
|
||||
\ · $INST_DIR:当前版本运行路径;\n\
|
||||
\ · $INST_MC_DIR:当前游戏文件夹路径;\n\
|
||||
\ · $INST_JAVA:游戏运行使用的 Java 路径;\n\
|
||||
\ · $INST_FORGE:若安装了 Forge,将会存在本环境变量;\n\
|
||||
\ · $INST_NEOFORGE:若安装了 NeoForge,将会存在本环境变量;\n\
|
||||
\ · $INST_LITELOADER:若安装了 LiteLoader,将会存在本环境变量;\n\
|
||||
\ · $INST_OPTIFINE:若安装了 OptiFine,将会存在本环境变量;\n\
|
||||
\ · $INST_FABRIC:若安装了 Fabric,将会存在本环境变量;\n\
|
||||
\ · $INST_QUILT:若安装了 Quilt,将会存在本环境变量。
|
||||
\ · $INST_NAME: 版本名称;\n\
|
||||
\ · $INST_ID: 版本名称;\n\
|
||||
\ · $INST_DIR: 当前版本运行路径;\n\
|
||||
\ · $INST_MC_DIR: 当前游戏文件夹路径;\n\
|
||||
\ · $INST_JAVA: 游戏运行使用的 Java 路径;\n\
|
||||
\ · $INST_FORGE: 若安装了 Forge,将会存在本环境变量;\n\
|
||||
\ · $INST_NEOFORGE: 若安装了 NeoForge,将会存在本环境变量;\n\
|
||||
\ · $INST_LITELOADER: 若安装了 LiteLoader,将会存在本环境变量;\n\
|
||||
\ · $INST_OPTIFINE: 若安装了 OptiFine,将会存在本环境变量;\n\
|
||||
\ · $INST_FABRIC: 若安装了 Fabric,将会存在本环境变量;\n\
|
||||
\ · $INST_QUILT: 若安装了 Quilt,将会存在本环境变量。
|
||||
settings.advanced.dont_check_game_completeness=不检查游戏完整性
|
||||
settings.advanced.dont_check_jvm_validity=不检查 JVM 与游戏的兼容性
|
||||
settings.advanced.dont_patch_natives=不尝试自动替换本地库
|
||||
@@ -1158,6 +1159,10 @@ version.manage.rename.fail=重命名版本失败,可能文件被占用或者
|
||||
version.settings=游戏设置
|
||||
version.update=更新整合包
|
||||
|
||||
wiki.tooltip=Minecraft Wiki 页面
|
||||
wiki.version.game.release=https://zh.minecraft.wiki/w/Java版%s?variant=zh-cn
|
||||
wiki.version.game.snapshot=https://zh.minecraft.wiki/w/%s?variant=zh-cn
|
||||
|
||||
wizard.prev=< 上一步
|
||||
wizard.failed=失败
|
||||
wizard.finish=完成
|
||||
|
||||
@@ -82,25 +82,25 @@
|
||||
"module": "javafx.base",
|
||||
"groupId": "org.openjfx",
|
||||
"artifactId": "javafx-base",
|
||||
"version": "17.0.13",
|
||||
"version": "19.0.2.1",
|
||||
"classifier": "mac",
|
||||
"sha1": "e1744403a6691aaa6b65a7e9b4ff9aad98831bb1"
|
||||
"sha1": "73e422d8426aaa23e8c712b9f4d9bebf70d3bfb9"
|
||||
},
|
||||
{
|
||||
"module": "javafx.graphics",
|
||||
"groupId": "org.openjfx",
|
||||
"artifactId": "javafx-graphics",
|
||||
"version": "17.0.13",
|
||||
"version": "19.0.2.1",
|
||||
"classifier": "mac",
|
||||
"sha1": "dbe733470094abee56560067d0fea3ad24991d2b"
|
||||
"sha1": "6ab6f3e23421fcfa04e692d9d26a8f55a830c114"
|
||||
},
|
||||
{
|
||||
"module": "javafx.controls",
|
||||
"groupId": "org.openjfx",
|
||||
"artifactId": "javafx-controls",
|
||||
"version": "17.0.13",
|
||||
"version": "19.0.2.1",
|
||||
"classifier": "mac",
|
||||
"sha1": "0d43a776d6c9e2622e3581ed04501e2cadcd6e65"
|
||||
"sha1": "b7786b1b63e741c0e234829825fae5fef9d96c31"
|
||||
}
|
||||
],
|
||||
"osx-arm64": [
|
||||
@@ -108,25 +108,25 @@
|
||||
"module": "javafx.base",
|
||||
"groupId": "org.openjfx",
|
||||
"artifactId": "javafx-base",
|
||||
"version": "17.0.13",
|
||||
"version": "19.0.2.1",
|
||||
"classifier": "mac-aarch64",
|
||||
"sha1": "d4dc7d2864c07b56a27e39fa5691856ddccf0ba4"
|
||||
"sha1": "1d0d887c492330ed527b0614d115a4f32d2d05a4"
|
||||
},
|
||||
{
|
||||
"module": "javafx.graphics",
|
||||
"groupId": "org.openjfx",
|
||||
"artifactId": "javafx-graphics",
|
||||
"version": "17.0.13",
|
||||
"version": "19.0.2.1",
|
||||
"classifier": "mac-aarch64",
|
||||
"sha1": "d6a49f19e90db56c134757d1bbab4935de075d45"
|
||||
"sha1": "64db28799e61e0f8f51e471c732599b2a6961803"
|
||||
},
|
||||
{
|
||||
"module": "javafx.controls",
|
||||
"groupId": "org.openjfx",
|
||||
"artifactId": "javafx-controls",
|
||||
"version": "17.0.13",
|
||||
"version": "19.0.2.1",
|
||||
"classifier": "mac-aarch64",
|
||||
"sha1": "ad564497edc49f7a6135c3b52d360962e19a2539"
|
||||
"sha1": "3a14bd5f3ebe45d344c1f2bade0fe074e6ea2a83"
|
||||
}
|
||||
],
|
||||
"linux-x86_64": [
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package moe.mickey.minecraft.skin.fx;
|
||||
package org.jackhuang.hmcl.ui.skin;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
@@ -8,7 +8,7 @@ import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.input.ScrollEvent;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import javafx.stage.Stage;
|
||||
import moe.mickey.minecraft.skin.fx.test.Test;
|
||||
import org.jackhuang.hmcl.ui.skin.test.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
+6
-6
@@ -1,13 +1,13 @@
|
||||
package moe.mickey.minecraft.skin.fx.test;
|
||||
package org.jackhuang.hmcl.ui.skin.test;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import moe.mickey.minecraft.skin.fx.FunctionHelper;
|
||||
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.ui.skin.FunctionHelper;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinCanvas;
|
||||
import org.jackhuang.hmcl.ui.skin.SkinCanvasSupport;
|
||||
import org.jackhuang.hmcl.ui.skin.animation.SkinAniRunning;
|
||||
import org.jackhuang.hmcl.ui.skin.animation.SkinAniWavingArms;
|
||||
import org.jackhuang.hmcl.game.TexturesLoader;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
@@ -6,7 +6,7 @@ dependencies {
|
||||
api("org.glavo:simple-png-javafx:0.3.0")
|
||||
api("com.google.code.gson:gson:2.11.0")
|
||||
api("com.moandjiezana.toml:toml4j:0.7.2")
|
||||
api("org.tukaani:xz:1.9")
|
||||
api("org.tukaani:xz:1.10")
|
||||
api("org.hildan.fxgson:fx-gson:5.0.0")
|
||||
api("org.jenkins-ci:constant-pool-scanner:1.2")
|
||||
api("com.github.steveice10:opennbt:1.5")
|
||||
|
||||
@@ -170,6 +170,7 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
|
||||
Version resolvedVersion = version.resolve(provider);
|
||||
String mainClass = resolvedVersion.getMainClass();
|
||||
return mainClass != null && (LAUNCH_WRAPPER_MAIN.equals(mainClass)
|
||||
|| mainClass.startsWith("net.minecraftforge")
|
||||
|| mainClass.startsWith("net.fabricmc")
|
||||
|| mainClass.startsWith("org.quiltmc")
|
||||
|| mainClass.startsWith("cpw.mods"));
|
||||
|
||||
@@ -33,7 +33,7 @@ public final class GameJavaVersion {
|
||||
public static final GameJavaVersion LATEST = JAVA_21;
|
||||
|
||||
public static GameJavaVersion getMinimumJavaVersion(GameVersionNumber gameVersion) {
|
||||
if (gameVersion.compareTo("1.21") >= 0)
|
||||
if (gameVersion.compareTo("1.20.5") >= 0)
|
||||
return JAVA_21;
|
||||
if (gameVersion.compareTo("1.18") >= 0)
|
||||
return JAVA_17;
|
||||
@@ -59,21 +59,6 @@ public final class GameJavaVersion {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSupportedPlatform(Platform platform) {
|
||||
OperatingSystem os = platform.getOperatingSystem();
|
||||
Architecture arch = platform.getArchitecture();
|
||||
switch (arch) {
|
||||
case X86:
|
||||
return os == OperatingSystem.WINDOWS || os == OperatingSystem.LINUX;
|
||||
case X86_64:
|
||||
return os == OperatingSystem.WINDOWS || os == OperatingSystem.LINUX || os == OperatingSystem.OSX;
|
||||
case ARM64:
|
||||
return os == OperatingSystem.WINDOWS || os == OperatingSystem.OSX;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<GameJavaVersion> getSupportedVersions(Platform platform) {
|
||||
OperatingSystem operatingSystem = platform.getOperatingSystem();
|
||||
Architecture architecture = platform.getArchitecture();
|
||||
|
||||
@@ -62,7 +62,14 @@ public enum JavaVersionConstraint {
|
||||
return analyzer != null && analyzer.has(LibraryAnalyzer.LibraryType.FORGE);
|
||||
}
|
||||
},
|
||||
MODDED_JAVA_17(false, GameVersionNumber.atLeast("1.18"), VersionNumber.between("17", "17.999")) {
|
||||
MODDED_JAVA_17(false, GameVersionNumber.between("1.18", "1.20.4"), VersionNumber.between("17", "17.999")) {
|
||||
@Override
|
||||
protected boolean appliesToVersionImpl(GameVersionNumber gameVersionNumber, @Nullable Version version,
|
||||
@Nullable JavaRuntime java, @Nullable LibraryAnalyzer analyzer) {
|
||||
return analyzer != null && analyzer.has(LibraryAnalyzer.LibraryType.FORGE);
|
||||
}
|
||||
},
|
||||
MODDED_JAVA_21(false, GameVersionNumber.atLeast("1.20.5"), VersionNumber.between("21", "21.999")) {
|
||||
@Override
|
||||
protected boolean appliesToVersionImpl(GameVersionNumber gameVersionNumber, @Nullable Version version,
|
||||
@Nullable JavaRuntime java, @Nullable LibraryAnalyzer analyzer) {
|
||||
|
||||
@@ -160,12 +160,17 @@ public final class ForgeNewModMetadata {
|
||||
|
||||
private static ModLoaderType analyzeLoader(Toml toml, String modID, int loaderACC, ModLoaderType defaultLoader) throws IOException {
|
||||
List<HashMap<String, Object>> dependencies = toml.getList("dependencies." + modID);
|
||||
if (dependencies != null) {
|
||||
for (HashMap<String, Object> dependency : dependencies) {
|
||||
switch ((String) dependency.get("modId")) {
|
||||
case "forge": return checkLoaderACC(loaderACC, ACC_FORGE, ModLoaderType.FORGE);
|
||||
case "neoforge": return checkLoaderACC(loaderACC, ACC_NEO_FORGED, ModLoaderType.NEO_FORGED);
|
||||
}
|
||||
if (dependencies == null) {
|
||||
dependencies = toml.getList("dependencies"); // ??? I have no idea why some of the Forge mods use [[dependencies]]
|
||||
if (dependencies == null) {
|
||||
return defaultLoader;
|
||||
}
|
||||
}
|
||||
|
||||
for (HashMap<String, Object> dependency : dependencies) {
|
||||
switch ((String) dependency.get("modId")) {
|
||||
case "forge": return checkLoaderACC(loaderACC, ACC_FORGE, ModLoaderType.FORGE);
|
||||
case "neoforge": return checkLoaderACC(loaderACC, ACC_NEO_FORGED, ModLoaderType.NEO_FORGED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.mod.modrinth;
|
||||
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.mod.ModManager;
|
||||
import org.jackhuang.hmcl.mod.ModpackCompletionException;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
@@ -27,6 +28,7 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
@@ -41,6 +43,7 @@ public class ModrinthCompletionTask extends Task<Void> {
|
||||
|
||||
private final DefaultDependencyManager dependency;
|
||||
private final DefaultGameRepository repository;
|
||||
private final ModManager modManager;
|
||||
private final String version;
|
||||
private ModrinthManifest manifest;
|
||||
private final List<Task<?>> dependencies = new ArrayList<>();
|
||||
@@ -69,6 +72,7 @@ public class ModrinthCompletionTask extends Task<Void> {
|
||||
public ModrinthCompletionTask(DefaultDependencyManager dependencyManager, String version, ModrinthManifest manifest) {
|
||||
this.dependency = dependencyManager;
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
this.modManager = repository.getModManager(version);
|
||||
this.version = version;
|
||||
this.manifest = manifest;
|
||||
|
||||
@@ -99,18 +103,28 @@ public class ModrinthCompletionTask extends Task<Void> {
|
||||
if (manifest == null)
|
||||
return;
|
||||
|
||||
Path runDirectory = repository.getRunDirectory(version).toPath();
|
||||
Path runDirectory = repository.getRunDirectory(version).toPath().toAbsolutePath().normalize();
|
||||
Path modsDirectory = runDirectory.resolve("mods");
|
||||
|
||||
for (ModrinthManifest.File file : manifest.getFiles()) {
|
||||
if (file.getEnv() != null && file.getEnv().getOrDefault("client", "required").equals("unsupported"))
|
||||
continue;
|
||||
Path filePath = runDirectory.resolve(file.getPath());
|
||||
if (!Files.exists(filePath) && !file.getDownloads().isEmpty()) {
|
||||
FileDownloadTask task = new FileDownloadTask(file.getDownloads().get(0), filePath.toFile());
|
||||
task.setCacheRepository(dependency.getCacheRepository());
|
||||
task.setCaching(true);
|
||||
dependencies.add(task.withCounter("hmcl.modpack.download"));
|
||||
}
|
||||
if (file.getDownloads().isEmpty())
|
||||
continue;
|
||||
|
||||
Path filePath = runDirectory.resolve(file.getPath()).toAbsolutePath().normalize();
|
||||
if (!filePath.startsWith(runDirectory))
|
||||
throw new IOException("Unsecure path: " + file.getPath());
|
||||
|
||||
if (Files.exists(filePath))
|
||||
continue;
|
||||
if (modsDirectory.equals(filePath.getParent()) && this.modManager.hasSimpleMod(FileUtils.getName(filePath)))
|
||||
continue;
|
||||
|
||||
FileDownloadTask task = new FileDownloadTask(file.getDownloads(), filePath.toFile());
|
||||
task.setCacheRepository(dependency.getCacheRepository());
|
||||
task.setCaching(true);
|
||||
dependencies.add(task.withCounter("hmcl.modpack.download"));
|
||||
}
|
||||
|
||||
if (!dependencies.isEmpty()) {
|
||||
|
||||
+41
-23
@@ -62,36 +62,54 @@ public final class MultiMCInstanceConfiguration implements ModpackManifest {
|
||||
private final MultiMCManifest mmcPack;
|
||||
|
||||
MultiMCInstanceConfiguration(String defaultName, InputStream contentStream, MultiMCManifest mmcPack) throws IOException {
|
||||
// instance.cfg is in .ini format. As it's like the .properties format, we use Properties to parse thie file.
|
||||
// Maybe this will provide some problems (and it does, such as https://github.com/HMCL-dev/HMCL/issues/2991), but this workaround works, doesn't it?
|
||||
Properties p = new Properties();
|
||||
p.load(new InputStreamReader(contentStream, StandardCharsets.UTF_8));
|
||||
|
||||
this.mmcPack = mmcPack;
|
||||
|
||||
instanceType = p.getProperty("InstanceType");
|
||||
autoCloseConsole = Boolean.parseBoolean(p.getProperty("AutoCloseConsole"));
|
||||
instanceType = readValue(p, "InstanceType");
|
||||
autoCloseConsole = Boolean.parseBoolean(readValue(p, "AutoCloseConsole"));
|
||||
gameVersion = mmcPack != null ? mmcPack.getComponents().stream().filter(e -> "net.minecraft".equals(e.getUid())).findAny()
|
||||
.orElseThrow(() -> new IOException("Malformed mmc-pack.json")).getVersion() : p.getProperty("IntendedVersion");
|
||||
javaPath = p.getProperty("JavaPath");
|
||||
jvmArgs = p.getProperty("JvmArgs");
|
||||
fullscreen = Boolean.parseBoolean(p.getProperty("LaunchMaximized"));
|
||||
maxMemory = Lang.toIntOrNull(p.getProperty("MaxMemAlloc"));
|
||||
minMemory = Lang.toIntOrNull(p.getProperty("MinMemAlloc"));
|
||||
height = Lang.toIntOrNull(p.getProperty("MinecraftWinHeight"));
|
||||
width = Lang.toIntOrNull(p.getProperty("MinecraftWinWidth"));
|
||||
overrideCommands = Boolean.parseBoolean(p.getProperty("OverrideCommands"));
|
||||
overrideConsole = Boolean.parseBoolean(p.getProperty("OverrideConsole"));
|
||||
overrideJavaArgs = Boolean.parseBoolean(p.getProperty("OverrideJavaArgs"));
|
||||
overrideJavaLocation = Boolean.parseBoolean(p.getProperty("OverrideJavaLocation"));
|
||||
overrideMemory = Boolean.parseBoolean(p.getProperty("OverrideMemory"));
|
||||
overrideWindow = Boolean.parseBoolean(p.getProperty("OverrideWindow"));
|
||||
permGen = Lang.toIntOrNull(p.getProperty("PermGen"));
|
||||
postExitCommand = p.getProperty("PostExitCommand");
|
||||
preLaunchCommand = p.getProperty("PreLaunchCommand");
|
||||
showConsole = Boolean.parseBoolean(p.getProperty("ShowConsole"));
|
||||
showConsoleOnError = Boolean.parseBoolean(p.getProperty("ShowConsoleOnError"));
|
||||
wrapperCommand = p.getProperty("WrapperCommand");
|
||||
.orElseThrow(() -> new IOException("Malformed mmc-pack.json")).getVersion() : readValue(p, "IntendedVersion");
|
||||
javaPath = readValue(p, "JavaPath");
|
||||
jvmArgs = readValue(p, "JvmArgs");
|
||||
fullscreen = Boolean.parseBoolean(readValue(p, "LaunchMaximized"));
|
||||
maxMemory = Lang.toIntOrNull(readValue(p, "MaxMemAlloc"));
|
||||
minMemory = Lang.toIntOrNull(readValue(p, "MinMemAlloc"));
|
||||
height = Lang.toIntOrNull(readValue(p, "MinecraftWinHeight"));
|
||||
width = Lang.toIntOrNull(readValue(p, "MinecraftWinWidth"));
|
||||
overrideCommands = Boolean.parseBoolean(readValue(p, "OverrideCommands"));
|
||||
overrideConsole = Boolean.parseBoolean(readValue(p, "OverrideConsole"));
|
||||
overrideJavaArgs = Boolean.parseBoolean(readValue(p, "OverrideJavaArgs"));
|
||||
overrideJavaLocation = Boolean.parseBoolean(readValue(p, "OverrideJavaLocation"));
|
||||
overrideMemory = Boolean.parseBoolean(readValue(p, "OverrideMemory"));
|
||||
overrideWindow = Boolean.parseBoolean(readValue(p, "OverrideWindow"));
|
||||
permGen = Lang.toIntOrNull(readValue(p, "PermGen"));
|
||||
postExitCommand = readValue(p, "PostExitCommand");
|
||||
preLaunchCommand = readValue(p, "PreLaunchCommand");
|
||||
showConsole = Boolean.parseBoolean(readValue(p, "ShowConsole"));
|
||||
showConsoleOnError = Boolean.parseBoolean(readValue(p, "ShowConsoleOnError"));
|
||||
wrapperCommand = readValue(p, "WrapperCommand");
|
||||
name = defaultName;
|
||||
notes = Optional.ofNullable(p.getProperty("notes")).orElse("");
|
||||
notes = Optional.ofNullable(readValue(p, "notes")).orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
* A workaround for <a href="https://github.com/HMCL-dev/HMCL/issues/2991">...</a>
|
||||
*/
|
||||
private String readValue(Properties p, String key) {
|
||||
String value = p.getProperty(key);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int l = value.length();
|
||||
if (l >= 2 && value.charAt(0) == '"' && value.charAt(l - 1) == ':') {
|
||||
return value.substring(0, l - 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public MultiMCInstanceConfiguration(String instanceType, String name, String gameVersion, Integer permGen, String wrapperCommand, String preLaunchCommand, String postExitCommand, String notes, String javaPath, String jvmArgs, boolean fullscreen, Integer width, Integer height, Integer maxMemory, Integer minMemory, boolean showConsole, boolean showConsoleOnError, boolean autoCloseConsole, boolean overrideMemory, boolean overrideJavaLocation, boolean overrideJavaArgs, boolean overrideConsole, boolean overrideCommands, boolean overrideWindow) {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package org.jackhuang.hmcl.util.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
final class DirectoryStructurePrinter {
|
||||
private DirectoryStructurePrinter() {
|
||||
}
|
||||
|
||||
public static String list(Path path, int maxDepth) throws IOException {
|
||||
StringBuilder output = new StringBuilder(128);
|
||||
list(path, maxDepth, output);
|
||||
output.setLength(output.length() - 1);
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
private static void list(Path path, int maxDepth, StringBuilder output) throws IOException {
|
||||
output.append("Filesystem structure of: ").append(path).append('\n');
|
||||
|
||||
if (!Files.exists(path)) {
|
||||
pushMessage(output, "nonexistent path", 1);
|
||||
return;
|
||||
}
|
||||
if (Files.isRegularFile(path)) {
|
||||
pushMessage(output, "regular file path", 1);
|
||||
return;
|
||||
}
|
||||
if (Files.isDirectory(path)) {
|
||||
Files.walkFileTree(path, new FileVisitor<Path>() {
|
||||
private boolean isFolderEmpty;
|
||||
|
||||
private int depth = 1;
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
isFolderEmpty = true;
|
||||
|
||||
pushFile(output, dir, depth);
|
||||
if (depth == maxDepth) {
|
||||
pushMessage(output, "too deep", depth);
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
|
||||
depth++;
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
isFolderEmpty = false;
|
||||
|
||||
pushFile(output, file, depth);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file, IOException exc) {
|
||||
visitFile(file, null);
|
||||
|
||||
pushMessage(output, exc.toString(), depth);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
|
||||
if (isFolderEmpty) {
|
||||
pushMessage(output, "empty directory", depth);
|
||||
}
|
||||
|
||||
depth--;
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
pushMessage(output, "unknown file type", 1);
|
||||
}
|
||||
|
||||
private static void pushFile(StringBuilder output, Path file, int depth) {
|
||||
output.append("|");
|
||||
for (int i = 1; i < depth; i++) {
|
||||
output.append(" |");
|
||||
}
|
||||
output.append("-> ").append(FileUtils.getName(file)).append('\n');
|
||||
}
|
||||
|
||||
private static void pushMessage(StringBuilder output, String message, int depth) {
|
||||
output.append("| ");
|
||||
for (int i = 1; i < depth; i++) {
|
||||
output.append(" | ");
|
||||
}
|
||||
output.append('<').append(message).append(">\n");
|
||||
}
|
||||
}
|
||||
@@ -30,11 +30,7 @@ import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
@@ -199,7 +195,7 @@ public final class FileUtils {
|
||||
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
|
||||
* All bytes in byte array will be written into the file in binary format. Existing data will be erased.
|
||||
*
|
||||
* @param file the path to the file
|
||||
* @param file the path to the file
|
||||
* @param data the data being written to file
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@@ -212,7 +208,7 @@ public final class FileUtils {
|
||||
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
|
||||
* All bytes in byte array will be written into the file in binary format. Existing data will be erased.
|
||||
*
|
||||
* @param file the path to the file
|
||||
* @param file the path to the file
|
||||
* @param data the data being written to file
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@@ -591,4 +587,8 @@ public final class FileUtils {
|
||||
|
||||
Files.move(tmpFile, file, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
public static String printFileStructure(Path path, int maxDepth) throws IOException {
|
||||
return DirectoryStructurePrinter.list(path, maxDepth);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
project(HMCLauncher)
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8 /D_UNICODE /W4)
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
add_compile_options(/utf-8 /W4)
|
||||
add_link_options(/ENTRY:wWinMainCRTStartup)
|
||||
else()
|
||||
add_compile_options(-municode -Wall -Wextra -Wpedantic)
|
||||
|
||||
@@ -82,8 +82,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,4,0,0
|
||||
PRODUCTVERSION 3,4,0,0
|
||||
FILEVERSION 3,5,0,0
|
||||
PRODUCTVERSION 3,5,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
param(
|
||||
[string]$JavaDir,
|
||||
[string]$Arch
|
||||
)
|
||||
|
||||
$chinese = [System.Globalization.CultureInfo]::CurrentCulture.Name -eq 'zh-CN'
|
||||
|
||||
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
|
||||
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||
|
||||
# Choose Source Dialog
|
||||
|
||||
$dialog = New-Object System.Windows.Forms.Form
|
||||
$dialog.AutoSize = $true
|
||||
$dialog.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::GrowAndShrink
|
||||
if ($chinese) {
|
||||
$dialog.Text = '未能在这台电脑上找到 Java'
|
||||
} else {
|
||||
$dialog.Text = 'Java not found'
|
||||
}
|
||||
|
||||
$dialogLayout = New-Object System.Windows.Forms.FlowLayoutPanel
|
||||
$dialogLayout.AutoSize = $true
|
||||
$dialogLayout.FlowDirection = [System.Windows.Forms.FlowDirection]::TopDown
|
||||
$dialogLayout.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::GrowAndShrink
|
||||
|
||||
$messageLabel = New-Object System.Windows.Forms.Label
|
||||
$messageLabel.AutoSize = $true
|
||||
$messageLabel.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom
|
||||
if ($chinese) {
|
||||
$messageLabel.Text = "HMCL 需要 Java 运行时环境才能正常运行,是否自动下载安装 Java?"
|
||||
} else {
|
||||
$messageLabel.Text = "Running HMCL requires a Java runtime environment. `nDo you want to download and install Java automatically?"
|
||||
}
|
||||
|
||||
$useMirrorCheckBox = New-Object System.Windows.Forms.CheckBox
|
||||
$useMirrorCheckBox.AutoSize = $true
|
||||
$useMirrorCheckBox.Anchor = [System.Windows.Forms.AnchorStyles]::Right
|
||||
$useMirrorCheckBox.Checked = $false
|
||||
if ($chinese) {
|
||||
$useMirrorCheckBox.Text = '使用备用下载源(如果无法正常下载,请打开它再试一次)'
|
||||
} else {
|
||||
$useMirrorCheckBox.Text = 'Use the alternate download source'
|
||||
}
|
||||
|
||||
$selectButtonPanel = New-Object System.Windows.Forms.FlowLayoutPanel
|
||||
$selectButtonPanel.AutoSize = $true
|
||||
$selectButtonPanel.Anchor = [System.Windows.Forms.AnchorStyles]::Right
|
||||
$selectButtonPanel.FlowDirection = [System.Windows.Forms.FlowDirection]::LeftToRight
|
||||
$selectButtonPanel.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::GrowAndShrink
|
||||
|
||||
$yesButton = New-Object System.Windows.Forms.Button
|
||||
$noButton = New-Object System.Windows.Forms.Button
|
||||
$yesButton.DialogResult = [System.Windows.Forms.DialogResult]::Yes
|
||||
$noButton.DialogResult = [System.Windows.Forms.DialogResult]::No
|
||||
|
||||
if ($chinese) {
|
||||
$yesButton.Text = '是'
|
||||
$noButton.Text = '否'
|
||||
} else {
|
||||
$yesButton.Text = 'Yes'
|
||||
$noButton.Text = 'No'
|
||||
}
|
||||
$selectButtonPanel.Controls.Add($yesButton)
|
||||
$selectButtonPanel.Controls.Add($noButton)
|
||||
|
||||
$dialogLayout.Controls.Add($messageLabel)
|
||||
$dialogLayout.Controls.Add($useMirrorCheckBox)
|
||||
$dialogLayout.Controls.Add($selectButtonPanel)
|
||||
|
||||
$dialog.Controls.Add($dialogLayout)
|
||||
|
||||
$result = $dialog.ShowDialog()
|
||||
|
||||
if ($result -ne [System.Windows.Forms.DialogResult]::Yes) {
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($useMirrorCheckBox.Checked) {
|
||||
switch ($Arch) {
|
||||
'x86-64' {
|
||||
$script:url = 'https://download.bell-sw.com/java/17.0.2+9/bellsoft-jre17.0.2+9-windows-amd64-full.zip'
|
||||
}
|
||||
'x86' {
|
||||
$script:url = 'https://download.bell-sw.com/java/17.0.2+9/bellsoft-jre17.0.2+9-windows-i586-full.zip'
|
||||
}
|
||||
default { exit 1 }
|
||||
}
|
||||
} else {
|
||||
switch ($Arch) {
|
||||
'x86-64' {
|
||||
$script:url = 'https://cdn.azul.com/zulu/bin/zulu17.32.13-ca-fx-jre17.0.2-win_x64.zip'
|
||||
}
|
||||
'x86' {
|
||||
$script:url = 'https://cdn.azul.com/zulu/bin/zulu17.32.13-ca-fx-jre17.0.2-win_i686.zip'
|
||||
}
|
||||
default { exit 1 }
|
||||
}
|
||||
}
|
||||
|
||||
$securityProtocol = [System.Net.ServicePointManager]::SecurityProtocol.value__
|
||||
if (($securityProtocol -ne 0) -and (($securityProtocol -band 0x00000C00) -eq 0)) { # Try using HTTP when the platform does not support TLS 1.2
|
||||
$script:url = $script:url -replace '^https:', 'http:'
|
||||
}
|
||||
|
||||
# Download Winodw
|
||||
|
||||
do {
|
||||
$tempFileName = "hmcl-java-$(Get-Random).zip"
|
||||
$script:tempFile = Join-Path ([System.IO.Path]::GetTempPath()) $tempFileName
|
||||
} while (Test-Path $script:tempFile)
|
||||
|
||||
$form = New-Object System.Windows.Forms.Form
|
||||
$form.AutoSize = $true
|
||||
$form.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::GrowAndShrink
|
||||
if ($chinese) {
|
||||
$form.Text = '正在下载 Java 中'
|
||||
} else {
|
||||
$form.Text = 'Downloading Java'
|
||||
}
|
||||
|
||||
$tip = New-Object System.Windows.Forms.Label
|
||||
$tip.AutoSize = $true
|
||||
if ($chinese) {
|
||||
$tip.Text = '正在下载 Java。这需要一段时间,请耐心等待。'
|
||||
} else {
|
||||
$tip.Text = 'Downloading Java. Please wait patiently for the download to complete.'
|
||||
}
|
||||
|
||||
$layout = New-Object System.Windows.Forms.FlowLayoutPanel
|
||||
$layout.AutoSize = $true
|
||||
$layout.FlowDirection = [System.Windows.Forms.FlowDirection]::TopDown
|
||||
$layout.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::GrowAndShrink
|
||||
|
||||
$progressBar = New-Object System.Windows.Forms.ProgressBar
|
||||
$progressBar.Maximum = 100
|
||||
|
||||
$label = New-Object System.Windows.Forms.Label
|
||||
$label.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom
|
||||
|
||||
if ($chinese) {
|
||||
$label.Text = '准备下载'
|
||||
} else {
|
||||
$label.Text = 'In preparation'
|
||||
}
|
||||
|
||||
$box = New-Object System.Windows.Forms.FlowLayoutPanel
|
||||
$box.AutoSize = $true
|
||||
$box.FlowDirection = [System.Windows.Forms.FlowDirection]::LeftToRight
|
||||
$box.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::GrowAndShrink
|
||||
$box.Controls.Add($progressBar)
|
||||
$box.Controls.Add($label)
|
||||
|
||||
$cancelButton = New-Object System.Windows.Forms.Button
|
||||
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
|
||||
$cancelButton.Anchor = [System.Windows.Forms.AnchorStyles]::Right
|
||||
if ($chinese) {
|
||||
$cancelButton.Text = '取消'
|
||||
} else {
|
||||
$cancelButton.Text = 'Cancel'
|
||||
}
|
||||
|
||||
$layout.Controls.Add($tip)
|
||||
$layout.Controls.Add($box)
|
||||
$box.Controls.Add($cancelButton)
|
||||
|
||||
$form.Controls.Add($layout)
|
||||
|
||||
[System.Net.DownloadProgressChangedEventHandler]$progressChangedEventHandler = {
|
||||
param($sender, [System.Net.DownloadProgressChangedEventArgs]$ChangedEventArgs)
|
||||
$bytesReceived = $ChangedEventArgs.BytesReceived
|
||||
$totalBytes = $ChangedEventArgs.TotalBytesToReceive
|
||||
|
||||
$percentage = ([double]$bytesReceived)/([double]$totalBytes) * 100
|
||||
|
||||
$progressBar.Value = [int][System.Math]::Truncate($percentage)
|
||||
$label.Text = [string]::Format("{0:0.00}%", $percentage)
|
||||
}
|
||||
|
||||
[System.ComponentModel.AsyncCompletedEventHandler]$downloadFileCompletedEventHandler = {
|
||||
param($sender, [System.ComponentModel.AsyncCompletedEventArgs]$CompletedEventArgs)
|
||||
if (!$form.IsDisposed) {
|
||||
$label.Refresh()
|
||||
if ($CompletedEventArgs.Cancelled) {
|
||||
$form.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
|
||||
} elseif ($CompletedEventArgs.Error -ne $null) {
|
||||
if ($chinese) {
|
||||
[System.Windows.Forms.MessageBox]::Show($CompletedEventArgs.Error.Message, '下载失败', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Exclamation)
|
||||
} else {
|
||||
[System.Windows.Forms.MessageBox]::Show($CompletedEventArgs.Error.Message, 'Download failed', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Exclamation)
|
||||
}
|
||||
$form.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
|
||||
} else {
|
||||
$form.DialogResult = [System.Windows.Forms.DialogResult]::OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$client = New-Object System.Net.WebClient
|
||||
$client.Headers.Add('User-Agent', 'Wget/1.20.3 (linux-gnu)')
|
||||
$client.add_DownloadProgressChanged($progressChangedEventHandler)
|
||||
$client.add_DownloadFileCompleted($downloadFileCompletedEventHandler)
|
||||
|
||||
$client.DownloadFileAsync($script:url, $script:tempFile)
|
||||
|
||||
$result = $form.ShowDialog()
|
||||
$client.CancelAsync()
|
||||
$form.Dispose()
|
||||
|
||||
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
|
||||
$null = New-Item -Type Directory -Force $JavaDir
|
||||
$app = New-Object -ComObject Shell.Application
|
||||
$items = $app.NameSpace($script:tempFile).items()
|
||||
foreach ($item in $items) {
|
||||
$app.NameSpace($JavaDir).copyHere($item)
|
||||
}
|
||||
}
|
||||
|
||||
if ([System.IO.File]::Exists($script:tempFile)) {
|
||||
try {
|
||||
[System.IO.File]::Delete($script:tempFile)
|
||||
} catch {
|
||||
Write-Error $_
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,7 @@
|
||||
|
||||
#define ERROR_PROMPT L"The Java runtime environment is required to run HMCL and Minecraft,\n"\
|
||||
L"Click 'OK' to start downloading java.\n"\
|
||||
L"Please restart HMCL after installing Java.\n"\
|
||||
L"Click 'Help' go for help."
|
||||
L"Please restart HMCL after installing Java."
|
||||
|
||||
#define ERROR_PROMPT_ZH L"运行 HMCL 以及 Minecraft 需要 Java 运行时环境,点击“确定”开始下载。\n"\
|
||||
L"请在安装 Java 完成后重新启动 HMCL。\n"\
|
||||
L"点击“帮助”寻求帮助。"
|
||||
L"请在安装 Java 完成后重新启动 HMCL。"
|
||||
@@ -75,12 +75,11 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
|
||||
bool useChinese = GetUserDefaultUILanguage() == 2052; // zh-CN
|
||||
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo(&systemInfo);
|
||||
// TODO: check whether the bundled JRE is valid.
|
||||
MyArchitecture architecture = MyGetArchitecture();
|
||||
|
||||
// First try the Java packaged together.
|
||||
bool isX64 = (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64);
|
||||
bool isARM64 = (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64);
|
||||
bool isX64 = architecture == MyArchitecture::X86_64;
|
||||
bool isARM64 = architecture == MyArchitecture::ARM64;
|
||||
|
||||
if (isARM64) {
|
||||
RawLaunchJVM(L"jre-arm64\\bin\\javaw.exe", workdir, exeName, jvmOptions);
|
||||
@@ -143,7 +142,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
|
||||
if (isARM64) {
|
||||
downloadLink = L"https://docs.hmcl.net/downloads/windows/arm64.html";
|
||||
} if (isX64) {
|
||||
} else if (isX64) {
|
||||
downloadLink = L"https://docs.hmcl.net/downloads/windows/x86_64.html";
|
||||
} else {
|
||||
downloadLink = L"https://docs.hmcl.net/downloads/windows/x86.html";
|
||||
|
||||
@@ -1,6 +1,41 @@
|
||||
#include "stdafx.h"
|
||||
#include "os.h"
|
||||
|
||||
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS2) (HANDLE, PUSHORT, PUSHORT);
|
||||
|
||||
MyArchitecture MyGetArchitecture() {
|
||||
LPFN_ISWOW64PROCESS2 fnIsWow64Process2 = (LPFN_ISWOW64PROCESS2)GetProcAddress(
|
||||
GetModuleHandle(L"Kernel32.dll"), "IsWow64Process2");
|
||||
if (NULL != fnIsWow64Process2) {
|
||||
USHORT uProcessMachine = 0;
|
||||
USHORT uNativeMachine = 0;
|
||||
if (fnIsWow64Process2(GetCurrentProcess(), &uProcessMachine, &uNativeMachine)) {
|
||||
if (uNativeMachine == 0xAA64) {
|
||||
return MyArchitecture::ARM64;
|
||||
}
|
||||
|
||||
if (uNativeMachine == 0x8664) {
|
||||
return MyArchitecture::X86_64;
|
||||
}
|
||||
|
||||
return MyArchitecture::X86;
|
||||
}
|
||||
}
|
||||
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo(&systemInfo);
|
||||
|
||||
if (systemInfo.wProcessorArchitecture == 12) { // PROCESSOR_ARCHITECTURE_ARM64
|
||||
return MyArchitecture::ARM64;
|
||||
}
|
||||
|
||||
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
|
||||
return MyArchitecture::X86_64;
|
||||
}
|
||||
|
||||
return MyArchitecture::X86;
|
||||
}
|
||||
|
||||
LSTATUS MyRegQueryValue(HKEY hKey, LPCWSTR subKey, DWORD dwType,
|
||||
std::wstring &out) {
|
||||
DWORD dwSize = 0;
|
||||
|
||||
@@ -8,9 +8,13 @@
|
||||
const int MAX_KEY_LENGTH = 255;
|
||||
const int MAX_VALUE_NAME = 16383;
|
||||
|
||||
#ifndef PROCESSOR_ARCHITECTURE_ARM64
|
||||
#define PROCESSOR_ARCHITECTURE_ARM64 12
|
||||
#endif
|
||||
enum MyArchitecture {
|
||||
X86,
|
||||
X86_64,
|
||||
ARM64
|
||||
};
|
||||
|
||||
MyArchitecture MyGetArchitecture();
|
||||
|
||||
// Query registry value of class root hKey, key path subKey, stores result in
|
||||
// parameter out.
|
||||
|
||||
+5
-5
@@ -17,20 +17,20 @@
|
||||
|
||||
Legend:
|
||||
|
||||
* ✅: Official supported platform.
|
||||
* ✅: Officially supported platform.
|
||||
|
||||
Fully supported by Mojang official. Problems encountered in the game should be directly reported to the Mojang.
|
||||
Fully supported by Mojang officials. Problems encountered in the game should be directly reported to the Mojang.
|
||||
|
||||
* 👌: Supported platforms.
|
||||
|
||||
Support is provided by HMCL, tested to work, but may have more issues than a fully supported platform.
|
||||
Support is provided by HMCL, tested to work, but may have more problems than a fully supported platform.
|
||||
Support for versions below Minecraft 1.6 is not guaranteed.
|
||||
If you encounter a problem that does not exist on fully supported platforms, you can report it to HMCL.
|
||||
|
||||
* ❔: Low level supported platforms.
|
||||
* ❔: Low-level supported platforms.
|
||||
|
||||
HMCL can run on this platform and has some basic support. However, launching the game directly is not yet available.
|
||||
If you want to start the game, you will need to get the native libraries needed by Minecraft in other way and specify the native path in the instance settings.
|
||||
If you want to start the game, you will need to get the native libraries needed by Minecraft in another way and specify the native path in the instance settings.
|
||||
|
||||
* `/`: Not applicable.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
## Introduction
|
||||
|
||||
HMCL is an open-source, cross-platform Minecraft launcher that supports Mod Management, Game Customizing, ModLoader Installing (Forge, NeoForge, Fabric, Quilt, LiteLoader and OptiFine), Modpack Creating, UI Customization, and more.
|
||||
HMCL is an open-source, cross-platform Minecraft launcher that supports Mod Management, Game Customizing, ModLoader Installing (Forge, NeoForge, Fabric, Quilt, LiteLoader, and OptiFine), Modpack Creating, UI Customization, and more.
|
||||
|
||||
HMCL has amazing cross-platform capabilities. Not only does it run on different operating systems like Windows, Linux, and macOS, but it also supports various CPU architectures such as x86, ARM, MIPS, and LoongArch. You can easily enjoy Minecraft across different platforms through HMCL.
|
||||
|
||||
@@ -46,7 +46,7 @@ If you want to submit a pull request, here are some requirements:
|
||||
|
||||
### Compilation
|
||||
|
||||
Simply execute the following command in project root directory:
|
||||
Simply execute the following command in the project root directory:
|
||||
|
||||
```bash
|
||||
./gradlew clean build
|
||||
@@ -59,13 +59,13 @@ Make sure you have at least JavaFX 8 installed. Liberica Full JDK 8 or later is
|
||||
| Parameter | Description |
|
||||
| -------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `-Dhmcl.home=<path>` | Override HMCL directory |
|
||||
| `-Dhmcl.self_integrity_check.disable=true` | Bypass the self integrity check when checking for update |
|
||||
| `-Dhmcl.bmclapi.override=<url>` | Override API Root of BMCLAPI download provider, defaults to `https://bmclapi2.bangbang93.com` |
|
||||
| `-Dhmcl.self_integrity_check.disable=true` | Bypass the self integrity check when checking for updates |
|
||||
| `-Dhmcl.bmclapi.override=<url>` | Override API Root of BMCLAPI download provider. Defaults to `https://bmclapi2.bangbang93.com` |
|
||||
| `-Dhmcl.font.override=<font family>` | Override font family |
|
||||
| `-Dhmcl.version.override=<version>` | Override the version number |
|
||||
| `-Dhmcl.update_source.override=<url>` | Override the update source for HMCL itself |
|
||||
| `-Dhmcl.authlibinjector.location=<path>` | Use specified authlib-injector (instead of downloading one) |
|
||||
| `-Dhmcl.openjfx.repo=<maven repository url>` | Add custom Maven repository for download OpenJFX |
|
||||
| `-Dhmcl.authlibinjector.location=<path>` | Use the specified authlib-injector (instead of downloading one) |
|
||||
| `-Dhmcl.openjfx.repo=<maven repository url>` | Add custom Maven repository for downloading OpenJFX |
|
||||
| `-Dhmcl.native.encoding=<encoding>` | Override the native encoding |
|
||||
| `-Dhmcl.microsoft.auth.id=<App ID>` | Override Microsoft OAuth App ID |
|
||||
| `-Dhmcl.microsoft.auth.secret=<App Secret>` | Override Microsoft OAuth App secret |
|
||||
| `-Dhmcl.microsoft.auth.secret=<App Secret>` | Override Microsoft OAuth App Secret |
|
||||
@@ -94,6 +94,13 @@ tasks.create("checkTranslations") {
|
||||
}
|
||||
}
|
||||
|
||||
zh_CN.forEach {
|
||||
if (it.value.toString().contains("其它")) {
|
||||
project.logger.warn("The misspelled '其它' in '${it.key}' should be replaced by '其他'")
|
||||
success = false
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
throw GradleException("Part of the translation is missing")
|
||||
}
|
||||
|
||||
+2
-2
@@ -33,8 +33,8 @@ val jfxPlatforms = listOf(
|
||||
Platform("windows-x86", "win-x86", version = oldJfxVersion),
|
||||
Platform("windows-x86_64", "win"),
|
||||
Platform("windows-arm64", "win", groupId = "org.glavo.hmcl.openjfx", version = "18.0.2+1-arm64"),
|
||||
Platform("osx-x86_64", "mac"),
|
||||
Platform("osx-arm64", "mac-aarch64"),
|
||||
Platform("osx-x86_64", "mac", version = oldJfxVersion),
|
||||
Platform("osx-arm64", "mac-aarch64", version = oldJfxVersion),
|
||||
Platform("linux-x86_64", "linux"),
|
||||
Platform("linux-arm32", "linux-arm32-monocle", version = oldJfxVersion),
|
||||
Platform("linux-arm64", "linux-aarch64", version = oldJfxVersion),
|
||||
|
||||
Reference in new issue
Block a user