Compare commits

...
Author SHA1 Message Date
Glavo a072fb7bea 改进任务栏图标质量 (#2864)
* 改进任务栏图标质量

* update
2024-02-29 02:03:42 +08:00
Glavo 08a3850dcf Fix #2861: MaintainTask 中不应调用 getGameVersion (#2863)
* Fix #2861: MaintainTask 中不应调用 getGameVersion

* update

* fix checkstyle
2024-02-29 00:06:50 +08:00
Glavo 030fba4630 Fix #2855: tokenize 应支持变量插值 (#2858)
* Fix #2855: tokenize 应支持变量插值

* update

* update

* update

* update

* update
2024-02-27 21:12:51 +08:00
Glavo 559aefd6b6 Fix #2854: 修复 LibraryAnalyzer.analyze 无法获得游戏版本的问题 (#2859)
* Fix #2854: 修复 LibraryAnalyzer.analyze 无法获得游戏版本的问题

* delete debug code

* update
2024-02-27 21:12:35 +08:00
Burning_TNT 2ee5d9ceed Fix #2831. (#2857) 2024-02-27 16:35:00 +08:00
zkitefly 20ed42ab8a 移除残留的 MCBBS 按钮 (#2849)
* remove

* fix
2024-02-25 01:20:42 +08:00
Glavo 815b90845a Fix #2850: fix i18n (#2852)
* Fix #2850: fix i18n

* update

* update

* update

* update
2024-02-25 00:56:29 +08:00
zkitefly e9846ea644 zkitefly-add-thanks-to-@ZekerZhayard (#2807)
* zkitefly-add-thanks-to-@ZekerZhayard

* fix

* add image
2024-02-25 00:25:15 +08:00
Glavo 02065094ca 修复使用 Java 19+ 启动游戏时控制台乱码的问题 (#2846) 2024-02-22 23:20:30 +08:00
Burning_TNTandGlavo 9f6124d617 Remove the link of MCBBS in README.md. (#2844)
* Remove the link of MCBBS in README.md.

* Remove MCBBS in sponsor.bmclapi

* Update I18N_zh.properties

---------

Co-authored-by: Glavo <zjx001202@gmail.com>
2024-02-21 21:54:50 +08:00
Glavo 76229a894c Fix Linux RISC-V 64 Support (#2840) 2024-02-20 02:41:24 +08:00
Glavo 03de1598c8 在 Jenkins CI 上使用腾讯云镜像下载 Gradle Wrapper (#2837)
* 使用腾讯云下载 Gradle Wrapper

* Create config-jenkins.sh

* update script
2024-02-20 01:42:51 +08:00
Glavo 3a13ff0e10 更新 downloadType 的默认值 (#2839) 2024-02-19 22:15:08 +08:00
42 changed files with 341 additions and 238 deletions

No files matched your search

@@ -282,7 +282,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
}
if (LibraryAnalyzer.isModded(this, version)) {
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version, null);
if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FABRIC))
return VersionIconType.FABRIC.getIcon();
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FORGE))
@@ -93,7 +93,7 @@ public final class HMCLModpackInstallTask extends Task<Void> {
public void execute() throws Exception {
String json = CompressingUtils.readTextZipEntry(zipFile, "minecraft/pack.json");
Version originalVersion = JsonUtils.GSON.fromJson(json, Version.class).setId(name).setJar(null);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(originalVersion);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(originalVersion, null);
Task<Version> libraryTask = Task.supplyAsync(() -> originalVersion);
// reinstall libraries
// libraries of Forge and OptiFine should be obtained by installation.
@@ -417,7 +417,7 @@ public final class LauncherHelper {
JavaVersionConstraint violatedMandatoryConstraint = null;
List<JavaVersionConstraint> violatedSuggestedConstraints = null;
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version, gameVersion.toString());
for (JavaVersionConstraint constraint : JavaVersionConstraint.ALL) {
if (constraint.appliesToVersion(gameVersion, version, javaVersion, analyzer)) {
if (!constraint.checkJava(gameVersion, version, javaVersion)) {
@@ -137,7 +137,7 @@ public final class Config implements Cloneable, Observable {
private IntegerProperty downloadThreads = new SimpleIntegerProperty(64);
@SerializedName("downloadType")
private StringProperty downloadType = new SimpleStringProperty("mcbbs");
private StringProperty downloadType = new SimpleStringProperty(DownloadProviders.DEFAULT_RAW_PROVIDER_ID);
@SerializedName("autoChooseDownloadType")
private BooleanProperty autoChooseDownloadType = new SimpleBooleanProperty(true);
@@ -61,7 +61,6 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import static org.jackhuang.hmcl.setting.ConfigHolder.*;
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class Controllers {
@@ -262,7 +261,7 @@ public final class Controllers {
decorator.getDecorator().prefHeightProperty().bind(scene.heightProperty());
scene.getStylesheets().setAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily()));
stage.getIcons().add(newBuiltinImage("/assets/img/icon.png"));
FXUtils.setIcon(stage);
stage.setTitle(Metadata.FULL_TITLE);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
@@ -30,7 +30,6 @@ import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.countly.CrashReport;
import org.jackhuang.hmcl.upgrade.UpdateChecker;
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
/**
@@ -70,7 +69,7 @@ public class CrashWindow extends Stage {
Scene scene = new Scene(pane, 800, 480);
setScene(scene);
getIcons().add(newBuiltinImage("/assets/img/icon.png"));
FXUtils.setIcon(this);
setTitle(i18n("message.error"));
setOnCloseRequest(e -> System.exit(1));
@@ -43,6 +43,7 @@ import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.Duration;
import javafx.util.StringConverter;
@@ -676,6 +677,16 @@ public final class FXUtils {
comboBox.getSelectionModel().selectedIndexProperty().removeListener(listener);
}
public static void setIcon(Stage stage) {
String icon;
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
icon = "/assets/img/icon.png";
} else {
icon = "/assets/img/icon@4x.png";
}
stage.getIcons().add(newBuiltinImage(icon));
}
/**
* Suppress IllegalArgumentException since the url is supposed to be correct definitely.
*
@@ -769,8 +780,8 @@ public final class FXUtils {
Task.runAsync(() -> {
Path newPath = Files.createTempFile("hmcl-net-resource-cache-", ".cache");
try ( // Make sure the file is released from JVM before we put the path into remoteImageCache.
OutputStream outputStream = Files.newOutputStream(newPath);
PNGWriter writer = new PNGWriter(outputStream, PNGType.RGBA, PNGWriter.DEFAULT_COMPRESS_LEVEL)
OutputStream outputStream = Files.newOutputStream(newPath);
PNGWriter writer = new PNGWriter(outputStream, PNGType.RGBA, PNGWriter.DEFAULT_COMPRESS_LEVEL)
) {
writer.write(PNGJavaFXUtils.asArgbImage(image));
} catch (IOException e) {
@@ -66,7 +66,6 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
@@ -99,7 +98,7 @@ public class GameCrashWindow extends Stage {
this.version = version;
this.launchOptions = launchOptions;
this.logs = logs;
this.analyzer = LibraryAnalyzer.analyze(version);
this.analyzer = LibraryAnalyzer.analyze(version, repository.getGameVersion(version).orElse(null));
memory = Optional.ofNullable(launchOptions.getMaxMemory()).map(i -> i + " MB").orElse("-");
@@ -116,7 +115,7 @@ public class GameCrashWindow extends Stage {
setScene(new Scene(view, 800, 480));
getScene().getStylesheets().addAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily()));
setTitle(i18n("game.crash.title"));
getIcons().add(newBuiltinImage("/assets/img/icon.png"));
FXUtils.setIcon(this);
analyzeCrashReport();
}
@@ -60,7 +60,6 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.StringUtils.parseEscapeSequence;
@@ -98,7 +97,7 @@ public final class LogWindow extends Stage {
setScene(new Scene(impl, 800, 480));
getScene().getStylesheets().addAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily()));
setTitle(i18n("logwindow.title"));
getIcons().add(newBuiltinImage("/assets/img/icon.png"));
FXUtils.setIcon(this);
levelShownMap.values().forEach(property -> property.addListener((a, b, newValue) -> shakeLogs()));
@@ -29,7 +29,6 @@ import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.setting.Theme;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
public class WebStage extends Stage {
protected final StackPane pane = new StackPane();
@@ -44,7 +43,7 @@ public class WebStage extends Stage {
public WebStage(int width, int height) {
setScene(new Scene(pane, width, height));
getScene().getStylesheets().addAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily()));
getIcons().add(newBuiltinImage("/assets/img/icon.png"));
FXUtils.setIcon(this);
webView.getEngine().setUserDataDirectory(Metadata.HMCL_DIRECTORY.toFile());
webView.setContextMenuEnabled(false);
progressBar.progressProperty().bind(webView.getEngine().getLoadWorker().progressProperty());
@@ -84,7 +84,8 @@ class AdditionalInstallersPage extends InstallersPage {
@Override
protected void reload() {
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version.resolvePreservingPatches(repository));
Version resolved = version.resolvePreservingPatches(repository);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(resolved, repository.getGameVersion(resolved).orElse(null));
String game = analyzer.getVersion(MINECRAFT).orElse(null);
String currentGameVersion = Lang.nonNull(getVersion("game"), game);
@@ -61,13 +61,19 @@ public class AboutPage extends StackPane {
bangbang93.setTitle("bangbang93");
bangbang93.setSubtitle(i18n("about.thanks_to.bangbang93.statement"));
bangbang93.setExternalLink("https://bmclapi2.bangbang93.com/");
IconedTwoLineListItem glavo = new IconedTwoLineListItem();
glavo.setImage(FXUtils.newBuiltinImage("/assets/img/glavo.png"));
glavo.setTitle("Glavo");
glavo.setSubtitle(i18n("about.thanks_to.glavo.statement"));
glavo.setExternalLink("https://github.com/Glavo");
IconedTwoLineListItem zekerzhayard = new IconedTwoLineListItem();
zekerzhayard.setImage(FXUtils.newBuiltinImage("/assets/img/zekerzhayard.png"));
zekerzhayard.setTitle("ZekerZhayard");
zekerzhayard.setSubtitle(i18n("about.thanks_to.zekerzhayard.statement"));
zekerzhayard.setExternalLink("https://github.com/ZekerZhayard");
IconedTwoLineListItem zkitefly = new IconedTwoLineListItem();
zkitefly.setImage(FXUtils.newBuiltinImage("/assets/img/zkitefly.png"));
zkitefly.setTitle("Zkitefly");
@@ -109,7 +115,7 @@ public class AboutPage extends StackPane {
users.setSubtitle(i18n("about.thanks_to.users.statement"));
users.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/sponsor");
thanks.getContent().setAll(yushijinhun, bangbang93, glavo, zkitefly, /* mcbbs, */ mcmod, gamerteam, redLnn, contributors, users);
thanks.getContent().setAll(yushijinhun, bangbang93, glavo, zekerzhayard, zkitefly, /* mcbbs, */ mcmod, gamerteam, redLnn, contributors, users);
}
ComponentList dep = new ComponentList();
@@ -413,7 +413,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
searchAction.handle(event);
});
lastPageButton.setDisable(true);
control.pageCount.addListener((observable, oldValue, newValue) -> lastPageButton.setDisable(control.pageCount.get() == -1));
control.pageCount.addListener((observable, oldValue, newValue) -> lastPageButton.setDisable(control.pageCount.get() == -1 || control.pageOffset.get() >= control.pageCount.get() - 1));
Pane placeholder = new Pane();
HBox.setHgrow(placeholder, Priority.SOMETIMES);
@@ -32,9 +32,9 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.FileChooser;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.HMCLGameRepository;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.mod.ModLoaderType;
import org.jackhuang.hmcl.mod.ModManager;
import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.setting.Profile;
@@ -254,13 +254,13 @@ public class DownloadPage extends Control implements DecoratorPage {
openMcmodButton.setMinWidth(Region.USE_PREF_SIZE);
runInFX(() -> FXUtils.installFastTooltip(openMcmodButton, i18n("mods.mcmod")));
if (StringUtils.isNotBlank(getSkinnable().mod.getMcbbs())) {
JFXHyperlink openMcbbsButton = new JFXHyperlink(i18n("mods.mcbbs"));
openMcbbsButton.setExternalLink(ModManager.getMcbbsUrl(getSkinnable().mod.getMcbbs()));
descriptionPane.getChildren().add(openMcbbsButton);
openMcbbsButton.setMinWidth(Region.USE_PREF_SIZE);
runInFX(() -> FXUtils.installFastTooltip(openMcbbsButton, i18n("mods.mcbbs")));
}
// if (StringUtils.isNotBlank(getSkinnable().mod.getMcbbs())) {
// JFXHyperlink openMcbbsButton = new JFXHyperlink(i18n("mods.mcbbs"));
// openMcbbsButton.setExternalLink(ModManager.getMcbbsUrl(getSkinnable().mod.getMcbbs()));
// descriptionPane.getChildren().add(openMcbbsButton);
// openMcbbsButton.setMinWidth(Region.USE_PREF_SIZE);
// runInFX(() -> FXUtils.installFastTooltip(openMcbbsButton, i18n("mods.mcbbs")));
// }
}
JFXHyperlink openUrlButton = new JFXHyperlink(control.page.getLocalizedOfficialPage());
@@ -292,8 +292,9 @@ public class DownloadPage extends Control implements DecoratorPage {
if (control.versions == null) return;
if (control.version.getProfile() != null && control.version.getVersion() != null) {
Version game = control.version.getProfile().getRepository().getResolvedPreservingPatchesVersion(control.version.getVersion());
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(game);
HMCLGameRepository repository = control.version.getProfile().getRepository();
Version game = repository.getResolvedPreservingPatchesVersion(control.version.getVersion());
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(game, repository.getGameVersion(game).orElse(null));
libraryAnalyzer.getVersion(LibraryAnalyzer.LibraryType.MINECRAFT).ifPresent(currentGameVersion -> {
Set<ModLoaderType> currentGameModLoaders = libraryAnalyzer.getModLoaders();
if (control.versions.containsKey(currentGameVersion)) {
@@ -59,10 +59,10 @@ public class GameItem extends Control {
this.version = id;
// GameVersion.minecraftVersion() is a time-costing job (up to ~200 ms)
CompletableFuture.supplyAsync(() -> profile.getRepository().getGameVersion(id).orElse(i18n("message.unknown")), POOL_VERSION_RESOLVE)
CompletableFuture.supplyAsync(() -> profile.getRepository().getGameVersion(id), POOL_VERSION_RESOLVE)
.thenAcceptAsync(game -> {
StringBuilder libraries = new StringBuilder(game);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(id));
StringBuilder libraries = new StringBuilder(game.orElse(i18n("message.unknown")));
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(id), game.orElse(null));
for (LibraryAnalyzer.LibraryMark mark : analyzer) {
String libraryId = mark.getLibraryId();
String libraryVersion = mark.getLibraryVersion();
@@ -72,7 +72,7 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
CompletableFuture.supplyAsync(() -> {
gameVersion = profile.getRepository().getGameVersion(version).orElse(null);
return LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(versionId));
return LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(versionId), gameVersion);
}).thenAcceptAsync(analyzer -> {
Function<String, Runnable> removeAction = libraryId -> () -> {
profile.getDependency().removeLibraryAsync(version, libraryId)
@@ -24,6 +24,8 @@ import javafx.collections.ObservableList;
import javafx.scene.control.Skin;
import javafx.stage.FileChooser;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.HMCLGameRepository;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.mod.LocalModFile;
import org.jackhuang.hmcl.mod.ModManager;
import org.jackhuang.hmcl.setting.Profile;
@@ -84,7 +86,9 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
this.profile = profile;
this.versionId = id;
libraryAnalyzer = LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(id));
HMCLGameRepository repository = profile.getRepository();
Version resolved = repository.getResolvedPreservingPatchesVersion(id);
libraryAnalyzer = LibraryAnalyzer.analyze(resolved, repository.getGameVersion(resolved).orElse(null));
modded.set(libraryAnalyzer.hasModLoader());
loadMods(profile.getRepository().getModManager(id));
}
@@ -391,14 +391,14 @@ class ModListPageSkin extends SkinBase<ModListPage> {
getActions().add(officialPageButton);
}
if (modInfo.getMod() != null && StringUtils.isNotBlank(modInfo.getMod().getMcbbs())) {
JFXHyperlink mcbbsButton = new JFXHyperlink(i18n("mods.mcbbs"));
mcbbsButton.setOnAction(e -> {
fireEvent(new DialogCloseEvent());
FXUtils.openLink(ModManager.getMcbbsUrl(modInfo.getMod().getMcbbs()));
});
getActions().add(mcbbsButton);
}
// if (modInfo.getMod() != null && StringUtils.isNotBlank(modInfo.getMod().getMcbbs())) {
// JFXHyperlink mcbbsButton = new JFXHyperlink(i18n("mods.mcbbs"));
// mcbbsButton.setOnAction(e -> {
// fireEvent(new DialogCloseEvent());
// FXUtils.openLink(ModManager.getMcbbsUrl(modInfo.getMod().getMcbbs()));
// });
// getActions().add(mcbbsButton);
// }
if (modInfo.getMod() == null || StringUtils.isBlank(modInfo.getMod().getMcmod())) {
JFXHyperlink searchButton = new JFXHyperlink(i18n("mods.mcmod.search"));
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@@ -34,6 +34,7 @@ about.thanks_to.contributors=All contributors on GitHub
about.thanks_to.contributors.statement=Without the awesome open-source community, Hello Minecraft! Launcher would not make it so far.
about.thanks_to.gamerteam.statement=For providing the default background image.
about.thanks_to.glavo.statement=Contribute a lot of technical support to HMCL.
about.thanks_to.zekerzhayard.statement=Contribute a lot of technical support to HMCL.
about.thanks_to.zkitefly.statement=Contribute a lot of technical support to HMCL.
about.thanks_to.mcbbs=MCBBS (Minecraft Chinese Forum)
about.thanks_to.mcbbs.statement=For providing mcbbs.net download mirror for Mainland China users.
@@ -339,7 +340,7 @@ download.java=Downloading Java
download.javafx=Downloading dependencies for the launcher...
download.javafx.notes=We are currently downloading dependencies for HMCL from the Internet.\n\
\n\
You can click on 'Change Download Mirror' to select the download mirror or click on "Cancel" to stop and exit.\n\
You can click on 'Change Download Source' to select the download source or\nclick on 'Cancel' to stop and exit.\n\
Note: If your download speed is too slow, you can try switching to another mirror.
download.javafx.component=Downloading module %s
download.javafx.prepare=Preparing to download
@@ -1169,7 +1170,7 @@ settings.type.special.edit=Edit Current Instance Settings
settings.type.special.edit.hint=Current instance [%s] has enabled per-instance settings, all options on this page will NOT affect that instance. Click here to modify its own options.
sponsor=Donators
sponsor.bmclapi=Downloads are provided by BMCLAPI and MCBBS. Click here for more information.
sponsor.bmclapi=Downloads are provided by BMCLAPI. Click here for more information.
sponsor.hmcl=Hello Minecraft! Launcher is a FOSS Minecraft launcher which allows users to manage multiple Minecraft instances easily. You can donate to us on Afdian to support our file hosting and project development. Click here for more information.
system.architecture=Architecture
@@ -34,6 +34,7 @@ about.thanks_to.contributors=Todos los colaboradores en GitHub
about.thanks_to.contributors.statement=Sin la impresionante comunidad de código abierto, Hello Minecraft! Launcher no habría llegado tan lejos.
about.thanks_to.gamerteam.statement=Por proporcionar la imagen de fondo por defecto.
about.thanks_to.glavo.statement=Aportar mucho apoyo técnico a HMCL.
about.thanks_to.zekerzhayard.statement=Aportar mucho apoyo técnico a HMCL.
about.thanks_to.zkitefly.statement=Aportar mucho apoyo técnico a HMCL.
about.thanks_to.mcbbs=MCBBS (Foro chino de Minecraft)
about.thanks_to.mcbbs.statement=Por proporcionar un espejo de descarga de mcbbs.net para los usuarios de China continental.
@@ -319,7 +320,7 @@ download.provider.mirror=Desde espejo
download.javafx=Descargar las dependencias para el launcher...
download.javafx.notes=Estamos descargando dependencias para HMCL desde Internet.\n\
\n\
Puede hacer clic en "Cambiar el espejo de descarga" para seleccionar el espejo de descarga o hacer clic en "Cancelar" para detener y salir.\n\
Puede hacer clic en "Cambiar fuente de descarga" para seleccionar el espejo 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.
download.javafx.component=Descargando módulo %s
download.javafx.prepare=Preparando la descarga
@@ -1048,7 +1049,7 @@ settings.type.special.edit=Editar ajustes de la instancia actual
settings.type.special.edit.hint=La instancia actual [%s] tiene activada la configuración por instancia, todas las opciones de esta página NO afectarán a esa instancia. Haga clic aquí para modificar sus propias opciones.
sponsor=Donantes
sponsor.bmclapi=Las descargas son proporcionadas por BMCLAPI y MCBBS. Haz clic aquí para obtener más información.
sponsor.bmclapi=Las descargas son proporcionadas por BMCLAPI. Haz clic aquí para obtener más información.
sponsor.hmcl=¡Hello Minecraft! Launcher es un launcher FOSS de Minecraft que permite a los usuarios gestionar múltiples instancias de Minecraft fácilmente. Usted puede donar a nosotros en Afdian para apoyar nuestro alojamiento de archivos y el desarrollo del proyecto. Haga clic aquí para obtener más información.
system.architecture=Arquitectura
@@ -32,6 +32,7 @@ about.thanks_to.contributors=問題、プルリクエストなどを介してこ
about.thanks_to.contributors.statement=Hello Minecraftをサポートしてくれたオープンソースコミュニティに感謝します!ランチャー
about.thanks_to.gamerteam.statement=デフォルトの背景画像プロバイダー。
about.thanks_to.glavo.statement=HMCLに多くのテクニカルサポートを提供
about.thanks_to.zekerzhayard.statement=HMCLに多くのテクニカルサポートを提供
about.thanks_to.zkitefly.statement=HMCLに多くのテクニカルサポートを提供。
about.thanks_to.mcbbs=MCBBS
about.thanks_to.mcbbs.statement=MCBBSダウンロードソースプロバイダー。
@@ -860,7 +861,7 @@ settings.type.special.edit=現在のゲーム設定を構成します
settings.type.special.edit.hint=現在のゲームバージョン %s で特殊な設定が有効になっているため、現在のページのオプションはそのゲームバージョンに適用されません。リンクをクリックして、現在のゲーム設定を構成します。
sponsor=寄付
sponsor.bmclapi=ダウンロードサービスはBMCLAPIとMCBBSによって提供されます。詳細については、ここをクリックしてください。
sponsor.bmclapi=ダウンロードサービスはBMCLAPIによって提供されます。詳細については、ここをクリックしてください。
sponsor.hmcl=こんにちはマインクラフト! Launcherは、無料のオープンソースのMinecraftランチャーであり、ユーザーは複数の個別のMinecraftインストールを簡単に管理できます。私たちはAfdianを使用して、ホスティングとプロジェクト開発の費用を引き続き支払います。詳細については、ここをクリックしてください。
system.architecture=Arch
@@ -34,6 +34,7 @@ about.thanks_to.contributors=Всем участникам на GitHub
about.thanks_to.contributors.statement=Без потрясающего сообщества с открытым исходным кодом, Hello Minecraft! Launcher не смог бы добраться так далеко.
about.thanks_to.gamerteam.statement=За предоставление фонового изображения.
about.thanks_to.glavo.statement=Оказал большую техническую поддержку HMCL.
about.thanks_to.zekerzhayard.statement=Оказал большую техническую поддержку HMCL.
about.thanks_to.zkitefly.statement=Оказал большую техническую поддержку HMCL.
about.thanks_to.mcbbs=MCBBS (Minecraft Chinese Forum)
about.thanks_to.mcbbs.statement=За предоставление зеркала скачивания MCBBS.NET для пользователей Китая.
@@ -320,7 +321,7 @@ download.java=Скачивание Java
download.javafx=Скачивание зависимостей лаунчера...
download.javafx.notes=Скачиваем зависимостей лаунчера из интернета.\n\
\n\
Можно нажать «Изменить зеркало скачивания», чтобы выбрать зеркало загрузки, или нажать «Отмена», чтобы остановить и выйти.\n\
Можно нажать «Изменить источник скачивания», чтобы выбрать зеркало загрузки, или нажать «Отмена», чтобы остановить и выйти.\n\
Примечание\: Если ваша скорость скачивания слишком низкая, вы можете попробовать переключиться на другое зеркало.
download.javafx.component=Скачивание %s
download.javafx.prepare=Подготовка к скачиванию
@@ -935,7 +936,7 @@ settings.type.special.edit=Изменить настройки текущего
settings.type.special.edit.hint=В текущем экземпляре [%s] включены раздельные настройки для экземпляров, параметры на этой странице НЕ повлияют на этот экземпляр. Нажмите здесь, чтобы изменить раздельные параметры.
sponsor=Спонсоры
sponsor.bmclapi=Скачивание предоставляется BMCLAPI и MCBBS. Нажмите здесь для получения подробностей.
sponsor.bmclapi=Скачивание предоставляется BMCLAPI. Нажмите здесь для получения подробностей.
sponsor.hmcl=Hello Minecraft! Launcher — лаунчер Minecraft с открытым исходным кодом, который позволяет пользователям легко управлять несколькими экземплярами Minecraft. Пожертвуйте нам на Afdian для поддержки нашего файлового хостинга и развития проекта. Для получения подробностей нажмите здесь.
system.architecture=Архитектура
@@ -32,6 +32,7 @@ about.thanks_to.contributors=所有通過 Issues、Pull Requests 等管道參與
about.thanks_to.contributors.statement=沒有開源社區的支持,Hello Minecraft! Launcher 無法走到今天
about.thanks_to.gamerteam.statement=提供預設背景圖
about.thanks_to.glavo.statement=為 HMCL 貢獻許多技術支持
about.thanks_to.zekerzhayard.statement=為 HMCL 貢獻許多技術支持
about.thanks_to.zkitefly.statement=為 HMCL 貢獻許多技術支持
about.thanks_to.mcbbs=MCBBS 我的世界中文論壇
about.thanks_to.mcbbs.statement=提供 MCBBS 下載地點
@@ -1034,7 +1035,7 @@ settings.type.special.edit=編輯遊戲特定設置
settings.type.special.edit.hint=當前遊戲版本 %s 啟動了遊戲特定設置,本頁面選項不對當前遊戲生效。點擊連結以修改當前遊戲設置。
sponsor=贊助
sponsor.bmclapi=大中華區下載源由 BMCLAPI 和我的世界中文論壇 (MCBBS) 提供高速下載服務
sponsor.bmclapi=大中華區下載源由 BMCLAPI 提供高速下載服務
sponsor.hmcl=Hello Minecraft! Launcher 是一個免費、開源的 Minecraft 啟動器,允許玩家方便快捷地安裝、管理、執行遊戲。您的贊助將幫助 Hello Minecraft! Launcher 獲得更好的發展、支援穩定高速的遊戲安裝與檔案下載服務。點選此處查閱更多詳細訊息。
system.architecture=架構
@@ -32,6 +32,7 @@ about.thanks_to.contributors=所有通过 Issues、Pull Requests 等方式参与
about.thanks_to.contributors.statement=没有开源社区的支持,Hello Minecraft! Launcher 就无法走到今天
about.thanks_to.gamerteam.statement=提供默认背景图
about.thanks_to.glavo.statement=为 HMCL 贡献许多技术支持
about.thanks_to.zekerzhayard.statement=为 HMCL 贡献许多技术支持
about.thanks_to.zkitefly.statement=为 HMCL 贡献许多技术支持
about.thanks_to.mcbbs=MCBBS 我的世界中文论坛
about.thanks_to.mcbbs.statement=提供 MCBBS 下载源
@@ -1041,7 +1042,7 @@ settings.type.special.edit=编辑游戏特定设置
settings.type.special.edit.hint=当前游戏版本 %s 启用了游戏特定设置,因此本页面选项不对该游戏生效。点击链接前往该游戏版本的游戏特定设置页
sponsor=赞助
sponsor.bmclapi=国内下载源由 BMCLAPI 和我的世界中文论坛 (MCBBS) 提供高速下载服务。BMCLAPI 为公益服务,赞助 BMCLAPI 可以帮助作者更好的提供稳定高速的下载服务,[点击此处查阅详细信息]
sponsor.bmclapi=国内下载源由 BMCLAPI 提供高速下载服务。BMCLAPI 为公益服务,赞助 BMCLAPI 可以帮助作者更好的提供稳定高速的下载服务,[点击此处查阅详细信息]
sponsor.hmcl=Hello Minecraft! Launcher 是一个免费、自由、开放源代码的 Minecraft 启动器。您的赞助将帮助 Hello Minecraft! Launcher 获得更好的发展,还可以获得 HMCL 的开发进展。[点击此处查阅更多详细信息]
system.architecture=架构
+35 -35
View File
@@ -2358,13 +2358,13 @@
}
},
"org.lwjgl:lwjgl:3.3.2:natives-linux": {
"name": "org.lwjgl:lwjgl:3.3.4-SNAPSHOT:natives-freebsd",
"name": "org.lwjgl:lwjgl:3.3.4-SNAPSHOT:natives-linux-riscv64",
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl/3.3.4-SNAPSHOT/lwjgl-3.3.4-20231218.151521-4-natives-freebsd.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl/3.3.4-SNAPSHOT/lwjgl-3.3.4-20231218.151521-4-natives-freebsd.jar",
"sha1": "2d38355b453edfe2daee1a567bcdb82c0485edcf",
"size": 95872
"path": "org/lwjgl/lwjgl/3.3.4-SNAPSHOT/lwjgl-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl/3.3.4-SNAPSHOT/lwjgl-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"sha1": "642848dc964fc5332cda40225771a5143740b49c",
"size": 79691
}
}
},
@@ -2380,13 +2380,13 @@
}
},
"org.lwjgl:lwjgl-jemalloc:3.3.2:natives-linux": {
"name": "org.lwjgl:lwjgl-jemalloc:3.3.4-SNAPSHOT:natives-freebsd",
"name": "org.lwjgl:lwjgl-jemalloc:3.3.4-SNAPSHOT:natives-linux-riscv64",
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl-jemalloc/3.3.4-SNAPSHOT/lwjgl-jemalloc-3.3.4-20231218.151521-4-natives-freebsd.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-jemalloc/3.3.4-SNAPSHOT/lwjgl-jemalloc-3.3.4-20231218.151521-4-natives-freebsd.jar",
"sha1": "bdba1662b621228679c7aed87945d1f28c590d5b",
"size": 155867
"path": "org/lwjgl/lwjgl-jemalloc/3.3.4-SNAPSHOT/lwjgl-jemalloc-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-jemalloc/3.3.4-SNAPSHOT/lwjgl-jemalloc-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"sha1": "01129d98674994eb8204f62c26b5717d4d989536",
"size": 200633
}
}
},
@@ -2402,13 +2402,13 @@
}
},
"org.lwjgl:lwjgl-openal:3.3.2:natives-linux": {
"name": "org.lwjgl:lwjgl-openal:3.3.4-SNAPSHOT:natives-freebsd",
"name": "org.lwjgl:lwjgl-openal:3.3.4-SNAPSHOT:natives-linux-riscv64",
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl-openal/3.3.4-SNAPSHOT/lwjgl-openal-3.3.4-20231218.151521-4-natives-freebsd.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-openal/3.3.4-SNAPSHOT/lwjgl-openal-3.3.4-20231218.151521-4-natives-freebsd.jar",
"sha1": "0fc6495e6752727b629cf03a105c9d56087d4edd",
"size": 597512
"path": "org/lwjgl/lwjgl-openal/3.3.4-SNAPSHOT/lwjgl-openal-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-openal/3.3.4-SNAPSHOT/lwjgl-openal-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"sha1": "bce3174f137d0ffcbbe88ddae305de11c5131137",
"size": 520217
}
}
},
@@ -2424,13 +2424,13 @@
}
},
"org.lwjgl:lwjgl-opengl:3.3.2:natives-linux": {
"name": "org.lwjgl:lwjgl-opengl:3.3.4-SNAPSHOT:natives-freebsd",
"name": "org.lwjgl:lwjgl-opengl:3.3.4-SNAPSHOT:natives-linux-riscv64",
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl-opengl/3.3.4-SNAPSHOT/lwjgl-opengl-3.3.4-20231218.151521-4-natives-freebsd.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-opengl/3.3.4-SNAPSHOT/lwjgl-opengl-3.3.4-20231218.151521-4-natives-freebsd.jar",
"sha1": "d3e8ec997cef8bc66819c7e0ad7a54182f7aff2a",
"size": 81034
"path": "org/lwjgl/lwjgl-opengl/3.3.4-SNAPSHOT/lwjgl-opengl-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-opengl/3.3.4-SNAPSHOT/lwjgl-opengl-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"sha1": "13dccf954b781883b0661bd55dfc423f8eece864",
"size": 57244
}
}
},
@@ -2446,13 +2446,13 @@
}
},
"org.lwjgl:lwjgl-glfw:3.3.2:natives-linux": {
"name": "org.lwjgl:lwjgl-glfw:3.3.4-SNAPSHOT:natives-freebsd",
"name": "org.lwjgl:lwjgl-glfw:3.3.4-SNAPSHOT:natives-linux-riscv64",
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl-glfw/3.3.4-SNAPSHOT/lwjgl-glfw-3.3.4-20231218.151521-4-natives-freebsd.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-glfw/3.3.4-SNAPSHOT/lwjgl-glfw-3.3.4-20231218.151521-4-natives-freebsd.jar",
"sha1": "4881a965c7679b4984c0d8a5890f07ea85c653c4",
"size": 101847
"path": "org/lwjgl/lwjgl-glfw/3.3.4-SNAPSHOT/lwjgl-glfw-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-glfw/3.3.4-SNAPSHOT/lwjgl-glfw-3.3.4-20231218.151521-4-natives-linux-riscv64.jar",
"sha1": "865417f4aa171aa8e7a448d88877a82844896c92",
"size": 113875
}
}
},
@@ -2468,13 +2468,13 @@
}
},
"org.lwjgl:lwjgl-stb:3.3.2:natives-linux": {
"name": "org.lwjgl:lwjgl-stb:3.3.4-SNAPSHOT:natives-freebsd",
"name": "org.lwjgl:lwjgl-stb:3.3.4-SNAPSHOT:natives-linux-riscv64",
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl-stb/3.3.4-SNAPSHOT/lwjgl-stb-3.3.4-20231218.151521-3-natives-freebsd.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-stb/3.3.4-SNAPSHOT/lwjgl-stb-3.3.4-20231218.151521-3-natives-freebsd.jar",
"sha1": "0aad82a857ebb9a3a212dc2c386761d57e11a8f2",
"size": 225735
"path": "org/lwjgl/lwjgl-stb/3.3.4-SNAPSHOT/lwjgl-stb-3.3.4-20231218.151521-3-natives-linux-riscv64.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-stb/3.3.4-SNAPSHOT/lwjgl-stb-3.3.4-20231218.151521-3-natives-linux-riscv64.jar",
"sha1": "f5b96c0fd649cb1e18816f63bed49e0dfe1d1f1a",
"size": 217005
}
}
},
@@ -2490,13 +2490,13 @@
}
},
"org.lwjgl:lwjgl-tinyfd:3.3.2:natives-linux": {
"name": "org.lwjgl:lwjgl-tinyfd:3.3.4-SNAPSHOT:natives-freebsd",
"name": "org.lwjgl:lwjgl-tinyfd:3.3.4-SNAPSHOT:natives-linux-riscv64",
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl-tinyfd/3.3.4-SNAPSHOT/lwjgl-tinyfd-3.3.4-20231218.151521-3-natives-freebsd.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-tinyfd/3.3.4-SNAPSHOT/lwjgl-tinyfd-3.3.4-20231218.151521-3-natives-freebsd.jar",
"sha1": "124d0e48ae1584f09e5701588ae8ad139be26003",
"size": 39077
"path": "org/lwjgl/lwjgl-tinyfd/3.3.4-SNAPSHOT/lwjgl-tinyfd-3.3.4-20231218.151521-3-natives-linux-riscv64.jar",
"url": "https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-tinyfd/3.3.4-SNAPSHOT/lwjgl-tinyfd-3.3.4-20231218.151521-3-natives-linux-riscv64.jar",
"sha1": "f042c17188c5db910b195d298c284bbfbe550c53",
"size": 46885
}
}
},
@@ -106,7 +106,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
Version original = repository.getVersion(version.getId());
Version resolved = original.resolvePreservingPatches(repository);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(resolved);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(resolved, gameVersion);
for (LibraryAnalyzer.LibraryType type : LibraryAnalyzer.LibraryType.values()) {
if (!analyzer.has(type))
continue;
@@ -218,8 +218,9 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
if (version.isResolved())
throw new IllegalArgumentException("removeLibraryWithoutSavingAsync requires non-resolved version");
Version independentVersion = version.resolvePreservingPatches(repository);
String gameVersion = repository.getGameVersion(independentVersion).orElse(null);
return Task.supplyAsync(() -> LibraryAnalyzer.analyze(independentVersion).removeLibrary(libraryId).build());
return Task.supplyAsync(() -> LibraryAnalyzer.analyze(independentVersion, gameVersion).removeLibrary(libraryId).build());
}
}
@@ -130,12 +130,16 @@ public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMa
return version;
}
public static LibraryAnalyzer analyze(Version version) {
public static LibraryAnalyzer analyze(Version version, String gameVersion) {
if (version.getInheritsFrom() != null)
throw new IllegalArgumentException("LibraryAnalyzer can only analyze independent game version");
Map<String, Pair<Library, String>> libraries = new HashMap<>();
if (gameVersion != null) {
libraries.put(LibraryType.MINECRAFT.getPatchId(), pair(null, gameVersion));
}
List<Library> rawLibraries = version.resolve(null).getLibraries();
for (Library library : rawLibraries) {
for (LibraryType type : LibraryType.values()) {
@@ -63,7 +63,7 @@ public class MaintainTask extends Task<Version> {
String mainClass = version.resolve(null).getMainClass();
if (mainClass != null && mainClass.equals(LibraryAnalyzer.LAUNCH_WRAPPER_MAIN)) {
version = maintainOptiFineLibrary(repository, maintainGameWithLaunchWrapper(unique(version), true), false);
version = maintainOptiFineLibrary(repository, maintainGameWithLaunchWrapper(repository, unique(version), true), false);
} else if (mainClass != null && mainClass.equals(LibraryAnalyzer.MOD_LAUNCHER_MAIN)) {
// Forge 1.13 and OptiFine
version = maintainOptiFineLibrary(repository, maintainGameWithCpwModLauncher(repository, unique(version)), true);
@@ -97,8 +97,8 @@ public class MaintainTask extends Task<Version> {
return newVersion.setPatches(version.getPatches()).markAsUnresolved();
}
private static Version maintainGameWithLaunchWrapper(Version version, boolean reorderTweakClass) {
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
private static Version maintainGameWithLaunchWrapper(GameRepository repository, Version version, boolean reorderTweakClass) {
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version, null);
VersionLibraryBuilder builder = new VersionLibraryBuilder(version);
String mainClass = null;
@@ -147,7 +147,7 @@ public class MaintainTask extends Task<Version> {
}
private static Version maintainGameWithCpwModLauncher(GameRepository repository, Version version) {
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version, null);
VersionLibraryBuilder builder = new VersionLibraryBuilder(version);
if (!libraryAnalyzer.has(FORGE)) return version;
@@ -205,7 +205,7 @@ public class MaintainTask extends Task<Version> {
// Fix wrong configurations when launching 1.17+ with Forge.
private static Version maintainGameWithCpwBoostrapLauncher(GameRepository repository, Version version) {
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version, null);
VersionLibraryBuilder builder = new VersionLibraryBuilder(version);
if (!libraryAnalyzer.has(FORGE) && !libraryAnalyzer.has(NEO_FORGE)) return version;
@@ -247,7 +247,7 @@ public class MaintainTask extends Task<Version> {
}
private static Version maintainOptiFineLibrary(GameRepository repository, Version version, boolean remove) {
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version, null);
List<Library> libraries = new ArrayList<>(version.getLibraries());
if (libraryAnalyzer.has(OPTIFINE)) {
@@ -63,7 +63,7 @@ public final class GameVerificationFixTask extends Task<Void> {
@Override
public void execute() throws IOException {
File jar = dependencyManager.getGameRepository().getVersionJar(version);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version, gameVersion);
if (jar.exists() && GameVersionNumber.compare(gameVersion, "1.6") < 0 && analyzer.has(LibraryAnalyzer.LibraryType.FORGE)) {
try (FileSystem fs = CompressingUtils.createWritableZipFileSystem(jar.toPath(), StandardCharsets.UTF_8)) {
@@ -226,7 +226,7 @@ public enum JavaVersionConstraint {
public static VersionRanges findSuitableJavaVersionRange(GameVersionNumber gameVersion, Version version) {
VersionRange<VersionNumber> mandatoryJavaRange = VersionRange.all();
VersionRange<VersionNumber> suggestedJavaRange = VersionRange.all();
LibraryAnalyzer analyzer = version != null ? LibraryAnalyzer.analyze(version) : null;
LibraryAnalyzer analyzer = version != null ? LibraryAnalyzer.analyze(version, gameVersion != null ? gameVersion.toString() : null) : null;
for (JavaVersionConstraint java : ALL) {
if (java.appliesToVersion(gameVersion, version, null, analyzer)) {
VersionRange<VersionNumber> javaVersionRange = java.getJavaVersionRange(version);
@@ -150,8 +150,14 @@ public class DefaultLauncher extends Launcher {
LOG.log(Level.WARNING, "Bad file encoding", ex);
}
}
res.addDefault("-Dsun.stdout.encoding=", encoding.name());
res.addDefault("-Dsun.stderr.encoding=", encoding.name());
if (options.getJava().getParsedVersion() < 19) {
res.addDefault("-Dsun.stdout.encoding=", encoding.name());
res.addDefault("-Dsun.stderr.encoding=", encoding.name());
} else {
res.addDefault("-Dstdout.encoding=", encoding.name());
res.addDefault("-Dstderr.encoding=", encoding.name());
}
// Fix RCE vulnerability of log4j2
res.addDefault("-Djava.rmi.server.useCodebaseOnly=", "true");
@@ -424,7 +430,7 @@ public class DefaultLauncher extends Launcher {
// To guarantee that when failed to generate launch command line, we will not call pre-launch command
List<String> rawCommandLine = command.commandLine.asList();
if (StringUtils.isNotBlank(options.getWrapper())) {
rawCommandLine.addAll(0, StringUtils.parseCommand(options.getWrapper(), getEnvVars()));
rawCommandLine.addAll(0, StringUtils.tokenize(options.getWrapper(), getEnvVars()));
}
if (command.tempNativeFolder != null) {
@@ -446,7 +452,7 @@ public class DefaultLauncher extends Launcher {
File runDirectory = repository.getRunDirectory(version.getId());
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
ProcessBuilder builder = new ProcessBuilder(StringUtils.parseCommand(options.getPreLaunchCommand(), getEnvVars())).directory(runDirectory);
ProcessBuilder builder = new ProcessBuilder(StringUtils.tokenize(options.getPreLaunchCommand(), getEnvVars())).directory(runDirectory);
builder.environment().putAll(getEnvVars());
SystemUtils.callExternalProcess(builder);
}
@@ -499,7 +505,7 @@ public class DefaultLauncher extends Launcher {
}
}
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version, repository.getGameVersion(version).orElse(null));
if (analyzer.has(LibraryAnalyzer.LibraryType.FORGE)) {
env.put("INST_FORGE", "1");
}
@@ -677,7 +683,7 @@ public class DefaultLauncher extends Launcher {
if (StringUtils.isNotBlank(options.getPostExitCommand())) {
try {
ProcessBuilder builder = new ProcessBuilder(StringUtils.parseCommand(options.getPostExitCommand(), getEnvVars())).directory(options.getGameDir());
ProcessBuilder builder = new ProcessBuilder(StringUtils.tokenize(options.getPostExitCommand(), getEnvVars())).directory(options.getGameDir());
builder.environment().putAll(getEnvVars());
SystemUtils.callExternalProcess(builder);
} catch (Throwable e) {
@@ -82,9 +82,9 @@ public class McbbsModpackExportTask extends Task<Void> {
}
});
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(version));
String gameVersion = repository.getGameVersion(version)
.orElseThrow(() -> new IOException("Cannot parse the version of " + version));
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(version), gameVersion);
// Mcbbs manifest
List<McbbsModpackManifest.Addon> addons = new ArrayList<>();
@@ -70,9 +70,9 @@ public class MultiMCModpackExportTask extends Task<Void> {
try (Zipper zip = new Zipper(output.toPath())) {
zip.putDirectory(repository.getRunDirectory(versionId).toPath(), ".minecraft", path -> Modpack.acceptFile(path, blackList, whitelist));
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(versionId));
String gameVersion = repository.getGameVersion(versionId)
.orElseThrow(() -> new IOException("Cannot parse the version of " + versionId));
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(versionId), gameVersion);
List<MultiMCManifest.MultiMCManifestComponent> components = new ArrayList<>();
components.add(new MultiMCManifest.MultiMCManifestComponent(true, false, "net.minecraft", gameVersion));
analyzer.getVersion(FORGE).ifPresent(forgeVersion ->
@@ -78,9 +78,9 @@ public class ServerModpackExportTask extends Task<Void> {
}
});
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(versionId));
String gameVersion = repository.getGameVersion(versionId)
.orElseThrow(() -> new IOException("Cannot parse the version of " + versionId));
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(versionId), gameVersion);
List<ServerModpackManifest.Addon> addons = new ArrayList<>();
addons.add(new ServerModpackManifest.Addon(MINECRAFT.getPatchId(), gameVersion));
analyzer.getVersion(FORGE).ifPresent(forgeVersion ->
@@ -207,93 +207,135 @@ public final class StringUtils {
return false;
}
public static List<String> tokenize(String str) {
if (isBlank(str)) {
return new ArrayList<>();
} else {
// Split the string with ' and space cleverly.
ArrayList<String> parts = new ArrayList<>();
boolean hasValue = false;
StringBuilder current = new StringBuilder(str.length());
for (int i = 0; i < str.length(); ) {
char c = str.charAt(i);
if (c == '\'') {
hasValue = true;
int end = str.indexOf(c, i + 1);
if (end < 0) {
end = str.length();
}
current.append(str, i + 1, end);
i = end + 1;
} else if (c == '"') {
hasValue = true;
i++;
while (i < str.length()) {
c = str.charAt(i++);
if (c == '"') {
break;
} else if (c == '\\' && i < str.length()) {
c = str.charAt(i++);
switch (c) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'v':
c = '\u000b';
break;
case 'a':
c = '\u0007';
break;
}
current.append(c);
} else {
current.append(c);
}
}
} else if (c == ' ') {
if (hasValue) {
parts.add(current.toString());
current.setLength(0);
hasValue = false;
}
i++;
} else {
hasValue = true;
current.append(c);
i++;
}
}
if (hasValue) {
parts.add(current.toString());
}
return parts;
}
private static boolean isVarNameStart(char ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
}
public static List<String> parseCommand(String command, Map<String, String> env) {
StringBuilder stringBuilder = new StringBuilder(command);
for (Map.Entry<String, String> entry : env.entrySet()) {
String key = "$" + entry.getKey();
int i = 0;
while (true) {
i = stringBuilder.indexOf(key, i);
if (i == -1) {
private static boolean isVarNamePart(char ch) {
return isVarNameStart(ch) || (ch >= '0' && ch <= '9');
}
private static int findVarEnd(String str, int offset) {
if (offset < str.length() - 1 && isVarNameStart(str.charAt(offset))) {
int end = offset + 1;
while (end < str.length()) {
if (!isVarNamePart(str.charAt(end))) {
break;
}
stringBuilder.replace(i, i + key.length(), entry.getValue());
end++;
}
return end;
}
return tokenize(stringBuilder.toString());
return -1;
}
public static List<String> tokenize(String str) {
return tokenize(str, null);
}
public static List<String> tokenize(String str, Map<String, String> vars) {
if (isBlank(str)) {
return new ArrayList<>();
}
if (vars == null) {
vars = Collections.emptyMap();
}
// Split the string with ' and space cleverly.
ArrayList<String> parts = new ArrayList<>();
int varEnd;
boolean hasValue = false;
StringBuilder current = new StringBuilder(str.length());
for (int i = 0; i < str.length(); ) {
char c = str.charAt(i);
if (c == '\'') {
hasValue = true;
int end = str.indexOf(c, i + 1);
if (end < 0) {
end = str.length();
}
current.append(str, i + 1, end);
i = end + 1;
} else if (c == '"') {
hasValue = true;
i++;
while (i < str.length()) {
c = str.charAt(i++);
if (c == '"') {
break;
} else if (c == '`' && i < str.length()) {
c = str.charAt(i++);
switch (c) {
case 'a':
c = '\u0007';
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'v':
c = '\u000b';
break;
}
current.append(c);
} else if (c == '$' && (varEnd = findVarEnd(str, i)) >= 0) {
String key = str.substring(i, varEnd);
String value = vars.get(key);
if (value != null) {
current.append(value);
} else {
current.append('$').append(key);
}
i = varEnd;
} else {
current.append(c);
}
}
} else if (c == ' ') {
if (hasValue) {
parts.add(current.toString());
current.setLength(0);
hasValue = false;
}
i++;
} else if (c == '$' && (varEnd = findVarEnd(str, i + 1)) >= 0) {
hasValue = true;
String key = str.substring(i + 1, varEnd);
String value = vars.get(key);
if (value != null) {
current.append(value);
} else {
current.append('$').append(key);
}
i = varEnd;
} else {
hasValue = true;
current.append(c);
i++;
}
}
if (hasValue) {
parts.add(current.toString());
}
return parts;
}
public static String parseColorEscapes(String original) {
@@ -1,40 +1,61 @@
package org.jackhuang.hmcl.util;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class TokenizerTest {
private void test(String source, String... expected) {
Assertions.assertEquals(Arrays.asList(expected), StringUtils.tokenize(source));
}
import static org.junit.jupiter.api.Assertions.assertEquals;
public final class TokenizerTest {
@Test
public void textTokenizer() {
test(
"\"C:/Program Files/Bellsoft/JDK-11/bin.java.exe\" -version \"a.b.c\" something else",
"C:/Program Files/Bellsoft/JDK-11/bin.java.exe", "-version", "a.b.c", "something", "else"
assertEquals(
Arrays.asList("C:/Program Files/Bellsoft/JDK-11/bin.java.exe", "-version", "a.b.c", "something", "else"),
StringUtils.tokenize("\"C:/Program Files/Bellsoft/JDK-11/bin.java.exe\" -version \"a.b.c\" something else")
);
test(
"\"Another\"Text something else",
"AnotherText", "something", "else"
assertEquals(
Arrays.asList("AnotherText", "something", "else"),
StringUtils.tokenize("\"Another\"Text something else")
);
test(
"Text without quote",
"Text", "without", "quote"
assertEquals(
Arrays.asList("Text", "without", "quote"),
StringUtils.tokenize("Text without quote")
);
test(
"Text with multiple spaces",
"Text", "with", "multiple", "spaces"
assertEquals(
Arrays.asList("Text", "with", "multiple", "spaces"),
StringUtils.tokenize("Text with multiple spaces")
);
test(
"Text with empty part ''",
"Text", "with", "empty", "part", ""
assertEquals(
Arrays.asList("Text", "with", "empty", "part", ""),
StringUtils.tokenize("Text with empty part ''")
);
test(
"head\"abc\\n\\\\\\\"\"end",
"headabc\n\\\"end"
assertEquals(
Arrays.asList("headabc\n`\"$end"),
StringUtils.tokenize("head\"abc`n```\"\"$end")
);
String instName = "1.20.4";
String instDir = "C:\\Program Files (x86)\\Minecraft\\";
Map<String, String> env = new HashMap<>();
env.put("INST_NAME", instName);
env.put("INST_DIR", instDir);
env.put("EMPTY", "");
assertEquals(
Arrays.asList("cd", instDir),
StringUtils.tokenize("cd $INST_DIR", env)
);
assertEquals(
Arrays.asList("Text", "with", "empty", "part", ""),
StringUtils.tokenize("Text with empty part $EMPTY", env)
);
assertEquals(
Arrays.asList("head", "1.20.4", "$UNKNOWN", instDir, "", instDir + instName + "$UNKNOWN" + instDir + "$INST_DIR\n$UNKNOWN $$"),
StringUtils.tokenize("head $INST_NAME $UNKNOWN $INST_DIR $EMPTY $INST_DIR$INST_NAME$UNKNOWN\"$INST_DIR`$INST_DIR`n$UNKNOWN $EMPTY$\"$", env)
);
}
}
+13 -13
View File
@@ -59,16 +59,16 @@ Make sure you have Java installed with JavaFX 8 at least. Liberica Full JDK 8 or
## JVM Options (for debugging)
| Parameter | Description |
|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `-Dhmcl.home=<path>` | Override HMCL directory. |
| `-Dhmcl.self_integrity_check.disable=true` | Bypass the self integrity check when checking for update. |
| `-Dhmcl.bmclapi.override=<version>` | Override API Root of BMCLAPI download provider, defaults to `https://bmclapi2.bangbang93.com`. e.g. `https://download.mcbbs.net`. |
| `-Dhmcl.font.override=<font family>` | Override font family. |
| `-Dhmcl.version.override=<version>` | Override the version number. |
| `-Dhmcl.update_source.override=<url>` | Override the update source for HMCL itself. |
| `-Dhmcl.authlibinjector.location=<path>` | Use specified authlib-injector (instead of downloading one). |
| `-Dhmcl.openjfx.repo=<maven repository url>` | Add custom Maven repository for download OpenJFX. |
| `-Dhmcl.native.encoding=<encoding>` | Override the native encoding. |
| `-Dhmcl.microsoft.auth.id=<App ID>` | Override Microsoft OAuth App ID. |
| `-Dhmcl.microsoft.auth.secret=<App Secret>` | Override Microsoft OAuth App secret. |
| Parameter | Description |
|----------------------------------------------|------------------------------------------------------------------------------------------------|
| `-Dhmcl.home=<path>` | Override HMCL directory. |
| `-Dhmcl.self_integrity_check.disable=true` | Bypass the self integrity check when checking for update. |
| `-Dhmcl.bmclapi.override=<version>` | Override API Root of BMCLAPI download provider, defaults to `https://bmclapi2.bangbang93.com`. |
| `-Dhmcl.font.override=<font family>` | Override font family. |
| `-Dhmcl.version.override=<version>` | Override the version number. |
| `-Dhmcl.update_source.override=<url>` | Override the update source for HMCL itself. |
| `-Dhmcl.authlibinjector.location=<path>` | Use specified authlib-injector (instead of downloading one). |
| `-Dhmcl.openjfx.repo=<maven repository url>` | Add custom Maven repository for download OpenJFX. |
| `-Dhmcl.native.encoding=<encoding>` | Override the native encoding. |
| `-Dhmcl.microsoft.auth.id=<App ID>` | Override Microsoft OAuth App ID. |
| `-Dhmcl.microsoft.auth.secret=<App Secret>` | Override Microsoft OAuth App secret. |
+13 -13
View File
@@ -57,16 +57,16 @@ HMCL 有着强大的跨平台能力. 它不仅支持 Windows、Linux、macOS 等
## JVM 选项 (用于调试)
| 参数 | 简介 |
|------------------------------------------------|-------------------------------------------------------------------------------------------------|
| `-Dhmcl.home=<path>` | 覆盖 HMCL 数据文件夹. |
| `-Dhmcl.self_integrity_check.disable=true` | 检查更新时绕过本体完整性检查. |
| `-Dhmcl.bmclapi.override=<version>` | 覆盖 BMCLAPI 的 API Root, 默认值为 `https://bmclapi2.bangbang93.com`. 例如 `https://download.mcbbs.net`. |
| `-Dhmcl.font.override=<font family>` | 覆盖字族. |
| `-Dhmcl.version.override=<version>` | 覆盖版本号. |
| `-Dhmcl.update_source.override=<url>` | 覆盖 HMCL 更新源. |
| `-Dhmcl.authlibinjector.location=<path>` | 使用指定的 authlib-injector (而非下载一个). |
| `-Dhmcl.openjfx.repo=<maven repository url>` | 添加用于下载 OpenJFX 的自定义 Maven 仓库 |
| `-Dhmcl.native.encoding=<encoding>` | 覆盖原生编码. |
| `-Dhmcl.microsoft.auth.id=<App ID>` | 覆盖 Microsoft OAuth App ID. |
| `-Dhmcl.microsoft.auth.secret=<App Secret>` | 覆盖 Microsoft OAuth App 密钥. |
| 参数 | 简介 |
|----------------------------------------------|----------------------------------------------------------------|
| `-Dhmcl.home=<path>` | 覆盖 HMCL 数据文件夹. |
| `-Dhmcl.self_integrity_check.disable=true` | 检查更新时绕过本体完整性检查. |
| `-Dhmcl.bmclapi.override=<version>` | 覆盖 BMCLAPI 的 API Root, 默认值为 `https://bmclapi2.bangbang93.com`. |
| `-Dhmcl.font.override=<font family>` | 覆盖字族. |
| `-Dhmcl.version.override=<version>` | 覆盖版本号. |
| `-Dhmcl.update_source.override=<url>` | 覆盖 HMCL 更新源. |
| `-Dhmcl.authlibinjector.location=<path>` | 使用指定的 authlib-injector (而非下载一个). |
| `-Dhmcl.openjfx.repo=<maven repository url>` | 添加用于下载 OpenJFX 的自定义 Maven 仓库 |
| `-Dhmcl.native.encoding=<encoding>` | 覆盖原生编码. |
| `-Dhmcl.microsoft.auth.id=<App ID>` | 覆盖 Microsoft OAuth App ID. |
| `-Dhmcl.microsoft.auth.secret=<App Secret>` | 覆盖 Microsoft OAuth App 密钥. |
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
_HMCL_PROJECT_ROOT=$(dirname "${BASH_SOURCE[0]}")
sed -i 's,//services.gradle.org/distributions/,//mirrors.cloud.tencent.com/gradle/,g' "$_HMCL_PROJECT_ROOT/gradle/wrapper/gradle-wrapper.properties"