mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-04-24 18:50:52 +08:00
Compare commits
36 Commits
release-3.
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
c252d7027e | ||
|
9d0c8da310 | ||
|
84b3312ebb | ||
|
f351d1d133 | ||
|
5ca1120223 | ||
|
6aa4019221 | ||
|
73fb8bda10 | ||
|
cc16f84992 | ||
|
b4945a150e | ||
|
8bcbe74d82 | ||
|
69c2429e92 | ||
|
88e83dc44a | ||
|
87c2126e5a | ||
|
abf1ec3eb8 | ||
|
139fb41149 | ||
|
6c986921d6 | ||
|
b8e6d6fc96 | ||
|
75e4aee8aa | ||
|
abda9f50e1 | ||
|
c33ef5170b | ||
|
a3cb871928 | ||
|
62e965c6fe | ||
|
99a031cea4 | ||
|
f97b9b9382 | ||
|
a8929560df | ||
|
22c8c59b5d | ||
|
78b043c19c | ||
|
fd51fb7d26 | ||
|
43c59dad9c | ||
|
81b0547610 | ||
|
997a16486b | ||
|
36ebdab698 | ||
|
a6471bca09 | ||
|
cb6320ffae | ||
|
7cf520cb48 | ||
|
7dc922d4bd |
15
.github/ISSUE_TEMPLATE/feature.yml
vendored
15
.github/ISSUE_TEMPLATE/feature.yml
vendored
@ -9,12 +9,12 @@ body:
|
|||||||
请确认 Issues 列表无重复的项目。
|
请确认 Issues 列表无重复的项目。
|
||||||
Please make sure that no duplicate issues have already been submitted.
|
Please make sure that no duplicate issues have already been submitted.
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: summary
|
||||||
attributes:
|
attributes:
|
||||||
label: 描述 | Description
|
label: 概述 | Summary
|
||||||
description: |
|
description: |
|
||||||
请详细描述你想加入的新功能。
|
请介绍你想加入的新功能。
|
||||||
Please describe the new feature in detail.
|
Please describe the new feature.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@ -26,3 +26,10 @@ body:
|
|||||||
Please describe why you want to add the feature or enhancement to HMCL.
|
Please describe why you want to add the feature or enhancement to HMCL.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: 详情 | Description
|
||||||
|
description: |
|
||||||
|
在这里可以补充描述该功能的具体实现方式或建议。(可选)
|
||||||
|
Describe implementation details or suggestions here. (Optional)
|
||||||
|
46
.github/workflows/build-launcher.yml
vendored
46
.github/workflows/build-launcher.yml
vendored
@ -1,46 +0,0 @@
|
|||||||
name: Build HMCLauncher
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'HMCLauncher/**'
|
|
||||||
- '.github/workflows/build-launcher.yml'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'HMCLauncher/**'
|
|
||||||
- '.github/workflows/build-launcher.yml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Add msbuild to PATH
|
|
||||||
uses: microsoft/setup-msbuild@v2
|
|
||||||
with:
|
|
||||||
msbuild-architecture: x86
|
|
||||||
- name: Build HMCLauncher
|
|
||||||
run: msbuild /p:Configuration=Release /t:Rebuild /verbosity:detailed .\HMCLauncher\
|
|
||||||
- name: Copy HMCLauncher to assets
|
|
||||||
run: Copy-Item .\HMCLauncher\Release\HMCLauncher.exe -Destination .\HMCL\src\main\resources\assets\HMCLauncher.exe
|
|
||||||
- name: Set up JDK 11
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: 'zulu'
|
|
||||||
java-version: '11'
|
|
||||||
java-package: 'jdk+fx'
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: .\gradlew makeExecutables --no-daemon
|
|
||||||
env:
|
|
||||||
MICROSOFT_AUTH_ID: ${{ secrets.MICROSOFT_AUTH_ID }}
|
|
||||||
MICROSOFT_AUTH_SECRET: ${{ secrets.MICROSOFT_AUTH_SECRET }}
|
|
||||||
CURSEFORGE_API_KEY: ${{ secrets.CURSEFORGE_API_KEY }}
|
|
||||||
- name: Get short SHA
|
|
||||||
run: echo "SHORT_SHA=$("${{ github.sha }}".SubString(0, 7))" >> $env:GITHUB_ENV
|
|
||||||
- name: Copy HMCLauncher to libs
|
|
||||||
run: Copy-Item .\HMCLauncher\Release\HMCLauncher.exe -Destination .\HMCL\build\libs\HMCLauncher.exe
|
|
||||||
- name: Upload Artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: HMCLauncher-${{ env.SHORT_SHA }}
|
|
||||||
path: HMCL/build/libs/*.exe
|
|
1
.github/workflows/gradle.yml
vendored
1
.github/workflows/gradle.yml
vendored
@ -5,7 +5,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
- 'HMCLauncher/**'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -42,7 +42,6 @@ minecraft-exported-crash-info*
|
|||||||
.nb-gradle
|
.nb-gradle
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
!/HMCL/src/main/resources/assets/HMCLauncher.exe
|
|
||||||
|
|
||||||
# macos
|
# macos
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
@ -33,12 +33,18 @@ val microsoftAuthId = System.getenv("MICROSOFT_AUTH_ID") ?: ""
|
|||||||
val microsoftAuthSecret = System.getenv("MICROSOFT_AUTH_SECRET") ?: ""
|
val microsoftAuthSecret = System.getenv("MICROSOFT_AUTH_SECRET") ?: ""
|
||||||
val curseForgeApiKey = System.getenv("CURSEFORGE_API_KEY") ?: ""
|
val curseForgeApiKey = System.getenv("CURSEFORGE_API_KEY") ?: ""
|
||||||
|
|
||||||
|
val launcherExe = System.getenv("HMCL_LAUNCHER_EXE")
|
||||||
|
|
||||||
version = "$versionRoot.$buildNumber"
|
version = "$versionRoot.$buildNumber"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":HMCLCore"))
|
implementation(project(":HMCLCore"))
|
||||||
implementation("libs:JFoenix")
|
implementation("libs:JFoenix")
|
||||||
implementation("com.twelvemonkeys.imageio:imageio-webp:3.12.0")
|
implementation("com.twelvemonkeys.imageio:imageio-webp:3.12.0")
|
||||||
|
|
||||||
|
if (launcherExe == null) {
|
||||||
|
implementation("org.glavo.hmcl:HMCLauncher:3.6.0.1")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun digest(algorithm: String, bytes: ByteArray): ByteArray = MessageDigest.getInstance(algorithm).digest(bytes)
|
fun digest(algorithm: String, bytes: ByteArray): ByteArray = MessageDigest.getInstance(algorithm).digest(bytes)
|
||||||
@ -154,23 +160,18 @@ tasks.getByName<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("sha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (launcherExe != null) {
|
||||||
|
into("assets") {
|
||||||
|
from(file(launcherExe))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
attachSignature(jarPath)
|
attachSignature(jarPath)
|
||||||
createChecksum(jarPath)
|
createChecksum(jarPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createExecutable(suffix: String, header: String) {
|
|
||||||
val output = File(jarPath.parentFile, jarPath.nameWithoutExtension + '.' + suffix)
|
|
||||||
|
|
||||||
output.outputStream().use {
|
|
||||||
it.write(File(project.projectDir, header).readBytes())
|
|
||||||
it.write(jarPath.readBytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
createChecksum(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.processResources {
|
tasks.processResources {
|
||||||
into("META-INF/versions/11") {
|
into("META-INF/versions/11") {
|
||||||
from(sourceSets["java11"].output)
|
from(sourceSets["java11"].output)
|
||||||
@ -179,10 +180,30 @@ tasks.processResources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val makeExecutables = tasks.create("makeExecutables") {
|
val makeExecutables = tasks.create("makeExecutables") {
|
||||||
|
val extensions = listOf("exe", "sh")
|
||||||
|
|
||||||
dependsOn(tasks.jar)
|
dependsOn(tasks.jar)
|
||||||
|
|
||||||
|
inputs.file(jarPath)
|
||||||
|
outputs.files(extensions.map { File(jarPath.parentFile, jarPath.nameWithoutExtension + '.' + it) })
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
createExecutable("exe", "src/main/resources/assets/HMCLauncher.exe")
|
val jarContent = jarPath.readBytes()
|
||||||
createExecutable("sh", "src/main/resources/assets/HMCLauncher.sh")
|
|
||||||
|
ZipFile(jarPath).use { zipFile ->
|
||||||
|
for (extension in extensions) {
|
||||||
|
val output = File(jarPath.parentFile, jarPath.nameWithoutExtension + '.' + extension)
|
||||||
|
val entry = zipFile.getEntry("assets/HMCLauncher.$extension")
|
||||||
|
?: throw GradleException("HMCLauncher.$extension not found")
|
||||||
|
|
||||||
|
output.outputStream().use { outputStream ->
|
||||||
|
zipFile.getInputStream(entry).use { it.copyTo(outputStream) }
|
||||||
|
outputStream.write(jarContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
createChecksum(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,9 +211,9 @@ tasks.build {
|
|||||||
dependsOn(makeExecutables)
|
dependsOn(makeExecutables)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseToolOptions(options: String?): List<String> {
|
fun parseToolOptions(options: String?): MutableList<String> {
|
||||||
if (options == null)
|
if (options == null)
|
||||||
return listOf()
|
return mutableListOf()
|
||||||
|
|
||||||
val builder = StringBuilder()
|
val builder = StringBuilder()
|
||||||
val result = mutableListOf<String>()
|
val result = mutableListOf<String>()
|
||||||
@ -249,10 +270,22 @@ tasks.create<JavaExec>("run") {
|
|||||||
workingDir = rootProject.rootDir
|
workingDir = rootProject.rootDir
|
||||||
|
|
||||||
val vmOptions = parseToolOptions(System.getenv("HMCL_JAVA_OPTS"))
|
val vmOptions = parseToolOptions(System.getenv("HMCL_JAVA_OPTS"))
|
||||||
|
if (vmOptions.none { it.startsWith("-Dhmcl.offline.auth.restricted=") })
|
||||||
|
vmOptions += "-Dhmcl.offline.auth.restricted=false"
|
||||||
|
|
||||||
jvmArgs(vmOptions)
|
jvmArgs(vmOptions)
|
||||||
|
|
||||||
|
val hmclJavaHome = System.getenv("HMCL_JAVA_HOME")
|
||||||
|
if (hmclJavaHome != null) {
|
||||||
|
this.executable(
|
||||||
|
file(hmclJavaHome).resolve("bin")
|
||||||
|
.resolve(if (System.getProperty("os.name").lowercase().startsWith("windows")) "java.exe" else "java")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
doFirst {
|
doFirst {
|
||||||
logger.quiet("HMCL_JAVA_OPTS: $vmOptions")
|
logger.quiet("HMCL_JAVA_OPTS: {}", vmOptions)
|
||||||
|
logger.quiet("HMCL_JAVA_HOME: {}", hmclJavaHome ?: System.getProperty("java.home"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,12 +37,16 @@ public final class Metadata {
|
|||||||
public static final String TITLE = NAME + " " + VERSION;
|
public static final String TITLE = NAME + " " + VERSION;
|
||||||
public static final String FULL_TITLE = FULL_NAME + " v" + VERSION;
|
public static final String FULL_TITLE = FULL_NAME + " v" + VERSION;
|
||||||
|
|
||||||
public static final String HMCL_UPDATE_URL = System.getProperty("hmcl.update_source.override", "https://hmcl.huangyuhui.net/api/update_link");
|
|
||||||
public static final String CONTACT_URL = "https://docs.hmcl.net/help.html";
|
|
||||||
public static final String HELP_URL = "https://docs.hmcl.net";
|
|
||||||
public static final String CHANGELOG_URL = "https://docs.hmcl.net/changelog/";
|
|
||||||
public static final String PUBLISH_URL = "https://hmcl.huangyuhui.net";
|
public static final String PUBLISH_URL = "https://hmcl.huangyuhui.net";
|
||||||
public static final String EULA_URL = "https://docs.hmcl.net/eula/hmcl.html";
|
public static final String ABOUT_URL = PUBLISH_URL + "/about";
|
||||||
|
public static final String DOWNLOAD_URL = PUBLISH_URL + "/download";
|
||||||
|
public static final String HMCL_UPDATE_URL = System.getProperty("hmcl.update_source.override", PUBLISH_URL + "/api/update_link");
|
||||||
|
|
||||||
|
public static final String DOCS_URL = "https://docs.hmcl.net";
|
||||||
|
public static final String CONTACT_URL = DOCS_URL + "/help.html";
|
||||||
|
public static final String CHANGELOG_URL = DOCS_URL + "/changelog/";
|
||||||
|
public static final String EULA_URL = DOCS_URL + "/eula/hmcl.html";
|
||||||
|
public static final String GROUPS_URL = DOCS_URL + "/groups.html";
|
||||||
|
|
||||||
public static final String BUILD_CHANNEL = JarUtils.getManifestAttribute("Build-Channel", "nightly");
|
public static final String BUILD_CHANNEL = JarUtils.getManifestAttribute("Build-Channel", "nightly");
|
||||||
public static final String GITHUB_SHA = JarUtils.getManifestAttribute("GitHub-SHA", null);
|
public static final String GITHUB_SHA = JarUtils.getManifestAttribute("GitHub-SHA", null);
|
||||||
|
@ -509,16 +509,16 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
|||||||
|
|
||||||
public static long getAllocatedMemory(long minimum, long available, boolean auto) {
|
public static long getAllocatedMemory(long minimum, long available, boolean auto) {
|
||||||
if (auto) {
|
if (auto) {
|
||||||
available -= 384 * 1024 * 1024; // Reserve 384MiB memory for off-heap memory and HMCL itself
|
available -= 512 * 1024 * 1024; // Reserve 512 MiB memory for off-heap memory and HMCL itself
|
||||||
if (available <= 0) {
|
if (available <= 0) {
|
||||||
return minimum;
|
return minimum;
|
||||||
}
|
}
|
||||||
|
|
||||||
final long threshold = 8L * 1024 * 1024 * 1024;
|
final long threshold = 8L * 1024 * 1024 * 1024; // 8 GiB
|
||||||
final long suggested = Math.min(available <= threshold
|
final long suggested = Math.min(available <= threshold
|
||||||
? (long) (available * 0.8)
|
? (long) (available * 0.8)
|
||||||
: (long) (threshold * 0.8 + (available - threshold) * 0.2),
|
: (long) (threshold * 0.8 + (available - threshold) * 0.2),
|
||||||
16384L * 1024 * 1024);
|
16L * 1024 * 1024 * 1024);
|
||||||
return Math.max(minimum, suggested);
|
return Math.max(minimum, suggested);
|
||||||
} else {
|
} else {
|
||||||
return minimum;
|
return minimum;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.game;
|
package org.jackhuang.hmcl.game;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
||||||
import org.jackhuang.hmcl.mod.Modpack;
|
import org.jackhuang.hmcl.mod.Modpack;
|
||||||
@ -64,7 +64,7 @@ public final class HMCLModpackProvider implements ModpackProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Modpack readManifest(ZipFile file, Path path, Charset encoding) throws IOException, JsonParseException {
|
public Modpack readManifest(ZipArchiveReader file, Path path, Charset encoding) throws IOException, JsonParseException {
|
||||||
String manifestJson = CompressingUtils.readTextZipEntry(file, "modpack.json");
|
String manifestJson = CompressingUtils.readTextZipEntry(file, "modpack.json");
|
||||||
Modpack manifest = JsonUtils.fromNonNullJson(manifestJson, HMCLModpack.class).setEncoding(encoding);
|
Modpack manifest = JsonUtils.fromNonNullJson(manifestJson, HMCLModpack.class).setEncoding(encoding);
|
||||||
String gameJson = CompressingUtils.readTextZipEntry(file, "minecraft/pack.json");
|
String gameJson = CompressingUtils.readTextZipEntry(file, "minecraft/pack.json");
|
||||||
|
@ -894,9 +894,6 @@ public final class LauncherHelper {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String ORACLEJDK_DOWNLOAD_LINK = "https://www.java.com/download/";
|
|
||||||
private static final String OPENJDK_DOWNLOAD_LINK = "https://learn.microsoft.com/java/openjdk/download";
|
|
||||||
|
|
||||||
public static final Queue<ManagedProcess> PROCESSES = new ConcurrentLinkedQueue<>();
|
public static final Queue<ManagedProcess> PROCESSES = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
public static void stopManagedProcesses() {
|
public static void stopManagedProcesses() {
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.game;
|
package org.jackhuang.hmcl.game;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.mod.*;
|
import org.jackhuang.hmcl.mod.*;
|
||||||
import org.jackhuang.hmcl.mod.curse.CurseModpackProvider;
|
import org.jackhuang.hmcl.mod.curse.CurseModpackProvider;
|
||||||
import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackManifest;
|
import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackManifest;
|
||||||
@ -83,7 +83,7 @@ public final class ModpackHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Modpack readModpackManifest(Path file, Charset charset) throws UnsupportedModpackException, ManuallyCreatedModpackException {
|
public static Modpack readModpackManifest(Path file, Charset charset) throws UnsupportedModpackException, ManuallyCreatedModpackException {
|
||||||
try (ZipFile zipFile = CompressingUtils.openZipFile(file, charset)) {
|
try (ZipArchiveReader zipFile = CompressingUtils.openZipFile(file, charset)) {
|
||||||
// Order for trying detecting manifest is necessary here.
|
// Order for trying detecting manifest is necessary here.
|
||||||
// Do not change to iterating providers.
|
// Do not change to iterating providers.
|
||||||
for (ModpackProvider provider : new ModpackProvider[]{
|
for (ModpackProvider provider : new ModpackProvider[]{
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.java;
|
package org.jackhuang.hmcl.java;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
import kala.compress.archivers.ArchiveEntry;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.DigestUtils;
|
import org.jackhuang.hmcl.util.DigestUtils;
|
||||||
import org.jackhuang.hmcl.util.Hex;
|
import org.jackhuang.hmcl.util.Hex;
|
||||||
|
@ -22,6 +22,7 @@ import javafx.beans.Observable;
|
|||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.auth.*;
|
import org.jackhuang.hmcl.auth.*;
|
||||||
@ -50,6 +51,7 @@ import java.util.*;
|
|||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
import static javafx.collections.FXCollections.observableArrayList;
|
import static javafx.collections.FXCollections.observableArrayList;
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
|
import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
|
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
|
||||||
import static org.jackhuang.hmcl.util.Lang.immutableListOf;
|
import static org.jackhuang.hmcl.util.Lang.immutableListOf;
|
||||||
import static org.jackhuang.hmcl.util.Lang.mapOf;
|
import static org.jackhuang.hmcl.util.Lang.mapOf;
|
||||||
@ -277,6 +279,30 @@ public final class Accounts {
|
|||||||
selected = accounts.get(0);
|
selected = accounts.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!globalConfig().isEnableOfflineAccount())
|
||||||
|
for (Account account : accounts) {
|
||||||
|
if (account instanceof MicrosoftAccount) {
|
||||||
|
globalConfig().setEnableOfflineAccount(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!globalConfig().isEnableOfflineAccount())
|
||||||
|
accounts.addListener(new ListChangeListener<Account>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(Change<? extends Account> change) {
|
||||||
|
while (change.next()) {
|
||||||
|
for (Account account : change.getAddedSubList()) {
|
||||||
|
if (account instanceof MicrosoftAccount) {
|
||||||
|
accounts.removeListener(this);
|
||||||
|
globalConfig().setEnableOfflineAccount(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
selectedAccount.set(selected);
|
selectedAccount.set(selected);
|
||||||
|
|
||||||
InvalidationListener listener = o -> {
|
InvalidationListener listener = o -> {
|
||||||
|
@ -20,6 +20,7 @@ package org.jackhuang.hmcl.setting;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.ToNumberPolicy;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import javafx.beans.InvalidationListener;
|
import javafx.beans.InvalidationListener;
|
||||||
import javafx.beans.Observable;
|
import javafx.beans.Observable;
|
||||||
@ -60,6 +61,7 @@ public final class Config implements Observable {
|
|||||||
.registerTypeAdapter(EnumBackgroundImage.class, new EnumOrdinalDeserializer<>(EnumBackgroundImage.class)) // backward compatibility for backgroundType
|
.registerTypeAdapter(EnumBackgroundImage.class, new EnumOrdinalDeserializer<>(EnumBackgroundImage.class)) // backward compatibility for backgroundType
|
||||||
.registerTypeAdapter(Proxy.Type.class, new EnumOrdinalDeserializer<>(Proxy.Type.class)) // backward compatibility for hasProxy
|
.registerTypeAdapter(Proxy.Type.class, new EnumOrdinalDeserializer<>(Proxy.Type.class)) // backward compatibility for hasProxy
|
||||||
.setPrettyPrinting()
|
.setPrettyPrinting()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -21,7 +21,9 @@ import com.google.gson.*;
|
|||||||
import com.google.gson.annotations.JsonAdapter;
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
import javafx.beans.InvalidationListener;
|
import javafx.beans.InvalidationListener;
|
||||||
import javafx.beans.Observable;
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableSet;
|
import javafx.collections.ObservableSet;
|
||||||
@ -53,6 +55,8 @@ public final class GlobalConfig implements Observable {
|
|||||||
|
|
||||||
private final IntegerProperty logRetention = new SimpleIntegerProperty();
|
private final IntegerProperty logRetention = new SimpleIntegerProperty();
|
||||||
|
|
||||||
|
private final BooleanProperty enableOfflineAccount = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
private final ObservableSet<String> userJava = FXCollections.observableSet(new LinkedHashSet<>());
|
private final ObservableSet<String> userJava = FXCollections.observableSet(new LinkedHashSet<>());
|
||||||
|
|
||||||
private final ObservableSet<String> disabledJava = FXCollections.observableSet(new LinkedHashSet<>());
|
private final ObservableSet<String> disabledJava = FXCollections.observableSet(new LinkedHashSet<>());
|
||||||
@ -115,6 +119,18 @@ public final class GlobalConfig implements Observable {
|
|||||||
this.logRetention.set(logRetention);
|
this.logRetention.set(logRetention);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEnableOfflineAccount() {
|
||||||
|
return enableOfflineAccount.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanProperty enableOfflineAccountProperty() {
|
||||||
|
return enableOfflineAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableOfflineAccount(boolean value) {
|
||||||
|
enableOfflineAccount.set(value);
|
||||||
|
}
|
||||||
|
|
||||||
public ObservableSet<String> getUserJava() {
|
public ObservableSet<String> getUserJava() {
|
||||||
return userJava;
|
return userJava;
|
||||||
}
|
}
|
||||||
@ -129,7 +145,8 @@ public final class GlobalConfig implements Observable {
|
|||||||
"platformPromptVersion",
|
"platformPromptVersion",
|
||||||
"logRetention",
|
"logRetention",
|
||||||
"userJava",
|
"userJava",
|
||||||
"disabledJava"
|
"disabledJava",
|
||||||
|
"enableOfflineAccount"
|
||||||
));
|
));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -142,6 +159,9 @@ public final class GlobalConfig implements Observable {
|
|||||||
jsonObject.add("agreementVersion", context.serialize(src.getAgreementVersion()));
|
jsonObject.add("agreementVersion", context.serialize(src.getAgreementVersion()));
|
||||||
jsonObject.add("platformPromptVersion", context.serialize(src.getPlatformPromptVersion()));
|
jsonObject.add("platformPromptVersion", context.serialize(src.getPlatformPromptVersion()));
|
||||||
jsonObject.add("logRetention", context.serialize(src.getLogRetention()));
|
jsonObject.add("logRetention", context.serialize(src.getLogRetention()));
|
||||||
|
if (src.enableOfflineAccount.get())
|
||||||
|
jsonObject.addProperty("enableOfflineAccount", true);
|
||||||
|
|
||||||
if (!src.getUserJava().isEmpty())
|
if (!src.getUserJava().isEmpty())
|
||||||
jsonObject.add("userJava", context.serialize(src.getUserJava()));
|
jsonObject.add("userJava", context.serialize(src.getUserJava()));
|
||||||
|
|
||||||
@ -165,6 +185,7 @@ public final class GlobalConfig implements Observable {
|
|||||||
config.setAgreementVersion(Optional.ofNullable(obj.get("agreementVersion")).map(JsonElement::getAsInt).orElse(0));
|
config.setAgreementVersion(Optional.ofNullable(obj.get("agreementVersion")).map(JsonElement::getAsInt).orElse(0));
|
||||||
config.setPlatformPromptVersion(Optional.ofNullable(obj.get("platformPromptVersion")).map(JsonElement::getAsInt).orElse(0));
|
config.setPlatformPromptVersion(Optional.ofNullable(obj.get("platformPromptVersion")).map(JsonElement::getAsInt).orElse(0));
|
||||||
config.setLogRetention(Optional.ofNullable(obj.get("logRetention")).map(JsonElement::getAsInt).orElse(20));
|
config.setLogRetention(Optional.ofNullable(obj.get("logRetention")).map(JsonElement::getAsInt).orElse(20));
|
||||||
|
config.setEnableOfflineAccount(Optional.ofNullable(obj.get("enableOfflineAccount")).map(JsonElement::getAsBoolean).orElse(false));
|
||||||
|
|
||||||
JsonElement userJava = obj.get("userJava");
|
JsonElement userJava = obj.get("userJava");
|
||||||
if (userJava != null && userJava.isJsonArray()) {
|
if (userJava != null && userJava.isJsonArray()) {
|
||||||
|
@ -422,7 +422,7 @@ public class GameCrashWindow extends Stage {
|
|||||||
logButton.setOnAction(e -> showLogWindow());
|
logButton.setOnAction(e -> showLogWindow());
|
||||||
|
|
||||||
JFXButton helpButton = FXUtils.newRaisedButton(i18n("help"));
|
JFXButton helpButton = FXUtils.newRaisedButton(i18n("help"));
|
||||||
helpButton.setOnAction(e -> FXUtils.openLink("https://docs.hmcl.net/help.html"));
|
helpButton.setOnAction(e -> FXUtils.openLink(Metadata.CONTACT_URL));
|
||||||
FXUtils.installFastTooltip(helpButton, i18n("logwindow.help"));
|
FXUtils.installFastTooltip(helpButton, i18n("logwindow.help"));
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui.account;
|
|||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
@ -44,14 +45,37 @@ import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
|||||||
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
|
||||||
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
|
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor;
|
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor;
|
||||||
|
|
||||||
public class AccountListPage extends DecoratorAnimatedPage implements DecoratorPage {
|
public final class AccountListPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||||
|
static final BooleanProperty RESTRICTED = new SimpleBooleanProperty(true);
|
||||||
|
|
||||||
|
static {
|
||||||
|
String property = System.getProperty("hmcl.offline.auth.restricted", "auto");
|
||||||
|
|
||||||
|
if ("false".equals(property)
|
||||||
|
|| "auto".equals(property) && "Asia/Shanghai".equals(ZoneId.systemDefault().getId())
|
||||||
|
|| globalConfig().isEnableOfflineAccount())
|
||||||
|
RESTRICTED.set(false);
|
||||||
|
else
|
||||||
|
globalConfig().enableOfflineAccountProperty().addListener(new ChangeListener<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void changed(ObservableValue<? extends Boolean> o, Boolean oldValue, Boolean newValue) {
|
||||||
|
if (newValue) {
|
||||||
|
globalConfig().enableOfflineAccountProperty().removeListener(this);
|
||||||
|
RESTRICTED.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private final ObservableList<AccountListItem> items;
|
private final ObservableList<AccountListItem> items;
|
||||||
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.manage")));
|
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.manage")));
|
||||||
private final ListProperty<Account> accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList());
|
private final ListProperty<Account> accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList());
|
||||||
@ -88,6 +112,7 @@ public class AccountListPage extends DecoratorAnimatedPage implements DecoratorP
|
|||||||
private static class AccountListPageSkin extends DecoratorAnimatedPageSkin<AccountListPage> {
|
private static class AccountListPageSkin extends DecoratorAnimatedPageSkin<AccountListPage> {
|
||||||
|
|
||||||
private final ObservableList<AdvancedListItem> authServerItems;
|
private final ObservableList<AdvancedListItem> authServerItems;
|
||||||
|
private ChangeListener<Boolean> holder;
|
||||||
|
|
||||||
public AccountListPageSkin(AccountListPage skinnable) {
|
public AccountListPageSkin(AccountListPage skinnable) {
|
||||||
super(skinnable);
|
super(skinnable);
|
||||||
@ -96,24 +121,21 @@ public class AccountListPage extends DecoratorAnimatedPage implements DecoratorP
|
|||||||
VBox boxMethods = new VBox();
|
VBox boxMethods = new VBox();
|
||||||
{
|
{
|
||||||
boxMethods.getStyleClass().add("advanced-list-box-content");
|
boxMethods.getStyleClass().add("advanced-list-box-content");
|
||||||
boxMethods.getChildren().add(new ClassTitle(i18n("account.create").toUpperCase(Locale.ROOT)));
|
|
||||||
FXUtils.setLimitWidth(boxMethods, 200);
|
FXUtils.setLimitWidth(boxMethods, 200);
|
||||||
|
|
||||||
AdvancedListItem offlineItem = new AdvancedListItem();
|
|
||||||
offlineItem.getStyleClass().add("navigation-drawer-item");
|
|
||||||
offlineItem.setActionButtonVisible(false);
|
|
||||||
offlineItem.setTitle(i18n("account.methods.offline"));
|
|
||||||
offlineItem.setLeftGraphic(wrap(SVG.PERSON));
|
|
||||||
offlineItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_OFFLINE)));
|
|
||||||
boxMethods.getChildren().add(offlineItem);
|
|
||||||
|
|
||||||
AdvancedListItem microsoftItem = new AdvancedListItem();
|
AdvancedListItem microsoftItem = new AdvancedListItem();
|
||||||
microsoftItem.getStyleClass().add("navigation-drawer-item");
|
microsoftItem.getStyleClass().add("navigation-drawer-item");
|
||||||
microsoftItem.setActionButtonVisible(false);
|
microsoftItem.setActionButtonVisible(false);
|
||||||
microsoftItem.setTitle(i18n("account.methods.microsoft"));
|
microsoftItem.setTitle(i18n("account.methods.microsoft"));
|
||||||
microsoftItem.setLeftGraphic(wrap(SVG.MICROSOFT));
|
microsoftItem.setLeftGraphic(wrap(SVG.MICROSOFT));
|
||||||
microsoftItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_MICROSOFT)));
|
microsoftItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_MICROSOFT)));
|
||||||
boxMethods.getChildren().add(microsoftItem);
|
|
||||||
|
AdvancedListItem offlineItem = new AdvancedListItem();
|
||||||
|
offlineItem.getStyleClass().add("navigation-drawer-item");
|
||||||
|
offlineItem.setActionButtonVisible(false);
|
||||||
|
offlineItem.setTitle(i18n("account.methods.offline"));
|
||||||
|
offlineItem.setLeftGraphic(wrap(SVG.PERSON));
|
||||||
|
offlineItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_OFFLINE)));
|
||||||
|
|
||||||
VBox boxAuthServers = new VBox();
|
VBox boxAuthServers = new VBox();
|
||||||
authServerItems = MappedObservableList.create(skinnable.authServersProperty(), server -> {
|
authServerItems = MappedObservableList.create(skinnable.authServersProperty(), server -> {
|
||||||
@ -149,7 +171,29 @@ public class AccountListPage extends DecoratorAnimatedPage implements DecoratorP
|
|||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
Bindings.bindContent(boxAuthServers.getChildren(), authServerItems);
|
Bindings.bindContent(boxAuthServers.getChildren(), authServerItems);
|
||||||
boxMethods.getChildren().add(boxAuthServers);
|
|
||||||
|
ClassTitle title = new ClassTitle(i18n("account.create").toUpperCase(Locale.ROOT));
|
||||||
|
if (RESTRICTED.get()) {
|
||||||
|
VBox wrapper = new VBox(offlineItem, boxAuthServers);
|
||||||
|
wrapper.setPadding(Insets.EMPTY);
|
||||||
|
FXUtils.installFastTooltip(wrapper, i18n("account.login.restricted"));
|
||||||
|
|
||||||
|
offlineItem.setDisable(true);
|
||||||
|
boxAuthServers.setDisable(true);
|
||||||
|
|
||||||
|
boxMethods.getChildren().setAll(title, microsoftItem, wrapper);
|
||||||
|
|
||||||
|
holder = FXUtils.onWeakChange(RESTRICTED, value -> {
|
||||||
|
if (!value) {
|
||||||
|
holder = null;
|
||||||
|
offlineItem.setDisable(false);
|
||||||
|
boxAuthServers.setDisable(false);
|
||||||
|
boxMethods.getChildren().setAll(title, microsoftItem, offlineItem, boxAuthServers);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
boxMethods.getChildren().setAll(title, microsoftItem, offlineItem, boxAuthServers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AdvancedListItem addAuthServerItem = new AdvancedListItem();
|
AdvancedListItem addAuthServerItem = new AdvancedListItem();
|
||||||
|
@ -35,6 +35,8 @@ import javafx.scene.control.Hyperlink;
|
|||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.TextInputControl;
|
import javafx.scene.control.TextInputControl;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.auth.AccountFactory;
|
import org.jackhuang.hmcl.auth.AccountFactory;
|
||||||
import org.jackhuang.hmcl.auth.CharacterSelector;
|
import org.jackhuang.hmcl.auth.CharacterSelector;
|
||||||
import org.jackhuang.hmcl.auth.NoSelectedCharacterException;
|
import org.jackhuang.hmcl.auth.NoSelectedCharacterException;
|
||||||
@ -106,12 +108,17 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
|
|||||||
|
|
||||||
public CreateAccountPane(AccountFactory<?> factory) {
|
public CreateAccountPane(AccountFactory<?> factory) {
|
||||||
if (factory == null) {
|
if (factory == null) {
|
||||||
showMethodSwitcher = true;
|
if (AccountListPage.RESTRICTED.get()) {
|
||||||
String preferred = config().getPreferredLoginType();
|
showMethodSwitcher = false;
|
||||||
try {
|
factory = Accounts.FACTORY_MICROSOFT;
|
||||||
factory = Accounts.getAccountFactory(preferred);
|
} else {
|
||||||
} catch (IllegalArgumentException e) {
|
showMethodSwitcher = true;
|
||||||
factory = Accounts.FACTORY_OFFLINE;
|
String preferred = config().getPreferredLoginType();
|
||||||
|
try {
|
||||||
|
factory = Accounts.getAccountFactory(preferred);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
factory = Accounts.FACTORY_OFFLINE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showMethodSwitcher = false;
|
showMethodSwitcher = false;
|
||||||
@ -337,7 +344,7 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
|
|||||||
hintPane.setSegment(i18n("account.methods.microsoft.snapshot"));
|
hintPane.setSegment(i18n("account.methods.microsoft.snapshot"));
|
||||||
|
|
||||||
JFXHyperlink officialWebsite = new JFXHyperlink(i18n("account.methods.microsoft.snapshot.website"));
|
JFXHyperlink officialWebsite = new JFXHyperlink(i18n("account.methods.microsoft.snapshot.website"));
|
||||||
officialWebsite.setExternalLink("https://hmcl.huangyuhui.net");
|
officialWebsite.setExternalLink(Metadata.PUBLISH_URL);
|
||||||
|
|
||||||
vbox.getChildren().setAll(hintPane, officialWebsite);
|
vbox.getChildren().setAll(hintPane, officialWebsite);
|
||||||
btnAccept.setDisable(true);
|
btnAccept.setDisable(true);
|
||||||
|
@ -154,7 +154,7 @@ public class OfflineAccountSkinPane extends StackPane {
|
|||||||
result.getCape() != null ? result.getCape().getImage() : null);
|
result.getCape() != null ? result.getCape().getImage() : null);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}, skinItem.selectedDataProperty(), cslApiField.textProperty(), skinSelector.valueProperty(), capeSelector.valueProperty());
|
}, skinItem.selectedDataProperty(), cslApiField.textProperty(), modelCombobox.valueProperty(), skinSelector.valueProperty(), capeSelector.valueProperty());
|
||||||
|
|
||||||
FXUtils.onChangeAndOperate(skinItem.selectedDataProperty(), selectedData -> {
|
FXUtils.onChangeAndOperate(skinItem.selectedDataProperty(), selectedData -> {
|
||||||
GridPane gridPane = new GridPane();
|
GridPane gridPane = new GridPane();
|
||||||
|
@ -203,7 +203,11 @@ public class DecoratorController {
|
|||||||
case CUSTOM:
|
case CUSTOM:
|
||||||
String backgroundImage = config().getBackgroundImage();
|
String backgroundImage = config().getBackgroundImage();
|
||||||
if (backgroundImage != null)
|
if (backgroundImage != null)
|
||||||
image = tryLoadImage(Paths.get(backgroundImage));
|
try {
|
||||||
|
image = tryLoadImage(Paths.get(backgroundImage));
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warning("Couldn't load background image", e);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NETWORK:
|
case NETWORK:
|
||||||
String backgroundImageUrl = config().getBackgroundImageUrl();
|
String backgroundImageUrl = config().getBackgroundImageUrl();
|
||||||
|
@ -34,6 +34,8 @@ import javafx.scene.layout.*;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
import org.jackhuang.hmcl.setting.Theme;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
@ -190,7 +192,7 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
btnHelp.setFocusTraversable(false);
|
btnHelp.setFocusTraversable(false);
|
||||||
btnHelp.setGraphic(SVG.HELP.createIcon(Theme.foregroundFillBinding(), -1));
|
btnHelp.setGraphic(SVG.HELP.createIcon(Theme.foregroundFillBinding(), -1));
|
||||||
btnHelp.getStyleClass().add("jfx-decorator-button");
|
btnHelp.getStyleClass().add("jfx-decorator-button");
|
||||||
btnHelp.setOnAction(e -> FXUtils.openLink("https://docs.hmcl.net/help.html"));
|
btnHelp.setOnAction(e -> FXUtils.openLink(Metadata.CONTACT_URL));
|
||||||
|
|
||||||
JFXButton btnMin = new JFXButton();
|
JFXButton btnMin = new JFXButton();
|
||||||
btnMin.setFocusTraversable(false);
|
btnMin.setFocusTraversable(false);
|
||||||
|
@ -130,7 +130,7 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void download(Profile profile, @Nullable String version, RemoteMod.Version file, String subdirectoryName) {
|
public static void download(Profile profile, @Nullable String version, RemoteMod.Version file, String subdirectoryName) {
|
||||||
if (version == null) version = profile.getSelectedVersion();
|
if (version == null) version = profile.getSelectedVersion();
|
||||||
|
|
||||||
Path runDirectory = profile.getRepository().hasVersion(version) ? profile.getRepository().getRunDirectory(version).toPath() : profile.getRepository().getBaseDirectory().toPath();
|
Path runDirectory = profile.getRepository().hasVersion(version) ? profile.getRepository().getRunDirectory(version).toPath() : profile.getRepository().getBaseDirectory().toPath();
|
||||||
|
@ -292,6 +292,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
|||||||
switch (it.getVersionType()) {
|
switch (it.getVersionType()) {
|
||||||
case RELEASE:
|
case RELEASE:
|
||||||
return chkRelease.isSelected();
|
return chkRelease.isSelected();
|
||||||
|
case PENDING:
|
||||||
case SNAPSHOT:
|
case SNAPSHOT:
|
||||||
return chkSnapshot.isSelected();
|
return chkSnapshot.isSelected();
|
||||||
case OLD:
|
case OLD:
|
||||||
@ -411,11 +412,10 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
|
|||||||
content.setImage(VersionIconType.GRASS.getIcon());
|
content.setImage(VersionIconType.GRASS.getIcon());
|
||||||
content.setExternalLink(i18n("wiki.version.game.release", remoteVersion.getGameVersion()));
|
content.setExternalLink(i18n("wiki.version.game.release", remoteVersion.getGameVersion()));
|
||||||
break;
|
break;
|
||||||
|
case PENDING:
|
||||||
case SNAPSHOT:
|
case SNAPSHOT:
|
||||||
content.getTags().setAll(i18n("version.game.snapshot"));
|
content.getTags().setAll(i18n("version.game.snapshot"));
|
||||||
content.setImage(VersionIconType.COMMAND.getIcon());
|
content.setImage(VersionIconType.COMMAND.getIcon());
|
||||||
|
|
||||||
|
|
||||||
content.setExternalLink(i18n("wiki.version.game.snapshot", remoteVersion.getGameVersion()));
|
content.setExternalLink(i18n("wiki.version.game.snapshot", remoteVersion.getGameVersion()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -27,6 +27,8 @@ import javafx.scene.Node;
|
|||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
||||||
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||||
@ -173,7 +175,7 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
|||||||
|
|
||||||
if (skinnable.controller.getSettings().get(MODPACK_TYPE) == MODPACK_TYPE_SERVER) {
|
if (skinnable.controller.getSettings().get(MODPACK_TYPE) == MODPACK_TYPE_SERVER) {
|
||||||
Hyperlink hyperlink = new Hyperlink(i18n("modpack.wizard.step.initialization.server"));
|
Hyperlink hyperlink = new Hyperlink(i18n("modpack.wizard.step.initialization.server"));
|
||||||
hyperlink.setOnAction(e -> FXUtils.openLink("https://docs.hmcl.net/modpack/serverpack.html"));
|
hyperlink.setOnAction(e -> FXUtils.openLink(Metadata.DOCS_URL + "/modpack/serverpack.html"));
|
||||||
borderPane.setTop(hyperlink);
|
borderPane.setTop(hyperlink);
|
||||||
} else {
|
} else {
|
||||||
HintPane pane = new HintPane(MessageDialogPane.MessageType.INFO);
|
HintPane pane = new HintPane(MessageDialogPane.MessageType.INFO);
|
||||||
|
@ -43,12 +43,15 @@ public final class ModpackTypeSelectionPage extends VBox implements WizardPage {
|
|||||||
|
|
||||||
public ModpackTypeSelectionPage(WizardController controller) {
|
public ModpackTypeSelectionPage(WizardController controller) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
|
this.setPadding(new Insets(10));
|
||||||
|
|
||||||
Label title = new Label(i18n("modpack.export.as"));
|
Label title = new Label(i18n("modpack.export.as"));
|
||||||
title.setPadding(new Insets(8));
|
VBox.setMargin(title, new Insets(8, 0, 8, 12));
|
||||||
|
|
||||||
this.getStyleClass().add("jfx-list-view");
|
this.getStyleClass().add("jfx-list-view");
|
||||||
this.setMaxSize(300, 150);
|
this.setMaxSize(400, 150);
|
||||||
|
this.setSpacing(8);
|
||||||
|
|
||||||
this.getChildren().setAll(
|
this.getChildren().setAll(
|
||||||
title,
|
title,
|
||||||
createButton(MODPACK_TYPE_MCBBS, McbbsModpackExportTask.OPTION),
|
createButton(MODPACK_TYPE_MCBBS, McbbsModpackExportTask.OPTION),
|
||||||
@ -59,6 +62,8 @@ public final class ModpackTypeSelectionPage extends VBox implements WizardPage {
|
|||||||
|
|
||||||
private JFXButton createButton(String type, ModpackExportInfo.Options option) {
|
private JFXButton createButton(String type, ModpackExportInfo.Options option) {
|
||||||
JFXButton button = new JFXButton();
|
JFXButton button = new JFXButton();
|
||||||
|
|
||||||
|
button.getStyleClass().add("card");
|
||||||
button.setOnAction(e -> {
|
button.setOnAction(e -> {
|
||||||
controller.getSettings().put(MODPACK_TYPE, type);
|
controller.getSettings().put(MODPACK_TYPE, type);
|
||||||
controller.getSettings().put(MODPACK_INFO_OPTION, option);
|
controller.getSettings().put(MODPACK_INFO_OPTION, option);
|
||||||
|
@ -50,7 +50,7 @@ public final class AboutPage extends StackPane {
|
|||||||
launcher.setImage(FXUtils.newBuiltinImage("/assets/img/icon.png"));
|
launcher.setImage(FXUtils.newBuiltinImage("/assets/img/icon.png"));
|
||||||
launcher.setTitle("Hello Minecraft! Launcher");
|
launcher.setTitle("Hello Minecraft! Launcher");
|
||||||
launcher.setSubtitle(Metadata.VERSION);
|
launcher.setSubtitle(Metadata.VERSION);
|
||||||
launcher.setExternalLink("https://hmcl.huangyuhui.net");
|
launcher.setExternalLink(Metadata.PUBLISH_URL);
|
||||||
|
|
||||||
IconedTwoLineListItem author = new IconedTwoLineListItem();
|
IconedTwoLineListItem author = new IconedTwoLineListItem();
|
||||||
author.setImage(FXUtils.newBuiltinImage("/assets/img/yellow_fish.png"));
|
author.setImage(FXUtils.newBuiltinImage("/assets/img/yellow_fish.png"));
|
||||||
@ -70,7 +70,7 @@ public final class AboutPage extends StackPane {
|
|||||||
IconedTwoLineListItem copyright = new IconedTwoLineListItem();
|
IconedTwoLineListItem copyright = new IconedTwoLineListItem();
|
||||||
copyright.setTitle(i18n("about.copyright"));
|
copyright.setTitle(i18n("about.copyright"));
|
||||||
copyright.setSubtitle(i18n("about.copyright.statement"));
|
copyright.setSubtitle(i18n("about.copyright.statement"));
|
||||||
copyright.setExternalLink("https://hmcl.huangyuhui.net/about/");
|
copyright.setExternalLink(Metadata.ABOUT_URL);
|
||||||
|
|
||||||
IconedTwoLineListItem claim = new IconedTwoLineListItem();
|
IconedTwoLineListItem claim = new IconedTwoLineListItem();
|
||||||
claim.setTitle(i18n("about.claim"));
|
claim.setTitle(i18n("about.claim"));
|
||||||
|
@ -27,6 +27,8 @@ import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
|||||||
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.Metadata;
|
||||||
|
|
||||||
public class FeedbackPage extends SpinnerPane {
|
public class FeedbackPage extends SpinnerPane {
|
||||||
|
|
||||||
public FeedbackPage() {
|
public FeedbackPage() {
|
||||||
@ -45,7 +47,7 @@ public class FeedbackPage extends SpinnerPane {
|
|||||||
users.setImage(FXUtils.newBuiltinImage("/assets/img/icon.png"));
|
users.setImage(FXUtils.newBuiltinImage("/assets/img/icon.png"));
|
||||||
users.setTitle(i18n("feedback.qq_group"));
|
users.setTitle(i18n("feedback.qq_group"));
|
||||||
users.setSubtitle(i18n("feedback.qq_group.statement"));
|
users.setSubtitle(i18n("feedback.qq_group.statement"));
|
||||||
users.setExternalLink("https://docs.hmcl.net/groups.html");
|
users.setExternalLink(Metadata.GROUPS_URL);
|
||||||
|
|
||||||
IconedTwoLineListItem github = new IconedTwoLineListItem();
|
IconedTwoLineListItem github = new IconedTwoLineListItem();
|
||||||
github.setImage(FXUtils.newBuiltinImage("/assets/img/github.png"));
|
github.setImage(FXUtils.newBuiltinImage("/assets/img/github.png"));
|
||||||
|
@ -53,7 +53,7 @@ public class HelpPage extends SpinnerPane {
|
|||||||
IconedTwoLineListItem docPane = new IconedTwoLineListItem();
|
IconedTwoLineListItem docPane = new IconedTwoLineListItem();
|
||||||
docPane.setTitle(i18n("help.doc"));
|
docPane.setTitle(i18n("help.doc"));
|
||||||
docPane.setSubtitle(i18n("help.detail"));
|
docPane.setSubtitle(i18n("help.detail"));
|
||||||
docPane.setExternalLink(Metadata.HELP_URL);
|
docPane.setExternalLink(Metadata.DOCS_URL);
|
||||||
ComponentList doc = new ComponentList();
|
ComponentList doc = new ComponentList();
|
||||||
doc.getContent().setAll(docPane);
|
doc.getContent().setAll(docPane);
|
||||||
content.getChildren().add(doc);
|
content.getChildren().add(doc);
|
||||||
@ -63,7 +63,7 @@ public class HelpPage extends SpinnerPane {
|
|||||||
|
|
||||||
private void loadHelp() {
|
private void loadHelp() {
|
||||||
showSpinner();
|
showSpinner();
|
||||||
Task.supplyAsync(() -> HttpRequest.GET("https://docs.hmcl.net/index.json").getJson(listTypeOf(HelpCategory.class)))
|
Task.supplyAsync(() -> HttpRequest.GET(Metadata.DOCS_URL + "/index.json").getJson(listTypeOf(HelpCategory.class)))
|
||||||
.thenAcceptAsync(Schedulers.javafx(), helpCategories -> {
|
.thenAcceptAsync(Schedulers.javafx(), helpCategories -> {
|
||||||
for (HelpCategory category : helpCategories) {
|
for (HelpCategory category : helpCategories) {
|
||||||
ComponentList categoryPane = new ComponentList();
|
ComponentList categoryPane = new ComponentList();
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
package org.jackhuang.hmcl.ui.main;
|
package org.jackhuang.hmcl.ui.main;
|
||||||
|
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.event.EventBus;
|
import org.jackhuang.hmcl.event.EventBus;
|
||||||
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
||||||
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||||
@ -179,7 +181,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
|||||||
chatItem.setLeftGraphic(wrap(SVG.CHAT));
|
chatItem.setLeftGraphic(wrap(SVG.CHAT));
|
||||||
chatItem.setActionButtonVisible(false);
|
chatItem.setActionButtonVisible(false);
|
||||||
chatItem.setTitle(i18n("chat"));
|
chatItem.setTitle(i18n("chat"));
|
||||||
chatItem.setOnAction(e -> FXUtils.openLink("https://docs.hmcl.net/groups.html"));
|
chatItem.setOnAction(e -> FXUtils.openLink(Metadata.GROUPS_URL));
|
||||||
|
|
||||||
// the left sidebar
|
// the left sidebar
|
||||||
AdvancedListBox sideBar = new AdvancedListBox()
|
AdvancedListBox sideBar = new AdvancedListBox()
|
||||||
|
@ -22,7 +22,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
|||||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
import org.apache.commons.compress.utils.BoundedInputStream;
|
import kala.compress.utils.BoundedInputStream;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
@ -17,6 +17,7 @@ import org.jackhuang.hmcl.setting.VersionSetting;
|
|||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.*;
|
import org.jackhuang.hmcl.ui.construct.*;
|
||||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||||
|
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||||
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -197,9 +198,18 @@ public final class AdvancedVersionSettingPage extends StackPane implements Decor
|
|||||||
useNativeOpenALPane.setTitle(i18n("settings.advanced.use_native_openal"));
|
useNativeOpenALPane.setTitle(i18n("settings.advanced.use_native_openal"));
|
||||||
|
|
||||||
workaroundPane.getContent().setAll(
|
workaroundPane.getContent().setAll(
|
||||||
nativesDirSublist, rendererPane,
|
nativesDirSublist, rendererPane, noJVMArgsPane, noGameCheckPane,
|
||||||
noJVMArgsPane, noGameCheckPane, noJVMCheckPane, noNativesPatchPane,
|
noJVMCheckPane, noNativesPatchPane
|
||||||
useNativeGLFWPane, useNativeOpenALPane);
|
);
|
||||||
|
|
||||||
|
if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) {
|
||||||
|
workaroundPane.getContent().addAll(useNativeGLFWPane, useNativeOpenALPane);
|
||||||
|
} else {
|
||||||
|
ComponentSublist unsupportedOptionsSublist = new ComponentSublist();
|
||||||
|
unsupportedOptionsSublist.setTitle(i18n("settings.advanced.unsupported_system_options"));
|
||||||
|
unsupportedOptionsSublist.getContent().addAll(useNativeGLFWPane, useNativeOpenALPane);
|
||||||
|
workaroundPane.getContent().add(unsupportedOptionsSublist);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootPane.getChildren().addAll(
|
rootPane.getChildren().addAll(
|
||||||
|
@ -60,10 +60,7 @@ import org.jackhuang.hmcl.util.i18n.I18n;
|
|||||||
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
||||||
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent;
|
import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent;
|
||||||
@ -156,7 +153,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
FXUtils.runInFX(() -> selectedVersion.set(versionID));
|
FXUtils.runInFX(() -> selectedVersion.set(versionID));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void search(String userGameVersion, RemoteModRepository.Category category, int pageOffset, String searchFilter, RemoteModRepository.SortType sort) {
|
private void search(String userGameVersion, RemoteModRepository.Category category, int pageOffset, String searchFilter, RemoteModRepository.SortType sort) {
|
||||||
retrySearch = null;
|
retrySearch = null;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setFailed(false);
|
setFailed(false);
|
||||||
@ -171,7 +168,9 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
? version.getProfile().getRepository().getGameVersion(version.getVersion()).orElse("")
|
? version.getProfile().getRepository().getGameVersion(version.getVersion()).orElse("")
|
||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
}).thenApplyAsync(gameVersion -> repository.search(gameVersion, category, pageOffset, 50, searchFilter, sort, RemoteModRepository.SortOrder.DESC)).whenComplete(Schedulers.javafx(), (result, exception) -> {
|
}).thenApplyAsync(
|
||||||
|
gameVersion -> repository.search(gameVersion, category, pageOffset, 50, searchFilter, sort, RemoteModRepository.SortOrder.DESC)
|
||||||
|
).whenComplete(Schedulers.javafx(), (result, exception) -> {
|
||||||
if (searchID != currentSearchID) {
|
if (searchID != currentSearchID) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -312,7 +311,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
|
|
||||||
StackPane categoryStackPane = new StackPane();
|
StackPane categoryStackPane = new StackPane();
|
||||||
JFXComboBox<CategoryIndented> categoryComboBox = new JFXComboBox<>();
|
JFXComboBox<CategoryIndented> categoryComboBox = new JFXComboBox<>();
|
||||||
categoryComboBox.getItems().setAll(new CategoryIndented(0, null));
|
categoryComboBox.getItems().setAll(CategoryIndented.ALL);
|
||||||
categoryStackPane.getChildren().setAll(categoryComboBox);
|
categoryStackPane.getChildren().setAll(categoryComboBox);
|
||||||
categoryComboBox.prefWidthProperty().bind(categoryStackPane.widthProperty());
|
categoryComboBox.prefWidthProperty().bind(categoryStackPane.widthProperty());
|
||||||
categoryComboBox.getStyleClass().add("fit-width");
|
categoryComboBox.getStyleClass().add("fit-width");
|
||||||
@ -320,14 +319,22 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
categoryComboBox.getSelectionModel().select(0);
|
categoryComboBox.getSelectionModel().select(0);
|
||||||
categoryComboBox.setConverter(stringConverter(getSkinnable()::getLocalizedCategoryIndent));
|
categoryComboBox.setConverter(stringConverter(getSkinnable()::getLocalizedCategoryIndent));
|
||||||
FXUtils.onChangeAndOperate(getSkinnable().downloadSource, downloadSource -> {
|
FXUtils.onChangeAndOperate(getSkinnable().downloadSource, downloadSource -> {
|
||||||
|
categoryComboBox.getItems().setAll(CategoryIndented.ALL);
|
||||||
|
categoryComboBox.getSelectionModel().select(0);
|
||||||
|
|
||||||
Task.supplyAsync(() -> getSkinnable().repository.getCategories())
|
Task.supplyAsync(() -> getSkinnable().repository.getCategories())
|
||||||
.thenAcceptAsync(Schedulers.javafx(), categories -> {
|
.thenAcceptAsync(Schedulers.javafx(), categories -> {
|
||||||
|
if (!Objects.equals(getSkinnable().downloadSource.get(), downloadSource)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<CategoryIndented> result = new ArrayList<>();
|
List<CategoryIndented> result = new ArrayList<>();
|
||||||
result.add(new CategoryIndented(0, null));
|
result.add(CategoryIndented.ALL);
|
||||||
for (RemoteModRepository.Category category : Lang.toIterable(categories)) {
|
for (RemoteModRepository.Category category : Lang.toIterable(categories)) {
|
||||||
resolveCategory(category, 0, result);
|
resolveCategory(category, 0, result);
|
||||||
}
|
}
|
||||||
categoryComboBox.getItems().setAll(result);
|
categoryComboBox.getItems().setAll(result);
|
||||||
|
categoryComboBox.getSelectionModel().select(0);
|
||||||
}).start();
|
}).start();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -344,7 +351,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
IntegerProperty filterID = new SimpleIntegerProperty(this, "Filter ID", 0);
|
IntegerProperty filterID = new SimpleIntegerProperty(this, "Filter ID", 0);
|
||||||
IntegerProperty currentFilterID = new SimpleIntegerProperty(this, "Current Filter ID", -1);
|
IntegerProperty currentFilterID = new SimpleIntegerProperty(this, "Current Filter ID", -1);
|
||||||
EventHandler<ActionEvent> searchAction = e -> {
|
EventHandler<ActionEvent> searchAction = e -> {
|
||||||
if (currentFilterID.get() != filterID.get()) {
|
if (currentFilterID.get() != -1 && currentFilterID.get() != filterID.get()) {
|
||||||
control.pageOffset.set(0);
|
control.pageOffset.set(0);
|
||||||
}
|
}
|
||||||
currentFilterID.set(filterID.get());
|
currentFilterID.set(filterID.get());
|
||||||
@ -379,8 +386,8 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
JFXButton firstPageButton = FXUtils.newBorderButton(i18n("search.first_page"));
|
JFXButton firstPageButton = FXUtils.newBorderButton(i18n("search.first_page"));
|
||||||
firstPageButton.setOnAction(event -> {
|
firstPageButton.setOnAction(event -> {
|
||||||
control.pageOffset.set(0);
|
control.pageOffset.set(0);
|
||||||
changeButton.value.run();
|
|
||||||
searchAction.handle(event);
|
searchAction.handle(event);
|
||||||
|
changeButton.value.run();
|
||||||
});
|
});
|
||||||
|
|
||||||
JFXButton previousPageButton = FXUtils.newBorderButton(i18n("search.previous_page"));
|
JFXButton previousPageButton = FXUtils.newBorderButton(i18n("search.previous_page"));
|
||||||
@ -388,8 +395,8 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
int pageOffset = control.pageOffset.get();
|
int pageOffset = control.pageOffset.get();
|
||||||
if (pageOffset > 0) {
|
if (pageOffset > 0) {
|
||||||
control.pageOffset.set(pageOffset - 1);
|
control.pageOffset.set(pageOffset - 1);
|
||||||
changeButton.value.run();
|
|
||||||
searchAction.handle(event);
|
searchAction.handle(event);
|
||||||
|
changeButton.value.run();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -404,16 +411,16 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
int nv = control.pageOffset.get() + 1;
|
int nv = control.pageOffset.get() + 1;
|
||||||
if (nv < control.pageCount.get()) {
|
if (nv < control.pageCount.get()) {
|
||||||
control.pageOffset.set(nv);
|
control.pageOffset.set(nv);
|
||||||
changeButton.value.run();
|
|
||||||
searchAction.handle(event);
|
searchAction.handle(event);
|
||||||
|
changeButton.value.run();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
JFXButton lastPageButton = FXUtils.newBorderButton(i18n("search.last_page"));
|
JFXButton lastPageButton = FXUtils.newBorderButton(i18n("search.last_page"));
|
||||||
lastPageButton.setOnAction(event -> {
|
lastPageButton.setOnAction(event -> {
|
||||||
control.pageOffset.set(control.pageCount.get() - 1);
|
control.pageOffset.set(control.pageCount.get() - 1);
|
||||||
changeButton.value.run();
|
|
||||||
searchAction.handle(event);
|
searchAction.handle(event);
|
||||||
|
changeButton.value.run();
|
||||||
});
|
});
|
||||||
|
|
||||||
firstPageButton.setDisable(true);
|
firstPageButton.setDisable(true);
|
||||||
@ -529,6 +536,8 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class CategoryIndented {
|
private static class CategoryIndented {
|
||||||
|
private static final CategoryIndented ALL = new CategoryIndented(0, null);
|
||||||
|
|
||||||
private final int indent;
|
private final int indent;
|
||||||
private final RemoteModRepository.Category category;
|
private final RemoteModRepository.Category category;
|
||||||
|
|
||||||
|
@ -439,9 +439,25 @@ public class DownloadPage extends Control implements DecoratorPage {
|
|||||||
|
|
||||||
private static final class ModVersion extends JFXDialogLayout {
|
private static final class ModVersion extends JFXDialogLayout {
|
||||||
public ModVersion(RemoteMod.Version version, DownloadPage selfPage) {
|
public ModVersion(RemoteMod.Version version, DownloadPage selfPage) {
|
||||||
boolean isModpack = selfPage.repository.getType() == RemoteModRepository.Type.MODPACK;
|
RemoteModRepository.Type type = selfPage.repository.getType();
|
||||||
|
|
||||||
this.setHeading(new HBox(new Label(i18n(isModpack ? "modpack.download.title" : "mods.download.title", version.getName()))));
|
String title;
|
||||||
|
switch (type) {
|
||||||
|
case WORLD:
|
||||||
|
title = "world.download.title";
|
||||||
|
break;
|
||||||
|
case MODPACK:
|
||||||
|
title = "modpack.download.title";
|
||||||
|
break;
|
||||||
|
case RESOURCE_PACK:
|
||||||
|
title = "resourcepack.download.title";
|
||||||
|
break;
|
||||||
|
case MOD:
|
||||||
|
default:
|
||||||
|
title = "mods.download.title";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.setHeading(new HBox(new Label(i18n(title, version.getName()))));
|
||||||
|
|
||||||
VBox box = new VBox(8);
|
VBox box = new VBox(8);
|
||||||
box.setPadding(new Insets(8));
|
box.setPadding(new Insets(8));
|
||||||
@ -463,14 +479,17 @@ public class DownloadPage extends Control implements DecoratorPage {
|
|||||||
|
|
||||||
this.setBody(box);
|
this.setBody(box);
|
||||||
|
|
||||||
JFXButton downloadButton = new JFXButton(isModpack ? i18n("install.modpack") : i18n("mods.install"));
|
JFXButton downloadButton = null;
|
||||||
downloadButton.getStyleClass().add("dialog-accept");
|
if (selfPage.callback != null) {
|
||||||
downloadButton.setOnAction(e -> {
|
downloadButton = new JFXButton(type == RemoteModRepository.Type.MODPACK ? i18n("install.modpack") : i18n("mods.install"));
|
||||||
if (isModpack || !spinnerPane.isLoading() && spinnerPane.getFailedReason() == null) {
|
downloadButton.getStyleClass().add("dialog-accept");
|
||||||
fireEvent(new DialogCloseEvent());
|
downloadButton.setOnAction(e -> {
|
||||||
}
|
if (type == RemoteModRepository.Type.MODPACK || !spinnerPane.isLoading() && spinnerPane.getFailedReason() == null) {
|
||||||
selfPage.download(version);
|
fireEvent(new DialogCloseEvent());
|
||||||
});
|
}
|
||||||
|
selfPage.download(version);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
JFXButton saveAsButton = new JFXButton(i18n("mods.save_as"));
|
JFXButton saveAsButton = new JFXButton(i18n("mods.save_as"));
|
||||||
saveAsButton.getStyleClass().add("dialog-accept");
|
saveAsButton.getStyleClass().add("dialog-accept");
|
||||||
@ -485,7 +504,11 @@ public class DownloadPage extends Control implements DecoratorPage {
|
|||||||
cancelButton.getStyleClass().add("dialog-cancel");
|
cancelButton.getStyleClass().add("dialog-cancel");
|
||||||
cancelButton.setOnAction(e -> fireEvent(new DialogCloseEvent()));
|
cancelButton.setOnAction(e -> fireEvent(new DialogCloseEvent()));
|
||||||
|
|
||||||
this.setActions(downloadButton, saveAsButton, cancelButton);
|
if (downloadButton == null) {
|
||||||
|
this.setActions(saveAsButton, cancelButton);
|
||||||
|
} else {
|
||||||
|
this.setActions(downloadButton, saveAsButton, cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
this.prefWidthProperty().bind(BindingMapping.of(Controllers.getStage().widthProperty()).map(w -> w.doubleValue() * 0.7));
|
this.prefWidthProperty().bind(BindingMapping.of(Controllers.getStage().widthProperty()).map(w -> w.doubleValue() * 0.7));
|
||||||
this.prefHeightProperty().bind(BindingMapping.of(Controllers.getStage().heightProperty()).map(w -> w.doubleValue() * 0.7));
|
this.prefHeightProperty().bind(BindingMapping.of(Controllers.getStage().heightProperty()).map(w -> w.doubleValue() * 0.7));
|
||||||
|
@ -55,11 +55,11 @@ public final class HMCLLocalizedDownloadListPage extends DownloadListPage {
|
|||||||
repository = new Repository(type, curseForge, modrinth);
|
repository = new Repository(type, curseForge, modrinth);
|
||||||
|
|
||||||
supportChinese.set(true);
|
supportChinese.set(true);
|
||||||
downloadSources.get().setAll("mods.curseforge", "mods.modrinth");
|
downloadSources.get().setAll("mods.modrinth", "mods.curseforge");
|
||||||
if (curseForge != null) {
|
if (modrinth != null) {
|
||||||
downloadSource.set("mods.curseforge");
|
|
||||||
} else if (modrinth != null) {
|
|
||||||
downloadSource.set("mods.modrinth");
|
downloadSource.set("mods.modrinth");
|
||||||
|
} else if (curseForge != null) {
|
||||||
|
downloadSource.set("mods.curseforge");
|
||||||
} else {
|
} else {
|
||||||
throw new AssertionError("Should not be here.");
|
throw new AssertionError("Should not be here.");
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ public final class HMCLLocalizedDownloadListPage extends DownloadListPage {
|
|||||||
try {
|
try {
|
||||||
return I18n.getResourceBundle().getString(key);
|
return I18n.getResourceBundle().getString(key);
|
||||||
} catch (MissingResourceException e) {
|
} catch (MissingResourceException e) {
|
||||||
LOG.warning("Cannot find key " + key + " in resource bundle", e);
|
LOG.warning("Cannot find key " + key + " in resource bundle");
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -446,7 +446,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
repository instanceof CurseForgeRemoteModRepository ? HMCLLocalizedDownloadListPage.ofCurseForgeMod(null, false) : HMCLLocalizedDownloadListPage.ofModrinthMod(null, false),
|
repository instanceof CurseForgeRemoteModRepository ? HMCLLocalizedDownloadListPage.ofCurseForgeMod(null, false) : HMCLLocalizedDownloadListPage.ofModrinthMod(null, false),
|
||||||
remoteMod,
|
remoteMod,
|
||||||
new Profile.ProfileVersion(ModListPageSkin.this.getSkinnable().getProfile(), ModListPageSkin.this.getSkinnable().getVersionId()),
|
new Profile.ProfileVersion(ModListPageSkin.this.getSkinnable().getProfile(), ModListPageSkin.this.getSkinnable().getVersionId()),
|
||||||
null
|
(profile, version, file) -> org.jackhuang.hmcl.ui.download.DownloadPage.download(profile, version, file, "mods")
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
button.setDisable(false);
|
button.setDisable(false);
|
||||||
|
@ -140,7 +140,7 @@ public final class WorldBackupsPage extends ListPageBase<WorldBackupsPage.Backup
|
|||||||
}
|
}
|
||||||
|
|
||||||
void createBackup() {
|
void createBackup() {
|
||||||
Controllers.taskDialog(new WorldBackupTask(world, backupsDir).setName(i18n("world.backup")).thenApplyAsync(path -> {
|
Controllers.taskDialog(new WorldBackupTask(world, backupsDir).setName(i18n("world.backup.processing")).thenApplyAsync(path -> {
|
||||||
Matcher matcher = backupFileNamePattern.matcher(path.getFileName().toString());
|
Matcher matcher = backupFileNamePattern.matcher(path.getFileName().toString());
|
||||||
if (!matcher.matches()) {
|
if (!matcher.matches()) {
|
||||||
throw new AssertionError("Wrong backup file name" + path);
|
throw new AssertionError("Wrong backup file name" + path);
|
||||||
@ -176,7 +176,7 @@ public final class WorldBackupsPage extends ListPageBase<WorldBackupsPage.Backup
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Node> initializeToolbar(WorldBackupsPage skinnable) {
|
protected List<Node> initializeToolbar(WorldBackupsPage skinnable) {
|
||||||
return Arrays.asList(createToolbarButton2(i18n("button.refresh"), SVG.REFRESH, skinnable::refresh), createToolbarButton2(i18n("world.backup"), SVG.ARCHIVE, skinnable::createBackup));
|
return Arrays.asList(createToolbarButton2(i18n("button.refresh"), SVG.REFRESH, skinnable::refresh), createToolbarButton2(i18n("world.backup.create.new_one"), SVG.ARCHIVE, skinnable::createBackup));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,9 +113,8 @@ public final class UpdateHandler {
|
|||||||
|
|
||||||
Task<?> task = new HMCLDownloadTask(version, downloaded);
|
Task<?> task = new HMCLDownloadTask(version, downloaded);
|
||||||
|
|
||||||
TaskExecutor executor = task.executor(false);
|
TaskExecutor executor = task.executor();
|
||||||
Controllers.taskDialog(executor, i18n("message.downloading"), TaskCancellationAction.NORMAL);
|
Controllers.taskDialog(executor, i18n("message.downloading"), TaskCancellationAction.NORMAL);
|
||||||
executor.start();
|
|
||||||
thread(() -> {
|
thread(() -> {
|
||||||
boolean success = executor.test();
|
boolean success = executor.test();
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler {
|
|||||||
map.put("version", Metadata.VERSION);
|
map.put("version", Metadata.VERSION);
|
||||||
map.put("log", LOG.getLogs());
|
map.put("log", LOG.getLogs());
|
||||||
try {
|
try {
|
||||||
String response = NetworkUtils.doPost(NetworkUtils.toURL("https://hmcl.huangyuhui.net/hmcl/crash.php"), map);
|
String response = NetworkUtils.doPost(NetworkUtils.toURL(Metadata.PUBLISH_URL + "/hmcl/crash.php"), map);
|
||||||
if (StringUtils.isNotBlank(response))
|
if (StringUtils.isNotBlank(response))
|
||||||
LOG.error("Crash server response: " + response);
|
LOG.error("Crash server response: " + response);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
Binary file not shown.
@ -88,6 +88,7 @@ account.login.skip=Log in offline
|
|||||||
account.login.retry=Retry
|
account.login.retry=Retry
|
||||||
account.login.refresh=Log in again
|
account.login.refresh=Log in again
|
||||||
account.login.refresh.microsoft.hint=You need to log in to your Microsoft account again because the account authorization is invalid.
|
account.login.refresh.microsoft.hint=You need to log in to your Microsoft account again because the account authorization is invalid.
|
||||||
|
account.login.restricted=Sign in to your Microsoft account to enable this feature
|
||||||
account.logout=Logout
|
account.logout=Logout
|
||||||
account.register=Register
|
account.register=Register
|
||||||
account.manage=Account List
|
account.manage=Account List
|
||||||
@ -328,7 +329,7 @@ download=Download
|
|||||||
download.hint=Install games and modpacks or download mods, resource packs, and worlds.
|
download.hint=Install games and modpacks or download mods, resource packs, and worlds.
|
||||||
download.code.404=File "%s" not found on the remote server.
|
download.code.404=File "%s" not found on the remote server.
|
||||||
download.content=Addons
|
download.content=Addons
|
||||||
download.curseforge.unavailable=HMCL Nightly channel build does not support access to CurseForge. Please use Release or Beta channel builds to download.
|
download.curseforge.unavailable=This HMCL build does not support access to CurseForge. Please use the official build to access CurseForge.
|
||||||
download.existing=The file cannot be saved because it already exists. You can click "Save As" to save the file elsewhere.
|
download.existing=The file cannot be saved because it already exists. You can click "Save As" to save the file elsewhere.
|
||||||
download.external_link=Visit Download Website
|
download.external_link=Visit Download Website
|
||||||
download.failed=Failed to download "%1$s", response code: %2$d.
|
download.failed=Failed to download "%1$s", response code: %2$d.
|
||||||
@ -1047,17 +1048,20 @@ web.view_in_browser=View in browser
|
|||||||
|
|
||||||
world=Worlds
|
world=Worlds
|
||||||
world.add=Add World
|
world.add=Add World
|
||||||
world.backup=Backup World
|
world.backup=World Backup
|
||||||
|
world.backup.create.new_one=Create New Backup
|
||||||
world.backup.create.failed=Failed to create backup.\n%s
|
world.backup.create.failed=Failed to create backup.\n%s
|
||||||
world.backup.create.locked=The world is currently in use. Please close the game and try again.
|
world.backup.create.locked=The world is currently in use. Please close the game and try again.
|
||||||
world.backup.create.success=Successfully created a new backup: %s
|
world.backup.create.success=Successfully created a new backup: %s
|
||||||
world.backup.delete=Delete this backup
|
world.backup.delete=Delete this backup
|
||||||
|
world.backup.processing=Backing up ...
|
||||||
world.backup.reveal=Show in folder
|
world.backup.reveal=Show in folder
|
||||||
world.backup.title=World [%s] - Backups
|
world.backup.title=World [%s] - Backups
|
||||||
world.datapack=Manage Datapacks
|
world.datapack=Manage Datapacks
|
||||||
world.datapack.1_13=Only Minecraft 1.13 or later supports datapacks.
|
world.datapack.1_13=Only Minecraft 1.13 or later supports datapacks.
|
||||||
world.datetime=Last played on %s
|
world.datetime=Last played on %s
|
||||||
world.download=Download World
|
world.download=Download World
|
||||||
|
world.download.title=Download World - %1s
|
||||||
world.export=Export the World
|
world.export=Export the World
|
||||||
world.export.title=Choose the directory for this exported world
|
world.export.title=Choose the directory for this exported world
|
||||||
world.export.location=Save As
|
world.export.location=Save As
|
||||||
@ -1129,6 +1133,7 @@ repositories.chooser=HMCL requires JavaFX to work.\n\
|
|||||||
repositories.chooser.title=Choose download source for JavaFX
|
repositories.chooser.title=Choose download source for JavaFX
|
||||||
|
|
||||||
resourcepack=Resource Packs
|
resourcepack=Resource Packs
|
||||||
|
resourcepack.download.title=Download Resource Pack - %1s
|
||||||
|
|
||||||
search=Search
|
search=Search
|
||||||
search.hint.chinese=Search in English and Chinese
|
search.hint.chinese=Search in English and Chinese
|
||||||
@ -1209,6 +1214,7 @@ settings.advanced.renderer.llvmpipe=Software (Poor performance, best compatibili
|
|||||||
settings.advanced.renderer.zink=Vulkan (Best performance, poor compatibility)
|
settings.advanced.renderer.zink=Vulkan (Best performance, poor compatibility)
|
||||||
settings.advanced.server_ip=Server Address
|
settings.advanced.server_ip=Server Address
|
||||||
settings.advanced.server_ip.prompt=Automatically join after launching the game
|
settings.advanced.server_ip.prompt=Automatically join after launching the game
|
||||||
|
settings.advanced.unsupported_system_options=Settings not applicable to the current system
|
||||||
settings.advanced.use_native_glfw=[Linux/FreeBSD Only] Use System GLFW
|
settings.advanced.use_native_glfw=[Linux/FreeBSD Only] Use System GLFW
|
||||||
settings.advanced.use_native_openal=[Linux/FreeBSD Only] Use System OpenAL
|
settings.advanced.use_native_openal=[Linux/FreeBSD Only] Use System OpenAL
|
||||||
settings.advanced.workaround=Workaround
|
settings.advanced.workaround=Workaround
|
||||||
|
@ -73,7 +73,7 @@ account.failed.server_disconnected=No se ha podido conectar con el servidor de a
|
|||||||
account.failed.server_response_malformed=Respuesta del servidor no válida, el servidor de autenticación puede no estar funcionando.
|
account.failed.server_response_malformed=Respuesta del servidor no válida, el servidor de autenticación puede no estar funcionando.
|
||||||
account.failed.ssl=Se ha producido un error SSL al conectar con el servidor. Por favor, intente actualizar su Java.
|
account.failed.ssl=Se ha producido un error SSL al conectar con el servidor. Por favor, intente actualizar su Java.
|
||||||
account.failed.wrong_account=Ha iniciado sesión en la cuenta equivocada.
|
account.failed.wrong_account=Ha iniciado sesión en la cuenta equivocada.
|
||||||
account.hmcl.hint=Debe hacer clic en "Iniciar sesión" y completar el proceso en la ventana abierta del navegador.
|
account.hmcl.hint=Debe hacer clic en «Iniciar sesión» y completar el proceso en la ventana abierta del navegador.
|
||||||
account.injector.add=Nuevo servidor Auth
|
account.injector.add=Nuevo servidor Auth
|
||||||
account.injector.empty=Ninguno (Puedes hacer clic en el botón más de la derecha para añadir uno)
|
account.injector.empty=Ninguno (Puedes hacer clic en el botón más de la derecha para añadir uno)
|
||||||
account.injector.http=Atención: Este servidor utiliza el protocolo HTTP inseguro. Cualquiera entre su conexión podrá ver sus credenciales en texto claro.
|
account.injector.http=Atención: Este servidor utiliza el protocolo HTTP inseguro. Cualquiera entre su conexión podrá ver sus credenciales en texto claro.
|
||||||
@ -102,21 +102,21 @@ account.methods.microsoft.close_page=La autorización de la cuenta de Microsoft
|
|||||||
account.methods.microsoft.makegameidsettings=Crear perfil / Editar nombre del perfil
|
account.methods.microsoft.makegameidsettings=Crear perfil / Editar nombre del perfil
|
||||||
account.methods.microsoft.deauthorize=Desautorizar
|
account.methods.microsoft.deauthorize=Desautorizar
|
||||||
account.methods.microsoft.error.add_family=Un adulto debe añadirte a una familia para que puedas jugar a Minecraft porque aún no tienes 18 años.
|
account.methods.microsoft.error.add_family=Un adulto debe añadirte a una familia para que puedas jugar a Minecraft porque aún no tienes 18 años.
|
||||||
account.methods.microsoft.error.add_family_probably=Por favor, compruebe si la edad indicada en la configuración de su cuenta es de al menos 18 años. Si no es así y cree que se trata de un error, puede hacer clic en "Cómo cambiar la fecha de nacimiento de su cuenta" para saber cómo cambiarla.
|
account.methods.microsoft.error.add_family_probably=Por favor, compruebe si la edad indicada en la configuración de su cuenta es de al menos 18 años. Si no es así y cree que se trata de un error, puede hacer clic en «Cómo cambiar la fecha de nacimiento de su cuenta» para saber cómo cambiarla.
|
||||||
account.methods.microsoft.error.country_unavailable=Xbox Live no está disponible en tu país/región actual.
|
account.methods.microsoft.error.country_unavailable=Xbox Live no está disponible en tu país/región actual.
|
||||||
account.methods.microsoft.error.missing_xbox_account=Tu cuenta Microsoft aún no tiene una cuenta Xbox vinculada. Haga clic en "Crear perfil / Editar nombre de perfil" para crear una antes de continuar.
|
account.methods.microsoft.error.missing_xbox_account=Tu cuenta Microsoft aún no tiene una cuenta Xbox vinculada. Haga clic en «Crear perfil / Editar nombre de perfil» para crear una antes de continuar.
|
||||||
account.methods.microsoft.error.no_character=Por favor, asegúrese de que ha comprado Minecraft: Java Edition. \nSi ya lo has comprado, es posible que no hayas creado un perfil de juego.\nPor favor, haga clic en "Crear perfil / Editar nombre de perfil" para crearlo.
|
account.methods.microsoft.error.no_character=Por favor, asegúrese de que ha comprado Minecraft: Java Edition. \nSi ya lo has comprado, es posible que no hayas creado un perfil de juego.\nPor favor, haga clic en «Crear perfil / Editar nombre de perfil» para crearlo.
|
||||||
account.methods.microsoft.error.unknown=No se ha podido iniciar sesión, error: %d.
|
account.methods.microsoft.error.unknown=No se ha podido iniciar sesión, error: %d.
|
||||||
account.methods.microsoft.error.wrong_verify_method=Inicie sesión con su contraseña en la página de inicio de sesión de la cuenta Microsoft y no utilice un código de verificación para iniciar sesión.
|
account.methods.microsoft.error.wrong_verify_method=Inicie sesión con su contraseña en la página de inicio de sesión de la cuenta Microsoft y no utilice un código de verificación para iniciar sesión.
|
||||||
account.methods.microsoft.logging_in=Iniciando sesión...
|
account.methods.microsoft.logging_in=Iniciando sesión...
|
||||||
account.methods.microsoft.hint=Por favor, haga clic en "Iniciar sesión" y copie el código que aparece aquí para completar el proceso de inicio de sesión en la ventana del navegador que se abre.\n\
|
account.methods.microsoft.hint=Por favor, haga clic en «Iniciar sesión» y copie el código que aparece aquí para completar el proceso de inicio de sesión en la ventana del navegador que se abre.\n\
|
||||||
\n\
|
\n\
|
||||||
Si el token utilizado para iniciar sesión en la cuenta de Microsoft se ha filtrado, puedes hacer clic en "Desautorizar" para desautorizarlo.
|
Si el token utilizado para iniciar sesión en la cuenta de Microsoft se ha filtrado, puedes hacer clic en «Desautorizar» para desautorizarlo.
|
||||||
account.methods.microsoft.manual=El código de su dispositivo es <b>%1$s</b>. Por favor, haga clic aquí para copiarlo.\n\
|
account.methods.microsoft.manual=El código de su dispositivo es <b>%1$s</b>. Por favor, haga clic aquí para copiarlo.\n\
|
||||||
\n\
|
\n\
|
||||||
Después de hacer clic en "Iniciar sesión", debe completar el proceso de inicio de sesión en la ventana abierta del navegador. Si no se muestra, puede navegar a %2$s manualmente.\n\
|
Después de hacer clic en «Iniciar sesión», debe completar el proceso de inicio de sesión en la ventana abierta del navegador. Si no se muestra, puede navegar a %2$s manualmente.\n\
|
||||||
\n\
|
\n\
|
||||||
Si el token utilizado para iniciar sesión en la cuenta de Microsoft se ha filtrado, puedes hacer clic en "Desautorizar" para desautorizarlo.
|
Si el token utilizado para iniciar sesión en la cuenta de Microsoft se ha filtrado, puedes hacer clic en «Desautorizar» para desautorizarlo.
|
||||||
account.methods.microsoft.profile=Perfil de la cuenta
|
account.methods.microsoft.profile=Perfil de la cuenta
|
||||||
account.methods.microsoft.purchase=Comprar Minecraft
|
account.methods.microsoft.purchase=Comprar Minecraft
|
||||||
account.methods.microsoft.snapshot=Está utilizando una versión no oficial de HMCL. Por favor, descargue la versión oficial para iniciar sesión.
|
account.methods.microsoft.snapshot=Está utilizando una versión no oficial de HMCL. Por favor, descargue la versión oficial para iniciar sesión.
|
||||||
@ -168,7 +168,7 @@ archive.version=Versión
|
|||||||
|
|
||||||
assets.download=Descargando assets
|
assets.download=Descargando assets
|
||||||
assets.download_all=Verificando la integridad de los archivos
|
assets.download_all=Verificando la integridad de los archivos
|
||||||
assets.index.malformed=Los archivos de índice de los activos descargados estaban dañados. Puede intentar utilizar "Actualizar activos del juego" en la configuración de su instancia del juego para solucionar este problema.
|
assets.index.malformed=Los archivos de índice de los activos descargados estaban dañados. Puede intentar utilizar «Actualizar activos del juego» en la configuración de su instancia del juego para solucionar este problema.
|
||||||
|
|
||||||
button.cancel=Cancelar
|
button.cancel=Cancelar
|
||||||
button.change_source=Cambiar fuente de descarga
|
button.change_source=Cambiar fuente de descarga
|
||||||
@ -328,8 +328,8 @@ download=Descargar
|
|||||||
download.hint=Instalar juegos y modpacks o descargar mods, paquetes de recursos y mundos.
|
download.hint=Instalar juegos y modpacks o descargar mods, paquetes de recursos y mundos.
|
||||||
download.code.404=Archivo no encontrado en el servidor remoto: %s
|
download.code.404=Archivo no encontrado en el servidor remoto: %s
|
||||||
download.content=Complementos
|
download.content=Complementos
|
||||||
download.curseforge.unavailable=La versión Nightly de HMCL no admite el acceso a CurseForge. Utilice las versiones Release o Beta para descargarlas.
|
download.curseforge.unavailable=Esta versión de HMCL no permite acceder a CurseForge. Utilice la versión oficial para acceder a CurseForge.
|
||||||
download.existing=El archivo no se puede guardar porque ya existe. Puedes hacer clic en "Guardar como" para guardar el archivo en otro lugar.
|
download.existing=El archivo no se puede guardar porque ya existe. Puedes hacer clic en «Guardar como» para guardar el archivo en otro lugar.
|
||||||
download.external_link=Abrir sitio web
|
download.external_link=Abrir sitio web
|
||||||
download.failed=Falló la descarga de %1$s, código de respuesta: %2$d.
|
download.failed=Falló la descarga de %1$s, código de respuesta: %2$d.
|
||||||
download.failed.empty=No hay versiones disponibles, por favor haga clic aquí para volver.
|
download.failed.empty=No hay versiones disponibles, por favor haga clic aquí para volver.
|
||||||
@ -346,14 +346,14 @@ download.java.override=Esta versión de Java ya existe. ¿Desea desinstalarla y
|
|||||||
download.javafx=Descargando dependencias para el launcher...
|
download.javafx=Descargando dependencias para el launcher...
|
||||||
download.javafx.notes=Estamos descargando dependencias para HMCL desde Internet.\n\
|
download.javafx.notes=Estamos descargando dependencias para HMCL desde Internet.\n\
|
||||||
\n\
|
\n\
|
||||||
Puede hacer clic en "Cambiar fuente de descarga" para seleccionar el\nespejo de descarga o hacer clic en "Cancelar" para detener y salir.\n\
|
Puede hacer clic en «Cambiar fuente de descarga» para seleccionar el\nespejo de descarga o hacer clic en «Cancelar» para detener y salir.\n\
|
||||||
Nota: Si su velocidad de descarga es demasiado lenta, puede intentar cambiar a otro espejo.
|
Nota: Si su velocidad de descarga es demasiado lenta, puede intentar cambiar a otro espejo.
|
||||||
download.javafx.component=Descargando módulo %s
|
download.javafx.component=Descargando módulo %s
|
||||||
download.javafx.prepare=Preparando la descarga
|
download.javafx.prepare=Preparando la descarga
|
||||||
|
|
||||||
exception.access_denied=HMCL no puede acceder al archivo %s. Puede estar bloqueado por otro proceso.\n\
|
exception.access_denied=HMCL no puede acceder al archivo %s. Puede estar bloqueado por otro proceso.\n\
|
||||||
\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.\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.\n\
|
||||||
Si no es así, comprueba si tu cuenta tiene permisos suficientes para acceder a ella.
|
Si no es así, comprueba si tu cuenta tiene permisos suficientes para acceder a ella.
|
||||||
exception.artifact_malformed=No se puede verificar la integridad de los archivos descargados.
|
exception.artifact_malformed=No se puede verificar la integridad de los archivos descargados.
|
||||||
exception.ssl_handshake=No se pudo establecer una conexión SSL porque falta el certificado SSL en la instalación actual de Java. Puede intentar abrir HMCL con otro Java y volver a intentarlo.
|
exception.ssl_handshake=No se pudo establecer una conexión SSL porque falta el certificado SSL en la instalación actual de Java. Puede intentar abrir HMCL con otro Java y volver a intentarlo.
|
||||||
@ -377,9 +377,9 @@ fatal.config_in_temp_dir=Estás abriendo Hello Minecraft! Launcher en un directo
|
|||||||
Se recomienda trasladar el HMCL a otro lugar y reabrirlo.\n\
|
Se recomienda trasladar el HMCL a otro lugar y reabrirlo.\n\
|
||||||
¿Todavía quieres continuar?
|
¿Todavía quieres continuar?
|
||||||
fatal.config_loading_failure=No se pueden cargar los archivos de configuración.\n\
|
fatal.config_loading_failure=No se pueden cargar los archivos de configuración.\n\
|
||||||
Por favor, asegúrese de que Hello Minecraft! Launcher tiene acceso de lectura y escritura a "%s" y a los archivos que contiene.\n\
|
Por favor, asegúrese de que Hello Minecraft! Launcher tiene acceso de lectura y escritura a «%s» y a los archivos que contiene.\n\
|
||||||
Para macOS, intente colocar HMCL en un lugar con permiso que no sea "Escritorio", "Descargas" y "Documentos" y vuelva a intentarlo.
|
Para macOS, intente colocar HMCL en un lugar con permiso que no sea «Escritorio», «Descargas» y «Documentos» y vuelva a intentarlo.
|
||||||
fatal.config_loading_failure.unix=No se pudo cargar el archivo de configuración porque fue creado por el usuario "%1$s".\n\
|
fatal.config_loading_failure.unix=No se pudo cargar el archivo de configuración porque fue creado por el usuario «%1$s».\n\
|
||||||
Por favor, abra HMCL como usuario root (no recomendado), o ejecute el siguiente comando en el terminal para cambiar la propiedad del archivo de configuración al usuario actual:\n%2$s
|
Por favor, abra HMCL como usuario root (no recomendado), o ejecute el siguiente comando en el terminal para cambiar la propiedad del archivo de configuración al usuario actual:\n%2$s
|
||||||
fatal.mac_app_translocation=El sistema operativo aísla Hello Minecraft! Launcher en un directorio temporal debido a los mecanismos de seguridad de macOS.\n\
|
fatal.mac_app_translocation=El sistema operativo aísla Hello Minecraft! Launcher en un directorio temporal debido a los mecanismos de seguridad de macOS.\n\
|
||||||
Por favor, mueve HMCL a un directorio diferente antes de intentar abrirlo. De lo contrario, tus ajustes y datos de juego podrían perderse tras reiniciar.\n\
|
Por favor, mueve HMCL a un directorio diferente antes de intentar abrirlo. De lo contrario, tus ajustes y datos de juego podrían perderse tras reiniciar.\n\
|
||||||
@ -393,11 +393,11 @@ fatal.apply_update_need_win7=Hello Minecraft! Launcher no puede actualizarse aut
|
|||||||
\n\
|
\n\
|
||||||
Puedes actualizar manualmente descargando una versión más reciente del launcher desde %s.
|
Puedes actualizar manualmente descargando una versión más reciente del launcher desde %s.
|
||||||
fatal.samba=Si ha abierto Hello Minecraft! Launcher desde una unidad de red Samba, es posible que algunas funciones no funcionen. Intenta actualizar tu Java o mover el launcher a otro directorio.
|
fatal.samba=Si ha abierto Hello Minecraft! Launcher desde una unidad de red Samba, es posible que algunas funciones no funcionen. Intenta actualizar tu Java o mover el launcher a otro directorio.
|
||||||
fatal.illegal_char=Su ruta de usuario contiene un carácter ilegal "=", por lo que algunas características podrían no funcionar correctamente.\n\
|
fatal.illegal_char=Su ruta de usuario contiene un carácter ilegal «=», por lo que algunas características podrían no funcionar correctamente.\n\
|
||||||
Por ejemplo, no podrá utilizar authlib-injector o cambiar el skin de su cuenta offline.
|
Por ejemplo, no podrá utilizar authlib-injector o cambiar el skin de su cuenta offline.
|
||||||
fatal.unsupported_platform=Minecraft aún no es totalmente compatible con tu plataforma, por lo que es posible que te falten funciones o incluso que no puedas iniciar el juego.\n\
|
fatal.unsupported_platform=Minecraft aún no es totalmente compatible con tu plataforma, por lo que es posible que te falten funciones o incluso que no puedas iniciar el juego.\n\
|
||||||
\n\
|
\n\
|
||||||
Si no puedes iniciar Minecraft 1.17 y versiones posteriores, puedes probar a cambiar el "Renderizador" a "Software" en "Config. Global/Específica de instancia → Configuración avanzada" para utilizar el renderizado de la CPU y mejorar la compatibilidad.
|
Si no puedes iniciar Minecraft 1.17 y versiones posteriores, puedes probar a cambiar el «Renderizador» a «Software» en «Config. Global/Específica de instancia → Configuración avanzada» para utilizar el renderizado de la CPU y mejorar la compatibilidad.
|
||||||
fatal.unsupported_platform.loongarch=Hello Minecraft! Launcher ha prestado apoyo a la plataforma Loongson.\n\
|
fatal.unsupported_platform.loongarch=Hello Minecraft! Launcher ha prestado apoyo a la plataforma Loongson.\n\
|
||||||
Si tienes problemas al jugar, puedes visitar https://docs.hmcl.net/groups.html para obtener ayuda.
|
Si tienes problemas al jugar, puedes visitar https://docs.hmcl.net/groups.html para obtener ayuda.
|
||||||
fatal.unsupported_platform.osx_arm64=Hello Minecraft! Launcher ha proporcionado soporte para la plataforma de chips de Apple, utilizando Java nativo de ARM para ejecutar juegos y conseguir una experiencia de juego más fluida.\n\
|
fatal.unsupported_platform.osx_arm64=Hello Minecraft! Launcher ha proporcionado soporte para la plataforma de chips de Apple, utilizando Java nativo de ARM para ejecutar juegos y conseguir una experiencia de juego más fluida.\n\
|
||||||
@ -439,15 +439,15 @@ game.crash.reason.block=El juego se ha colgado debido a un bloqueo en el mundo.\
|
|||||||
\n\
|
\n\
|
||||||
Tipo de bloque: %1$s\n\
|
Tipo de bloque: %1$s\n\
|
||||||
Ubicación: %2$s
|
Ubicación: %2$s
|
||||||
game.crash.reason.bootstrap_failed=El juego se ha colgado debido al mod "%1$s".\n\
|
game.crash.reason.bootstrap_failed=El juego se ha colgado debido al mod «%1$s».\n\
|
||||||
\n\
|
\n\
|
||||||
Puedes intentar borrarlo o actualizarlo.
|
Puedes intentar borrarlo o actualizarlo.
|
||||||
game.crash.reason.config=El juego se ha colgado debido a que el mod "%1$s" no ha podido analizar su archivo de configuración "%2$s".
|
game.crash.reason.config=El juego se ha colgado debido a que el mod «%1$s» no ha podido analizar su archivo de configuración «%2$s».
|
||||||
game.crash.reason.debug_crash=El juego se ha colgado porque lo has activado manualmente. Así que probablemente sepas por qué :)
|
game.crash.reason.debug_crash=El juego se ha colgado porque lo has activado manualmente. Así que probablemente sepas por qué :)
|
||||||
game.crash.reason.mixin_apply_mod_failed=El juego se ha colgado porque no se ha podido aplicar el mixin al mod "%1$s".\n\
|
game.crash.reason.mixin_apply_mod_failed=El juego se ha colgado porque no se ha podido aplicar el mixin al mod «%1$s».\n\
|
||||||
\n\
|
\n\
|
||||||
Puedes probar a borrar o actualizar el mod para resolver el problema.
|
Puedes probar a borrar o actualizar el mod para resolver el problema.
|
||||||
game.crash.reason.duplicated_mod=El juego no puede iniciarse debido a la existencia de mods duplicados: "%1$s".\n\
|
game.crash.reason.duplicated_mod=El juego no puede iniciarse debido a la existencia de mods duplicados: «%1$s».\n\
|
||||||
\n\
|
\n\
|
||||||
%2$s\n\
|
%2$s\n\
|
||||||
\n\
|
\n\
|
||||||
@ -462,7 +462,7 @@ game.crash.reason.fabric_version_0_12=La versión de Fabric Loader 0.12 o poster
|
|||||||
game.crash.reason.fabric_warnings=El cargador de Fabric Loader ha advertido:\n\
|
game.crash.reason.fabric_warnings=El cargador de Fabric Loader ha advertido:\n\
|
||||||
\n\
|
\n\
|
||||||
%1$s
|
%1$s
|
||||||
game.crash.reason.file_already_exists=El juego se ha colgado porque el archivo "%1$s" ya existe.\n\
|
game.crash.reason.file_already_exists=El juego se ha colgado porque el archivo «%1$s» ya existe.\n\
|
||||||
\n\
|
\n\
|
||||||
Puedes intentar hacer una copia de seguridad y eliminar ese archivo, y luego volver a ejecutar el juego.
|
Puedes intentar hacer una copia de seguridad y eliminar ese archivo, y luego volver a ejecutar el juego.
|
||||||
game.crash.reason.file_changed=El juego se ha colgado porque ha fallado la verificación de archivos.\n\
|
game.crash.reason.file_changed=El juego se ha colgado porque ha fallado la verificación de archivos.\n\
|
||||||
@ -489,27 +489,27 @@ game.crash.reason.install_mixinbootstrap=El juego se ha colgado debido a la falt
|
|||||||
Puedes intentar instalar <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> para resolver el problema. Si se cuelga después de la instalación, prueba a añadir un signo de exclamación (!) delante del nombre de archivo de este mod para intentar resolver el problema.
|
Puedes intentar instalar <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> para resolver el problema. Si se cuelga después de la instalación, prueba a añadir un signo de exclamación (!) delante del nombre de archivo de este mod para intentar resolver el problema.
|
||||||
game.crash.reason.jdk_9=El juego se ha colgado porque la versión de Java es demasiado nueva para esta instancia.\n\
|
game.crash.reason.jdk_9=El juego se ha colgado porque la versión de Java es demasiado nueva para esta instancia.\n\
|
||||||
\n\
|
\n\
|
||||||
Tienes que descargar e instalar Java 8 y elegirlo en "Config. Global/Específica de instancia → Java".
|
Tienes que descargar e instalar Java 8 y elegirlo en «Config. Global/Específica de instancia → Java».
|
||||||
game.crash.reason.need_jdk11=El juego se ha colgado debido a una versión inadecuada de Java.\n\
|
game.crash.reason.need_jdk11=El juego se ha colgado debido a una versión inadecuada de Java.\n\
|
||||||
\n\
|
\n\
|
||||||
Debes descargar e instalar Java 11 y configurarlo en "Config. Global/Específica de instancia → Java".
|
Debes descargar e instalar Java 11 y configurarlo en «Config. Global/Específica de instancia → Java».
|
||||||
game.crash.reason.jvm_32bit=El juego se ha colgado porque la asignación de memoria actual excedía el límite de 32 bits JVM.\n\
|
game.crash.reason.jvm_32bit=El juego se ha colgado porque la asignación de memoria actual excedía el límite de 32 bits JVM.\n\
|
||||||
\n\
|
\n\
|
||||||
Si su sistema operativo es de 64 bits, instale y utilice una versión de Java de 64 bits. De lo contrario, es posible que tenga que volver a instalar un sistema operativo de 64 bits o adquirir un ordenador más moderno.\n\
|
Si su sistema operativo es de 64 bits, instale y utilice una versión de Java de 64 bits. De lo contrario, es posible que tenga que volver a instalar un sistema operativo de 64 bits o adquirir un ordenador más moderno.\n\
|
||||||
\n\
|
\n\
|
||||||
O bien, puede desactivar la opción "Asignar automáticamente" en "Config. Global/Específica de instancia → Memoria" y establecer el tamaño máximo de asignación de memoria en 1024 MB o menos.
|
O bien, puede desactivar la opción «Asignar automáticamente» en «Config. Global/Específica de instancia → Memoria» y establecer el tamaño máximo de asignación de memoria en 1024 MB o menos.
|
||||||
game.crash.reason.loading_crashed_forge=El juego se ha colgado debido al mod "%1$s" (%2$s).\n\
|
game.crash.reason.loading_crashed_forge=El juego se ha colgado debido al mod «%1$s» (%2$s).\n\
|
||||||
\n\
|
\n\
|
||||||
Puedes intentar borrarlo o actualizarlo.
|
Puedes intentar borrarlo o actualizarlo.
|
||||||
game.crash.reason.loading_crashed_fabric=El juego se ha colgado debido al mod "%1$s".\n\
|
game.crash.reason.loading_crashed_fabric=El juego se ha colgado debido al mod «%1$s».\n\
|
||||||
\n\
|
\n\
|
||||||
Puedes intentar borrarlo o actualizarlo.
|
Puedes intentar borrarlo o actualizarlo.
|
||||||
game.crash.reason.memory_exceeded=El juego se ha colgado debido a que se ha asignado demasiada memoria a un pequeño archivo de paginación.\n\
|
game.crash.reason.memory_exceeded=El juego se ha colgado debido a que se ha asignado demasiada memoria a un pequeño archivo de paginación.\n\
|
||||||
\n\
|
\n\
|
||||||
Puedes probar a desactivar la opción "Asignar automáticamente" en "Config. Global/Específica de instancia → Memoria" y ajustar el valor hasta que se inicie el juego.\n\
|
Puedes probar a desactivar la opción «Asignar automáticamente» en «Config. Global/Específica de instancia → Memoria» y ajustar el valor hasta que se inicie el juego.\n\
|
||||||
\n\
|
\n\
|
||||||
También puede tratar de aumentar el tamaño del archivo de paginación en la configuración del sistema.
|
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 colgado debido al mod "%1$s".\n\
|
game.crash.reason.mod=El juego se ha colgado debido al mod «%1$s».\n\
|
||||||
\n\
|
\n\
|
||||||
Puedes actualizar o eliminar el mod y volver a intentarlo.
|
Puedes actualizar o eliminar el mod y volver a intentarlo.
|
||||||
game.crash.reason.mod_resolution=El juego no puede seguir ejecutándose debido a problemas de dependencia de mods.\n\
|
game.crash.reason.mod_resolution=El juego no puede seguir ejecutándose debido a problemas de dependencia de mods.\n\
|
||||||
@ -532,20 +532,20 @@ game.crash.reason.night_config_fixes=El juego se colgó debido a algunos problem
|
|||||||
Para obtener más información, visite el <a href="https://www.github.com/Fuzss/nightconfigfixes">repositorio de GitHub</a> del mod.
|
Para obtener más información, visite el <a href="https://www.github.com/Fuzss/nightconfigfixes">repositorio de GitHub</a> del mod.
|
||||||
game.crash.reason.mod_resolution_collection=El juego se colgó porque la versión del mod no es compatible.\n\
|
game.crash.reason.mod_resolution_collection=El juego se colgó porque la versión del mod no es compatible.\n\
|
||||||
\n\
|
\n\
|
||||||
"%1$s" requiere mod "%2$s".\n\
|
«%1$s» requiere mod «%2$s».\n\
|
||||||
\n\
|
\n\
|
||||||
Necesitas actualizar o degradar "%3$s" antes de continuar.
|
Necesitas actualizar o degradar «%3$s» antes de continuar.
|
||||||
game.crash.reason.mod_resolution_conflict=El juego se ha colgado debido a mods conflictivos.\n\
|
game.crash.reason.mod_resolution_conflict=El juego se ha colgado debido a mods conflictivos.\n\
|
||||||
\n\
|
\n\
|
||||||
"%1$s" es incompatible con "%2$s".
|
«%1$s» es incompatible con «%2$s».
|
||||||
game.crash.reason.mod_resolution_missing=El juego se ha colgado porque algunos mods dependientes no estaban instalados.\n\
|
game.crash.reason.mod_resolution_missing=El juego se ha colgado porque algunos mods dependientes no estaban instalados.\n\
|
||||||
\n\
|
\n\
|
||||||
"%1$s" requiere mod "%2$s".\n\
|
«%1$s» requiere mod «%2$s».\n\
|
||||||
\n\
|
\n\
|
||||||
Esto significa que tienes que descargar e instalar "%2$s" primero para continuar jugando.
|
Esto significa que tienes que descargar e instalar «%2$s» primero para continuar jugando.
|
||||||
game.crash.reason.mod_resolution_missing_minecraft=El juego se ha colgado porque un mod es incompatible con la versión actual de Minecraft.\n\
|
game.crash.reason.mod_resolution_missing_minecraft=El juego se ha colgado porque un mod es incompatible con la versión actual de Minecraft.\n\
|
||||||
\n\
|
\n\
|
||||||
"%1$s" requiere la versión de Minecraft %2$s.\n\
|
«%1$s» requiere la versión de Minecraft %2$s.\n\
|
||||||
\n\
|
\n\
|
||||||
Si quieres jugar con esta versión del mod instalada, debes cambiar la versión del juego de tu instancia.\n\
|
Si quieres jugar con esta versión del mod instalada, debes cambiar la versión del juego de tu instancia.\n\
|
||||||
\n\
|
\n\
|
||||||
@ -556,10 +556,10 @@ game.crash.reason.forge_repeat_installation=El juego se ha colgado debido a una
|
|||||||
\n\
|
\n\
|
||||||
Se recomienda enviar comentarios en GitHub junto con este registro para que podamos encontrar más pistas y resolver el problema.\n\
|
Se recomienda enviar comentarios en GitHub junto con este registro para que podamos encontrar más pistas y resolver el problema.\n\
|
||||||
\n\
|
\n\
|
||||||
Actualmente puede desinstalar Forge y volver a instalarlo en "Editar Instancia → Cargadores".
|
Actualmente puede desinstalar Forge y volver a instalarlo en «Editar Instancia → Cargadores».
|
||||||
game.crash.reason.optifine_repeat_installation=El juego se ha colgado debido a una instalación duplicada de OptiFine.\n\
|
game.crash.reason.optifine_repeat_installation=El juego se ha colgado debido a una instalación duplicada de OptiFine.\n\
|
||||||
\n\
|
\n\
|
||||||
Elimine OptiFine del directorio "mods" o desinstálelo en "Editar instancia → Cargadores".
|
Elimine OptiFine del directorio «mods» o desinstálelo en «Editar instancia → Cargadores».
|
||||||
game.crash.reason.modmixin_failure=El juego se ha colgado debido a que algunos mods no se han inyectado.\n\
|
game.crash.reason.modmixin_failure=El juego se ha colgado debido a que algunos mods no se han inyectado.\n\
|
||||||
\n\
|
\n\
|
||||||
Esto generalmente significa que el mod tiene un error o no es compatible con el entorno actual. \n\
|
Esto generalmente significa que el mod tiene un error o no es compatible con el entorno actual. \n\
|
||||||
@ -578,21 +578,21 @@ game.crash.reason.forge_error=Forge/NeoForge puede haber proporcionado informaci
|
|||||||
game.crash.reason.mod_resolution0=El juego se ha colgado debido a algunos problemas con el mod. Puede consultar el registro para ver si hay un mod incorrecto.
|
game.crash.reason.mod_resolution0=El juego se ha colgado debido a algunos problemas con el mod. Puede consultar el registro para ver si hay un mod incorrecto.
|
||||||
game.crash.reason.java_version_is_too_high=El juego se ha colgado debido a que la versión de Java es demasiado nueva para seguir ejecutándose.\n\
|
game.crash.reason.java_version_is_too_high=El juego se ha colgado debido a que la versión de Java es demasiado nueva para seguir ejecutándose.\n\
|
||||||
\n\
|
\n\
|
||||||
Cambia la versión principal anterior de Java en "Config. Global/Específica de instancia → Java" y, a continuación, inicia el juego.\n\
|
Cambia la versión principal anterior de Java en «Config. Global/Específica de instancia → Java» y, a continuación, inicia el juego.\n\
|
||||||
\n\
|
\n\
|
||||||
Si no es así, puede descargarlo desde <a href="https://www.java.com/download/">java.com (Java 8)</a> o <a href="https://bell-sw.com/pages/downloads/#downloads">BellSoft Liberica Full JRE (Java 17)</a> y otras plataformas para descargar e instalar una (reinicie el iniciador después de la instalación).
|
Si no es así, puede descargarlo desde <a href="https://www.java.com/download/">java.com (Java 8)</a> o <a href="https://bell-sw.com/pages/downloads/#downloads">BellSoft Liberica Full JRE (Java 17)</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 se ha colgado debido a problemas con el nombre de archivo del mod.\n\
|
game.crash.reason.mod_name=El juego se ha colgado debido a problemas con el nombre de archivo del mod.\n\
|
||||||
\n\
|
\n\
|
||||||
Los nombres de los archivos Mod deben usar sólo letras inglesas (A~Z, a~z), números (0~9), líneas horizontales(-), subrayado (_) y puntos (.) a media altura.\n\
|
Los nombres de los archivos Mod deben usar sólo letras inglesas (A~Z, a~z), números (0~9), líneas horizontales(-), subrayado (_) y puntos (.) a media altura.\n\
|
||||||
\n\
|
\n\
|
||||||
Por favor, vaya al directorio "mods" y cambie todos los nombres de archivo de mods no conformes utilizando los caracteres conformes anteriores.
|
Por favor, vaya al directorio «mods» y cambie todos los nombres de archivo de mods no conformes utilizando los caracteres conformes anteriores.
|
||||||
game.crash.reason.incomplete_forge_installation=O jogo atual não pode continuar devido a uma instalação incompleta do Forge / NeoForge.\n\
|
game.crash.reason.incomplete_forge_installation=O jogo atual não pode continuar devido a uma instalação incompleta do Forge / NeoForge.\n\
|
||||||
\n\
|
\n\
|
||||||
Reinstale o Forge/NeoForge em "Editar Instância → Carregadores".
|
Reinstale o Forge/NeoForge em «Editar Instância → Carregadores».
|
||||||
game.crash.reason.modlauncher_8=El juego se ha colgado debido a que la versión actual de Forge no es compatible con tu instalación de Java. Intenta actualizar Forge.
|
game.crash.reason.modlauncher_8=El juego se ha colgado debido a que la versión actual de Forge no es compatible con tu instalación de Java. Intenta actualizar Forge.
|
||||||
game.crash.reason.no_class_def_found_error=El juego no puede ejecutarse debido a un código incompleto.\n\
|
game.crash.reason.no_class_def_found_error=El juego no puede ejecutarse debido a un código incompleto.\n\
|
||||||
\n\
|
\n\
|
||||||
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\
|
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\
|
\n\
|
||||||
Puede que tengas que reinstalar el juego y todos los mods o pedir ayuda a alguien.
|
Puede que tengas que reinstalar el juego y todos los mods o pedir ayuda a alguien.
|
||||||
game.crash.reason.no_such_method_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\
|
||||||
@ -606,10 +606,10 @@ game.crash.reason.opengl_not_supported=El juego se ha colgado porque tu controla
|
|||||||
O bien, puede intentar actualizar su controlador a la última versión y volver a intentarlo.\n\
|
O bien, puede intentar actualizar su controlador a la última versión y volver a intentarlo.\n\
|
||||||
\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.
|
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 JVM OpenJ9. Por favor, cambia a un Java que utilice la JVM Hotspot en "Config. Global/Específica de instancia → Java" y vuelve a ejecutar el juego. Si no dispones de una, puedes descargarla.
|
game.crash.reason.openj9=El juego no puede ejecutarse en una JVM OpenJ9. Por favor, cambia a un Java que utilice la JVM Hotspot en «Config. Global/Específica de instancia → Java» y vuelve a ejecutar el juego. Si no dispones de una, puedes descargarla.
|
||||||
game.crash.reason.out_of_memory=El juego se ha colgado porque el ordenador se ha quedado sin memoria.\n\
|
game.crash.reason.out_of_memory=El juego se ha colgado porque el ordenador se ha quedado sin memoria.\n\
|
||||||
\n\
|
\n\
|
||||||
Puede que no haya suficiente memoria disponible o que haya demasiados mods instalados. Puedes intentar resolverlo aumentando la memoria asignada en "Config. Global/Específica de instancia → Memoria".\n\
|
Puede que no haya suficiente memoria disponible o que haya demasiados mods instalados. Puedes intentar resolverlo aumentando la memoria asignada en «Config. Global/Específica de instancia → Memoria».\n\
|
||||||
\n\
|
\n\
|
||||||
Si sigues encontrando estos problemas, es posible que necesites una mejor computadora.
|
Si sigues encontrando estos problemas, es posible que necesites una mejor computadora.
|
||||||
game.crash.reason.resolution_too_high=El juego se ha colgado porque la resolución del paquete de recursos/texturas es demasiado alta.\n\
|
game.crash.reason.resolution_too_high=El juego se ha colgado porque la resolución del paquete de recursos/texturas es demasiado alta.\n\
|
||||||
@ -621,14 +621,14 @@ game.crash.reason.shaders_mod=El juego se ha colgado porque OptiFine y Shaders m
|
|||||||
game.crash.reason.rtss_forest_sodium=El juego se colgó porque el RivaTuner Statistical Server (RTSS) no es compatible con Sodium.\n\
|
game.crash.reason.rtss_forest_sodium=El juego se colgó porque el RivaTuner Statistical Server (RTSS) no es compatible con Sodium.\n\
|
||||||
\n\
|
\n\
|
||||||
Haz clic <a href="https://github.com/CaffeineMC/sodium-fabric/wiki/Known-Issues#rtss-incompatible">aquí</a> para obtener más detalles.
|
Haz clic <a href="https://github.com/CaffeineMC/sodium-fabric/wiki/Known-Issues#rtss-incompatible">aquí</a> para obtener más detalles.
|
||||||
game.crash.reason.stacktrace=El motivo del cuelgue es desconocido. Puedes ver los detalles haciendo clic en el botón "Registros".\n\
|
game.crash.reason.stacktrace=El motivo del cuelgue es desconocido. Puedes ver los detalles haciendo clic en el botón «Registros».\n\
|
||||||
\n\
|
\n\
|
||||||
Hay algunas palabras clave que pueden contener algunos nombres de mods. Puedes buscarlas en Internet para averiguar el problema tú mismo.\n\
|
Hay algunas palabras clave que pueden contener algunos nombres de mods. Puedes buscarlas en Internet para averiguar el problema tú mismo.\n\
|
||||||
\n\
|
\n\
|
||||||
%s
|
%s
|
||||||
game.crash.reason.too_old_java=El juego se ha colgado porque estás utilizando una versión de Java VM obsoleta.\n\
|
game.crash.reason.too_old_java=El juego se ha colgado porque estás utilizando una versión de Java VM obsoleta.\n\
|
||||||
\n\
|
\n\
|
||||||
Tienes que cambiar a una versión de Java más reciente (%1$s) en "Config. Global/Específica de instancia → Java" y, a continuación, volver a ejecutar el juego. Puede descargar Java desde <a href="https://learn.microsoft.com/java/openjdk/download">aquí</a>.
|
Tienes que cambiar a una versión de Java más reciente (%1$s) en «Config. Global/Específica de instancia → Java» y, a continuación, volver a ejecutar el juego. Puede descargar Java desde <a href="https://learn.microsoft.com/java/openjdk/download">aquí</a>.
|
||||||
game.crash.reason.unknown=No somos capaces de averiguar por qué se ha colgado el juego. Por favor, refiérase a los registros del juego.
|
game.crash.reason.unknown=No somos capaces de averiguar por qué se ha colgado el juego. Por favor, refiérase a los registros del juego.
|
||||||
game.crash.reason.unsatisfied_link_error=No se puede iniciar Minecraft porque faltan bibliotecas: %1$s.\n\
|
game.crash.reason.unsatisfied_link_error=No se puede iniciar Minecraft porque faltan bibliotecas: %1$s.\n\
|
||||||
\n\
|
\n\
|
||||||
@ -647,10 +647,10 @@ game.crash.reason.mod_files_are_decompressed=El juego se ha colgado porque se ha
|
|||||||
Si la extracción provoca errores en el juego, elimine el mod extraído en el directorio de mods y, a continuación, inicie el juego.
|
Si la extracción provoca errores en el juego, elimine el mod extraído en el directorio de mods y, a continuación, inicie el juego.
|
||||||
game.crash.reason.optifine_causes_the_world_to_fail_to_load=Es posible que el juego no siga ejecutándose debido al OptiFine.\n\
|
game.crash.reason.optifine_causes_the_world_to_fail_to_load=Es posible que el juego no siga ejecutándose debido al OptiFine.\n\
|
||||||
\n\
|
\n\
|
||||||
Este problema solo se produce en una versión específica de OptiFine. Puede probar a cambiar la versión de OptiFine en "Editar instancia → Cargadores".
|
Este problema solo se produce en una versión específica de OptiFine. Puede probar a cambiar la versión de OptiFine en «Editar instancia → Cargadores».
|
||||||
game.crash.reason.optifine_is_not_compatible_with_forge=El juego se ha colgado porque OptiFine no es compatible con la instalación actual de Forge.\n\
|
game.crash.reason.optifine_is_not_compatible_with_forge=El juego se ha colgado porque OptiFine no es compatible con la instalación actual de Forge.\n\
|
||||||
\n\
|
\n\
|
||||||
Por favor, navegue hasta la <a href="https://optifine.net/downloads">página oficial de OptiFine</a>, compruebe si la versión de Forge es compatible con OptiFine, y reinstale la instancia en estricta conformidad con la versión correspondiente, o cambie la versión de OptiFine en "Editar Instancia → Cargadores".\n\
|
Por favor, navegue hasta la <a href="https://optifine.net/downloads">página oficial de OptiFine</a>, compruebe si la versión de Forge es compatible con OptiFine, y reinstale la instancia en estricta conformidad con la versión correspondiente, o cambie la versión de OptiFine en «Editar Instancia → Cargadores».\n\
|
||||||
\n\
|
\n\
|
||||||
Tras realizar pruebas, creemos que las versiones de OptiFine demasiado altas o demasiado bajas pueden provocar fallos.
|
Tras realizar pruebas, creemos que las versiones de OptiFine demasiado altas o demasiado bajas pueden provocar fallos.
|
||||||
game.crash.reason.too_many_mods_lead_to_exceeding_the_id_limit=El juego se ha colgado porque has instalado demasiados mods y has superado el límite de ID del juego.\n\
|
game.crash.reason.too_many_mods_lead_to_exceeding_the_id_limit=El juego se ha colgado porque has instalado demasiados mods y has superado el límite de ID del juego.\n\
|
||||||
@ -676,10 +676,10 @@ install.failed=Fallo en la instalación
|
|||||||
install.failed.downloading=No se han podido descargar algunos archivos necesarios.
|
install.failed.downloading=No se han podido descargar algunos archivos necesarios.
|
||||||
install.failed.downloading.detail=No se ha podido descargar el archivo: %s
|
install.failed.downloading.detail=No se ha podido descargar el archivo: %s
|
||||||
install.failed.downloading.timeout=Tiempo de espera de la descarga: %s
|
install.failed.downloading.timeout=Tiempo de espera de la descarga: %s
|
||||||
install.failed.install_online=No se ha podido identificar el archivo proporcionado. Si está instalando un mod, vaya a la página "Mods".
|
install.failed.install_online=No se ha podido identificar el archivo proporcionado. Si está instalando un mod, vaya a la página «Mods».
|
||||||
install.failed.malformed=Los archivos descargados están dañados. Puedes intentar resolver este problema cambiando a otra fuente de descarga en "Ajustes → Descarga → Fuente de descarga".
|
install.failed.malformed=Los archivos descargados están dañados. Puedes intentar resolver este problema cambiando a otra fuente de descarga en «Ajustes → Descarga → Fuente de descarga».
|
||||||
install.failed.optifine_conflict=No se puede instalar tanto OptiFine como Fabric en Minecraft 1.13 o posterior.
|
install.failed.optifine_conflict=No se puede instalar tanto OptiFine como Fabric en Minecraft 1.13 o posterior.
|
||||||
install.failed.optifine_forge_1.17=Para Minecraft 1.17.1, Forge sólo es compatible con OptiFine H1 pre2 o posterior. Puedes instalarlos marcando "Snapshots" al elegir una versión de OptiFine en HMCL.
|
install.failed.optifine_forge_1.17=Para Minecraft 1.17.1, Forge sólo es compatible con OptiFine H1 pre2 o posterior. Puedes instalarlos marcando «Snapshots» al elegir una versión de OptiFine en HMCL.
|
||||||
install.failed.version_mismatch=Este cargador requiere la versión del juego %s, pero la instalada es %s.
|
install.failed.version_mismatch=Este cargador requiere la versión del juego %s, pero la instalada es %s.
|
||||||
install.installer.change_version=%s Incompatible
|
install.installer.change_version=%s Incompatible
|
||||||
install.installer.choose=Elija su versión %s
|
install.installer.choose=Elija su versión %s
|
||||||
@ -749,10 +749,10 @@ lang.default=Usar idioma del sistema
|
|||||||
|
|
||||||
launch.advice=%s ¿Todavía quieres continuar?
|
launch.advice=%s ¿Todavía quieres continuar?
|
||||||
launch.advice.multi=Se han detectado los siguientes problemas:\n\n%s\n\nEstos problemas pueden impedir que inicies el juego o afectar a la experiencia de juego.\n\n¿Todavía quieres continuar?
|
launch.advice.multi=Se han detectado los siguientes problemas:\n\n%s\n\nEstos problemas pueden impedir que inicies el juego o afectar a la experiencia de juego.\n\n¿Todavía quieres continuar?
|
||||||
launch.advice.java.auto=La versión actual de la máquina virtual de Java no cumple los requisitos del juego.\n\nHaga clic en "Sí" para elegir automáticamente la versión de Java VM más compatible. O bien, puede navegar hasta "Config. Global/Específica de instancia → Java" para elegir uno usted mismo.
|
launch.advice.java.auto=La versión actual de la máquina virtual de Java no cumple los requisitos del juego.\n\nHaga clic en «Sí» para elegir automáticamente la versión de Java VM más compatible. O bien, puede navegar hasta «Config. Global/Específica de instancia → Java» para elegir uno usted mismo.
|
||||||
launch.advice.java.modded_java_7=Minecraft 1.7.2 y versiones anteriores requieren Java 7 o anterior.
|
launch.advice.java.modded_java_7=Minecraft 1.7.2 y versiones anteriores requieren Java 7 o anterior.
|
||||||
launch.advice.corrected=Hemos solucionado el problema de la máquina virtual de Java. Si todavía quieres utilizar la versión de Java que elijas, puedes desactivar la opción "No comprobar la compatibilidad de la JVM" en "Config. Global/Específica de instancia → Configuración avanzada".
|
launch.advice.corrected=Hemos solucionado el problema de la máquina virtual de Java. Si todavía quieres utilizar la versión de Java que elijas, puedes desactivar la opción «No comprobar la compatibilidad de la JVM» en «Config. Global/Específica de instancia → Configuración avanzada».
|
||||||
launch.advice.uncorrected=Si todavía quieres utilizar la versión de Java que elijas, puedes desactivar la opción "No comprobar la compatibilidad de la JVM" en "Config. Global/Específica de instancia → Configuración avanzada".
|
launch.advice.uncorrected=Si todavía quieres utilizar la versión de Java que elijas, puedes desactivar la opción «No comprobar la compatibilidad de la JVM» en «Config. Global/Específica de instancia → Configuración avanzada».
|
||||||
launch.advice.different_platform=Se recomienda la versión de 64 bits de Java para tu dispositivo, pero has instalado una de 32 bits.
|
launch.advice.different_platform=Se recomienda la versión de 64 bits de Java para tu dispositivo, pero has instalado una de 32 bits.
|
||||||
launch.advice.forge2760_liteloader=La versión 2760 o posterior de Forge no es compatible con LiteLoader, por favor considere actualizar Forge a la versión 2773 o posterior.
|
launch.advice.forge2760_liteloader=La versión 2760 o posterior de Forge no es compatible con LiteLoader, por favor considere actualizar Forge a la versión 2773 o posterior.
|
||||||
launch.advice.forge28_2_2_optifine=La versión 28.2.2 o posterior de Forge no es compatible con OptiFine. Considere la posibilidad de actualizar Forge a la versión 28.2.1 o anterior.
|
launch.advice.forge28_2_2_optifine=La versión 28.2.2 o posterior de Forge no es compatible con OptiFine. Considere la posibilidad de actualizar Forge a la versión 28.2.1 o anterior.
|
||||||
@ -778,7 +778,7 @@ launch.failed.download_library=No se pudo descargar la biblioteca %s.
|
|||||||
launch.failed.executable_permission=No se pudo hacer ejecutable el script de ejecución.
|
launch.failed.executable_permission=No se pudo hacer ejecutable el script de ejecución.
|
||||||
launch.failed.execution_policy=Configuración de la política de ejecución
|
launch.failed.execution_policy=Configuración de la política de ejecución
|
||||||
launch.failed.execution_policy.failed_to_set=No se pudo establecer la política de ejecución
|
launch.failed.execution_policy.failed_to_set=No se pudo establecer la política de ejecución
|
||||||
launch.failed.execution_policy.hint=La política de ejecución actual impide la ejecución de scripts de PowerShell.\n\nHaga clic en "Aceptar" para permitir que el usuario actual ejecute scripts de PowerShell, o haga clic en "Cancelar" para mantenerlo como está.
|
launch.failed.execution_policy.hint=La política de ejecución actual impide la ejecución de scripts de PowerShell.\n\nHaga clic en «Aceptar» para permitir que el usuario actual ejecute scripts de PowerShell, o haga clic en «Cancelar» para mantenerlo como está.
|
||||||
launch.failed.exited_abnormally=El juego se ha bloqueado. Por favor, consulte el registro de errores para más detalles.
|
launch.failed.exited_abnormally=El juego se ha bloqueado. Por favor, consulte el registro de errores para más detalles.
|
||||||
launch.failed.java_version_too_low=La versión de Java que ha especificado es demasiado baja. Por favor, reajuste la versión de Java.
|
launch.failed.java_version_too_low=La versión de Java que ha especificado es demasiado baja. Por favor, reajuste la versión de Java.
|
||||||
launch.failed.no_accepted_java=No se ha podido encontrar una versión de Java compatible. Si crees que has descargado una compatible, puedes establecerla manualmente en los ajustes.
|
launch.failed.no_accepted_java=No se ha podido encontrar una versión de Java compatible. Si crees que has descargado una compatible, puedes establecerla manualmente en los ajustes.
|
||||||
@ -800,13 +800,13 @@ launcher.background=Imagen de fondo
|
|||||||
launcher.background.choose=Elige una imagen de fondo
|
launcher.background.choose=Elige una imagen de fondo
|
||||||
launcher.background.classic=Clásico
|
launcher.background.classic=Clásico
|
||||||
launcher.background.default=Por defecto
|
launcher.background.default=Por defecto
|
||||||
launcher.background.default.tooltip=O "background.png/.jpg/.gif/.webp" y las imágenes en el directorio "bg".
|
launcher.background.default.tooltip=O «background.png/.jpg/.gif/.webp» y las imágenes en el directorio «bg».
|
||||||
launcher.background.network=Desde la URL
|
launcher.background.network=Desde la URL
|
||||||
launcher.background.translucent=Translúcido
|
launcher.background.translucent=Translúcido
|
||||||
launcher.cache_directory=Directorio de la caché
|
launcher.cache_directory=Directorio de la caché
|
||||||
launcher.cache_directory.clean=Borrar caché
|
launcher.cache_directory.clean=Borrar caché
|
||||||
launcher.cache_directory.choose=Elegir el directorio de la 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.disabled=Desactivado
|
||||||
launcher.cache_directory.invalid=No se ha podido crear el directorio de la caché, volviendo a los valores por defecto.
|
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
|
launcher.contact=Contacta con nosotros
|
||||||
@ -1052,16 +1052,19 @@ web.view_in_browser=Ver en navegador
|
|||||||
world=Mundos
|
world=Mundos
|
||||||
world.add=Añadir mundo
|
world.add=Añadir mundo
|
||||||
world.backup=Copia de seguridad
|
world.backup=Copia de seguridad
|
||||||
|
world.backup.create.new_one=Crear uno nuevo
|
||||||
world.backup.create.failed=No se ha podido crear la copia de seguridad.\n%s
|
world.backup.create.failed=No se ha podido crear la copia de seguridad.\n%s
|
||||||
world.backup.create.locked=El mundo está actualmente en uso. Por favor, cierra el juego e inténtalo de nuevo.
|
world.backup.create.locked=El mundo está actualmente en uso. Por favor, cierra el juego e inténtalo de nuevo.
|
||||||
world.backup.create.success=Creada con éxito una nueva copia de seguridad: %s
|
world.backup.create.success=Creada con éxito una nueva copia de seguridad: %s
|
||||||
world.backup.delete=Eliminar esta copia de seguridad
|
world.backup.delete=Eliminar esta copia de seguridad
|
||||||
|
world.backup.processing=Creando nueva copia de seguridad ...
|
||||||
world.backup.reveal=Abrir el directorio
|
world.backup.reveal=Abrir el directorio
|
||||||
world.backup.title=Mundo [%s] - Copias de seguridad
|
world.backup.title=Mundo [%s] - Copias de seguridad
|
||||||
world.datapack=Gestionar paquetes de datos
|
world.datapack=Gestionar paquetes de datos
|
||||||
world.datapack.1_13=Sólo Minecraft 1.13 o posterior soporta paquetes de datos.
|
world.datapack.1_13=Sólo Minecraft 1.13 o posterior soporta paquetes de datos.
|
||||||
world.datetime=Jugado por última vez en %s
|
world.datetime=Jugado por última vez en %s
|
||||||
world.download=Descargar Mundo
|
world.download=Descargar Mundo
|
||||||
|
world.download.title=Descargar mundo - %1s
|
||||||
world.export=Exportar el mundo
|
world.export=Exportar el mundo
|
||||||
world.export.title=Elija el directorio para este mundo exportado
|
world.export.title=Elija el directorio para este mundo exportado
|
||||||
world.export.location=Guardar como
|
world.export.location=Guardar como
|
||||||
@ -1127,12 +1130,13 @@ repositories.maven_central=Universal (Maven Central)
|
|||||||
repositories.tencentcloud_mirror=Espejo de China continental (Repositorio Maven Tencent Cloud)
|
repositories.tencentcloud_mirror=Espejo de China continental (Repositorio Maven Tencent Cloud)
|
||||||
repositories.chooser=HMCL requiere JavaFX para funcionar.\n\
|
repositories.chooser=HMCL requiere JavaFX para funcionar.\n\
|
||||||
\n\
|
\n\
|
||||||
Por favor, haga clic en "Aceptar" para descargar JavaFX desde el repositorio especificado, o haga clic en "Cancelar" para salir.\n\
|
Por favor, haga clic en «Aceptar» para descargar JavaFX desde el repositorio especificado, o haga clic en «Cancelar» para salir.\n\
|
||||||
\n\
|
\n\
|
||||||
Repositorios:
|
Repositorios:
|
||||||
repositories.chooser.title=Elija la fuente de descarga de JavaFX
|
repositories.chooser.title=Elija la fuente de descarga de JavaFX
|
||||||
|
|
||||||
resourcepack=Paquetes de recursos
|
resourcepack=Paquetes de recursos
|
||||||
|
resourcepack.download.title=Descargar paquete de recursos - %1s
|
||||||
|
|
||||||
search=Búsqueda
|
search=Búsqueda
|
||||||
search.hint.chinese=Buscar en inglés y chino
|
search.hint.chinese=Buscar en inglés y chino
|
||||||
@ -1171,15 +1175,15 @@ settings.advanced.dont_check_game_completeness=No chequear integridad del juego
|
|||||||
settings.advanced.dont_check_jvm_validity=No comprobar la compatibilidad de la JVM
|
settings.advanced.dont_check_jvm_validity=No comprobar la compatibilidad de la JVM
|
||||||
settings.advanced.dont_patch_natives=No intente sustituir automáticamente las bibliotecas nativas
|
settings.advanced.dont_patch_natives=No intente sustituir automáticamente las bibliotecas nativas
|
||||||
settings.advanced.environment_variables=Variables de entorno
|
settings.advanced.environment_variables=Variables de entorno
|
||||||
settings.advanced.game_dir.default=Por defecto (".minecraft/")
|
settings.advanced.game_dir.default=Por defecto («.minecraft/»)
|
||||||
settings.advanced.game_dir.independent=Aislar (".minecraft/versions/<nombre de la instancia>/", excepto para los activos y las bibliotecas)
|
settings.advanced.game_dir.independent=Aislar («.minecraft/versions/<nombre de la instancia>/», excepto para los activos y las bibliotecas)
|
||||||
settings.advanced.java_permanent_generation_space=Espacio PermGen
|
settings.advanced.java_permanent_generation_space=Espacio PermGen
|
||||||
settings.advanced.java_permanent_generation_space.prompt=en MB
|
settings.advanced.java_permanent_generation_space.prompt=en MB
|
||||||
settings.advanced.jvm=Opciones de la máquina virtual de Java
|
settings.advanced.jvm=Opciones de la máquina virtual de Java
|
||||||
settings.advanced.jvm_args=Argumentos de la máquina virtual de Java
|
settings.advanced.jvm_args=Argumentos de la máquina virtual de Java
|
||||||
settings.advanced.jvm_args.prompt=\ · Si los argumentos introducidos en "Argumentos de la máquina virtual de Java" son los mismos que los argumentos por defecto, no se añadirán.\n\
|
settings.advanced.jvm_args.prompt=\ · Si los argumentos introducidos en «Argumentos de la máquina virtual de Java» son los mismos que los argumentos por defecto, no se añadirán.\n\
|
||||||
\ · Introduzca cualquier argumento GC en "Argumentos de la máquina virtual de Java", y se desactivará el argumento G1 de los argumentos por defecto.\n\
|
\ · Introduzca cualquier argumento GC en «Argumentos de la máquina virtual de Java», y se desactivará el argumento G1 de los argumentos por defecto.\n\
|
||||||
\ · Activa "No añadir argumentos por defecto de JVM" para ejecutar el juego sin añadir argumentos por defecto.
|
\ · Activa «No añadir argumentos por defecto de JVM» para ejecutar el juego sin añadir argumentos por defecto.
|
||||||
settings.advanced.launcher_visibility.close=Cerrar el launcher después de ejecutar el juego.
|
settings.advanced.launcher_visibility.close=Cerrar el launcher después de ejecutar el juego.
|
||||||
settings.advanced.launcher_visibility.hide=Ocultar el launcher después de ejecutar el juego.
|
settings.advanced.launcher_visibility.hide=Ocultar el launcher después de ejecutar el juego.
|
||||||
settings.advanced.launcher_visibility.hide_and_reopen=Ocultar el launcher y volver a abrirlo cuando se cierra el juego.
|
settings.advanced.launcher_visibility.hide_and_reopen=Ocultar el launcher y volver a abrirlo cuando se cierra el juego.
|
||||||
@ -1212,6 +1216,7 @@ settings.advanced.renderer.llvmpipe=Software (Bajo rendimiento, máxima compatib
|
|||||||
settings.advanced.renderer.zink=Vulkan (Máximo rendimiento, baja compatibilidad)
|
settings.advanced.renderer.zink=Vulkan (Máximo rendimiento, baja compatibilidad)
|
||||||
settings.advanced.server_ip=Dirección del servidor
|
settings.advanced.server_ip=Dirección del servidor
|
||||||
settings.advanced.server_ip.prompt=Entrar automáticamente después de ejecutar el juego
|
settings.advanced.server_ip.prompt=Entrar automáticamente después de ejecutar el juego
|
||||||
|
settings.advanced.unsupported_system_options=Configuración no aplicable al sistema actual
|
||||||
settings.advanced.use_native_glfw=[Sólo Linux/FreeBSD] Utilizar GLFW nativo
|
settings.advanced.use_native_glfw=[Sólo Linux/FreeBSD] Utilizar GLFW nativo
|
||||||
settings.advanced.use_native_openal=[Sólo Linux/FreeBSD] Utilizar OpenAL nativo
|
settings.advanced.use_native_openal=[Sólo Linux/FreeBSD] Utilizar OpenAL nativo
|
||||||
settings.advanced.workaround=Métodos alternativos
|
settings.advanced.workaround=Métodos alternativos
|
||||||
@ -1240,7 +1245,7 @@ settings.game.java_directory.version=Especifique la versión de Java
|
|||||||
settings.game.management=Gestionar
|
settings.game.management=Gestionar
|
||||||
settings.game.working_directory=Directorio de trabajo
|
settings.game.working_directory=Directorio de trabajo
|
||||||
settings.game.working_directory.choose=Elija el directorio de trabajo
|
settings.game.working_directory.choose=Elija el directorio de trabajo
|
||||||
settings.game.working_directory.hint=Activar la opción "Aislar" en "Directorio de trabajo" para permitir que la instancia actual almacene sus configuraciones, mundos y mods en un directorio separado.\n\
|
settings.game.working_directory.hint=Activar la opción «Aislar» en «Directorio de trabajo» para permitir que la instancia actual almacene sus configuraciones, mundos y mods en un directorio separado.\n\
|
||||||
\n\
|
\n\
|
||||||
Se recomienda activar esta opción para evitar conflictos con los mods, pero tendrás que mover tus guardados manualmente.
|
Se recomienda activar esta opción para evitar conflictos con los mods, pero tendrás que mover tus guardados manualmente.
|
||||||
|
|
||||||
@ -1262,7 +1267,7 @@ settings.launcher.general=General
|
|||||||
settings.launcher.language=Idioma
|
settings.launcher.language=Idioma
|
||||||
settings.launcher.launcher_log.export=Exportar registros del launcher
|
settings.launcher.launcher_log.export=Exportar registros del launcher
|
||||||
settings.launcher.launcher_log.export.failed=No se han podido exportar los registros
|
settings.launcher.launcher_log.export.failed=No se han podido exportar los registros
|
||||||
settings.launcher.launcher_log.export.success=Los registros se han exportado a "%s"
|
settings.launcher.launcher_log.export.success=Los registros se han exportado a «%s»
|
||||||
settings.launcher.launcher_log.reveal=Abrir el directorio
|
settings.launcher.launcher_log.reveal=Abrir el directorio
|
||||||
settings.launcher.log=Registro
|
settings.launcher.log=Registro
|
||||||
settings.launcher.log.font=Fuente
|
settings.launcher.log.font=Fuente
|
||||||
@ -1299,7 +1304,7 @@ settings.type.global.manage=Config. Global
|
|||||||
settings.type.global.edit=Editar Config. Global
|
settings.type.global.edit=Editar Config. Global
|
||||||
settings.type.special.enable=Activar Config. Específica de la instancia
|
settings.type.special.enable=Activar Config. Específica de la instancia
|
||||||
settings.type.special.edit=Editar configuración de la instancia actual
|
settings.type.special.edit=Editar configuración de la instancia actual
|
||||||
settings.type.special.edit.hint=La instancia actual "%s" ha activado la "Configuración específica de la instancia". Todas las configuraciones de esta página NO afectarán a esa instancia. Haga clic aquí para editar la configuración de la instancia.
|
settings.type.special.edit.hint=La instancia actual «%s» ha activado la «Configuración específica de la instancia». Todas las configuraciones de esta página NO afectarán a esa instancia. Haga clic aquí para editar la configuración de la instancia.
|
||||||
|
|
||||||
sponsor=Donantes
|
sponsor=Donantes
|
||||||
sponsor.bmclapi=Las descargas de China continental son proporcionadas por BMCLAPI. Haga clic aquí para obtener más información.
|
sponsor.bmclapi=Las descargas de China continental son proporcionadas por BMCLAPI. Haga clic aquí para obtener más información.
|
||||||
@ -1340,7 +1345,7 @@ version.name=Nombre de instancia
|
|||||||
version.cannot_read=No se ha podido analizar la instancia del juego, la instalación no puede continuar.
|
version.cannot_read=No se ha podido analizar la instancia del juego, la instalación no puede continuar.
|
||||||
version.empty=No hay instancias
|
version.empty=No hay instancias
|
||||||
version.empty.add=Añadir una instancia
|
version.empty.add=Añadir una instancia
|
||||||
version.empty.launch=No hay instancias. Puedes instalar una en "Descargar → Nuevo juego".
|
version.empty.launch=No hay instancias. Puedes instalar una en «Descargar → Nuevo juego».
|
||||||
version.empty.hint=No hay instancias de Minecraft aquí. Puedes intentar cambiar a otro directorio del juego o hacer clic aquí para descargar una.
|
version.empty.hint=No hay instancias de Minecraft aquí. Puedes intentar cambiar a otro directorio del juego o hacer clic aquí para descargar una.
|
||||||
version.game.old=Histórico
|
version.game.old=Histórico
|
||||||
version.game.release=Lanzamiento
|
version.game.release=Lanzamiento
|
||||||
@ -1356,7 +1361,7 @@ version.launch_script.save=Exportar script de ejecución
|
|||||||
version.launch_script.success=Exportado el script de ejecución como %s.
|
version.launch_script.success=Exportado el script de ejecución como %s.
|
||||||
version.manage=Todas las instancias
|
version.manage=Todas las instancias
|
||||||
version.manage.clean=Eliminar archivos de registros
|
version.manage.clean=Eliminar archivos de registros
|
||||||
version.manage.clean.tooltip=Eliminar los archivos de los directorios "logs" y "crash-reports".
|
version.manage.clean.tooltip=Eliminar los archivos de los directorios «logs» y «crash-reports».
|
||||||
version.manage.duplicate=Duplicar instancia
|
version.manage.duplicate=Duplicar instancia
|
||||||
version.manage.duplicate.duplicate_save=Duplicar mundos
|
version.manage.duplicate.duplicate_save=Duplicar mundos
|
||||||
version.manage.duplicate.prompt=Introduzca el nombre de la nueva instancia
|
version.manage.duplicate.prompt=Introduzca el nombre de la nueva instancia
|
||||||
@ -1365,8 +1370,8 @@ version.manage.manage=Editar instancia
|
|||||||
version.manage.manage.title=Editar instancia - %1s
|
version.manage.manage.title=Editar instancia - %1s
|
||||||
version.manage.redownload_assets_index=Actualizar activos del juego
|
version.manage.redownload_assets_index=Actualizar activos del juego
|
||||||
version.manage.remove=Eliminar instancia
|
version.manage.remove=Eliminar instancia
|
||||||
version.manage.remove.confirm=¿Está seguro de que quiere eliminar permanentemente la instancia "%s"? ¡Esta operación no se puede deshacer!
|
version.manage.remove.confirm=¿Está seguro de que quiere eliminar permanentemente la instancia «%s»? ¡Esta operación no se puede deshacer!
|
||||||
version.manage.remove.confirm.trash=¿Estás seguro de que quieres eliminar la instancia "%s"? Todavía puedes encontrar sus archivos en tu papelera de reciclaje con el nombre de "%s".
|
version.manage.remove.confirm.trash=¿Estás seguro de que quieres eliminar la instancia «%s»? Todavía puedes encontrar sus archivos en tu papelera de reciclaje con el nombre de «%s».
|
||||||
version.manage.remove.confirm.independent=Dado que esta instancia está almacenada en un directorio aislado, al eliminarla también se eliminarán sus guardados y otros datos. ¿Aún quieres borrar la instancia %s?
|
version.manage.remove.confirm.independent=Dado que esta instancia está almacenada en un directorio aislado, al eliminarla también se eliminarán sus guardados y otros datos. ¿Aún quieres borrar la instancia %s?
|
||||||
version.manage.remove_assets=Borrar todas las activos del juego
|
version.manage.remove_assets=Borrar todas las activos del juego
|
||||||
version.manage.remove_libraries=Borrar todas las bibliotecas
|
version.manage.remove_libraries=Borrar todas las bibliotecas
|
||||||
|
@ -804,6 +804,7 @@ settings.advanced.post_exit_command=終了後のコマンド
|
|||||||
settings.advanced.post_exit_command.prompt=ゲーム終了後に実行されます
|
settings.advanced.post_exit_command.prompt=ゲーム終了後に実行されます
|
||||||
settings.advanced.server_ip=サーバーアドレス
|
settings.advanced.server_ip=サーバーアドレス
|
||||||
settings.advanced.server_ip.prompt=ゲームの起動時にサーバーに参加する
|
settings.advanced.server_ip.prompt=ゲームの起動時にサーバーに参加する
|
||||||
|
settings.advanced.unsupported_system_options=サポートされていないシステムオプション
|
||||||
settings.advanced.use_native_glfw=[Linux/FreeBSDのみ]システムGLFWを使用する
|
settings.advanced.use_native_glfw=[Linux/FreeBSDのみ]システムGLFWを使用する
|
||||||
settings.advanced.use_native_openal=[Linux/FreeBSDのみ]システムOpenALを使用する
|
settings.advanced.use_native_openal=[Linux/FreeBSDのみ]システムOpenALを使用する
|
||||||
settings.advanced.workaround=デバッグ用オプション
|
settings.advanced.workaround=デバッグ用オプション
|
||||||
|
@ -329,7 +329,7 @@ download=Скачать
|
|||||||
download.hint=Установить игры и модпаки или скачать моды, пакеты ресурсов и миры.
|
download.hint=Установить игры и модпаки или скачать моды, пакеты ресурсов и миры.
|
||||||
download.code.404=Файл «%s» не найден на удаленном сервере.
|
download.code.404=Файл «%s» не найден на удаленном сервере.
|
||||||
download.content=Аддоны
|
download.content=Аддоны
|
||||||
download.curseforge.unavailable=Альфа-версия HMCL не поддерживает доступ к CurseForge. Для скачивания используйте версии релиза или бета.
|
download.curseforge.unavailable=Эта сборка HMCL не поддерживает доступ к CurseForge. Пожалуйста, используйте официальную сборку для доступа к CurseForge.
|
||||||
download.existing=Файл существует и по этому не может быть сохранён. Можно использовать «Сохранить как», чтобы сохранить файл в другом месте.
|
download.existing=Файл существует и по этому не может быть сохранён. Можно использовать «Сохранить как», чтобы сохранить файл в другом месте.
|
||||||
download.external_link=Открыть сайт
|
download.external_link=Открыть сайт
|
||||||
download.failed=Не удалось скачать «%1$s», код ответа: %2$d.
|
download.failed=Не удалось скачать «%1$s», код ответа: %2$d.
|
||||||
@ -1051,16 +1051,19 @@ web.view_in_browser=Смотреть в браузере
|
|||||||
world=Миры
|
world=Миры
|
||||||
world.add=Добавить мир
|
world.add=Добавить мир
|
||||||
world.backup=Резервный мир
|
world.backup=Резервный мир
|
||||||
|
world.backup.create.new_one=Создать новый
|
||||||
world.backup.create.failed=Не удалось создать резервную копию.\n%s
|
world.backup.create.failed=Не удалось создать резервную копию.\n%s
|
||||||
world.backup.create.locked=В настоящее время мир находится в эксплуатации. Закройте игру и попробуйте снова.
|
world.backup.create.locked=В настоящее время мир находится в эксплуатации. Закройте игру и попробуйте снова.
|
||||||
world.backup.create.success=Успешно создано новое резервное копирование: %s
|
world.backup.create.success=Успешно создано новое резервное копирование: %s
|
||||||
world.backup.delete=Удалить эту резервную копию
|
world.backup.delete=Удалить эту резервную копию
|
||||||
|
world.backup.processing=Создание новой резервной копии ...
|
||||||
world.backup.reveal=Показать в диспетчере файлов
|
world.backup.reveal=Показать в диспетчере файлов
|
||||||
world.backup.title=Мир [%s] - Резервные копии
|
world.backup.title=Мир [%s] - Резервные копии
|
||||||
world.datapack=Управлять наборами данных
|
world.datapack=Управлять наборами данных
|
||||||
world.datapack.1_13=Только Minecraft 1.13 или новее поддерживает наборы данных.
|
world.datapack.1_13=Только Minecraft 1.13 или новее поддерживает наборы данных.
|
||||||
world.datetime=Последний запуск игры %s
|
world.datetime=Последний запуск игры %s
|
||||||
world.download=Скачать мир
|
world.download=Скачать мир
|
||||||
|
world.download.title=Скачать мир - %1s
|
||||||
world.export=Экспорт мира
|
world.export=Экспорт мира
|
||||||
world.export.title=Выберите папку для экспорта мира
|
world.export.title=Выберите папку для экспорта мира
|
||||||
world.export.location=Экспорт в
|
world.export.location=Экспорт в
|
||||||
@ -1132,6 +1135,7 @@ repositories.chooser=Для работы HMCL требуется JavaFX.\n\
|
|||||||
repositories.chooser.title=Выберите зеркало для скачивания JavaFX
|
repositories.chooser.title=Выберите зеркало для скачивания JavaFX
|
||||||
|
|
||||||
resourcepack=Пакеты ресурсов
|
resourcepack=Пакеты ресурсов
|
||||||
|
resourcepack.download.title=Скачать пакет ресурсов - %1s
|
||||||
|
|
||||||
search=Поиск
|
search=Поиск
|
||||||
search.hint.chinese=Поиск на китайском и английском языках
|
search.hint.chinese=Поиск на китайском и английском языках
|
||||||
@ -1212,6 +1216,7 @@ settings.advanced.renderer.llvmpipe=ПО (Низкая производител
|
|||||||
settings.advanced.renderer.zink=Vulkan (Лучшая производительность, низкая совместимость)
|
settings.advanced.renderer.zink=Vulkan (Лучшая производительность, низкая совместимость)
|
||||||
settings.advanced.server_ip=Адрес сервера
|
settings.advanced.server_ip=Адрес сервера
|
||||||
settings.advanced.server_ip.prompt=Присоединяться к серверу при запуске игры
|
settings.advanced.server_ip.prompt=Присоединяться к серверу при запуске игры
|
||||||
|
settings.advanced.unsupported_system_options=Настройки, не применимые к текущей системе
|
||||||
settings.advanced.use_native_glfw=[Только для Linux/FreeBSD] Использовать системный GLFW
|
settings.advanced.use_native_glfw=[Только для Linux/FreeBSD] Использовать системный GLFW
|
||||||
settings.advanced.use_native_openal=[Только для Linux/FreeBSD] Использовать системный OpenAL
|
settings.advanced.use_native_openal=[Только для Linux/FreeBSD] Использовать системный OpenAL
|
||||||
settings.advanced.workaround=Обходные пути
|
settings.advanced.workaround=Обходные пути
|
||||||
|
@ -91,6 +91,7 @@ account.login.skip=跳過重新整理帳戶
|
|||||||
account.login.retry=再次重新整理帳戶
|
account.login.retry=再次重新整理帳戶
|
||||||
account.login.refresh=重新登入
|
account.login.refresh=重新登入
|
||||||
account.login.refresh.microsoft.hint=由於帳戶授權失效,你需要重新加入 Microsoft 帳戶
|
account.login.refresh.microsoft.hint=由於帳戶授權失效,你需要重新加入 Microsoft 帳戶
|
||||||
|
account.login.restricted=登入微軟帳戶以啟用此功能
|
||||||
account.logout=登出
|
account.logout=登出
|
||||||
account.register=註冊
|
account.register=註冊
|
||||||
account.manage=帳戶清單
|
account.manage=帳戶清單
|
||||||
@ -330,7 +331,7 @@ download=下載
|
|||||||
download.hint=安裝遊戲和模組包或下載模組、資源包和地圖
|
download.hint=安裝遊戲和模組包或下載模組、資源包和地圖
|
||||||
download.code.404=遠端伺服器沒有需要下載的檔案:%s
|
download.code.404=遠端伺服器沒有需要下載的檔案:%s
|
||||||
download.content=遊戲內容
|
download.content=遊戲內容
|
||||||
download.curseforge.unavailable=HMCL 預覽版暫不支援訪問 CurseForge,請使用穩定版或開發版進行下載。
|
download.curseforge.unavailable=這個 HMCL 版本不支援訪問 CurseForge。請使用官方版本進行下載。
|
||||||
download.existing=檔案已存在,無法儲存。你可以將檔案儲存至其他地方。
|
download.existing=檔案已存在,無法儲存。你可以將檔案儲存至其他地方。
|
||||||
download.external_link=打開下載網站
|
download.external_link=打開下載網站
|
||||||
download.failed=下載失敗:%1$s\n錯誤碼:%2$d
|
download.failed=下載失敗:%1$s\n錯誤碼:%2$d
|
||||||
@ -670,7 +671,7 @@ modpack.download=下載模組包
|
|||||||
modpack.download.title=模組包下載 - %1s
|
modpack.download.title=模組包下載 - %1s
|
||||||
modpack.enter_name=給遊戲取個你喜歡的名稱
|
modpack.enter_name=給遊戲取個你喜歡的名稱
|
||||||
modpack.export=匯出模組包
|
modpack.export=匯出模組包
|
||||||
modpack.export.as=請選取模組包類型。若你無法決定,請選取 MCBBS 類型。
|
modpack.export.as=請選取模組包類型
|
||||||
modpack.file_api=模組包下載連結前綴
|
modpack.file_api=模組包下載連結前綴
|
||||||
modpack.files.blueprints=BuildCraft 藍圖
|
modpack.files.blueprints=BuildCraft 藍圖
|
||||||
modpack.files.config=模組設定檔案
|
modpack.files.config=模組設定檔案
|
||||||
@ -703,7 +704,7 @@ modpack.type.curse=Curse
|
|||||||
modpack.type.curse.error=無法完成該模組包所需的相依元件下載,請多次重試或設定代理……
|
modpack.type.curse.error=無法完成該模組包所需的相依元件下載,請多次重試或設定代理……
|
||||||
modpack.type.curse.not_found=部分必需檔案已經從網路中被刪除並且再也無法下載,請嘗試該模組包的最新版本或者安裝其他模組包。
|
modpack.type.curse.not_found=部分必需檔案已經從網路中被刪除並且再也無法下載,請嘗試該模組包的最新版本或者安裝其他模組包。
|
||||||
modpack.type.manual.warning=該模組包由發佈者手動打包,其中可能已經包含啟動器,建議嘗試解壓後使用其內建的啟動器執行遊戲。\nHMCL 可以嘗試匯入該模組包,但不保證可用性,是否繼續?
|
modpack.type.manual.warning=該模組包由發佈者手動打包,其中可能已經包含啟動器,建議嘗試解壓後使用其內建的啟動器執行遊戲。\nHMCL 可以嘗試匯入該模組包,但不保證可用性,是否繼續?
|
||||||
modpack.type.mcbbs=MCBBS
|
modpack.type.mcbbs=MCBBS 模組包
|
||||||
modpack.type.mcbbs.export=可以被 Hello Minecraft! Launcher 匯入
|
modpack.type.mcbbs.export=可以被 Hello Minecraft! Launcher 匯入
|
||||||
modpack.type.modrinth=Modrinth
|
modpack.type.modrinth=Modrinth
|
||||||
modpack.type.multimc=MultiMC
|
modpack.type.multimc=MultiMC
|
||||||
@ -853,16 +854,19 @@ web.view_in_browser=在瀏覽器中查看
|
|||||||
|
|
||||||
world=世界
|
world=世界
|
||||||
world.add=加入世界
|
world.add=加入世界
|
||||||
world.backup=備份世界
|
world.backup=世界備份
|
||||||
|
world.backup.create.new_one=建立新備份
|
||||||
world.backup.create.failed=創建備份失敗。\n%s
|
world.backup.create.failed=創建備份失敗。\n%s
|
||||||
world.backup.create.locked=該世界正在使用中,請關閉遊戲後重試。
|
world.backup.create.locked=該世界正在使用中,請關閉遊戲後重試。
|
||||||
world.backup.create.success=成功創建新備份:%s
|
world.backup.create.success=成功創建新備份:%s
|
||||||
world.backup.delete=删除此備份
|
world.backup.delete=删除此備份
|
||||||
|
world.backup.processing=正在備份中……
|
||||||
world.backup.title=世界 [%s] - 備份
|
world.backup.title=世界 [%s] - 備份
|
||||||
world.datapack=管理資料包
|
world.datapack=管理資料包
|
||||||
world.datapack.1_13=僅 Minecraft 1.13 及之後的版本支援資料包
|
world.datapack.1_13=僅 Minecraft 1.13 及之後的版本支援資料包
|
||||||
world.datetime=上一次遊戲時間: %s
|
world.datetime=上一次遊戲時間: %s
|
||||||
world.download=下載世界
|
world.download=下載世界
|
||||||
|
world.download.title=世界下載 - %1s
|
||||||
world.export=匯出此世界
|
world.export=匯出此世界
|
||||||
world.export.title=選取該世界的儲存位置
|
world.export.title=選取該世界的儲存位置
|
||||||
world.export.location=儲存到
|
world.export.location=儲存到
|
||||||
@ -930,6 +934,7 @@ repositories.chooser=缺少 JavaFX 執行環境,HMCL 需要 JavaFX 才能正
|
|||||||
repositories.chooser.title=選取 JavaFX 下載源
|
repositories.chooser.title=選取 JavaFX 下載源
|
||||||
|
|
||||||
resourcepack=資源包
|
resourcepack=資源包
|
||||||
|
resourcepack.download.title=資源包下載 - %1s
|
||||||
|
|
||||||
search=搜尋
|
search=搜尋
|
||||||
search.hint.chinese=支援中英文搜尋
|
search.hint.chinese=支援中英文搜尋
|
||||||
@ -1007,6 +1012,7 @@ settings.advanced.renderer.llvmpipe=軟繪製器 (效能較差,相容性最好
|
|||||||
settings.advanced.renderer.zink=Vulkan (效能最好,相容性較差)
|
settings.advanced.renderer.zink=Vulkan (效能最好,相容性較差)
|
||||||
settings.advanced.server_ip=伺服器位址
|
settings.advanced.server_ip=伺服器位址
|
||||||
settings.advanced.server_ip.prompt=預設,啟動遊戲後直接進入對應伺服器
|
settings.advanced.server_ip.prompt=預設,啟動遊戲後直接進入對應伺服器
|
||||||
|
settings.advanced.unsupported_system_options=不適用於目前系統的選項
|
||||||
settings.advanced.use_native_glfw=[僅限 Linux/FreeBSD] 使用系統 GLFW
|
settings.advanced.use_native_glfw=[僅限 Linux/FreeBSD] 使用系統 GLFW
|
||||||
settings.advanced.use_native_openal=[僅限 Linux/FreeBSD] 使用系統 OpenAL
|
settings.advanced.use_native_openal=[僅限 Linux/FreeBSD] 使用系統 OpenAL
|
||||||
settings.advanced.workaround=除錯選項
|
settings.advanced.workaround=除錯選項
|
||||||
@ -1170,7 +1176,7 @@ version.settings=遊戲設定
|
|||||||
version.update=更新模組包
|
version.update=更新模組包
|
||||||
|
|
||||||
wiki.tooltip=Minecraft Wiki 頁面
|
wiki.tooltip=Minecraft Wiki 頁面
|
||||||
wiki.version.game.release=https://zh.minecraft.wiki/w/Java版%s?variant=zh-tw
|
wiki.version.game.release=https://zh.minecraft.wiki/w/Java%%E7%%89%%88%s?variant=zh-tw
|
||||||
wiki.version.game.snapshot=https://zh.minecraft.wiki/w/%s?variant=zh-tw
|
wiki.version.game.snapshot=https://zh.minecraft.wiki/w/%s?variant=zh-tw
|
||||||
|
|
||||||
wizard.prev=< 上一步
|
wizard.prev=< 上一步
|
||||||
|
@ -92,6 +92,7 @@ account.login.skip=跳过账户刷新
|
|||||||
account.login.retry=再次刷新账户
|
account.login.retry=再次刷新账户
|
||||||
account.login.refresh=重新登录
|
account.login.refresh=重新登录
|
||||||
account.login.refresh.microsoft.hint=由于账户授权失效,你需要重新添加微软账户。
|
account.login.refresh.microsoft.hint=由于账户授权失效,你需要重新添加微软账户。
|
||||||
|
account.login.restricted=登录微软账户以启用此功能
|
||||||
account.logout=登出
|
account.logout=登出
|
||||||
account.register=注册
|
account.register=注册
|
||||||
account.manage=账户列表
|
account.manage=账户列表
|
||||||
@ -339,7 +340,7 @@ download=下载
|
|||||||
download.hint=安装游戏和整合包或下载模组、资源包和地图
|
download.hint=安装游戏和整合包或下载模组、资源包和地图
|
||||||
download.code.404=远程服务器不包含需要下载的文件: %s\n你可以点击右上角帮助按钮进行求助。
|
download.code.404=远程服务器不包含需要下载的文件: %s\n你可以点击右上角帮助按钮进行求助。
|
||||||
download.content=游戏内容
|
download.content=游戏内容
|
||||||
download.curseforge.unavailable=HMCL 预览版暂不支持访问 CurseForge,请使用稳定版或开发版进行下载。
|
download.curseforge.unavailable=此 HMCL 版本不支持访问 CurseForge。请使用官方版本进行下载。
|
||||||
download.existing=文件已存在,无法保存。你可以将文件保存至其他地方。
|
download.existing=文件已存在,无法保存。你可以将文件保存至其他地方。
|
||||||
download.external_link=打开下载网站
|
download.external_link=打开下载网站
|
||||||
download.failed=下载失败: %1$s,\n错误码:%2$d\n你可以点击右上角帮助按钮进行求助。
|
download.failed=下载失败: %1$s,\n错误码:%2$d\n你可以点击右上角帮助按钮进行求助。
|
||||||
@ -681,7 +682,7 @@ modpack.download=下载整合包
|
|||||||
modpack.download.title=整合包下载 - %1s
|
modpack.download.title=整合包下载 - %1s
|
||||||
modpack.enter_name=给游戏起个你喜欢的名字
|
modpack.enter_name=给游戏起个你喜欢的名字
|
||||||
modpack.export=导出整合包
|
modpack.export=导出整合包
|
||||||
modpack.export.as=请选择整合包类型 (若无法决定,请选择“我的世界中文论坛整合包标准”)
|
modpack.export.as=请选择整合包类型
|
||||||
modpack.file_api=整合包下载链接前缀
|
modpack.file_api=整合包下载链接前缀
|
||||||
modpack.files.blueprints=BuildCraft 蓝图
|
modpack.files.blueprints=BuildCraft 蓝图
|
||||||
modpack.files.config=模组配置文件
|
modpack.files.config=模组配置文件
|
||||||
@ -714,7 +715,7 @@ modpack.type.curse=Curse
|
|||||||
modpack.type.curse.error=未能完成该整合包所需的依赖下载,请再次尝试或设置代理。\n你可以点击右上角帮助按钮进行求助。
|
modpack.type.curse.error=未能完成该整合包所需的依赖下载,请再次尝试或设置代理。\n你可以点击右上角帮助按钮进行求助。
|
||||||
modpack.type.curse.not_found=部分必需文件已经在网络中被删除并且再也无法下载,请尝试该整合包的最新版本或者安装其他整合包。\n如遇到问题,你可以点击右上角帮助按钮进行求助。
|
modpack.type.curse.not_found=部分必需文件已经在网络中被删除并且再也无法下载,请尝试该整合包的最新版本或者安装其他整合包。\n如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||||
modpack.type.manual.warning=该整合包由发布者手动打包,其中可能已经包含启动器,建议尝试解压后使用其自带的启动器运行游戏。\n如遇到问题,你可以点击右上角帮助按钮进行求助。\nHMCL 可以尝试导入该整合包,但不保证可用性,是否继续?
|
modpack.type.manual.warning=该整合包由发布者手动打包,其中可能已经包含启动器,建议尝试解压后使用其自带的启动器运行游戏。\n如遇到问题,你可以点击右上角帮助按钮进行求助。\nHMCL 可以尝试导入该整合包,但不保证可用性,是否继续?
|
||||||
modpack.type.mcbbs=我的世界中文论坛整合包标准
|
modpack.type.mcbbs=MCBBS 整合包 (推荐)
|
||||||
modpack.type.mcbbs.export=可以被 Hello Minecraft! Launcher 导入
|
modpack.type.mcbbs.export=可以被 Hello Minecraft! Launcher 导入
|
||||||
modpack.type.modrinth=Modrinth
|
modpack.type.modrinth=Modrinth
|
||||||
modpack.type.multimc=MultiMC
|
modpack.type.multimc=MultiMC
|
||||||
@ -864,16 +865,19 @@ web.view_in_browser=在浏览器中查看
|
|||||||
|
|
||||||
world=世界
|
world=世界
|
||||||
world.add=添加世界
|
world.add=添加世界
|
||||||
world.backup=备份世界
|
world.backup=世界备份
|
||||||
|
world.backup.create.new_one=创建新备份
|
||||||
world.backup.create.failed=创建备份失败。\n%s
|
world.backup.create.failed=创建备份失败。\n%s
|
||||||
world.backup.create.locked=该世界正在使用中,请关闭游戏后重试。
|
world.backup.create.locked=该世界正在使用中,请关闭游戏后重试。
|
||||||
world.backup.create.success=成功创建新备份:%s
|
world.backup.create.success=成功创建新备份:%s
|
||||||
world.backup.delete=删除此备份
|
world.backup.delete=删除此备份
|
||||||
|
world.backup.processing=正在备份中……
|
||||||
world.backup.title=世界 [%s] - 备份
|
world.backup.title=世界 [%s] - 备份
|
||||||
world.datapack=管理数据包
|
world.datapack=管理数据包
|
||||||
world.datapack.1_13=仅 Minecraft 1.13 及之后的版本支持数据包
|
world.datapack.1_13=仅 Minecraft 1.13 及之后的版本支持数据包
|
||||||
world.datetime=上一次游戏时间: %s
|
world.datetime=上一次游戏时间: %s
|
||||||
world.download=下载世界
|
world.download=下载世界
|
||||||
|
world.download.title=世界下载 - %1s
|
||||||
world.export=导出此世界
|
world.export=导出此世界
|
||||||
world.export.title=选择该世界的存储位置
|
world.export.title=选择该世界的存储位置
|
||||||
world.export.location=保存到
|
world.export.location=保存到
|
||||||
@ -941,6 +945,7 @@ repositories.chooser=缺少 JavaFX 运行环境,HMCL 需要 JavaFX 才能正
|
|||||||
repositories.chooser.title=选择 JavaFX 下载源
|
repositories.chooser.title=选择 JavaFX 下载源
|
||||||
|
|
||||||
resourcepack=资源包
|
resourcepack=资源包
|
||||||
|
resourcepack.download.title=资源包下载 - %1s
|
||||||
|
|
||||||
search=搜索
|
search=搜索
|
||||||
search.hint.chinese=支持中英文搜索
|
search.hint.chinese=支持中英文搜索
|
||||||
@ -1018,6 +1023,7 @@ settings.advanced.renderer.llvmpipe=软渲染器 (性能较差,兼容性最好
|
|||||||
settings.advanced.renderer.zink=Vulkan (性能最好,兼容性较差)
|
settings.advanced.renderer.zink=Vulkan (性能最好,兼容性较差)
|
||||||
settings.advanced.server_ip=服务器地址
|
settings.advanced.server_ip=服务器地址
|
||||||
settings.advanced.server_ip.prompt=默认,启动游戏后可以直接进入对应服务器
|
settings.advanced.server_ip.prompt=默认,启动游戏后可以直接进入对应服务器
|
||||||
|
settings.advanced.unsupported_system_options=不适用于当前系统的选项
|
||||||
settings.advanced.use_native_glfw=[仅 Linux/FreeBSD] 使用系统 GLFW
|
settings.advanced.use_native_glfw=[仅 Linux/FreeBSD] 使用系统 GLFW
|
||||||
settings.advanced.use_native_openal=[仅 Linux/FreeBSD] 使用系统 OpenAL
|
settings.advanced.use_native_openal=[仅 Linux/FreeBSD] 使用系统 OpenAL
|
||||||
settings.advanced.workaround=调试选项
|
settings.advanced.workaround=调试选项
|
||||||
@ -1181,7 +1187,7 @@ version.settings=游戏设置
|
|||||||
version.update=更新整合包
|
version.update=更新整合包
|
||||||
|
|
||||||
wiki.tooltip=Minecraft Wiki 页面
|
wiki.tooltip=Minecraft Wiki 页面
|
||||||
wiki.version.game.release=https://zh.minecraft.wiki/w/Java版%s?variant=zh-cn
|
wiki.version.game.release=https://zh.minecraft.wiki/w/Java%%E7%%89%%88%s?variant=zh-cn
|
||||||
wiki.version.game.snapshot=https://zh.minecraft.wiki/w/%s?variant=zh-cn
|
wiki.version.game.snapshot=https://zh.minecraft.wiki/w/%s?variant=zh-cn
|
||||||
|
|
||||||
wizard.prev=< 上一步
|
wizard.prev=< 上一步
|
||||||
|
@ -3979,6 +3979,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"com.github.oshi:oshi-core:6.6.5": {
|
||||||
|
"name": "com.github.oshi:oshi-core:6.8.0",
|
||||||
|
"downloads": {
|
||||||
|
"artifact": {
|
||||||
|
"path": "com/github/oshi/oshi-core/6.8.0/oshi-core-6.8.0.jar",
|
||||||
|
"url": "https://repo1.maven.org/maven2/com/github/oshi/oshi-core/6.8.0/oshi-core-6.8.0.jar",
|
||||||
|
"sha1": "004d12fac84286063e6842688610b8b2d43924a4",
|
||||||
|
"size": 1011309
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"net.java.jinput:jinput-platform:2.0.5:natives": null,
|
"net.java.jinput:jinput-platform:2.0.5:natives": null,
|
||||||
"com.mojang:text2speech:1.10.3:natives": null,
|
"com.mojang:text2speech:1.10.3:natives": null,
|
||||||
"com.mojang:text2speech:1.11.3:natives": null,
|
"com.mojang:text2speech:1.11.3:natives": null,
|
||||||
@ -3987,26 +3998,26 @@
|
|||||||
},
|
},
|
||||||
"windows-x86_64": {
|
"windows-x86_64": {
|
||||||
"mesa-loader": {
|
"mesa-loader": {
|
||||||
"name": "org.glavo:mesa-loader-windows:0.3.0:x64",
|
"name": "org.glavo:mesa-loader-windows:25.0.3:x64",
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"artifact": {
|
"artifact": {
|
||||||
"path": "org/glavo/mesa-loader-windows/0.3.0/mesa-loader-windows-0.3.0-x64.jar",
|
"path": "org/glavo/mesa-loader-windows/25.0.3/mesa-loader-windows-25.0.3-x64.jar",
|
||||||
"url": "https://repo1.maven.org/maven2/org/glavo/mesa-loader-windows/0.3.0/mesa-loader-windows-0.3.0-x64.jar",
|
"url": "https://repo1.maven.org/maven2/org/glavo/mesa-loader-windows/25.0.3/mesa-loader-windows-25.0.3-x64.jar",
|
||||||
"sha1": "629fca32417d6ec489cef8b2cbd0827131ec6801",
|
"sha1": "b2552fcc8c98e95b4559c39f2ff87cdb3aaaa513",
|
||||||
"size": 27174940
|
"size": 27971214
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"windows-x86": {
|
"windows-x86": {
|
||||||
"mesa-loader": {
|
"mesa-loader": {
|
||||||
"name": "org.glavo:mesa-loader-windows:0.3.0:x86",
|
"name": "org.glavo:mesa-loader-windows:25.0.3:x86",
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"artifact": {
|
"artifact": {
|
||||||
"path": "org/glavo/mesa-loader-windows/0.3.0/mesa-loader-windows-0.3.0-x86.jar",
|
"path": "org/glavo/mesa-loader-windows/25.0.3/mesa-loader-windows-25.0.3-x86.jar",
|
||||||
"url": "https://repo1.maven.org/maven2/org/glavo/mesa-loader-windows/0.3.0/mesa-loader-windows-0.3.0-x86.jar",
|
"url": "https://repo1.maven.org/maven2/org/glavo/mesa-loader-windows/25.0.3/mesa-loader-windows-25.0.3-x86.jar",
|
||||||
"sha1": "d25e0cdf5c5eb182acc9b93f700e0e6d8de36283",
|
"sha1": "6fd0fd7da88ca6636f735e1e0f6feb7f62f59715",
|
||||||
"size": 22528549
|
"size": 23311299
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4389,13 +4400,13 @@
|
|||||||
"com.mojang:text2speech:1.12.4:natives": null,
|
"com.mojang:text2speech:1.12.4:natives": null,
|
||||||
"com.mojang:text2speech:1.13.9:natives-windows": null,
|
"com.mojang:text2speech:1.13.9:natives-windows": null,
|
||||||
"mesa-loader": {
|
"mesa-loader": {
|
||||||
"name": "org.glavo:mesa-loader-windows:0.3.0:arm64",
|
"name": "org.glavo:mesa-loader-windows:25.0.3:arm64",
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"artifact": {
|
"artifact": {
|
||||||
"path": "org/glavo/mesa-loader-windows/0.3.0/mesa-loader-windows-0.3.0-arm64.jar",
|
"path": "org/glavo/mesa-loader-windows/25.0.3/mesa-loader-windows-25.0.3-arm64.jar",
|
||||||
"url": "https://repo1.maven.org/maven2/org/glavo/mesa-loader-windows/0.3.0/mesa-loader-windows-0.3.0-arm64.jar",
|
"url": "https://repo1.maven.org/maven2/org/glavo/mesa-loader-windows/25.0.3/mesa-loader-windows-25.0.3-arm64.jar",
|
||||||
"sha1": "1986490c6fbe950e64018c2fb62c8ecf77a247ed",
|
"sha1": "40ca5de3351bf48b7b9efa5d2598d5b6b4d1ab8e",
|
||||||
"size": 24082103
|
"size": 24905270
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,19 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
val kalaCompressVersion = "1.27.1-1"
|
||||||
|
|
||||||
|
api("org.glavo.kala:kala-compress-archivers-zip:$kalaCompressVersion")
|
||||||
|
api("org.glavo.kala:kala-compress-archivers-tar:$kalaCompressVersion")
|
||||||
api("org.glavo:simple-png-javafx:0.3.0")
|
api("org.glavo:simple-png-javafx:0.3.0")
|
||||||
api("com.google.code.gson:gson:2.12.1")
|
api("com.google.code.gson:gson:2.13.0")
|
||||||
api("com.moandjiezana.toml:toml4j:0.7.2")
|
api("com.moandjiezana.toml:toml4j:0.7.2")
|
||||||
api("org.tukaani:xz:1.10")
|
api("org.tukaani:xz:1.10")
|
||||||
api("org.hildan.fxgson:fx-gson:5.0.0")
|
api("org.hildan.fxgson:fx-gson:5.0.0")
|
||||||
api("org.jenkins-ci:constant-pool-scanner:1.2")
|
api("org.jenkins-ci:constant-pool-scanner:1.2")
|
||||||
api("com.github.steveice10:opennbt:1.5")
|
api("com.github.steveice10:opennbt:1.5")
|
||||||
api("org.nanohttpd:nanohttpd:2.3.1")
|
api("org.nanohttpd:nanohttpd:2.3.1")
|
||||||
api("org.apache.commons:commons-compress:1.25.0")
|
api("org.jsoup:jsoup:1.19.1")
|
||||||
api("org.jsoup:jsoup:1.18.3")
|
|
||||||
compileOnlyApi("org.jetbrains:annotations:26.0.1")
|
compileOnlyApi("org.jetbrains:annotations:26.0.1")
|
||||||
|
|
||||||
if (JavaVersion.current().isJava8) {
|
if (JavaVersion.current().isJava8) {
|
||||||
|
@ -269,5 +269,5 @@ public class YggdrasilService {
|
|||||||
.registerTypeAdapterFactory(ValidationTypeAdapterFactory.INSTANCE)
|
.registerTypeAdapterFactory(ValidationTypeAdapterFactory.INSTANCE)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
public static final String PURCHASE_URL = "https://www.microsoft.com/store/productid/9nxp44l49shj";
|
public static final String PURCHASE_URL = "https://www.xbox.com/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj";
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,8 @@ public final class BMCLAPIDownloadProvider implements DownloadProvider {
|
|||||||
pair("https://meta.fabricmc.net", apiRoot + "/fabric-meta"),
|
pair("https://meta.fabricmc.net", apiRoot + "/fabric-meta"),
|
||||||
pair("https://maven.fabricmc.net", apiRoot + "/maven"),
|
pair("https://maven.fabricmc.net", apiRoot + "/maven"),
|
||||||
pair("https://authlib-injector.yushi.moe", apiRoot + "/mirrors/authlib-injector"),
|
pair("https://authlib-injector.yushi.moe", apiRoot + "/mirrors/authlib-injector"),
|
||||||
pair("https://repo1.maven.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public")
|
pair("https://repo1.maven.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public"),
|
||||||
|
pair("https://zkitefly.github.io/unlisted-versions-of-minecraft", "https://vip.123pan.cn/1821946486/unlisted-versions-of-minecraft")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +127,7 @@ public class RemoteVersion implements Comparable<RemoteVersion> {
|
|||||||
UNCATEGORIZED,
|
UNCATEGORIZED,
|
||||||
RELEASE,
|
RELEASE,
|
||||||
SNAPSHOT,
|
SNAPSHOT,
|
||||||
OLD
|
OLD,
|
||||||
|
PENDING
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import org.jackhuang.hmcl.task.GetTask;
|
|||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.download.UnsupportedInstallationException.FABRIC_NOT_COMPATIBLE_WITH_FORGE;
|
import static org.jackhuang.hmcl.download.UnsupportedInstallationException.FABRIC_NOT_COMPATIBLE_WITH_FORGE;
|
||||||
@ -83,8 +84,12 @@ public final class FabricInstallTask extends Task<Version> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() throws IOException {
|
||||||
setResult(getPatch(JsonUtils.GSON.fromJson(launchMetaTask.getResult(), FabricInfo.class), remote.getGameVersion(), remote.getSelfVersion()));
|
FabricInfo fabricInfo = JsonUtils.GSON.fromJson(launchMetaTask.getResult(), FabricInfo.class);
|
||||||
|
if (fabricInfo == null)
|
||||||
|
throw new IOException("Fabric metadata is invalid");
|
||||||
|
|
||||||
|
setResult(getPatch(fabricInfo, remote.getGameVersion(), remote.getSelfVersion()));
|
||||||
|
|
||||||
dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true));
|
dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true));
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,8 @@ public final class GameRemoteVersion extends RemoteVersion {
|
|||||||
return Type.SNAPSHOT;
|
return Type.SNAPSHOT;
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
return Type.UNCATEGORIZED;
|
return Type.UNCATEGORIZED;
|
||||||
|
case PENDING:
|
||||||
|
return Type.PENDING;
|
||||||
default:
|
default:
|
||||||
return Type.OLD;
|
return Type.OLD;
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,17 @@ package org.jackhuang.hmcl.download.game;
|
|||||||
|
|
||||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
import org.jackhuang.hmcl.download.VersionList;
|
import org.jackhuang.hmcl.download.VersionList;
|
||||||
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
import org.jackhuang.hmcl.util.io.HttpRequest;
|
import org.jackhuang.hmcl.util.io.HttpRequest;
|
||||||
|
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
@ -50,10 +55,30 @@ public final class GameVersionList extends VersionList<GameRemoteVersion> {
|
|||||||
public CompletableFuture<?> refreshAsync() {
|
public CompletableFuture<?> refreshAsync() {
|
||||||
return HttpRequest.GET(downloadProvider.getVersionListURL()).getJsonAsync(GameRemoteVersions.class)
|
return HttpRequest.GET(downloadProvider.getVersionListURL()).getJsonAsync(GameRemoteVersions.class)
|
||||||
.thenAcceptAsync(root -> {
|
.thenAcceptAsync(root -> {
|
||||||
|
GameRemoteVersions unlistedVersions = null;
|
||||||
|
|
||||||
|
//noinspection DataFlowIssue
|
||||||
|
try (Reader input = new InputStreamReader(
|
||||||
|
GameVersionList.class.getResourceAsStream("/assets/game/unlisted-versions.json"))) {
|
||||||
|
unlistedVersions = JsonUtils.GSON.fromJson(input, GameRemoteVersions.class);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOG.error("Failed to load unlisted versions", e);
|
||||||
|
}
|
||||||
|
|
||||||
lock.writeLock().lock();
|
lock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
versions.clear();
|
versions.clear();
|
||||||
|
|
||||||
|
if (unlistedVersions != null) {
|
||||||
|
for (GameRemoteVersionInfo unlistedVersion : unlistedVersions.getVersions()) {
|
||||||
|
versions.put(unlistedVersion.getGameVersion(), new GameRemoteVersion(
|
||||||
|
unlistedVersion.getGameVersion(),
|
||||||
|
unlistedVersion.getGameVersion(),
|
||||||
|
Collections.singletonList(unlistedVersion.getUrl()),
|
||||||
|
unlistedVersion.getType(), unlistedVersion.getReleaseTime()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (GameRemoteVersionInfo remoteVersion : root.getVersions()) {
|
for (GameRemoteVersionInfo remoteVersion : root.getVersions()) {
|
||||||
versions.put(remoteVersion.getGameVersion(), new GameRemoteVersion(
|
versions.put(remoteVersion.getGameVersion(), new GameRemoteVersion(
|
||||||
remoteVersion.getGameVersion(),
|
remoteVersion.getGameVersion(),
|
||||||
|
@ -18,21 +18,16 @@
|
|||||||
package org.jackhuang.hmcl.download.liteloader;
|
package org.jackhuang.hmcl.download.liteloader;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider;
|
import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider;
|
||||||
|
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||||
import org.jackhuang.hmcl.download.VersionList;
|
import org.jackhuang.hmcl.download.VersionList;
|
||||||
|
import org.jackhuang.hmcl.util.Pair;
|
||||||
import org.jackhuang.hmcl.util.io.HttpRequest;
|
import org.jackhuang.hmcl.util.io.HttpRequest;
|
||||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public final class LiteLoaderBMCLVersionList extends VersionList<LiteLoaderRemoteVersion> {
|
public final class LiteLoaderBMCLVersionList extends VersionList<LiteLoaderRemoteVersion> {
|
||||||
@ -47,66 +42,44 @@ public final class LiteLoaderBMCLVersionList extends VersionList<LiteLoaderRemot
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doBranch(String key, String gameVersion, LiteLoaderRepository repository, LiteLoaderBranch branch, boolean snapshot) {
|
private static final class LiteLoaderBMCLVersion {
|
||||||
if (branch == null || repository == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (Map.Entry<String, LiteLoaderVersion> entry : branch.getLiteLoader().entrySet()) {
|
private final LiteLoaderVersion build;
|
||||||
String branchName = entry.getKey();
|
private final String version;
|
||||||
LiteLoaderVersion v = entry.getValue();
|
|
||||||
if ("latest".equals(branchName))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
String version = v.getVersion();
|
public LiteLoaderBMCLVersion(LiteLoaderVersion build, String version) {
|
||||||
String url = "https://bmclapi2.bangbang93.com/liteloader/download?version=" + version;
|
this.build = build;
|
||||||
if (snapshot) {
|
this.version = version;
|
||||||
try {
|
|
||||||
version = version.replace("SNAPSHOT", getLatestSnapshotVersion(repository.getUrl() + "com/mumfrey/liteloader/" + v.getVersion() + "/"));
|
|
||||||
url = repository.getUrl() + "com/mumfrey/liteloader/" + v.getVersion() + "/liteloader-" + version + "-release.jar";
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
versions.put(key, new LiteLoaderRemoteVersion(gameVersion,
|
|
||||||
version, Collections.singletonList(url),
|
|
||||||
v.getTweakClass(), v.getLibraries()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<?> refreshAsync() {
|
public CompletableFuture<?> refreshAsync() {
|
||||||
return HttpRequest.GET(downloadProvider.injectURL(LITELOADER_LIST)).getJsonAsync(LiteLoaderVersionsRoot.class)
|
throw new UnsupportedOperationException();
|
||||||
.thenAcceptAsync(root -> {
|
}
|
||||||
lock.writeLock().lock();
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<?> refreshAsync(String gameVersion) {
|
||||||
|
return HttpRequest.GET(
|
||||||
|
downloadProvider.injectURL("https://bmclapi2.bangbang93.com/liteloader/list"), Pair.pair("mcversion", gameVersion)
|
||||||
|
)
|
||||||
|
.getJsonAsync(LiteLoaderBMCLVersion.class)
|
||||||
|
.thenAccept(v -> {
|
||||||
|
lock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
versions.clear();
|
versions.clear();
|
||||||
|
|
||||||
for (Map.Entry<String, LiteLoaderGameVersions> entry : root.getVersions().entrySet()) {
|
versions.put(gameVersion, new LiteLoaderRemoteVersion(
|
||||||
String gameVersion = entry.getKey();
|
gameVersion, v.version, RemoteVersion.Type.UNCATEGORIZED,
|
||||||
LiteLoaderGameVersions liteLoader = entry.getValue();
|
Collections.singletonList(NetworkUtils.withQuery(
|
||||||
|
downloadProvider.injectURL("https://bmclapi2.bangbang93.com/liteloader/download"),
|
||||||
String gg = VersionNumber.normalize(gameVersion);
|
Collections.singletonMap("version", v.version)
|
||||||
doBranch(gg, gameVersion, liteLoader.getRepoitory(), liteLoader.getArtifacts(), false);
|
)),
|
||||||
doBranch(gg, gameVersion, liteLoader.getRepoitory(), liteLoader.getSnapshots(), true);
|
v.build.getTweakClass(), v.build.getLibraries()
|
||||||
}
|
));
|
||||||
} finally {
|
} finally {
|
||||||
lock.writeLock().unlock();
|
lock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String LITELOADER_LIST = "http://dl.liteloader.com/versions/versions.json";
|
|
||||||
|
|
||||||
private static String getLatestSnapshotVersion(String repo) throws Exception {
|
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
|
||||||
Document doc = builder.parse(repo + "maven-metadata.xml");
|
|
||||||
Element r = doc.getDocumentElement();
|
|
||||||
Element snapshot = (Element) r.getElementsByTagName("snapshot").item(0);
|
|
||||||
Node timestamp = snapshot.getElementsByTagName("timestamp").item(0);
|
|
||||||
Node buildNumber = snapshot.getElementsByTagName("buildNumber").item(0);
|
|
||||||
return timestamp.getTextContent() + "-" + buildNumber.getTextContent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import java.util.List;
|
|||||||
public class LiteLoaderRemoteVersion extends RemoteVersion {
|
public class LiteLoaderRemoteVersion extends RemoteVersion {
|
||||||
private final String tweakClass;
|
private final String tweakClass;
|
||||||
private final Collection<Library> libraries;
|
private final Collection<Library> libraries;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
@ -37,8 +38,8 @@ public class LiteLoaderRemoteVersion extends RemoteVersion {
|
|||||||
* @param selfVersion the version string of the remote version.
|
* @param selfVersion the version string of the remote version.
|
||||||
* @param urls the installer or universal jar original URL.
|
* @param urls the installer or universal jar original URL.
|
||||||
*/
|
*/
|
||||||
LiteLoaderRemoteVersion(String gameVersion, String selfVersion, List<String> urls, String tweakClass, Collection<Library> libraries) {
|
LiteLoaderRemoteVersion(String gameVersion, String selfVersion, Type type, List<String> urls, String tweakClass, Collection<Library> libraries) {
|
||||||
super(LibraryAnalyzer.LibraryType.LITELOADER.getPatchId(), gameVersion, selfVersion, null, urls);
|
super(LibraryAnalyzer.LibraryType.LITELOADER.getPatchId(), gameVersion, selfVersion, null, type, urls);
|
||||||
|
|
||||||
this.tweakClass = tweakClass;
|
this.tweakClass = tweakClass;
|
||||||
this.libraries = libraries;
|
this.libraries = libraries;
|
||||||
|
@ -18,21 +18,20 @@
|
|||||||
package org.jackhuang.hmcl.download.liteloader;
|
package org.jackhuang.hmcl.download.liteloader;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
|
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||||
import org.jackhuang.hmcl.download.VersionList;
|
import org.jackhuang.hmcl.download.VersionList;
|
||||||
import org.jackhuang.hmcl.util.io.HttpRequest;
|
import org.jackhuang.hmcl.util.io.HttpRequest;
|
||||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
import org.jsoup.Jsoup;
|
||||||
import org.w3c.dom.Document;
|
import org.jsoup.nodes.Document;
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import java.io.IOException;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import java.io.UncheckedIOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public final class LiteLoaderVersionList extends VersionList<LiteLoaderRemoteVersion> {
|
public final class LiteLoaderVersionList extends VersionList<LiteLoaderRemoteVersion> {
|
||||||
@ -45,52 +44,39 @@ public final class LiteLoaderVersionList extends VersionList<LiteLoaderRemoteVer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasType() {
|
public boolean hasType() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doBranch(String key, String gameVersion, LiteLoaderRepository repository, LiteLoaderBranch branch, boolean snapshot) {
|
public static final String LITELOADER_LIST = "https://dl.liteloader.com/versions/versions.json";
|
||||||
if (branch == null || repository == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (Map.Entry<String, LiteLoaderVersion> entry : branch.getLiteLoader().entrySet()) {
|
|
||||||
String branchName = entry.getKey();
|
|
||||||
LiteLoaderVersion v = entry.getValue();
|
|
||||||
if ("latest".equals(branchName))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
String version = v.getVersion();
|
|
||||||
String url = repository.getUrl() + "com/mumfrey/liteloader/" + gameVersion + "/" + v.getFile();
|
|
||||||
if (snapshot) {
|
|
||||||
try {
|
|
||||||
version = version.replace("SNAPSHOT", getLatestSnapshotVersion(repository.getUrl() + "com/mumfrey/liteloader/" + v.getVersion() + "/"));
|
|
||||||
url = repository.getUrl() + "com/mumfrey/liteloader/" + v.getVersion() + "/liteloader-" + version + "-release.jar";
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
versions.put(key, new LiteLoaderRemoteVersion(gameVersion,
|
|
||||||
version, Collections.singletonList(url),
|
|
||||||
v.getTweakClass(), v.getLibraries()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<?> refreshAsync() {
|
public CompletableFuture<?> refreshAsync(String gameVersion) {
|
||||||
return HttpRequest.GET(downloadProvider.injectURL(LITELOADER_LIST)).getJsonAsync(LiteLoaderVersionsRoot.class)
|
return HttpRequest.GET(downloadProvider.injectURL(LITELOADER_LIST)).getJsonAsync(LiteLoaderVersionsRoot.class)
|
||||||
.thenAcceptAsync(root -> {
|
.thenAcceptAsync(root -> {
|
||||||
|
LiteLoaderGameVersions versions = root.getVersions().get(gameVersion);
|
||||||
|
if (versions == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LiteLoaderRemoteVersion snapshot = null;
|
||||||
|
if (versions.getSnapshots() != null) {
|
||||||
|
try {
|
||||||
|
snapshot = loadSnapshotVersion(gameVersion, versions.getSnapshots().getLiteLoader().get("latest"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lock.writeLock().lock();
|
lock.writeLock().lock();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
versions.clear();
|
this.versions.clear();
|
||||||
|
|
||||||
for (Map.Entry<String, LiteLoaderGameVersions> entry : root.getVersions().entrySet()) {
|
if (versions.getRepoitory() != null && versions.getArtifacts() != null) {
|
||||||
String gameVersion = entry.getKey();
|
loadArtifactVersion(gameVersion, versions.getRepoitory(), versions.getArtifacts());
|
||||||
LiteLoaderGameVersions liteLoader = entry.getValue();
|
}
|
||||||
|
|
||||||
String gg = VersionNumber.normalize(gameVersion);
|
if (snapshot != null) {
|
||||||
doBranch(gg, gameVersion, liteLoader.getRepoitory(), liteLoader.getArtifacts(), false);
|
this.versions.put(gameVersion, snapshot);
|
||||||
doBranch(gg, gameVersion, liteLoader.getRepoitory(), liteLoader.getSnapshots(), true);
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
lock.writeLock().unlock();
|
lock.writeLock().unlock();
|
||||||
@ -98,16 +84,40 @@ public final class LiteLoaderVersionList extends VersionList<LiteLoaderRemoteVer
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String LITELOADER_LIST = "http://dl.liteloader.com/versions/versions.json";
|
@Override
|
||||||
|
public CompletableFuture<?> refreshAsync() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
private static String getLatestSnapshotVersion(String repo) throws Exception {
|
private void loadArtifactVersion(String gameVersion, LiteLoaderRepository repository, LiteLoaderBranch branch) {
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
for (Map.Entry<String, LiteLoaderVersion> entry : branch.getLiteLoader().entrySet()) {
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
String branchName = entry.getKey();
|
||||||
Document doc = builder.parse(repo + "maven-metadata.xml");
|
LiteLoaderVersion v = entry.getValue();
|
||||||
Element r = doc.getDocumentElement();
|
if ("latest".equals(branchName))
|
||||||
Element snapshot = (Element) r.getElementsByTagName("snapshot").item(0);
|
continue;
|
||||||
Node timestamp = snapshot.getElementsByTagName("timestamp").item(0);
|
|
||||||
Node buildNumber = snapshot.getElementsByTagName("buildNumber").item(0);
|
versions.put(gameVersion, new LiteLoaderRemoteVersion(
|
||||||
return timestamp.getTextContent() + "-" + buildNumber.getTextContent();
|
gameVersion, v.getVersion(), RemoteVersion.Type.RELEASE,
|
||||||
|
Collections.singletonList(repository.getUrl() + "com/mumfrey/liteloader/" + gameVersion + "/" + v.getFile()),
|
||||||
|
v.getTweakClass(), v.getLibraries()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround for https://github.com/HMCL-dev/HMCL/issues/3147: Some LiteLoader artifacts aren't published on http://dl.liteloader.com/repo
|
||||||
|
private static final String SNAPSHOT_METADATA = "https://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/%s-SNAPSHOT/maven-metadata.xml";
|
||||||
|
private static final String SNAPSHOT_FILE = "https://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/%s-SNAPSHOT/liteloader-%s-%s-%s-release.jar";
|
||||||
|
|
||||||
|
private LiteLoaderRemoteVersion loadSnapshotVersion(String gameVersion, LiteLoaderVersion v) throws IOException {
|
||||||
|
String root = HttpRequest.GET(String.format(SNAPSHOT_METADATA, gameVersion)).getString();
|
||||||
|
Document document = Jsoup.parseBodyFragment(root);
|
||||||
|
String timestamp = Objects.requireNonNull(document.select("timestamp"), "timestamp").text();
|
||||||
|
String buildNumber = Objects.requireNonNull(document.select("buildNumber"), "buildNumber").text();
|
||||||
|
|
||||||
|
return new LiteLoaderRemoteVersion(
|
||||||
|
gameVersion, timestamp + "-" + buildNumber, RemoteVersion.Type.SNAPSHOT,
|
||||||
|
Collections.singletonList(String.format(SNAPSHOT_FILE, gameVersion, gameVersion, timestamp, buildNumber)),
|
||||||
|
v.getTweakClass(), v.getLibraries()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.util.Lang.wrap;
|
import static org.jackhuang.hmcl.util.Lang.wrap;
|
||||||
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemoteVersion> {
|
public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemoteVersion> {
|
||||||
private final DownloadProvider downloadProvider;
|
private final DownloadProvider downloadProvider;
|
||||||
@ -56,8 +57,20 @@ public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemot
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (String version : results[1].versions) {
|
for (String version : results[1].versions) {
|
||||||
int si1 = version.indexOf('.'), si2 = version.indexOf('.', version.indexOf('.') + 1);
|
String mcVersion;
|
||||||
String mcVersion = "1." + version.substring(0, Integer.parseInt(version.substring(si1 + 1, si2)) == 0 ? si1 : si2);
|
|
||||||
|
try {
|
||||||
|
int si1 = version.indexOf('.'), si2 = version.indexOf('.', version.indexOf('.') + 1);
|
||||||
|
int majorVersion = Integer.parseInt(version.substring(0, si1));
|
||||||
|
if (majorVersion == 0) { // Snapshot version.
|
||||||
|
mcVersion = version.substring(si1 + 1, si2);
|
||||||
|
} else {
|
||||||
|
mcVersion = "1." + version.substring(0, Integer.parseInt(version.substring(si1 + 1, si2)) == 0 ? si1 : si2);
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
LOG.warning(String.format("Cannot parse NeoForge version %s for cracking its mc version.", version), e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
versions.put(mcVersion, new NeoForgeRemoteVersion(
|
versions.put(mcVersion, new NeoForgeRemoteVersion(
|
||||||
mcVersion, NeoForgeRemoteVersion.normalize(version),
|
mcVersion, NeoForgeRemoteVersion.normalize(version),
|
||||||
|
@ -27,6 +27,7 @@ public enum ReleaseType {
|
|||||||
MODIFIED("modified"),
|
MODIFIED("modified"),
|
||||||
OLD_BETA("old-beta"),
|
OLD_BETA("old-beta"),
|
||||||
OLD_ALPHA("old-alpha"),
|
OLD_ALPHA("old-alpha"),
|
||||||
|
PENDING("pending"),
|
||||||
UNKNOWN("unknown");
|
UNKNOWN("unknown");
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.java;
|
package org.jackhuang.hmcl.java;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
import kala.compress.archivers.ArchiveEntry;
|
||||||
import org.jackhuang.hmcl.util.KeyValuePairProperties;
|
import org.jackhuang.hmcl.util.KeyValuePairProperties;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
import org.jackhuang.hmcl.util.platform.Architecture;
|
import org.jackhuang.hmcl.util.platform.Architecture;
|
||||||
|
@ -189,30 +189,57 @@ public class DefaultLauncher extends Launcher {
|
|||||||
if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS)
|
if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS)
|
||||||
res.addDefault("-Duser.home=", options.getGameDir().getParent());
|
res.addDefault("-Duser.home=", options.getGameDir().getParent());
|
||||||
|
|
||||||
|
final int javaVersion = options.getJava().getParsedVersion();
|
||||||
|
final boolean is64bit = options.getJava().getBits() == Bits.BIT_64;
|
||||||
|
|
||||||
|
res.addUnstableDefault("UnlockExperimentalVMOptions", true);
|
||||||
|
res.addUnstableDefault("UnlockDiagnosticVMOptions", true);
|
||||||
|
|
||||||
// Using G1GC with its settings by default
|
// Using G1GC with its settings by default
|
||||||
if (options.getJava().getParsedVersion() >= 8
|
if (javaVersion >= 8
|
||||||
&& res.noneMatch(arg -> "-XX:-UseG1GC".equals(arg) || (arg.startsWith("-XX:+Use") && arg.endsWith("GC")))) {
|
&& res.noneMatch(arg -> "-XX:-UseG1GC".equals(arg) || (arg.startsWith("-XX:+Use") && arg.endsWith("GC")))) {
|
||||||
res.addUnstableDefault("UnlockExperimentalVMOptions", true);
|
|
||||||
res.addUnstableDefault("UseG1GC", true);
|
res.addUnstableDefault("UseG1GC", true);
|
||||||
|
res.addUnstableDefault("G1MixedGCCountTarget", "5");
|
||||||
res.addUnstableDefault("G1NewSizePercent", "20");
|
res.addUnstableDefault("G1NewSizePercent", "20");
|
||||||
res.addUnstableDefault("G1ReservePercent", "20");
|
res.addUnstableDefault("G1ReservePercent", "20");
|
||||||
res.addUnstableDefault("MaxGCPauseMillis", "50");
|
res.addUnstableDefault("MaxGCPauseMillis", "50");
|
||||||
res.addUnstableDefault("G1HeapRegionSize", "32m");
|
res.addUnstableDefault("G1HeapRegionSize", "32m");
|
||||||
}
|
}
|
||||||
|
|
||||||
res.addUnstableDefault("UseAdaptiveSizePolicy", false);
|
|
||||||
res.addUnstableDefault("OmitStackTraceInFastThrow", false);
|
res.addUnstableDefault("OmitStackTraceInFastThrow", false);
|
||||||
res.addUnstableDefault("DontCompileHugeMethods", false);
|
|
||||||
|
// JIT Options
|
||||||
|
if (javaVersion <= 8) {
|
||||||
|
res.addUnstableDefault("MaxInlineLevel", "15");
|
||||||
|
}
|
||||||
|
if (is64bit && OperatingSystem.TOTAL_MEMORY > 4 * 1024) {
|
||||||
|
res.addUnstableDefault("DontCompileHugeMethods", false);
|
||||||
|
res.addUnstableDefault("MaxNodeLimit", "240000");
|
||||||
|
res.addUnstableDefault("NodeLimitFudgeFactor", "8000");
|
||||||
|
res.addUnstableDefault("TieredCompileTaskTimeout", "10000");
|
||||||
|
res.addUnstableDefault("ReservedCodeCacheSize", "400M");
|
||||||
|
if (javaVersion >= 9) {
|
||||||
|
res.addUnstableDefault("NonNMethodCodeHeapSize", "12M");
|
||||||
|
res.addUnstableDefault("ProfiledCodeHeapSize", "194M");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (javaVersion >= 8) {
|
||||||
|
res.addUnstableDefault("NmethodSweepActivity", "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// As 32-bit JVM allocate 320KB for stack by default rather than 64-bit version allocating 1MB,
|
// As 32-bit JVM allocate 320KB for stack by default rather than 64-bit version allocating 1MB,
|
||||||
// causing Minecraft 1.13 crashed accounting for java.lang.StackOverflowError.
|
// causing Minecraft 1.13 crashed accounting for java.lang.StackOverflowError.
|
||||||
if (options.getJava().getBits() == Bits.BIT_32) {
|
if (!is64bit) {
|
||||||
res.addDefault("-Xss", "1m");
|
res.addDefault("-Xss", "1m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.getJava().getParsedVersion() == 16)
|
if (javaVersion == 16)
|
||||||
res.addDefault("--illegal-access=", "permit");
|
res.addDefault("--illegal-access=", "permit");
|
||||||
|
|
||||||
|
if (javaVersion == 24 || javaVersion == 25)
|
||||||
|
res.addDefault("--sun-misc-unsafe-memory-access=", "allow");
|
||||||
|
|
||||||
res.addDefault("-Dfml.ignoreInvalidMinecraftCertificates=", "true");
|
res.addDefault("-Dfml.ignoreInvalidMinecraftCertificates=", "true");
|
||||||
res.addDefault("-Dfml.ignorePatchDiscrepancies=", "true");
|
res.addDefault("-Dfml.ignorePatchDiscrepancies=", "true");
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.mod;
|
package org.jackhuang.hmcl.mod;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.game.LaunchOptions;
|
import org.jackhuang.hmcl.game.LaunchOptions;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
@ -44,7 +44,7 @@ public interface ModpackProvider {
|
|||||||
* @throws JsonParseException if the manifest.json is missing or malformed.
|
* @throws JsonParseException if the manifest.json is missing or malformed.
|
||||||
* @return the manifest.
|
* @return the manifest.
|
||||||
*/
|
*/
|
||||||
Modpack readManifest(ZipFile zipFile, Path file, Charset encoding) throws IOException, JsonParseException;
|
Modpack readManifest(ZipArchiveReader zipFile, Path file, Charset encoding) throws IOException, JsonParseException;
|
||||||
|
|
||||||
default void injectLaunchOptions(String modpackConfigurationJson, LaunchOptions.Builder builder) {
|
default void injectLaunchOptions(String modpackConfigurationJson, LaunchOptions.Builder builder) {
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,9 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
|
|||||||
@Override
|
@Override
|
||||||
public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder) throws IOException {
|
public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder) throws IOException {
|
||||||
int categoryId = 0;
|
int categoryId = 0;
|
||||||
if (category != null) categoryId = ((CurseAddon.Category) category.getSelf()).getId();
|
if (category != null && category.getSelf() instanceof CurseAddon.Category) {
|
||||||
|
categoryId = ((CurseAddon.Category) category.getSelf()).getId();
|
||||||
|
}
|
||||||
Response<List<CurseAddon>> response = HttpRequest.GET(PREFIX + "/v1/mods/search",
|
Response<List<CurseAddon>> response = HttpRequest.GET(PREFIX + "/v1/mods/search",
|
||||||
pair("gameId", "432"),
|
pair("gameId", "432"),
|
||||||
pair("classId", Integer.toString(section)),
|
pair("classId", Integer.toString(section)),
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
package org.jackhuang.hmcl.mod.curse;
|
package org.jackhuang.hmcl.mod.curse;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
||||||
import org.jackhuang.hmcl.mod.Modpack;
|
import org.jackhuang.hmcl.mod.Modpack;
|
||||||
@ -57,7 +57,7 @@ public final class CurseModpackProvider implements ModpackProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Modpack readManifest(ZipFile zip, Path file, Charset encoding) throws IOException, JsonParseException {
|
public Modpack readManifest(ZipArchiveReader zip, Path file, Charset encoding) throws IOException, JsonParseException {
|
||||||
CurseManifest manifest = JsonUtils.fromNonNullJson(CompressingUtils.readTextZipEntry(zip, "manifest.json"), CurseManifest.class);
|
CurseManifest manifest = JsonUtils.fromNonNullJson(CompressingUtils.readTextZipEntry(zip, "manifest.json"), CurseManifest.class);
|
||||||
String description = "No description";
|
String description = "No description";
|
||||||
try {
|
try {
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
package org.jackhuang.hmcl.mod.mcbbs;
|
package org.jackhuang.hmcl.mod.mcbbs;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.game.LaunchOptions;
|
import org.jackhuang.hmcl.game.LaunchOptions;
|
||||||
import org.jackhuang.hmcl.mod.*;
|
import org.jackhuang.hmcl.mod.*;
|
||||||
@ -70,7 +70,7 @@ public final class McbbsModpackProvider implements ModpackProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Modpack readManifest(ZipFile zip, Path file, Charset encoding) throws IOException, JsonParseException {
|
public Modpack readManifest(ZipArchiveReader zip, Path file, Charset encoding) throws IOException, JsonParseException {
|
||||||
ZipArchiveEntry mcbbsPackMeta = zip.getEntry("mcbbs.packmeta");
|
ZipArchiveEntry mcbbsPackMeta = zip.getEntry("mcbbs.packmeta");
|
||||||
if (mcbbsPackMeta != null) {
|
if (mcbbsPackMeta != null) {
|
||||||
return fromManifestFile(zip.getInputStream(mcbbsPackMeta), encoding);
|
return fromManifestFile(zip.getInputStream(mcbbsPackMeta), encoding);
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.mod.modrinth;
|
package org.jackhuang.hmcl.mod.modrinth;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
||||||
import org.jackhuang.hmcl.mod.Modpack;
|
import org.jackhuang.hmcl.mod.Modpack;
|
||||||
@ -55,7 +55,7 @@ public final class ModrinthModpackProvider implements ModpackProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Modpack readManifest(ZipFile zip, Path file, Charset encoding) throws IOException, JsonParseException {
|
public Modpack readManifest(ZipArchiveReader zip, Path file, Charset encoding) throws IOException, JsonParseException {
|
||||||
ModrinthManifest manifest = JsonUtils.fromNonNullJson(CompressingUtils.readTextZipEntry(zip, "modrinth.index.json"), ModrinthManifest.class);
|
ModrinthManifest manifest = JsonUtils.fromNonNullJson(CompressingUtils.readTextZipEntry(zip, "modrinth.index.json"), ModrinthManifest.class);
|
||||||
return new Modpack(manifest.getName(), "", manifest.getVersionId(), manifest.getGameVersion(), manifest.getSummary(), encoding, manifest) {
|
return new Modpack(manifest.getName(), "", manifest.getVersionId(), manifest.getGameVersion(), manifest.getSummary(), encoding, manifest) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
package org.jackhuang.hmcl.mod.multimc;
|
package org.jackhuang.hmcl.mod.multimc;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.util.Immutable;
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ public final class MultiMCManifest {
|
|||||||
* @throws IOException if zip file is malformed
|
* @throws IOException if zip file is malformed
|
||||||
* @throws com.google.gson.JsonParseException if manifest is malformed.
|
* @throws com.google.gson.JsonParseException if manifest is malformed.
|
||||||
*/
|
*/
|
||||||
public static MultiMCManifest readMultiMCModpackManifest(ZipFile zipFile, String rootEntryName) throws IOException {
|
public static MultiMCManifest readMultiMCModpackManifest(ZipArchiveReader zipFile, String rootEntryName) throws IOException {
|
||||||
ZipArchiveEntry mmcPack = zipFile.getEntry(rootEntryName + "mmc-pack.json");
|
ZipArchiveEntry mmcPack = zipFile.getEntry(rootEntryName + "mmc-pack.json");
|
||||||
if (mmcPack == null)
|
if (mmcPack == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.mod.multimc;
|
package org.jackhuang.hmcl.mod.multimc;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
||||||
import org.jackhuang.hmcl.mod.Modpack;
|
import org.jackhuang.hmcl.mod.Modpack;
|
||||||
@ -33,7 +33,6 @@ import java.io.InputStream;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public final class MultiMCModpackProvider implements ModpackProvider {
|
public final class MultiMCModpackProvider implements ModpackProvider {
|
||||||
@ -71,14 +70,12 @@ public final class MultiMCModpackProvider implements ModpackProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getRootEntryName(ZipFile file) throws IOException {
|
private static String getRootEntryName(ZipArchiveReader file) throws IOException {
|
||||||
final String instanceFileName = "instance.cfg";
|
final String instanceFileName = "instance.cfg";
|
||||||
|
|
||||||
if (file.getEntry(instanceFileName) != null) return "";
|
if (file.getEntry(instanceFileName) != null) return "";
|
||||||
|
|
||||||
Enumeration<ZipArchiveEntry> entries = file.getEntries();
|
for (ZipArchiveEntry entry : file.getEntries()) {
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
ZipArchiveEntry entry = entries.nextElement();
|
|
||||||
String entryName = entry.getName();
|
String entryName = entry.getName();
|
||||||
|
|
||||||
int idx = entryName.indexOf('/');
|
int idx = entryName.indexOf('/');
|
||||||
@ -92,7 +89,7 @@ public final class MultiMCModpackProvider implements ModpackProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Modpack readManifest(ZipFile modpackFile, Path modpackPath, Charset encoding) throws IOException {
|
public Modpack readManifest(ZipArchiveReader modpackFile, Path modpackPath, Charset encoding) throws IOException {
|
||||||
String rootEntryName = getRootEntryName(modpackFile);
|
String rootEntryName = getRootEntryName(modpackFile);
|
||||||
MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(modpackFile, rootEntryName);
|
MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(modpackFile, rootEntryName);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.mod.server;
|
package org.jackhuang.hmcl.mod.server;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
||||||
import org.jackhuang.hmcl.mod.Modpack;
|
import org.jackhuang.hmcl.mod.Modpack;
|
||||||
@ -55,7 +55,7 @@ public final class ServerModpackProvider implements ModpackProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Modpack readManifest(ZipFile zip, Path file, Charset encoding) throws IOException, JsonParseException {
|
public Modpack readManifest(ZipArchiveReader zip, Path file, Charset encoding) throws IOException, JsonParseException {
|
||||||
String json = CompressingUtils.readTextZipEntry(zip, "server-manifest.json");
|
String json = CompressingUtils.readTextZipEntry(zip, "server-manifest.json");
|
||||||
ServerModpackManifest manifest = JsonUtils.fromNonNullJson(json, ServerModpackManifest.class);
|
ServerModpackManifest manifest = JsonUtils.fromNonNullJson(json, ServerModpackManifest.class);
|
||||||
return manifest.toModpack(encoding);
|
return manifest.toModpack(encoding);
|
||||||
|
@ -288,7 +288,7 @@ public class CacheRepository {
|
|||||||
try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||||
FileLock lock = channel.lock();
|
FileLock lock = channel.lock();
|
||||||
try {
|
try {
|
||||||
ETagIndex indexOnDisk = fromMaybeMalformedJson(new String(IOUtils.readFullyWithoutClosing(Channels.newInputStream(channel)), UTF_8), ETagIndex.class);
|
ETagIndex indexOnDisk = fromMaybeMalformedJson(IOUtils.readFullyAsStringWithClosing(Channels.newInputStream(channel)), ETagIndex.class);
|
||||||
Map<String, ETagItem> newIndex = joinETagIndexes(indexOnDisk == null ? null : indexOnDisk.eTag, index.values());
|
Map<String, ETagItem> newIndex = joinETagIndexes(indexOnDisk == null ? null : indexOnDisk.eTag, index.values());
|
||||||
channel.truncate(0);
|
channel.truncate(0);
|
||||||
ByteBuffer writeTo = ByteBuffer.wrap(GSON.toJson(new ETagIndex(newIndex.values())).getBytes(UTF_8));
|
ByteBuffer writeTo = ByteBuffer.wrap(GSON.toJson(new ETagIndex(newIndex.values())).getBytes(UTF_8));
|
||||||
@ -424,11 +424,17 @@ public class CacheRepository {
|
|||||||
try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||||
FileLock lock = channel.lock();
|
FileLock lock = channel.lock();
|
||||||
try {
|
try {
|
||||||
Map<String, Object> indexOnDisk = fromMaybeMalformedJson(new String(IOUtils.readFullyWithoutClosing(Channels.newInputStream(channel)), UTF_8), mapTypeOf(String.class, Object.class));
|
Map<String, Object> indexOnDisk = fromMaybeMalformedJson(IOUtils.readFullyAsStringWithClosing(Channels.newInputStream(channel)), mapTypeOf(String.class, Object.class));
|
||||||
if (indexOnDisk == null) indexOnDisk = new HashMap<>();
|
if (indexOnDisk == null) indexOnDisk = new HashMap<>();
|
||||||
indexOnDisk.putAll(storage);
|
indexOnDisk.putAll(storage);
|
||||||
channel.truncate(0);
|
channel.truncate(0);
|
||||||
channel.write(ByteBuffer.wrap(GSON.toJson(storage).getBytes(UTF_8)));
|
|
||||||
|
ByteBuffer writeTo = ByteBuffer.wrap(GSON.toJson(storage).getBytes(UTF_8));
|
||||||
|
while (writeTo.hasRemaining()) {
|
||||||
|
if (channel.write(writeTo) == 0) {
|
||||||
|
throw new IOException("No value is written");
|
||||||
|
}
|
||||||
|
}
|
||||||
this.storage = indexOnDisk;
|
this.storage = indexOnDisk;
|
||||||
} finally {
|
} finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.io;
|
package org.jackhuang.hmcl.util.io;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||||
|
|
||||||
@ -54,19 +54,16 @@ public final class CompressingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean testEncoding(Path zipFile, Charset encoding) throws IOException {
|
public static boolean testEncoding(Path zipFile, Charset encoding) throws IOException {
|
||||||
try (ZipFile zf = openZipFile(zipFile, encoding)) {
|
try (ZipArchiveReader zf = openZipFile(zipFile, encoding)) {
|
||||||
return testEncoding(zf, encoding);
|
return testEncoding(zf, encoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean testEncoding(ZipFile zipFile, Charset encoding) throws IOException {
|
public static boolean testEncoding(ZipArchiveReader zipFile, Charset encoding) throws IOException {
|
||||||
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
|
|
||||||
CharsetDecoder cd = newCharsetDecoder(encoding);
|
CharsetDecoder cd = newCharsetDecoder(encoding);
|
||||||
CharBuffer cb = CharBuffer.allocate(32);
|
CharBuffer cb = CharBuffer.allocate(32);
|
||||||
|
|
||||||
while (entries.hasMoreElements()) {
|
for (ZipArchiveEntry entry : zipFile.getEntries()) {
|
||||||
ZipArchiveEntry entry = entries.nextElement();
|
|
||||||
|
|
||||||
if (entry.getGeneralPurposeBit().usesUTF8ForNames()) continue;
|
if (entry.getGeneralPurposeBit().usesUTF8ForNames()) continue;
|
||||||
|
|
||||||
cd.reset();
|
cd.reset();
|
||||||
@ -88,12 +85,12 @@ public final class CompressingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Charset findSuitableEncoding(Path zipFile) throws IOException {
|
public static Charset findSuitableEncoding(Path zipFile) throws IOException {
|
||||||
try (ZipFile zf = openZipFile(zipFile, StandardCharsets.UTF_8)) {
|
try (ZipArchiveReader zf = openZipFile(zipFile, StandardCharsets.UTF_8)) {
|
||||||
return findSuitableEncoding(zf);
|
return findSuitableEncoding(zf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Charset findSuitableEncoding(ZipFile zipFile) throws IOException {
|
public static Charset findSuitableEncoding(ZipArchiveReader zipFile) throws IOException {
|
||||||
if (testEncoding(zipFile, StandardCharsets.UTF_8)) return StandardCharsets.UTF_8;
|
if (testEncoding(zipFile, StandardCharsets.UTF_8)) return StandardCharsets.UTF_8;
|
||||||
if (OperatingSystem.NATIVE_CHARSET != StandardCharsets.UTF_8 && testEncoding(zipFile, OperatingSystem.NATIVE_CHARSET))
|
if (OperatingSystem.NATIVE_CHARSET != StandardCharsets.UTF_8 && testEncoding(zipFile, OperatingSystem.NATIVE_CHARSET))
|
||||||
return OperatingSystem.NATIVE_CHARSET;
|
return OperatingSystem.NATIVE_CHARSET;
|
||||||
@ -133,12 +130,12 @@ public final class CompressingUtils {
|
|||||||
throw new IOException("Cannot find suitable encoding for the zip.");
|
throw new IOException("Cannot find suitable encoding for the zip.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ZipFile openZipFile(Path zipFile) throws IOException {
|
public static ZipArchiveReader openZipFile(Path zipFile) throws IOException {
|
||||||
return new ZipFile(Files.newByteChannel(zipFile));
|
return new ZipArchiveReader(Files.newByteChannel(zipFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ZipFile openZipFile(Path zipFile, Charset charset) throws IOException {
|
public static ZipArchiveReader openZipFile(Path zipFile, Charset charset) throws IOException {
|
||||||
return new ZipFile(Files.newByteChannel(zipFile), charset.name());
|
return new ZipArchiveReader(zipFile, charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
@ -234,7 +231,7 @@ public final class CompressingUtils {
|
|||||||
* @return the plain text content of given file.
|
* @return the plain text content of given file.
|
||||||
*/
|
*/
|
||||||
public static String readTextZipEntry(File zipFile, String name) throws IOException {
|
public static String readTextZipEntry(File zipFile, String name) throws IOException {
|
||||||
try (ZipFile s = new ZipFile(zipFile)) {
|
try (ZipArchiveReader s = new ZipArchiveReader(zipFile.toPath())) {
|
||||||
return readTextZipEntry(s, name);
|
return readTextZipEntry(s, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,7 +244,7 @@ public final class CompressingUtils {
|
|||||||
* @throws IOException if the file is not a valid zip file.
|
* @throws IOException if the file is not a valid zip file.
|
||||||
* @return the plain text content of given file.
|
* @return the plain text content of given file.
|
||||||
*/
|
*/
|
||||||
public static String readTextZipEntry(ZipFile zipFile, String name) throws IOException {
|
public static String readTextZipEntry(ZipArchiveReader zipFile, String name) throws IOException {
|
||||||
return IOUtils.readFullyAsString(zipFile.getInputStream(zipFile.getEntry(name)));
|
return IOUtils.readFullyAsString(zipFile.getInputStream(zipFile.getEntry(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +257,7 @@ public final class CompressingUtils {
|
|||||||
* @return the plain text content of given file.
|
* @return the plain text content of given file.
|
||||||
*/
|
*/
|
||||||
public static String readTextZipEntry(Path zipFile, String name, Charset encoding) throws IOException {
|
public static String readTextZipEntry(Path zipFile, String name, Charset encoding) throws IOException {
|
||||||
try (ZipFile s = openZipFile(zipFile, encoding)) {
|
try (ZipArchiveReader s = openZipFile(zipFile, encoding)) {
|
||||||
return IOUtils.readFullyAsString(s.getInputStream(s.getEntry(name)));
|
return IOUtils.readFullyAsString(s.getInputStream(s.getEntry(name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.util.io;
|
package org.jackhuang.hmcl.util.io;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,6 +75,10 @@ public final class IOUtils {
|
|||||||
return readFully(stream).toString("UTF-8");
|
return readFully(stream).toString("UTF-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String readFullyAsString(InputStream stream, Charset charset) throws IOException {
|
||||||
|
return readFully(stream).toString(charset.name());
|
||||||
|
}
|
||||||
|
|
||||||
public static void copyTo(InputStream src, OutputStream dest) throws IOException {
|
public static void copyTo(InputStream src, OutputStream dest) throws IOException {
|
||||||
copyTo(src, dest, new byte[DEFAULT_BUFFER_SIZE]);
|
copyTo(src, dest, new byte[DEFAULT_BUFFER_SIZE]);
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.platform;
|
package org.jackhuang.hmcl.util.platform;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.File;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -192,30 +192,46 @@ public enum Architecture {
|
|||||||
static {
|
static {
|
||||||
CURRENT_ARCH = parseArchName(System.getProperty("os.arch"));
|
CURRENT_ARCH = parseArchName(System.getProperty("os.arch"));
|
||||||
|
|
||||||
String sysArchName = null;
|
Architecture sysArch = null;
|
||||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
|
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
|
||||||
String processorIdentifier = System.getenv("PROCESSOR_IDENTIFIER");
|
String processorIdentifier = System.getenv("PROCESSOR_IDENTIFIER");
|
||||||
if (processorIdentifier != null) {
|
if (processorIdentifier != null) {
|
||||||
int idx = processorIdentifier.indexOf(' ');
|
int idx = processorIdentifier.indexOf(' ');
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
sysArchName = processorIdentifier.substring(0, idx);
|
sysArch = parseArchName(processorIdentifier.substring(0, idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX) {
|
||||||
|
if (CURRENT_ARCH == X86_64) {
|
||||||
|
try {
|
||||||
|
Process process = Runtime.getRuntime().exec(new String[]{"/usr/sbin/sysctl", "-n", "sysctl.proc_translated"});
|
||||||
|
if (process.waitFor(3, TimeUnit.SECONDS) && process.exitValue() == 0
|
||||||
|
&& "1".equals(IOUtils.readFullyAsString(process.getInputStream(), OperatingSystem.NATIVE_CHARSET).trim())) {
|
||||||
|
sysArch = ARM64;
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace(System.err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
for (String uname : new String[]{
|
||||||
Process process = Runtime.getRuntime().exec(new String[]{"/bin/uname", "-m"});
|
"/bin/uname",
|
||||||
if (process.waitFor(3, TimeUnit.SECONDS)) {
|
"/usr/bin/uname"
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), OperatingSystem.NATIVE_CHARSET))) {
|
}) {
|
||||||
sysArchName = reader.readLine().trim();
|
if (new File(uname).exists()) {
|
||||||
} catch (Exception e) {
|
try {
|
||||||
e.printStackTrace();
|
Process process = Runtime.getRuntime().exec(new String[]{uname, "-m"});
|
||||||
|
if (process.waitFor(3, TimeUnit.SECONDS) && process.exitValue() == 0) {
|
||||||
|
sysArch = parseArchName(IOUtils.readFullyAsString(process.getInputStream(), OperatingSystem.NATIVE_CHARSET).trim());
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace(System.err);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Architecture sysArch = parseArchName(sysArchName);
|
SYSTEM_ARCH = sysArch == null || sysArch == UNKNOWN ? CURRENT_ARCH : sysArch;
|
||||||
SYSTEM_ARCH = sysArch == UNKNOWN ? CURRENT_ARCH : sysArch;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.tree;
|
package org.jackhuang.hmcl.util.tree;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
import kala.compress.archivers.ArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -39,7 +39,7 @@ public abstract class ArchiveFileTree<F, E extends ArchiveEntry> implements Clos
|
|||||||
|
|
||||||
String name = namePath.toString();
|
String name = namePath.toString();
|
||||||
if (name.endsWith(".jar") || name.endsWith(".zip")) {
|
if (name.endsWith(".jar") || name.endsWith(".zip")) {
|
||||||
return new ZipFileTree(new ZipFile(file));
|
return new ZipFileTree(new ZipArchiveReader(file));
|
||||||
} else if (name.endsWith(".tar") || name.endsWith(".tar.gz") || name.endsWith(".tgz")) {
|
} else if (name.endsWith(".tar") || name.endsWith(".tar.gz") || name.endsWith(".tgz")) {
|
||||||
return TarFileTree.open(file);
|
return TarFileTree.open(file);
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
package org.jackhuang.hmcl.util.tree;
|
package org.jackhuang.hmcl.util.tree;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
import kala.compress.archivers.tar.TarArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.tar.TarFile;
|
import kala.compress.archivers.tar.TarArchiveReader;
|
||||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -31,19 +31,19 @@ import java.util.zip.GZIPInputStream;
|
|||||||
/**
|
/**
|
||||||
* @author Glavo
|
* @author Glavo
|
||||||
*/
|
*/
|
||||||
public final class TarFileTree extends ArchiveFileTree<TarFile, TarArchiveEntry> {
|
public final class TarFileTree extends ArchiveFileTree<TarArchiveReader, TarArchiveEntry> {
|
||||||
|
|
||||||
public static TarFileTree open(Path file) throws IOException {
|
public static TarFileTree open(Path file) throws IOException {
|
||||||
String fileName = file.getFileName().toString();
|
String fileName = file.getFileName().toString();
|
||||||
|
|
||||||
if (fileName.endsWith(".tar.gz") || fileName.endsWith(".tgz")) {
|
if (fileName.endsWith(".tar.gz") || fileName.endsWith(".tgz")) {
|
||||||
Path tempFile = Files.createTempFile("hmcl-", ".tar");
|
Path tempFile = Files.createTempFile("hmcl-", ".tar");
|
||||||
TarFile tarFile;
|
TarArchiveReader tarFile;
|
||||||
try (GZIPInputStream input = new GZIPInputStream(Files.newInputStream(file));
|
try (GZIPInputStream input = new GZIPInputStream(Files.newInputStream(file));
|
||||||
OutputStream output = Files.newOutputStream(tempFile, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)
|
OutputStream output = Files.newOutputStream(tempFile, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)
|
||||||
) {
|
) {
|
||||||
IOUtils.copyTo(input, output);
|
IOUtils.copyTo(input, output);
|
||||||
tarFile = new TarFile(tempFile.toFile());
|
tarFile = new TarArchiveReader(tempFile);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
try {
|
try {
|
||||||
Files.deleteIfExists(tempFile);
|
Files.deleteIfExists(tempFile);
|
||||||
@ -55,14 +55,14 @@ public final class TarFileTree extends ArchiveFileTree<TarFile, TarArchiveEntry>
|
|||||||
|
|
||||||
return new TarFileTree(tarFile, tempFile);
|
return new TarFileTree(tarFile, tempFile);
|
||||||
} else {
|
} else {
|
||||||
return new TarFileTree(new TarFile(file), null);
|
return new TarFileTree(new TarArchiveReader(file), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Path tempFile;
|
private final Path tempFile;
|
||||||
private final Thread shutdownHook;
|
private final Thread shutdownHook;
|
||||||
|
|
||||||
public TarFileTree(TarFile file, Path tempFile) throws IOException {
|
public TarFileTree(TarArchiveReader file, Path tempFile) throws IOException {
|
||||||
super(file);
|
super(file);
|
||||||
this.tempFile = tempFile;
|
this.tempFile = tempFile;
|
||||||
try {
|
try {
|
||||||
|
@ -17,23 +17,21 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.tree;
|
package org.jackhuang.hmcl.util.tree;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Glavo
|
* @author Glavo
|
||||||
*/
|
*/
|
||||||
public final class ZipFileTree extends ArchiveFileTree<ZipFile, ZipArchiveEntry> {
|
public final class ZipFileTree extends ArchiveFileTree<ZipArchiveReader, ZipArchiveEntry> {
|
||||||
public ZipFileTree(ZipFile file) throws IOException {
|
public ZipFileTree(ZipArchiveReader file) throws IOException {
|
||||||
super(file);
|
super(file);
|
||||||
try {
|
try {
|
||||||
Enumeration<ZipArchiveEntry> entries = file.getEntries();
|
for (ZipArchiveEntry zipArchiveEntry : file.getEntries()) {
|
||||||
while (entries.hasMoreElements()) {
|
addEntry(zipArchiveEntry);
|
||||||
addEntry(entries.nextElement());
|
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
try {
|
try {
|
||||||
|
1362
HMCLCore/src/main/resources/assets/game/unlisted-versions.json
Normal file
1362
HMCLCore/src/main/resources/assets/game/unlisted-versions.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -812,4 +812,5 @@
|
|||||||
1.21.5-pre3
|
1.21.5-pre3
|
||||||
1.21.5-rc1
|
1.21.5-rc1
|
||||||
1.21.5-rc2
|
1.21.5-rc2
|
||||||
1.21.5
|
1.21.5
|
||||||
|
25w14craftmine
|
@ -1,4 +0,0 @@
|
|||||||
# Use the Google style in this project.
|
|
||||||
BasedOnStyle: Google
|
|
||||||
|
|
||||||
SortIncludes: false
|
|
5
HMCLauncher/.gitignore
vendored
5
HMCLauncher/.gitignore
vendored
@ -1,5 +0,0 @@
|
|||||||
Debug
|
|
||||||
Release
|
|
||||||
.vs
|
|
||||||
*.APS
|
|
||||||
cmake-build-*/
|
|
@ -1,18 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.25)
|
|
||||||
project(HMCLauncher)
|
|
||||||
if(MSVC)
|
|
||||||
add_definitions(-DUNICODE -D_UNICODE)
|
|
||||||
add_compile_options(/utf-8 /W4)
|
|
||||||
add_link_options(/ENTRY:wWinMainCRTStartup)
|
|
||||||
else()
|
|
||||||
add_compile_options(-municode -Wall -Wextra -Wpedantic)
|
|
||||||
add_link_options(-municode)
|
|
||||||
endif()
|
|
||||||
OPTION(ENABLE_MINGW_STATIC_LINK_LIBSTDCXX "Link the C++ standard library statically to the executable file(mingw only)." ON)
|
|
||||||
if(ENABLE_MINGW_STATIC_LINK_LIBSTDCXX AND MINGW)
|
|
||||||
add_link_options(-static)
|
|
||||||
endif()
|
|
||||||
set(CMAKE_WIN32_EXECUTABLE ON)
|
|
||||||
add_executable(HMCLauncher WIN32 HMCL/HMCL.rc HMCL/java.cpp HMCL/main.cpp HMCL/os.cpp HMCL/stdafx.cpp HMCL/Version.cpp)
|
|
||||||
target_link_libraries(HMCLauncher Version)
|
|
||||||
install(TARGETS HMCLauncher)
|
|
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
@ -1,143 +0,0 @@
|
|||||||
// Microsoft Visual C++ generated resource script.
|
|
||||||
//
|
|
||||||
#include "resource.h"
|
|
||||||
|
|
||||||
#define APSTUDIO_READONLY_SYMBOLS
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Generated from the TEXTINCLUDE 2 resource.
|
|
||||||
//
|
|
||||||
#ifndef APSTUDIO_INVOKED
|
|
||||||
#include "targetver.h"
|
|
||||||
#endif
|
|
||||||
#define APSTUDIO_HIDDEN_SYMBOLS
|
|
||||||
#include "windows.h"
|
|
||||||
#undef APSTUDIO_HIDDEN_SYMBOLS
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#undef APSTUDIO_READONLY_SYMBOLS
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 中文(简体,中国) resources
|
|
||||||
|
|
||||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
|
|
||||||
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Icon
|
|
||||||
//
|
|
||||||
|
|
||||||
// Icon with lowest ID value placed first to ensure application icon
|
|
||||||
// remains consistent on all systems.
|
|
||||||
IDI_HMCL ICON "HMCL.ico"
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Accelerator
|
|
||||||
//
|
|
||||||
|
|
||||||
IDC_HMCL ACCELERATORS
|
|
||||||
BEGIN
|
|
||||||
"?", IDM_ABOUT, ASCII, ALT
|
|
||||||
"/", IDM_ABOUT, ASCII, ALT
|
|
||||||
END
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef APSTUDIO_INVOKED
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// TEXTINCLUDE
|
|
||||||
//
|
|
||||||
|
|
||||||
1 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"resource.h\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
2 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"#ifndef APSTUDIO_INVOKED\r\n"
|
|
||||||
"#include ""targetver.h""\r\n"
|
|
||||||
"#endif\r\n"
|
|
||||||
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
|
|
||||||
"#include ""windows.h""\r\n"
|
|
||||||
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
|
|
||||||
"\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
3 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"\r\n"
|
|
||||||
"\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
#endif // APSTUDIO_INVOKED
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Version
|
|
||||||
//
|
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
|
||||||
FILEVERSION 3,5,0,0
|
|
||||||
PRODUCTVERSION 3,5,0,0
|
|
||||||
FILEFLAGSMASK 0x3fL
|
|
||||||
#ifdef _DEBUG
|
|
||||||
FILEFLAGS 0x1L
|
|
||||||
#else
|
|
||||||
FILEFLAGS 0x0L
|
|
||||||
#endif
|
|
||||||
FILEOS 0x40004L
|
|
||||||
FILETYPE 0x1L
|
|
||||||
FILESUBTYPE 0x0L
|
|
||||||
BEGIN
|
|
||||||
BLOCK "StringFileInfo"
|
|
||||||
BEGIN
|
|
||||||
BLOCK "080404b0"
|
|
||||||
BEGIN
|
|
||||||
VALUE "CompanyName", "huanghongxun"
|
|
||||||
VALUE "FileDescription", "Hello Minecraft! Launcher For Windows"
|
|
||||||
VALUE "FileVersion", "3.5.0.0"
|
|
||||||
VALUE "InternalName", "HMCL.exe"
|
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2021 huangyuhui"
|
|
||||||
VALUE "OriginalFilename", "HMCL.exe"
|
|
||||||
VALUE "ProductName", "Hello Minecraft! Launcher"
|
|
||||||
VALUE "ProductVersion", "3.5.0.0"
|
|
||||||
END
|
|
||||||
END
|
|
||||||
BLOCK "VarFileInfo"
|
|
||||||
BEGIN
|
|
||||||
VALUE "Translation", 0x804, 1200
|
|
||||||
END
|
|
||||||
END
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// String Table
|
|
||||||
//
|
|
||||||
|
|
||||||
STRINGTABLE
|
|
||||||
BEGIN
|
|
||||||
IDS_APP_TITLE "HMCL"
|
|
||||||
IDC_HMCL "HMCL"
|
|
||||||
END
|
|
||||||
|
|
||||||
#endif // 中文(简体,中国) resources
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef APSTUDIO_INVOKED
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Generated from the TEXTINCLUDE 3 resource.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#endif // not APSTUDIO_INVOKED
|
|
||||||
|
|
@ -1,192 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|x64">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<VCProjectVersion>15.0</VCProjectVersion>
|
|
||||||
<ProjectGuid>{672B1019-E741-4C0D-A986-627E2ACE157B}</ProjectGuid>
|
|
||||||
<Keyword>Win32Proj</Keyword>
|
|
||||||
<RootNamespace>HMCL</RootNamespace>
|
|
||||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
|
||||||
<ProjectName>HMCLauncher</ProjectName>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
|
||||||
<ImportGroup Label="ExtensionSettings">
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="Shared">
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<PropertyGroup Label="UserMacros" />
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<ConformanceMode>false</ConformanceMode>
|
|
||||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<AdditionalDependencies>version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<ClCompile>
|
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<ConformanceMode>false</ConformanceMode>
|
|
||||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>MinSpace</Optimization>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
|
||||||
<ConformanceMode>false</ConformanceMode>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
|
||||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
|
||||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<AdditionalDependencies>version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<ClCompile>
|
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>MinSpace</Optimization>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<ConformanceMode>false</ConformanceMode>
|
|
||||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
|
||||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
|
||||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Windows</SubSystem>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="java.h" />
|
|
||||||
<ClInclude Include="lang.h" />
|
|
||||||
<ClInclude Include="main.h" />
|
|
||||||
<ClInclude Include="os.h" />
|
|
||||||
<ClInclude Include="Resource.h" />
|
|
||||||
<ClInclude Include="stdafx.h" />
|
|
||||||
<ClInclude Include="targetver.h" />
|
|
||||||
<ClInclude Include="version.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="java.cpp" />
|
|
||||||
<ClCompile Include="main.cpp" />
|
|
||||||
<ClCompile Include="os.cpp" />
|
|
||||||
<ClCompile Include="stdafx.cpp">
|
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="version.cpp" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ResourceCompile Include="HMCL.rc" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Image Include="HMCL.ico" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
|
||||||
<ImportGroup Label="ExtensionTargets">
|
|
||||||
</ImportGroup>
|
|
||||||
</Project>
|
|
@ -1,70 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup>
|
|
||||||
<Filter Include="源文件">
|
|
||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="头文件">
|
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="资源文件">
|
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="stdafx.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="targetver.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Resource.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="main.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="version.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="java.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="os.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="lang.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="stdafx.cpp">
|
|
||||||
<Filter>源文件</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="main.cpp">
|
|
||||||
<Filter>源文件</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="version.cpp">
|
|
||||||
<Filter>源文件</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="java.cpp">
|
|
||||||
<Filter>源文件</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="os.cpp">
|
|
||||||
<Filter>源文件</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ResourceCompile Include="HMCL.rc">
|
|
||||||
<Filter>资源文件</Filter>
|
|
||||||
</ResourceCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Image Include="HMCL.ico">
|
|
||||||
<Filter>资源文件</Filter>
|
|
||||||
</Image>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup />
|
|
||||||
</Project>
|
|
@ -1,16 +0,0 @@
|
|||||||
#include "stdafx.h"
|
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
Version::Version(const std::wstring &rawString) {
|
|
||||||
int idx = 0;
|
|
||||||
ver[0] = ver[1] = ver[2] = ver[3] = 0;
|
|
||||||
for (auto &i : rawString) {
|
|
||||||
if (idx >= 4) break;
|
|
||||||
if (i == '.')
|
|
||||||
++idx;
|
|
||||||
else if (i == '_')
|
|
||||||
++idx;
|
|
||||||
else if (isdigit(i))
|
|
||||||
ver[idx] = ver[idx] * 10 + (i - L'0');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class Version {
|
|
||||||
public:
|
|
||||||
int ver[4];
|
|
||||||
|
|
||||||
Version(const std::wstring &rawString);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Version(std::initializer_list<T> ver_list) {
|
|
||||||
int i = 0;
|
|
||||||
for (const auto &data : ver_list) {
|
|
||||||
if (i >= 4) break;
|
|
||||||
ver[i++] = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const Version &other) const {
|
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
if (ver[i] != other.ver[i]) return ver[i] < other.ver[i];
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<=(const Version &other) const {
|
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
if (ver[i] != other.ver[i]) return ver[i] < other.ver[i];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,84 +0,0 @@
|
|||||||
#include "stdafx.h"
|
|
||||||
#include "java.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
const Version JAVA_8(L"1.8"), JAVA_11(L"11");
|
|
||||||
|
|
||||||
const LPCWSTR JDK_NEW = L"SOFTWARE\\JavaSoft\\JDK";
|
|
||||||
const LPCWSTR JRE_NEW = L"SOFTWARE\\JavaSoft\\JRE";
|
|
||||||
const LPCWSTR JDK_OLD = L"SOFTWARE\\JavaSoft\\Java Development Kit";
|
|
||||||
const LPCWSTR JRE_OLD = L"SOFTWARE\\JavaSoft\\Java Runtime Environment";
|
|
||||||
|
|
||||||
bool oldJavaFound = false;
|
|
||||||
|
|
||||||
bool FindJavaByRegistryKey(HKEY rootKey, LPCWSTR subKey, std::wstring& path) {
|
|
||||||
WCHAR javaVer[MAX_KEY_LENGTH]; // buffer for subkey name, special for
|
|
||||||
// JavaVersion
|
|
||||||
DWORD cbName; // size of name string
|
|
||||||
DWORD cSubKeys = 0; // number of subkeys
|
|
||||||
DWORD cbMaxSubKey; // longest subkey size
|
|
||||||
DWORD cValues; // number of values for key
|
|
||||||
DWORD cchMaxValue; // longest value name
|
|
||||||
DWORD cbMaxValueData; // longest value data
|
|
||||||
LSTATUS result;
|
|
||||||
|
|
||||||
HKEY hKey;
|
|
||||||
if (ERROR_SUCCESS !=
|
|
||||||
(result =
|
|
||||||
RegOpenKeyEx(rootKey, subKey, 0, KEY_WOW64_64KEY | KEY_READ, &hKey)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RegQueryInfoKey(hKey, // key handle
|
|
||||||
NULL, // buffer for class name
|
|
||||||
NULL, // size of class string
|
|
||||||
NULL, // reserved
|
|
||||||
&cSubKeys, // number of subkeys
|
|
||||||
&cbMaxSubKey, // longest subkey size
|
|
||||||
NULL, // longest class string
|
|
||||||
&cValues, // number of values for this key
|
|
||||||
&cchMaxValue, // longest value name
|
|
||||||
&cbMaxValueData, // longest value data
|
|
||||||
NULL, // security descriptor
|
|
||||||
NULL); // last write time
|
|
||||||
|
|
||||||
if (!cSubKeys) return false;
|
|
||||||
|
|
||||||
bool flag = false;
|
|
||||||
for (DWORD i = 0; i < cSubKeys; ++i) {
|
|
||||||
cbName = MAX_KEY_LENGTH;
|
|
||||||
if (ERROR_SUCCESS != (result = RegEnumKeyEx(hKey, i, javaVer, &cbName, NULL,
|
|
||||||
NULL, NULL, NULL)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
HKEY javaKey;
|
|
||||||
if (ERROR_SUCCESS != RegOpenKeyEx(hKey, javaVer, 0, KEY_READ, &javaKey))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ERROR_SUCCESS == MyRegQueryValue(javaKey, L"JavaHome", REG_SZ, path)) {
|
|
||||||
if (Version(javaVer) < JAVA_8)
|
|
||||||
oldJavaFound = true;
|
|
||||||
else
|
|
||||||
flag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
|
|
||||||
return flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FindJavaInRegistry(std::wstring& path) {
|
|
||||||
return FindJavaByRegistryKey(HKEY_LOCAL_MACHINE, JDK_NEW, path) ||
|
|
||||||
FindJavaByRegistryKey(HKEY_LOCAL_MACHINE, JRE_NEW, path) ||
|
|
||||||
FindJavaByRegistryKey(HKEY_LOCAL_MACHINE, JDK_OLD, path) ||
|
|
||||||
FindJavaByRegistryKey(HKEY_LOCAL_MACHINE, JRE_OLD, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FindJava(std::wstring& path) {
|
|
||||||
return ERROR_SUCCESS == MyGetEnvironmentVariable(L"HMCL_JAVA_HOME", path) ||
|
|
||||||
ERROR_SUCCESS == MyGetEnvironmentVariable(L"JAVA_HOME", path) ||
|
|
||||||
FindJavaInRegistry(path);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <windows.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// Find Java installation in system registry
|
|
||||||
bool FindJavaInRegistry(std::wstring &path);
|
|
||||||
|
|
||||||
// Find Java Installation in registry and environment variable
|
|
||||||
bool FindJava(std::wstring &path);
|
|
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define ERROR_TITLE L"Java not found"
|
|
||||||
|
|
||||||
#define ERROR_TITLE_ZH L"未找到 Java"
|
|
||||||
|
|
||||||
#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."
|
|
||||||
|
|
||||||
#define ERROR_PROMPT_ZH L"运行 HMCL 以及 Minecraft 需要 Java 运行时环境,点击“确定”开始下载。\n"\
|
|
||||||
L"请在安装 Java 完成后重新启动 HMCL。"
|
|
@ -1,155 +0,0 @@
|
|||||||
#include "stdafx.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "java.h"
|
|
||||||
#include "lang.h"
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
Version J8(TEXT("8"));
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
|
||||||
__declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPCWSTR VENDOR_DIRS[] = {
|
|
||||||
L"Java", L"Microsoft", L"BellSoft", L"Zulu", L"Eclipse Foundation", L"AdoptOpenJDK", L"Semeru"
|
|
||||||
};
|
|
||||||
|
|
||||||
void RawLaunchJVM(const std::wstring &javaPath, const std::wstring &workdir,
|
|
||||||
const std::wstring &jarPath, const std::wstring &jvmOptions) {
|
|
||||||
if (MyCreateProcess(L"\"" + javaPath + L"\" " + jvmOptions + L" -jar \"" + jarPath + L"\"", workdir))
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LaunchJVM(const std::wstring &javaPath, const std::wstring &workdir,
|
|
||||||
const std::wstring &jarPath, const std::wstring &jvmOptions) {
|
|
||||||
Version javaVersion(L"");
|
|
||||||
if (!MyGetFileVersionInfo(javaPath, javaVersion)) return;
|
|
||||||
|
|
||||||
if (J8 <= javaVersion) {
|
|
||||||
RawLaunchJVM(javaPath, workdir, jarPath, jvmOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindJavaInDirAndLaunchJVM(const std::wstring &baseDir, const std::wstring &workdir,
|
|
||||||
const std::wstring &jarPath, const std::wstring &jvmOptions) {
|
|
||||||
std::wstring pattern = baseDir + L"*";
|
|
||||||
|
|
||||||
WIN32_FIND_DATA data;
|
|
||||||
HANDLE hFind = FindFirstFile(pattern.c_str(), &data); // Search all subdirectory
|
|
||||||
|
|
||||||
if (hFind != INVALID_HANDLE_VALUE) {
|
|
||||||
do {
|
|
||||||
std::wstring javaw = baseDir + data.cFileName + std::wstring(L"\\bin\\javaw.exe");
|
|
||||||
if (FindFirstFileExists(javaw.c_str(), 0)) {
|
|
||||||
LaunchJVM(javaw, workdir, jarPath, jvmOptions);
|
|
||||||
}
|
|
||||||
} while (FindNextFile(hFind, &data));
|
|
||||||
FindClose(hFind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenHelpPage() {
|
|
||||||
ShellExecute(0, 0, L"https://docs.hmcl.net/help.html", 0, 0, SW_SHOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
||||||
LPWSTR lpCmdLine, int nCmdShow) {
|
|
||||||
std::wstring path, exeName, jvmOptions;
|
|
||||||
|
|
||||||
// Since Jar file is appended to this executable, we should first get the
|
|
||||||
// location of JAR file.
|
|
||||||
if (ERROR_SUCCESS != MyGetModuleFileName(NULL, exeName)) return 1;
|
|
||||||
|
|
||||||
std::wstring workdir;
|
|
||||||
size_t last_slash = exeName.find_last_of(L"/\\");
|
|
||||||
if (last_slash != std::wstring::npos && last_slash + 1 < exeName.size()) {
|
|
||||||
workdir = exeName.substr(0, last_slash);
|
|
||||||
exeName = exeName.substr(last_slash + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ERROR_SUCCESS != MyGetEnvironmentVariable(L"HMCL_JAVA_OPTS", jvmOptions)) {
|
|
||||||
jvmOptions = L"-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=15"; // Default Options
|
|
||||||
}
|
|
||||||
|
|
||||||
bool useChinese = GetUserDefaultUILanguage() == 2052; // zh-CN
|
|
||||||
|
|
||||||
MyArchitecture architecture = MyGetArchitecture();
|
|
||||||
|
|
||||||
// First try the Java packaged together.
|
|
||||||
bool isX64 = architecture == MyArchitecture::X86_64;
|
|
||||||
bool isARM64 = architecture == MyArchitecture::ARM64;
|
|
||||||
|
|
||||||
if (isARM64) {
|
|
||||||
RawLaunchJVM(L"jre-arm64\\bin\\javaw.exe", workdir, exeName, jvmOptions);
|
|
||||||
}
|
|
||||||
if (isX64) {
|
|
||||||
RawLaunchJVM(L"jre-x64\\bin\\javaw.exe", workdir, exeName, jvmOptions);
|
|
||||||
}
|
|
||||||
RawLaunchJVM(L"jre-x86\\bin\\javaw.exe", workdir, exeName, jvmOptions);
|
|
||||||
|
|
||||||
if (FindJava(path)) LaunchJVM(path + L"\\bin\\javaw.exe", workdir, exeName, jvmOptions);
|
|
||||||
|
|
||||||
std::wstring programFiles;
|
|
||||||
|
|
||||||
// Or we try to search Java in C:\Program Files
|
|
||||||
if (!SUCCEEDED(MySHGetFolderPath(CSIDL_PROGRAM_FILES, programFiles))) programFiles = L"C:\\Program Files\\";
|
|
||||||
for (LPCWSTR vendorDir : VENDOR_DIRS) {
|
|
||||||
std::wstring dir = programFiles;
|
|
||||||
MyPathAppend(dir, vendorDir);
|
|
||||||
MyPathAddBackslash(dir);
|
|
||||||
|
|
||||||
FindJavaInDirAndLaunchJVM(dir, workdir, exeName, jvmOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consider C:\Program Files (x86)
|
|
||||||
if (!SUCCEEDED(MySHGetFolderPath(CSIDL_PROGRAM_FILESX86, programFiles))) programFiles = L"C:\\Program Files (x86)\\";
|
|
||||||
for (LPCWSTR vendorDir : VENDOR_DIRS) {
|
|
||||||
std::wstring dir = programFiles;
|
|
||||||
MyPathAppend(dir, vendorDir);
|
|
||||||
MyPathAddBackslash(dir);
|
|
||||||
|
|
||||||
FindJavaInDirAndLaunchJVM(dir, workdir, exeName, jvmOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try java in PATH
|
|
||||||
RawLaunchJVM(L"javaw", workdir, exeName, jvmOptions);
|
|
||||||
|
|
||||||
std::wstring hmclJavaDir;
|
|
||||||
{
|
|
||||||
std::wstring buffer;
|
|
||||||
if (SUCCEEDED(MySHGetFolderPath(CSIDL_APPDATA, buffer)) || SUCCEEDED(MySHGetFolderPath(CSIDL_PROFILE, buffer))) {
|
|
||||||
MyPathAppend(buffer, L".hmcl");
|
|
||||||
MyPathAppend(buffer, L"java");
|
|
||||||
if (isARM64) {
|
|
||||||
MyPathAppend(buffer, L"windows-arm64");
|
|
||||||
} else if (isX64) {
|
|
||||||
MyPathAppend(buffer, L"windows-x86_64");
|
|
||||||
} else {
|
|
||||||
MyPathAppend(buffer, L"windows-x86");
|
|
||||||
}
|
|
||||||
MyPathAddBackslash(buffer);
|
|
||||||
hmclJavaDir = buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hmclJavaDir.empty()) {
|
|
||||||
FindJavaInDirAndLaunchJVM(hmclJavaDir, workdir, exeName, jvmOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
LPCWSTR downloadLink;
|
|
||||||
|
|
||||||
if (isARM64) {
|
|
||||||
downloadLink = L"https://docs.hmcl.net/downloads/windows/arm64.html";
|
|
||||||
} 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";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IDOK == MessageBox(NULL, useChinese ? ERROR_PROMPT_ZH : ERROR_PROMPT, useChinese ? ERROR_TITLE_ZH : ERROR_TITLE, MB_ICONWARNING | MB_OKCANCEL)) {
|
|
||||||
ShellExecute(0, 0, downloadLink, 0, 0, SW_SHOW);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "resource.h"
|
|
@ -1,203 +0,0 @@
|
|||||||
#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;
|
|
||||||
LSTATUS ret = RegQueryValueEx(hKey, subKey, 0, &dwType, NULL, &dwSize);
|
|
||||||
if (ret != ERROR_SUCCESS) return ret;
|
|
||||||
WCHAR *buffer = new WCHAR[dwSize];
|
|
||||||
ret = RegQueryValueEx(hKey, subKey, 0, &dwType, (LPBYTE)buffer, &dwSize);
|
|
||||||
if (ret != ERROR_SUCCESS) return ret;
|
|
||||||
out = buffer;
|
|
||||||
delete[] buffer;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
LSTATUS MyGetModuleFileName(HMODULE hModule, std::wstring &out) {
|
|
||||||
DWORD res, size = MAX_PATH;
|
|
||||||
out = std::wstring();
|
|
||||||
out.resize(size);
|
|
||||||
while ((res = GetModuleFileName(hModule, &out[0], size)) == size) {
|
|
||||||
out.resize(size += MAX_PATH);
|
|
||||||
}
|
|
||||||
if (res == 0)
|
|
||||||
return GetLastError();
|
|
||||||
else {
|
|
||||||
out.resize(size - MAX_PATH + res);
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LSTATUS MyGetEnvironmentVariable(LPCWSTR name, std::wstring &out) {
|
|
||||||
DWORD res, size = MAX_PATH;
|
|
||||||
out = std::wstring();
|
|
||||||
out.resize(size);
|
|
||||||
while ((res = GetEnvironmentVariable(name, &out[0], size)) == size) {
|
|
||||||
out.resize(size += MAX_PATH);
|
|
||||||
}
|
|
||||||
if (res == 0)
|
|
||||||
return GetLastError();
|
|
||||||
else {
|
|
||||||
out.resize(size - MAX_PATH + res);
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MyCreateProcess(const std::wstring &command, const std::wstring &workdir) {
|
|
||||||
std::wstring writable_command = command;
|
|
||||||
STARTUPINFO si;
|
|
||||||
PROCESS_INFORMATION pi;
|
|
||||||
si.cb = sizeof(si);
|
|
||||||
ZeroMemory(&si, sizeof(si));
|
|
||||||
ZeroMemory(&pi, sizeof(pi));
|
|
||||||
|
|
||||||
if (workdir.empty()) {
|
|
||||||
return CreateProcess(NULL, &writable_command[0], NULL, NULL, false,
|
|
||||||
NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
|
|
||||||
} else {
|
|
||||||
return CreateProcess(NULL, &writable_command[0], NULL, NULL, false,
|
|
||||||
NORMAL_PRIORITY_CLASS, NULL, workdir.c_str(), &si,
|
|
||||||
&pi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FindFirstFileExists(LPCWSTR lpPath, DWORD dwFilter) {
|
|
||||||
WIN32_FIND_DATA fd;
|
|
||||||
HANDLE hFind = FindFirstFile(lpPath, &fd);
|
|
||||||
bool bFilter = (false == dwFilter) ? true : fd.dwFileAttributes & dwFilter;
|
|
||||||
bool ret = ((hFind != INVALID_HANDLE_VALUE) && bFilter) ? true : false;
|
|
||||||
FindClose(hFind);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MyGetFileVersionInfo(const std::wstring &filePath, Version &version) {
|
|
||||||
DWORD verHandle = 0;
|
|
||||||
UINT size = 0;
|
|
||||||
LPBYTE lpBuffer = NULL;
|
|
||||||
VS_FIXEDFILEINFO *pFileInfo;
|
|
||||||
DWORD dwSize = GetFileVersionInfoSize(filePath.c_str(), NULL);
|
|
||||||
|
|
||||||
if (!dwSize) return false;
|
|
||||||
|
|
||||||
LPBYTE data = new BYTE[dwSize];
|
|
||||||
if (!GetFileVersionInfo(filePath.c_str(), 0, dwSize, data)) {
|
|
||||||
delete[] data;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!VerQueryValue(data, TEXT("\\"), (LPVOID *)&pFileInfo, &size)) {
|
|
||||||
delete[] data;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
version = Version{(pFileInfo->dwFileVersionMS >> 16) & 0xFFFF,
|
|
||||||
(pFileInfo->dwFileVersionMS >> 0) & 0xFFFF,
|
|
||||||
(pFileInfo->dwFileVersionLS >> 16) & 0xFFFF,
|
|
||||||
(pFileInfo->dwFileVersionLS >> 0) & 0xFFFF};
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT MySHGetFolderPath(int csidl, std::wstring &out) {
|
|
||||||
out = std::wstring();
|
|
||||||
out.resize(MAX_PATH);
|
|
||||||
|
|
||||||
HRESULT res = SHGetFolderPath(NULL, csidl, NULL, 0, &out[0]);
|
|
||||||
if (SUCCEEDED(res)) {
|
|
||||||
out.resize(wcslen(&out[0]));
|
|
||||||
} else {
|
|
||||||
out.resize(0);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyPathAppend(std::wstring &filePath, const std::wstring &more) {
|
|
||||||
if (filePath.back() != L'\\') {
|
|
||||||
filePath += L'\\';
|
|
||||||
}
|
|
||||||
|
|
||||||
filePath += more;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyPathAddBackslash(std::wstring &filePath) {
|
|
||||||
if (filePath.back() != L'\\') {
|
|
||||||
filePath += L'\\';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LSTATUS MyGetTempFile(const std::wstring &prefixString, const std::wstring &ext, std::wstring &out) {
|
|
||||||
out.resize(MAX_PATH);
|
|
||||||
DWORD res = GetTempPath(MAX_PATH, &out[0]);
|
|
||||||
if (res == 0) {
|
|
||||||
return GetLastError();
|
|
||||||
}
|
|
||||||
|
|
||||||
out.resize(res);
|
|
||||||
|
|
||||||
GUID guid;
|
|
||||||
CoCreateGuid(&guid);
|
|
||||||
|
|
||||||
WCHAR buffer[MAX_PATH];
|
|
||||||
int n = StringFromGUID2(guid, buffer, MAX_PATH);
|
|
||||||
if (n == 0) {
|
|
||||||
return CO_E_PATHTOOLONG;
|
|
||||||
}
|
|
||||||
|
|
||||||
MyPathAddBackslash(out);
|
|
||||||
out += prefixString;
|
|
||||||
out += buffer;
|
|
||||||
out += L'.';
|
|
||||||
out += ext;
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAppendPathToCommandLine(std::wstring &commandLine, const std::wstring &path) {
|
|
||||||
commandLine += L'"';
|
|
||||||
for (size_t i = 0; i < path.size(); i++) {
|
|
||||||
WCHAR ch = path[i];
|
|
||||||
if (ch == L'\\' && (i + 1 == path.size() || path[i + 1] == L'"')) {
|
|
||||||
commandLine += L"\\\\";
|
|
||||||
} else if (ch == L'"') {
|
|
||||||
commandLine += L"\\\"";
|
|
||||||
} else {
|
|
||||||
commandLine += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
commandLine += L'"';
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <string>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <shlobj.h>
|
|
||||||
#include <Objbase.h>
|
|
||||||
#include "Version.h"
|
|
||||||
|
|
||||||
const int MAX_KEY_LENGTH = 255;
|
|
||||||
const int MAX_VALUE_NAME = 16383;
|
|
||||||
|
|
||||||
enum MyArchitecture {
|
|
||||||
X86,
|
|
||||||
X86_64,
|
|
||||||
ARM64
|
|
||||||
};
|
|
||||||
|
|
||||||
MyArchitecture MyGetArchitecture();
|
|
||||||
|
|
||||||
// Query registry value of class root hKey, key path subKey, stores result in
|
|
||||||
// parameter out.
|
|
||||||
LSTATUS MyRegQueryValue(HKEY hKey, LPCWSTR subKey, DWORD dwType,
|
|
||||||
std::wstring &out);
|
|
||||||
|
|
||||||
// Get module file name, stores result in parameter out.
|
|
||||||
LSTATUS MyGetModuleFileName(HMODULE hModule, std::wstring &out);
|
|
||||||
|
|
||||||
// Get environment variable by name, C++ style, stores the value in parameter
|
|
||||||
// out.
|
|
||||||
LSTATUS MyGetEnvironmentVariable(LPCWSTR name, std::wstring &out);
|
|
||||||
|
|
||||||
// Create process by invoking CreateProcess, only pass command.
|
|
||||||
bool MyCreateProcess(const std::wstring &command, const std::wstring &workdir);
|
|
||||||
|
|
||||||
// Check if file lpPath exists.
|
|
||||||
bool FindFirstFileExists(LPCWSTR lpPath, DWORD dwFilter);
|
|
||||||
|
|
||||||
bool MyGetFileVersionInfo(const std::wstring &filePath, Version &version);
|
|
||||||
|
|
||||||
HRESULT MySHGetFolderPath(int csidl, std::wstring &out);
|
|
||||||
|
|
||||||
void MyPathAppend(std::wstring &filePath, const std::wstring &more);
|
|
||||||
|
|
||||||
void MyPathAddBackslash(std::wstring &filePath);
|
|
||||||
|
|
||||||
LSTATUS MyGetTempFile(const std::wstring &prefixString, const std::wstring &ext, std::wstring &out);
|
|
||||||
|
|
||||||
void MyAppendPathToCommandLine(std::wstring &commandLine, const std::wstring &path);
|
|
@ -1,25 +0,0 @@
|
|||||||
//{{NO_DEPENDENCIES}}
|
|
||||||
// Microsoft Visual C++ 生成的包含文件。
|
|
||||||
// 供 HMCL.rc 使用
|
|
||||||
//
|
|
||||||
#define IDC_MYICON 2
|
|
||||||
#define IDD_HMCL_DIALOG 102
|
|
||||||
#define IDS_APP_TITLE 103
|
|
||||||
#define IDM_ABOUT 104
|
|
||||||
#define IDI_HMCL 107
|
|
||||||
#define IDC_HMCL 109
|
|
||||||
#define IDR_MAINFRAME 128
|
|
||||||
#define ID_SCRIPT_DOWNLOAD_JAVA 160
|
|
||||||
#define IDC_STATIC -1
|
|
||||||
|
|
||||||
// Next default values for new objects
|
|
||||||
//
|
|
||||||
#ifdef APSTUDIO_INVOKED
|
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
|
||||||
#define _APS_NO_MFC 1
|
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 129
|
|
||||||
#define _APS_NEXT_COMMAND_VALUE 32771
|
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
|
||||||
#define _APS_NEXT_SYMED_VALUE 110
|
|
||||||
#endif
|
|
||||||
#endif
|
|
@ -1,8 +0,0 @@
|
|||||||
// stdafx.cpp : 只包括标准包含文件的源文件
|
|
||||||
// HMCL.pch 将作为预编译标头
|
|
||||||
// stdafx.obj 将包含预编译类型信息
|
|
||||||
|
|
||||||
#include "stdafx.h"
|
|
||||||
|
|
||||||
// TODO: 在 STDAFX.H 中引用任何所需的附加头文件,
|
|
||||||
//而不是在此文件中引用
|
|
@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "targetver.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string>
|
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// Windows 7
|
|
||||||
|
|
||||||
#define WINVER 0x0601
|
|
||||||
#define _WIN32_WINNT 0x0601
|
|
||||||
|
|
||||||
#include <SDKDDKVer.h>
|
|
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio 15
|
|
||||||
VisualStudioVersion = 15.0.27428.2005
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HMCL", "HMCL\HMCL.vcxproj", "{672B1019-E741-4C0D-A986-627E2ACE157B}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|x86 = Debug|x86
|
|
||||||
Release|x86 = Release|x86
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{672B1019-E741-4C0D-A986-627E2ACE157B}.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{672B1019-E741-4C0D-A986-627E2ACE157B}.Debug|x86.Build.0 = Debug|Win32
|
|
||||||
{672B1019-E741-4C0D-A986-627E2ACE157B}.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{672B1019-E741-4C0D-A986-627E2ACE157B}.Release|x86.Build.0 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {FE40055B-673D-42F5-8AE4-6DF2C87EB659}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
Loading…
x
Reference in New Issue
Block a user