Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d70712a18f | ||
|
|
05c5b53c52 | ||
|
|
e98c7dfef1 | ||
|
|
8ba0e16dd9 | ||
|
|
77397f6722 | ||
|
|
c9ba789b7c | ||
|
|
91135b961e | ||
|
|
435790aa03 | ||
|
|
c252d7027e | ||
|
|
9d0c8da310 |
No files matched your search
@@ -9,12 +9,12 @@ body:
|
||||
请确认 Issues 列表无重复的项目。
|
||||
Please make sure that no duplicate issues have already been submitted.
|
||||
- type: textarea
|
||||
id: description
|
||||
id: summary
|
||||
attributes:
|
||||
label: 描述 | Description
|
||||
label: 概述 | Summary
|
||||
description: |
|
||||
请详细描述你想加入的新功能。
|
||||
Please describe the new feature in detail.
|
||||
请介绍你想加入的新功能。
|
||||
Please describe the new feature.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
@@ -26,3 +26,10 @@ body:
|
||||
Please describe why you want to add the feature or enhancement to HMCL.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: 详情 | Description
|
||||
description: |
|
||||
在这里可以补充描述该功能的具体实现方式或建议。(可选)
|
||||
Describe implementation details or suggestions here. (Optional)
|
||||
@@ -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
|
||||
@@ -5,7 +5,6 @@ on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'HMCLauncher/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -42,7 +42,6 @@ minecraft-exported-crash-info*
|
||||
.nb-gradle
|
||||
|
||||
*.exe
|
||||
!/HMCL/src/main/resources/assets/HMCLauncher.exe
|
||||
|
||||
# macos
|
||||
.DS_Store
|
||||
|
||||
+41
-18
@@ -33,12 +33,18 @@ val microsoftAuthId = System.getenv("MICROSOFT_AUTH_ID") ?: ""
|
||||
val microsoftAuthSecret = System.getenv("MICROSOFT_AUTH_SECRET") ?: ""
|
||||
val curseForgeApiKey = System.getenv("CURSEFORGE_API_KEY") ?: ""
|
||||
|
||||
val launcherExe = System.getenv("HMCL_LAUNCHER_EXE")
|
||||
|
||||
version = "$versionRoot.$buildNumber"
|
||||
|
||||
dependencies {
|
||||
implementation(project(":HMCLCore"))
|
||||
implementation("libs:JFoenix")
|
||||
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)
|
||||
@@ -106,7 +112,7 @@ tasks.jar {
|
||||
|
||||
val jarPath = tasks.jar.get().archiveFile.get().asFile
|
||||
|
||||
tasks.getByName<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
|
||||
tasks.shadowJar {
|
||||
archiveClassifier.set(null as String?)
|
||||
|
||||
exclude("**/package-info.class")
|
||||
@@ -154,23 +160,18 @@ tasks.getByName<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("sha
|
||||
}
|
||||
}
|
||||
|
||||
if (launcherExe != null) {
|
||||
into("assets") {
|
||||
from(file(launcherExe))
|
||||
}
|
||||
}
|
||||
|
||||
doLast {
|
||||
attachSignature(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 {
|
||||
into("META-INF/versions/11") {
|
||||
from(sourceSets["java11"].output)
|
||||
@@ -178,11 +179,31 @@ tasks.processResources {
|
||||
dependsOn(tasks["java11Classes"])
|
||||
}
|
||||
|
||||
val makeExecutables = tasks.create("makeExecutables") {
|
||||
val makeExecutables by tasks.registering {
|
||||
val extensions = listOf("exe", "sh")
|
||||
|
||||
dependsOn(tasks.jar)
|
||||
|
||||
inputs.file(jarPath)
|
||||
outputs.files(extensions.map { File(jarPath.parentFile, jarPath.nameWithoutExtension + '.' + it) })
|
||||
|
||||
doLast {
|
||||
createExecutable("exe", "src/main/resources/assets/HMCLauncher.exe")
|
||||
createExecutable("sh", "src/main/resources/assets/HMCLauncher.sh")
|
||||
val jarContent = jarPath.readBytes()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +261,7 @@ fun parseToolOptions(options: String?): MutableList<String> {
|
||||
return result
|
||||
}
|
||||
|
||||
tasks.create<JavaExec>("run") {
|
||||
tasks.register<JavaExec>("run") {
|
||||
dependsOn(tasks.jar)
|
||||
|
||||
group = "application"
|
||||
@@ -256,8 +277,10 @@ tasks.create<JavaExec>("run") {
|
||||
|
||||
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"))
|
||||
this.executable(
|
||||
file(hmclJavaHome).resolve("bin")
|
||||
.resolve(if (System.getProperty("os.name").lowercase().startsWith("windows")) "java.exe" else "java")
|
||||
)
|
||||
}
|
||||
|
||||
doFirst {
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
import org.jackhuang.hmcl.util.logging.Logger;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.Zipper;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
@@ -93,9 +94,8 @@ public final class LogExporter {
|
||||
if (Files.isRegularFile(file)) {
|
||||
FileTime time = Files.readAttributes(file, BasicFileAttributes.class).lastModifiedTime();
|
||||
if (time.toMillis() >= processStartTime) {
|
||||
try {
|
||||
String crashLog = Logger.filterForbiddenToken(FileUtils.readText(file, OperatingSystem.NATIVE_CHARSET));
|
||||
zipper.putTextFile(crashLog, file.getFileName().toString());
|
||||
try (BufferedReader reader = IOUtils.newBufferedReaderMaybeNativeEncoding(file)) {
|
||||
zipper.putLines(reader.lines().map(Logger::filterForbiddenToken), file.getFileName().toString());
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to read log file: " + file, e);
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ public class GameCrashWindow extends Stage {
|
||||
|
||||
String log;
|
||||
try {
|
||||
log = FileUtils.readText(latestLog);
|
||||
log = FileUtils.readTextMaybeNativeEncoding(latestLog);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to read logs/latest.log", e);
|
||||
return pair(new HashSet<CrashReportAnalyzer.Result>(), new HashSet<String>());
|
||||
|
||||
@@ -362,7 +362,9 @@ public class InstallerItem extends Control {
|
||||
}
|
||||
return i18n("install.installer.version", s.version);
|
||||
} else if (state instanceof InstallableState) {
|
||||
return i18n("install.installer.not_installed");
|
||||
return control.style == Style.CARD
|
||||
? i18n("install.installer.do_not_install")
|
||||
: i18n("install.installer.not_installed");
|
||||
} else if (state instanceof IncompatibleState) {
|
||||
return i18n("install.installer.incompatible", i18n("install.installer." + ((IncompatibleState) state).incompatibleItemName));
|
||||
} else {
|
||||
|
||||
@@ -19,6 +19,9 @@ package org.jackhuang.hmcl.ui.account;
|
||||
|
||||
import com.jfoenix.controls.*;
|
||||
import com.jfoenix.validation.base.ValidatorBase;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.NamedArg;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
@@ -36,6 +39,7 @@ import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextInputControl;
|
||||
import javafx.scene.layout.*;
|
||||
|
||||
import javafx.util.Duration;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.auth.AccountFactory;
|
||||
import org.jackhuang.hmcl.auth.CharacterSelector;
|
||||
@@ -264,16 +268,33 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
|
||||
};
|
||||
|
||||
if (factory instanceof OfflineAccountFactory && username != null && !USERNAME_CHECKER_PATTERN.matcher(username).matches()) {
|
||||
Controllers.confirm(
|
||||
JFXButton btnYes = new JFXButton(i18n("button.ok"));
|
||||
btnYes.getStyleClass().add("dialog-error");
|
||||
btnYes.setOnAction(e -> doCreate.run());
|
||||
btnYes.setDisable(true);
|
||||
|
||||
int countdown = 10;
|
||||
KeyFrame[] keyFrames = new KeyFrame[countdown + 1];
|
||||
for (int i = 0; i < countdown; i++) {
|
||||
keyFrames[i] = new KeyFrame(Duration.seconds(i),
|
||||
new KeyValue(btnYes.textProperty(), i18n("button.ok.countdown", countdown - i)));
|
||||
}
|
||||
keyFrames[countdown] = new KeyFrame(Duration.seconds(countdown),
|
||||
new KeyValue(btnYes.textProperty(), i18n("button.ok")),
|
||||
new KeyValue(btnYes.disableProperty(), false));
|
||||
|
||||
Timeline timeline = new Timeline(keyFrames);
|
||||
Controllers.confirmAction(
|
||||
i18n("account.methods.offline.name.invalid"), i18n("message.warning"),
|
||||
MessageDialogPane.MessageType.WARNING,
|
||||
doCreate,
|
||||
btnYes,
|
||||
() -> {
|
||||
lblErrorMessage.setText(i18n("account.methods.offline.name.invalid.tip"));
|
||||
timeline.stop();
|
||||
body.setDisable(false);
|
||||
spinner.hideSpinner();
|
||||
}
|
||||
);
|
||||
timeline.play();
|
||||
} else {
|
||||
doCreate.run();
|
||||
}
|
||||
|
||||
@@ -26,12 +26,15 @@ import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.StackPane;
|
||||
@@ -254,6 +257,15 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
FXUtils.installFastTooltip(menuButton, i18n("version.switch"));
|
||||
menuButton.setGraphic(graphic);
|
||||
|
||||
EventHandler<MouseEvent> secondaryClickHandle = event -> {
|
||||
if (event.getButton() == MouseButton.SECONDARY && event.getClickCount() == 1) {
|
||||
menuButton.fire();
|
||||
event.consume();
|
||||
}
|
||||
};
|
||||
launchButton.addEventHandler(MouseEvent.MOUSE_CLICKED, secondaryClickHandle);
|
||||
menuButton.addEventHandler(MouseEvent.MOUSE_CLICKED, secondaryClickHandle);
|
||||
|
||||
launchPane.getChildren().setAll(launchButton, separator, menuButton);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -124,13 +124,12 @@ account.methods.microsoft.snapshot=You are using an unofficial build of HMCL. Pl
|
||||
account.methods.microsoft.snapshot.website=Official Website
|
||||
account.methods.offline=Offline
|
||||
account.methods.offline.name.special_characters=Using only English letters, numbers, and underscores is recommended
|
||||
account.methods.offline.name.invalid.tip=It is recommended to use only English letters, numbers and underscores for the username, and the length should not exceed 16 characters.
|
||||
account.methods.offline.name.invalid=It is recommended to use only English letters, numbers and underscores for the username, and the length should not exceed 16 characters.\n\
|
||||
\n\
|
||||
\ · Legitimate: HuangYu, huang_Yu, Huang_Yu_123;\n\
|
||||
\ · Illegal: Huang Yu, Huang-Yu_%%%, Huang_Yu_hello_world_hello_world.\n\
|
||||
\n\
|
||||
If you believe there is a corresponding mod or plugin on the server side to remove this restriction, you can ignore this warning.
|
||||
Using the illegal username will prevent you from joining most servers and may conflict with some mods, causing the game to crash.
|
||||
account.methods.offline.uuid=UUID
|
||||
account.methods.offline.uuid.hint=UUID is a unique identifier for Minecraft players, and each launcher may generate UUIDs differently. Changing it to the one generated by other launchers allows you to keep your items in your offline account inventory.\n\
|
||||
\n\
|
||||
@@ -181,6 +180,7 @@ button.install=Install
|
||||
button.export=Export
|
||||
button.no=No
|
||||
button.ok=OK
|
||||
button.ok.countdown=OK (%d)
|
||||
button.refresh=Refresh
|
||||
button.remove=Remove
|
||||
button.remove.confirm=Are you sure you want to permanently remove it? This action cannot be undone!
|
||||
@@ -681,6 +681,7 @@ install.failed.version_mismatch=This loader requires the game version %s, but th
|
||||
install.installer.change_version=%s Incompatible
|
||||
install.installer.choose=Choose Your %s Version
|
||||
install.installer.depend=Requires %s
|
||||
install.installer.do_not_install=Do not install
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.fabric-api=Fabric API
|
||||
install.installer.fabric-api.warning=Warning: Fabric API is a mod and will be installed into the mod directory of the game instance. Please do not change the working directory of the game, or the Fabric API will not function. If you do want to change the directory, you should reinstall it.
|
||||
@@ -695,7 +696,7 @@ install.installer.install_offline.tooltip=We support using the local (Neo)Forge/
|
||||
install.installer.install_online=Online Install
|
||||
install.installer.install_online.tooltip=We currently support Forge, NeoForge, OptiFine, Fabric, Quilt, and LiteLoader.
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=Do not install
|
||||
install.installer.not_installed=Not installed
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.quilt=Quilt
|
||||
install.installer.quilt-api=QSL/QFAPI
|
||||
|
||||
@@ -88,6 +88,7 @@ account.login.skip=Iniciar sesión sin conexión
|
||||
account.login.retry=Reintentar
|
||||
account.login.refresh=Iniciar sesión de nuevo
|
||||
account.login.refresh.microsoft.hint=Debe volver a iniciar sesión en su cuenta Microsoft porque la autorización de la cuenta no es válida.
|
||||
account.login.restricted=Iniciar sesión en su cuenta Microsoft para activar esta función
|
||||
account.logout=Salir
|
||||
account.register=Registrarse
|
||||
account.manage=Lista de cuentas
|
||||
@@ -684,6 +685,7 @@ install.failed.version_mismatch=Este cargador requiere la versión del juego %s,
|
||||
install.installer.change_version=%s Incompatible
|
||||
install.installer.choose=Elija su versión %s
|
||||
install.installer.depend=Requiere %s
|
||||
install.installer.do_not_install=No instalar
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.fabric-api=Fabric API
|
||||
install.installer.fabric-api.warning=Atención: Fabric API es un mod, y se instalará en el directorio de mods de la instancia del juego. Por favor, no cambies el directorio de trabajo del juego, o el Fabric API no funcionará. Si quieres cambiar esta configuración, debes reinstalarlo.
|
||||
@@ -698,7 +700,7 @@ install.installer.install_offline.tooltip=Apoyamos el uso del instalador local d
|
||||
install.installer.install_online=Instalación en línea
|
||||
install.installer.install_online.tooltip=Actualmente soportamos Forge, NeoForge, OptiFine, Fabric, Quilt y LiteLoader.
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=No instalar
|
||||
install.installer.not_installed=No está instalado
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.quilt=Quilt
|
||||
install.installer.quilt-api=QSL/QFAPI
|
||||
|
||||
@@ -91,6 +91,7 @@ account.login.skip=Войти в режиме офлайн
|
||||
account.login.retry=Повторить снова
|
||||
account.login.refresh=Войти снова
|
||||
account.login.refresh.microsoft.hint=Вам необходимо снова войти в аккаунт Microsoft, поскольку авторизация аккаунта недействительна.
|
||||
account.login.restricted=Войти в свою аккаунт Microsoft, чтобы включить эту функцию
|
||||
account.logout=Выйти
|
||||
account.register=Зарегестрироваться
|
||||
account.manage=Список аккаунтов
|
||||
@@ -680,6 +681,7 @@ install.failed.version_mismatch=Этот загрузчик требует ве
|
||||
install.installer.change_version=%s (Несовместимо)
|
||||
install.installer.choose=Выберите версию %s
|
||||
install.installer.depend=Требуется %s
|
||||
install.installer.do_not_install=Не устанавливать
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.fabric-api=Fabric API
|
||||
install.installer.fabric-api.warning=Предупреждение: Fabric API является модом и будет установлен в папку mod в сборке игры. Пожалуйста, не меняйте рабочую папку сборки, иначе Fabric API не будет работать. Если вы все же хотите изменить папку, вам следует переустановить сборку.
|
||||
@@ -694,7 +696,7 @@ install.installer.install_offline.tooltip=Поддерживаются уста
|
||||
install.installer.install_online=Установить с интернета
|
||||
install.installer.install_online.tooltip=Поддерживаются Forge, NeoForge, OptiFine, Fabric, Quilt и LiteLoader.
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=Не устанавливать
|
||||
install.installer.not_installed=Не установлено
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.quilt=Quilt
|
||||
install.installer.quilt-api=QSL/QFAPI
|
||||
|
||||
@@ -130,13 +130,12 @@ account.methods.microsoft.snapshot=你正在使用第三方提供的 HMCL,請
|
||||
account.methods.microsoft.snapshot.website=官方網站
|
||||
account.methods.offline=離線模式
|
||||
account.methods.offline.name.special_characters=建議使用英文字母、數字以及底線命名
|
||||
account.methods.offline.name.invalid.tip=遊戲使用者名稱建議僅使用英文字母、數字及底線,且長度不超過 16 個字元。
|
||||
account.methods.offline.name.invalid=遊戲使用者名稱建議僅使用英文字母、數字及底線,且長度不超過 16 個字元。\n\
|
||||
\n\
|
||||
\ · 一些有效的使用者名稱:HuangYu、huang_Yu、Huang_Yu_123;\n\
|
||||
\ · 一些無效的使用者名稱:黃魚,Huang Yu、Huang-Yu_%%%、Huang_Yu_hello_world_hello_world。\n\
|
||||
\n\
|
||||
如果你相信伺服器端有相應的模組或插件來解除此限制,你可以忽略本警告。
|
||||
使用非法使用者名稱會導致你無法加入大部分伺服器,並可能與部分模組衝突而使遊戲崩潰。
|
||||
account.methods.offline.uuid=UUID
|
||||
account.methods.offline.uuid.hint=UUID 是 Minecraft 玩家的唯一標識符,每個啟動器生成 UUID 的方式可能不同。\n透過修改 UUID 選項至原啟動器所生成的 UUID,你可以保證在切換啟動器後,遊戲還能將你的遊戲角色識別為給定 UUID 所對應的角色,從而保留原來角色的背包物品。\nUUID 選項為進階選項,除非你知道你在做什麼,否則你不需要調整該選項。
|
||||
account.methods.offline.uuid.malformed=格式錯誤
|
||||
@@ -184,6 +183,7 @@ button.install=安裝
|
||||
button.export=匯出
|
||||
button.no=否
|
||||
button.ok=確定
|
||||
button.ok.countdown=確定 (%d)
|
||||
button.refresh=重新整理
|
||||
button.remove=刪除
|
||||
button.remove.confirm=你確認要刪除嗎?該操作無法復原!
|
||||
@@ -497,6 +497,7 @@ install.failed.version_mismatch=該載入器需要的遊戲版本為 %s,但實
|
||||
install.installer.change_version=%s 與目前遊戲不相容,請更換版本
|
||||
install.installer.choose=選取 %s 版本
|
||||
install.installer.depend=需要先安裝 %s
|
||||
install.installer.do_not_install=不安裝
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.fabric-api=Fabric API
|
||||
install.installer.fabric-api.warning=警告:Fabric API 是模組,將會被安裝到新遊戲的模組目錄,請你在安裝遊戲後不要修改目前遊戲的「執行路徑」設定,如果你在之後修改了相關設定,則需要重新安裝 Fabric API。
|
||||
@@ -511,7 +512,7 @@ install.installer.install_offline.tooltip=支援匯入已經下載好的 (Neo)Fo
|
||||
install.installer.install_online=線上安裝
|
||||
install.installer.install_online.tooltip=支援安裝 Forge、NeoForge、Fabric、Quilt、LiteLoader 和 OptiFine
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=不安裝
|
||||
install.installer.not_installed=未安裝
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.quilt=Quilt
|
||||
install.installer.quilt-api=QSL/QFAPI
|
||||
|
||||
@@ -138,14 +138,12 @@ account.methods.microsoft.snapshot=你正在使用第三方提供的 HMCL,请
|
||||
account.methods.microsoft.snapshot.website=官方网站
|
||||
account.methods.offline=离线模式
|
||||
account.methods.offline.name.special_characters=建议使用英文字符、数字以及下划线命名
|
||||
account.methods.offline.name.invalid.tip=游戏用户名建议仅使用英文字母、数字及下划线,且长度不超过 16 个字符。
|
||||
account.methods.offline.name.invalid=游戏用户名建议仅使用英文字母、数字及下划线,且长度不超过 16 个字符。\n\
|
||||
\n\
|
||||
\ · 一些合法用户名:HuangYu、huang_Yu、Huang_Yu_123;\n\
|
||||
\ · 一些非法用户名:黄鱼、Huang Yu、Huang-Yu_%%%、Huang_Yu_hello_world_hello_world。\n\
|
||||
\n\
|
||||
如果你相信服务端有相应模组或插件解除此限制,可以忽略本警告。\n\
|
||||
如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||
使用非法用户名会导致你无法加入大部分服务器,并可能与部分模组冲突而使游戏崩溃。
|
||||
account.methods.offline.uuid=UUID
|
||||
account.methods.offline.uuid.hint=UUID 是 Minecraft 玩家的唯一标识符,每个启动器生成 UUID 的方式可能不同。通过将 UUID 修改为原启动器所生成的 UUID,你可以保证在切换启动器后,游戏还能将你的游戏角色识别为给定 UUID 所对应的角色,从而保留原角色的背包物品。UUID 选项为高级选项,除非你知道你在做什么,否则你不需要调整该选项。
|
||||
account.methods.offline.uuid.malformed=格式错误
|
||||
@@ -193,6 +191,7 @@ button.install=安装
|
||||
button.export=导出
|
||||
button.no=否
|
||||
button.ok=确定
|
||||
button.ok.countdown=确定 (%d)
|
||||
button.refresh=刷新
|
||||
button.remove=删除
|
||||
button.remove.confirm=你确定要删除吗?此操作无法撤销!
|
||||
@@ -508,6 +507,7 @@ install.failed.version_mismatch=该组件需要的游戏版本为 %s,但实际
|
||||
install.installer.change_version=%s 与当前游戏不兼容,请更换版本
|
||||
install.installer.choose=选择 %s 版本
|
||||
install.installer.depend=需要先安装 %s
|
||||
install.installer.do_not_install=不安装
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.fabric-api=Fabric API
|
||||
install.installer.fabric-api.warning=警告:Fabric API 是一个模组,将会被安装到新游戏的模组文件夹,请你在安装游戏后不要修改当前游戏的“运行路径”设置,如果你在之后修改了相关设置,则需要重新安装 Fabric API。
|
||||
@@ -522,7 +522,7 @@ install.installer.install_offline.tooltip=支持导入已经下载好的 (Neo)Fo
|
||||
install.installer.install_online=在线安装
|
||||
install.installer.install_online.tooltip=支持安装 Forge、NeoForge、Fabric、Quilt、LiteLoader 和 OptiFine
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=不安装
|
||||
install.installer.not_installed=未安装
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.quilt=Quilt
|
||||
install.installer.quilt-api=QSL/QFAPI
|
||||
|
||||
@@ -16,6 +16,7 @@ dependencies {
|
||||
api("com.github.steveice10:opennbt:1.5")
|
||||
api("org.nanohttpd:nanohttpd:2.3.1")
|
||||
api("org.jsoup:jsoup:1.19.1")
|
||||
api("org.glavo:chardet:2.5.0")
|
||||
compileOnlyApi("org.jetbrains:annotations:26.0.1")
|
||||
|
||||
if (JavaVersion.current().isJava8) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.io;
|
||||
|
||||
import org.glavo.chardet.DetectedCharset;
|
||||
import org.glavo.chardet.UniversalDetector;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
|
||||
@@ -128,6 +130,24 @@ public final class FileUtils {
|
||||
return new String(Files.readAllBytes(file), charset);
|
||||
}
|
||||
|
||||
public static String readTextMaybeNativeEncoding(Path file) throws IOException {
|
||||
byte[] bytes = Files.readAllBytes(file);
|
||||
|
||||
if (OperatingSystem.NATIVE_CHARSET == UTF_8)
|
||||
return new String(bytes, UTF_8);
|
||||
|
||||
UniversalDetector detector = new UniversalDetector();
|
||||
detector.handleData(bytes);
|
||||
detector.dataEnd();
|
||||
|
||||
DetectedCharset detectedCharset = detector.getDetectedCharset();
|
||||
if (detectedCharset != null && detectedCharset.isSupported()
|
||||
&& (detectedCharset == DetectedCharset.UTF_8 || detectedCharset == DetectedCharset.US_ASCII))
|
||||
return new String(bytes, UTF_8);
|
||||
else
|
||||
return new String(bytes, OperatingSystem.NATIVE_CHARSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write plain text to file. Characters are encoded into bytes using UTF-8.
|
||||
* <p>
|
||||
|
||||
@@ -17,10 +17,20 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.io;
|
||||
|
||||
import org.glavo.chardet.DetectedCharset;
|
||||
import org.glavo.chardet.UniversalDetector;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.*;
|
||||
import static org.jackhuang.hmcl.util.platform.OperatingSystem.NATIVE_CHARSET;
|
||||
|
||||
/**
|
||||
* This utility class consists of some util methods operating on InputStream/OutputStream.
|
||||
*
|
||||
@@ -33,6 +43,25 @@ public final class IOUtils {
|
||||
|
||||
public static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
|
||||
|
||||
public static BufferedReader newBufferedReaderMaybeNativeEncoding(Path file) throws IOException {
|
||||
if (NATIVE_CHARSET == UTF_8)
|
||||
return Files.newBufferedReader(file);
|
||||
|
||||
FileChannel channel = FileChannel.open(file);
|
||||
try {
|
||||
long oldPosition = channel.position();
|
||||
DetectedCharset detectedCharset = UniversalDetector.detectCharset(channel);
|
||||
Charset charset = detectedCharset != null && detectedCharset.isSupported()
|
||||
&& (detectedCharset.getCharset() == UTF_8 || detectedCharset.getCharset() == US_ASCII)
|
||||
? UTF_8 : NATIVE_CHARSET;
|
||||
channel.position(oldPosition);
|
||||
return new BufferedReader(new InputStreamReader(Channels.newInputStream(channel), charset));
|
||||
} catch (Throwable e) {
|
||||
closeQuietly(channel, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all bytes to a buffer from given input stream. The stream will not be closed.
|
||||
*
|
||||
|
||||
@@ -19,14 +19,12 @@ package org.jackhuang.hmcl.util.io;
|
||||
|
||||
import org.jackhuang.hmcl.util.function.ExceptionalPredicate;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
@@ -155,6 +153,27 @@ public final class Zipper implements Closeable {
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
public void putLines(Stream<String> lines, String path) throws IOException {
|
||||
zos.putNextEntry(new ZipEntry(normalize(path)));
|
||||
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zos));
|
||||
lines.forEachOrdered(line -> {
|
||||
try {
|
||||
writer.write(line);
|
||||
writer.write('\n');
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
});
|
||||
writer.flush();
|
||||
} catch (UncheckedIOException e) {
|
||||
throw e.getCause();
|
||||
} finally {
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
public void putTextFile(String text, String path) throws IOException {
|
||||
putTextFile(text, StandardCharsets.UTF_8, path);
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Use the Google style in this project.
|
||||
BasedOnStyle: Google
|
||||
|
||||
SortIncludes: false
|
||||
@@ -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: 49 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
|
||||
+1
-1
@@ -55,7 +55,7 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.create("checkTranslations") {
|
||||
tasks.register("checkTranslations") {
|
||||
doLast {
|
||||
val hmclLangDir = file("HMCL/src/main/resources/assets/lang")
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||
networkTimeout=120000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
+2
-2
@@ -76,7 +76,7 @@ if (!jfxInClasspath && JavaVersion.current() >= JavaVersion.VERSION_11) {
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.tasks.create("generateOpenJFXDependencies") {
|
||||
rootProject.tasks.register("generateOpenJFXDependencies") {
|
||||
doLast {
|
||||
val jfxDependencies = jfxPlatforms.associate { platform ->
|
||||
platform.name to jfxModules.map { module ->
|
||||
@@ -99,7 +99,7 @@ rootProject.tasks.create("generateOpenJFXDependencies") {
|
||||
}
|
||||
|
||||
// Ensure that the mirror repository caches files
|
||||
rootProject.tasks.create("preTouchOpenJFXDependencies") {
|
||||
rootProject.tasks.register("preTouchOpenJFXDependencies") {
|
||||
doLast {
|
||||
for (repo in jfxMirrorRepos) {
|
||||
for (platform in jfxPlatforms) {
|
||||
|
||||
Reference in new issue
Block a user