Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4f89fac1f | ||
|
|
5262150d3c | ||
|
|
b5f56eb2b5 | ||
|
|
9a375fd0d1 | ||
|
|
6ca4aeb5a2 | ||
|
|
8ed4a9a5f2 | ||
|
|
a4578405cf | ||
|
|
73f147b7e2 | ||
|
|
5c3d735315 | ||
|
|
200621996d | ||
|
|
a912a0a07e | ||
|
|
4146ceb048 | ||
|
|
ad568d2b9f |
No files matched your search
@@ -21,6 +21,7 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.download.MaintainTask;
|
||||
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
|
||||
import org.jackhuang.hmcl.game.GameVersion;
|
||||
@@ -35,6 +36,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class InstallerController {
|
||||
private Profile profile;
|
||||
@@ -43,9 +45,6 @@ public class InstallerController {
|
||||
@FXML
|
||||
private ScrollPane scrollPane;
|
||||
@FXML private VBox contentPane;
|
||||
private String forge;
|
||||
private String liteLoader;
|
||||
private String optiFine;
|
||||
|
||||
@FXML
|
||||
private void initialize() {
|
||||
@@ -58,32 +57,22 @@ public class InstallerController {
|
||||
this.version = profile.getRepository().getResolvedVersion(versionId);
|
||||
|
||||
contentPane.getChildren().clear();
|
||||
forge = liteLoader = optiFine = null;
|
||||
|
||||
for (Library library : version.getLibraries()) {
|
||||
Consumer<InstallerItem> removeAction = x -> {
|
||||
LinkedList<Library> newList = new LinkedList<>(version.getLibraries());
|
||||
newList.remove(library);
|
||||
new MaintainTask(version.setLibraries(newList))
|
||||
.then(variables -> new VersionJsonSaveTask(profile.getRepository(), variables.get(MaintainTask.ID)))
|
||||
.with(profile.getRepository().refreshVersionsAsync())
|
||||
.with(Task.of(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId)))
|
||||
.start();
|
||||
};
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
||||
|
||||
if (library.getGroupId().equalsIgnoreCase("net.minecraftforge") && library.getArtifactId().equalsIgnoreCase("forge")) {
|
||||
contentPane.getChildren().add(new InstallerItem("Forge", library.getVersion(), removeAction));
|
||||
forge = library.getVersion();
|
||||
}
|
||||
if (library.getGroupId().equalsIgnoreCase("com.mumfrey") && library.getArtifactId().equalsIgnoreCase("liteloader")) {
|
||||
contentPane.getChildren().add(new InstallerItem("LiteLoader", library.getVersion(), removeAction));
|
||||
liteLoader = library.getVersion();
|
||||
}
|
||||
if (library.getGroupId().equalsIgnoreCase("net.optifine") && library.getArtifactId().equalsIgnoreCase("optifine")) {
|
||||
contentPane.getChildren().add(new InstallerItem("OptiFine", library.getVersion(), removeAction));
|
||||
optiFine = library.getVersion();
|
||||
}
|
||||
}
|
||||
Function<Library, Consumer<InstallerItem>> removeAction = library -> x -> {
|
||||
LinkedList<Library> newList = new LinkedList<>(version.getLibraries());
|
||||
newList.remove(library);
|
||||
new MaintainTask(version.setLibraries(newList))
|
||||
.then(variables -> new VersionJsonSaveTask(profile.getRepository(), variables.get(MaintainTask.ID)))
|
||||
.with(profile.getRepository().refreshVersionsAsync())
|
||||
.with(Task.of(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId)))
|
||||
.start();
|
||||
};
|
||||
|
||||
analyzer.getForge().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("Forge", library.getVersion(), removeAction.apply(library))));
|
||||
analyzer.getLiteLoader().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("LiteLoader", library.getVersion(), removeAction.apply(library))));
|
||||
analyzer.getOptiFine().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("OptiFine", library.getVersion(), removeAction.apply(library))));
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -93,6 +82,6 @@ public class InstallerController {
|
||||
if (!gameVersion.isPresent())
|
||||
Controllers.dialog(i18n("version.cannot_read"));
|
||||
else
|
||||
Controllers.getDecorator().startWizard(new InstallerWizardProvider(profile, gameVersion.get(), version, forge, liteLoader, optiFine));
|
||||
Controllers.getDecorator().startWizard(new InstallerWizardProvider(profile, gameVersion.get(), version));
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.event.EventBus;
|
||||
import org.jackhuang.hmcl.event.ProfileChangedEvent;
|
||||
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
||||
@@ -119,17 +120,10 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
item.setGameVersion(game);
|
||||
|
||||
StringBuilder libraries = new StringBuilder();
|
||||
for (Library library : version.getLibraries()) {
|
||||
if (library.getGroupId().equalsIgnoreCase("net.minecraftforge") && library.getArtifactId().equalsIgnoreCase("forge")) {
|
||||
libraries.append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", ""))).append("\n");
|
||||
}
|
||||
if (library.getGroupId().equalsIgnoreCase("com.mumfrey") && library.getArtifactId().equalsIgnoreCase("liteloader")) {
|
||||
libraries.append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", ""))).append("\n");
|
||||
}
|
||||
if (library.getGroupId().equalsIgnoreCase("net.optifine") && library.getArtifactId().equalsIgnoreCase("optifine")) {
|
||||
libraries.append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", ""))).append("\n");
|
||||
}
|
||||
}
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
||||
analyzer.getForge().ifPresent(library -> libraries.append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", ""))).append("\n"));
|
||||
analyzer.getLiteLoader().ifPresent(library -> libraries.append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", ""))).append("\n"));
|
||||
analyzer.getOptiFine().ifPresent(library -> libraries.append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", ""))).append("\n"));
|
||||
|
||||
item.setLibraries(libraries.toString());
|
||||
});
|
||||
@@ -236,6 +230,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
|
||||
private void loadVersions(HMCLGameRepository repository) {
|
||||
List<Node> children = repository.getVersions().parallelStream()
|
||||
.filter(version -> !version.isHidden())
|
||||
.sorted((a, b) -> VersionNumber.COMPARATOR.compare(VersionNumber.asVersion(a.getId()), VersionNumber.asVersion(b.getId())))
|
||||
.map(version -> buildNode(repository, version, () -> GameVersion.minecraftVersion(repository.getVersionJar(version.getId())).orElse("Unknown")))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -21,7 +21,9 @@ import javafx.scene.Node;
|
||||
|
||||
import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
@@ -40,16 +42,14 @@ public final class InstallerWizardProvider implements WizardProvider {
|
||||
private final String optiFine;
|
||||
|
||||
public InstallerWizardProvider(Profile profile, String gameVersion, Version version) {
|
||||
this(profile, gameVersion, version, null, null, null);
|
||||
}
|
||||
|
||||
public InstallerWizardProvider(Profile profile, String gameVersion, Version version, String forge, String liteLoader, String optiFine) {
|
||||
this.profile = profile;
|
||||
this.gameVersion = gameVersion;
|
||||
this.version = version;
|
||||
this.forge = forge;
|
||||
this.liteLoader = liteLoader;
|
||||
this.optiFine = optiFine;
|
||||
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
||||
forge = analyzer.getForge().map(Library::getVersion).orElse(null);
|
||||
liteLoader = analyzer.getLiteLoader().map(Library::getVersion).orElse(null);
|
||||
optiFine = analyzer.getOptiFine().map(Library::getVersion).orElse(null);
|
||||
}
|
||||
|
||||
public Profile getProfile() {
|
||||
|
||||
@@ -47,7 +47,7 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
||||
private final DownloadProvider downloadProvider;
|
||||
private final String libraryId;
|
||||
private final String title;
|
||||
private final Runnable callback;
|
||||
private final WizardController controller;
|
||||
|
||||
@FXML
|
||||
private JFXListView<VersionsPageItem> list;
|
||||
@@ -77,7 +77,7 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
||||
this.gameVersion = gameVersion;
|
||||
this.downloadProvider = downloadProvider;
|
||||
this.libraryId = libraryId;
|
||||
this.callback = callback;
|
||||
this.controller = controller;
|
||||
this.versionList = downloadProvider.getVersionListById(libraryId);
|
||||
|
||||
FXUtils.loadFXML(this, "/assets/fxml/download/versions.fxml");
|
||||
@@ -127,10 +127,16 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
||||
List<VersionsPageItem> items = loadVersions();
|
||||
|
||||
Platform.runLater(() -> {
|
||||
if (items.isEmpty()) {
|
||||
if (versionList.getVersions(gameVersion).isEmpty()) {
|
||||
transitionHandler.setContent(emptyPane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
} else {
|
||||
list.getItems().setAll(items);
|
||||
if (items.isEmpty()) {
|
||||
chkRelease.setSelected(true);
|
||||
chkSnapshot.setSelected(true);
|
||||
chkOld.setSelected(true);
|
||||
} else {
|
||||
list.getItems().setAll(items);
|
||||
}
|
||||
transitionHandler.setContent(centrePane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
}
|
||||
});
|
||||
@@ -160,5 +166,5 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onBack() { callback.run(); }
|
||||
private void onBack() { controller.onPrev(true); }
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2018 huangyuhui <[email protected]>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.upgrade;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Pack200;
|
||||
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.tukaani.xz.XZInputStream;
|
||||
|
||||
class HMCLDownloadTask extends FileDownloadTask {
|
||||
|
||||
private RemoteVersion.Type archiveFormat;
|
||||
|
||||
public HMCLDownloadTask(RemoteVersion version, Path target) {
|
||||
super(NetworkUtils.toURL(version.getUrl()), target.toFile(), version.getIntegrityCheck());
|
||||
archiveFormat = version.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
super.execute();
|
||||
|
||||
try {
|
||||
Path target = getFile().toPath();
|
||||
|
||||
switch (archiveFormat) {
|
||||
case JAR:
|
||||
break;
|
||||
|
||||
case PACK_XZ:
|
||||
byte[] raw = Files.readAllBytes(target);
|
||||
try (InputStream in = new XZInputStream(new ByteArrayInputStream(raw));
|
||||
JarOutputStream out = new JarOutputStream(Files.newOutputStream(target))) {
|
||||
Pack200.newUnpacker().unpack(in, out);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown format: " + archiveFormat);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
getFile().delete();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import java.util.zip.ZipFile;
|
||||
|
||||
import org.jackhuang.hmcl.util.DigestUtils;
|
||||
import org.jackhuang.hmcl.util.IOUtils;
|
||||
import org.jackhuang.hmcl.util.JarUtils;
|
||||
|
||||
/**
|
||||
* A class that checks the integrity of HMCL.
|
||||
@@ -123,8 +124,7 @@ public final class IntegrityChecker {
|
||||
}
|
||||
|
||||
private static void verifySelf() throws IOException {
|
||||
Path self = LocalVersion.current().orElseThrow(() -> new IOException("Failed to find myself"))
|
||||
.getLocation();
|
||||
Path self = JarUtils.thisJar().orElseThrow(() -> new IOException("Failed to find current HMCL location"));
|
||||
requireVerifiedJar(self);
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2018 huangyuhui <[email protected]>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.upgrade;
|
||||
|
||||
import org.jackhuang.hmcl.Launcher;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.JarUtils;
|
||||
import org.tukaani.xz.XZInputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Pack200;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
|
||||
/**
|
||||
* A class used to manage the local HMCL repository.
|
||||
*
|
||||
* @author yushijinhun
|
||||
*/
|
||||
final class LocalRepository {
|
||||
private LocalRepository() {}
|
||||
|
||||
private static Path localStorage = Launcher.HMCL_DIRECTORY.toPath().resolve("hmcl.jar");
|
||||
private static Path hmclVersionJson = Launcher.HMCL_DIRECTORY.toPath().resolve("hmclver.json");
|
||||
|
||||
/**
|
||||
* Gets the current stored executable in local repository.
|
||||
*/
|
||||
public static Optional<LocalVersion> getStored() {
|
||||
if (!Files.isRegularFile(localStorage)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(localStorage)
|
||||
.flatMap(JarUtils::getImplementationVersion)
|
||||
.map(version -> new LocalVersion(version, localStorage));
|
||||
}
|
||||
|
||||
private static void writeToStorage(Path source, boolean checkHeaders) throws IOException {
|
||||
IntegrityChecker.requireVerifiedJar(source);
|
||||
Files.createDirectories(localStorage.getParent());
|
||||
if (checkHeaders) {
|
||||
ExecutableHeaderHelper.copyWithoutHeader(source, localStorage);
|
||||
} else {
|
||||
Files.copy(source, localStorage, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
Optional<LocalVersion> stored = getStored();
|
||||
if (stored.isPresent()) {
|
||||
Map<String, String> json = new HashMap<>();
|
||||
json.put("ver", stored.get().getVersion());
|
||||
json.put("loc", stored.get().getLocation().toString());
|
||||
FileUtils.writeText(hmclVersionJson.toFile(), Constants.GSON.toJson(json));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task that downloads the given version to local repository.
|
||||
*/
|
||||
public static FileDownloadTask downloadFromRemote(RemoteVersion version) throws IOException {
|
||||
Path downloaded = Files.createTempFile("hmcl-update-", null);
|
||||
return new FileDownloadTask(new URL(version.getUrl()), downloaded.toFile(), version.getIntegrityCheck()) {
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
super.execute();
|
||||
|
||||
try {
|
||||
switch (version.getType()) {
|
||||
case JAR:
|
||||
writeToStorage(downloaded, false);
|
||||
break;
|
||||
|
||||
case PACK_XZ:
|
||||
Path unpacked = Files.createTempFile("hmcl-update-unpack-", null);
|
||||
try {
|
||||
try (InputStream in = new XZInputStream(Files.newInputStream(downloaded));
|
||||
JarOutputStream out = new JarOutputStream(Files.newOutputStream(unpacked))) {
|
||||
Pack200.newUnpacker().unpack(in, out);
|
||||
}
|
||||
writeToStorage(unpacked, false);
|
||||
} finally {
|
||||
Files.deleteIfExists(unpacked);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown type: " + version.getType());
|
||||
}
|
||||
} finally {
|
||||
Files.deleteIfExists(downloaded);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the current HMCL executable to local repository.
|
||||
*/
|
||||
public static void downloadFromCurrent() {
|
||||
Optional<LocalVersion> current = LocalVersion.current();
|
||||
if (current.isPresent()) {
|
||||
Path currentPath = current.get().getLocation();
|
||||
if (!Files.isRegularFile(currentPath)) {
|
||||
LOG.warning("Failed to download " + current.get() + ", it isn't a file");
|
||||
return;
|
||||
}
|
||||
if (isSameAsLocalStorage(currentPath)) {
|
||||
LOG.warning("Trying to download from self, ignored");
|
||||
return;
|
||||
}
|
||||
LOG.info("Downloading " + current.get());
|
||||
try {
|
||||
writeToStorage(current.get().getLocation(), true);
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to download " + current.get(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the executable stored in local repository to the given location.
|
||||
*/
|
||||
public static void applyTo(Path target) throws IOException {
|
||||
if (isSameAsLocalStorage(target)) {
|
||||
throw new IOException("Cannot apply update to self");
|
||||
}
|
||||
|
||||
LOG.info("Applying update to " + target);
|
||||
IntegrityChecker.requireVerifiedJar(localStorage);
|
||||
ExecutableHeaderHelper.copyWithHeader(localStorage, target);
|
||||
}
|
||||
|
||||
private static boolean isSameAsLocalStorage(Path path) {
|
||||
return path.toAbsolutePath().equals(localStorage.toAbsolutePath());
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2018 huangyuhui <[email protected]>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.upgrade;
|
||||
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.util.JarUtils;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
class LocalVersion {
|
||||
|
||||
public static Optional<LocalVersion> current() {
|
||||
return JarUtils.thisJar().map(path -> new LocalVersion(Metadata.VERSION, path));
|
||||
}
|
||||
|
||||
private String version;
|
||||
private Path location;
|
||||
|
||||
public LocalVersion(String version, Path location) {
|
||||
this.version = version;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public Path getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + version + " at " + location + "]";
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,10 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.upgrade;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.checkFxUserThread;
|
||||
import static org.jackhuang.hmcl.util.IntVersionNumber.isIntVersionNumber;
|
||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
import static org.jackhuang.hmcl.util.VersionNumber.asVersion;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -30,6 +29,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -45,9 +45,12 @@ import org.jackhuang.hmcl.task.TaskExecutor;
|
||||
import org.jackhuang.hmcl.ui.Controllers;
|
||||
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageBox;
|
||||
import org.jackhuang.hmcl.util.JarUtils;
|
||||
import org.jackhuang.hmcl.util.JavaVersion;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
@@ -58,9 +61,7 @@ public final class UpdateHandler {
|
||||
* @return whether to exit
|
||||
*/
|
||||
public static boolean processArguments(String[] args) {
|
||||
if (!isIntVersionNumber(Metadata.VERSION)) {
|
||||
return false;
|
||||
}
|
||||
breakForceUpdateFeature();
|
||||
|
||||
if (isNestedApplication()) {
|
||||
// updated from old versions
|
||||
@@ -88,33 +89,69 @@ public final class UpdateHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
Optional<LocalVersion> local = LocalRepository.getStored();
|
||||
if (local.isPresent()) {
|
||||
int difference = asVersion(local.get().getVersion()).compareTo(asVersion(Metadata.VERSION));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (difference < 0) {
|
||||
LocalRepository.downloadFromCurrent();
|
||||
public static void updateFrom(RemoteVersion version) {
|
||||
checkFxUserThread();
|
||||
|
||||
} else if (difference > 0) {
|
||||
Optional<LocalVersion> current = LocalVersion.current();
|
||||
if (current.isPresent() && IntegrityChecker.isSelfVerified()) {
|
||||
try {
|
||||
requestUpdate(local.get().getLocation(), current.get().getLocation());
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to update from local repository", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
LocalRepository.downloadFromCurrent();
|
||||
Path downloaded;
|
||||
try {
|
||||
downloaded = Files.createTempFile("hmcl-update-", ".jar");
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to create temp file", e);
|
||||
return;
|
||||
}
|
||||
|
||||
return false;
|
||||
Task task = new HMCLDownloadTask(version, downloaded);
|
||||
|
||||
TaskExecutor executor = task.executor();
|
||||
Region dialog = Controllers.taskDialog(executor, i18n("message.downloading"), "", null);
|
||||
thread(() -> {
|
||||
boolean success = executor.test();
|
||||
Platform.runLater(() -> dialog.fireEvent(new DialogCloseEvent()));
|
||||
|
||||
if (success) {
|
||||
try {
|
||||
if (!IntegrityChecker.isSelfVerified()) {
|
||||
throw new IOException("Current JAR is not verified");
|
||||
}
|
||||
|
||||
requestUpdate(downloaded, getCurrentLocation());
|
||||
System.exit(0);
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to update to " + version, e);
|
||||
Platform.runLater(() -> Controllers.dialog(StringUtils.getStackTrace(e), i18n("update.failed"), MessageBox.ERROR_MESSAGE));
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
Throwable e = task.getLastException();
|
||||
LOG.log(Level.WARNING, "Failed to update to " + version, e);
|
||||
Platform.runLater(() -> Controllers.dialog(e.toString(), i18n("update.failed"), MessageBox.ERROR_MESSAGE));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void applyUpdate(Path target) throws IOException {
|
||||
LOG.info("Applying update to " + target);
|
||||
|
||||
Path self = getCurrentLocation();
|
||||
IntegrityChecker.requireVerifiedJar(self);
|
||||
ExecutableHeaderHelper.copyWithHeader(self, target);
|
||||
|
||||
Optional<Path> newFilename = tryRename(target, Metadata.VERSION);
|
||||
if (newFilename.isPresent()) {
|
||||
LOG.info("Move " + target + " to " + newFilename.get());
|
||||
try {
|
||||
Files.move(target, newFilename.get());
|
||||
target = newFilename.get();
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to move target", e);
|
||||
}
|
||||
}
|
||||
|
||||
startJava(target);
|
||||
}
|
||||
|
||||
private static void requestUpdate(Path updateTo, Path self) throws IOException {
|
||||
@@ -122,28 +159,6 @@ public final class UpdateHandler {
|
||||
startJava(updateTo, "--apply-to", self.toString());
|
||||
}
|
||||
|
||||
private static void applyUpdate(Path target) throws IOException {
|
||||
LocalRepository.applyTo(target);
|
||||
|
||||
Optional<String> newVersion = LocalRepository.getStored().map(LocalVersion::getVersion);
|
||||
if (newVersion.isPresent()) {
|
||||
Optional<Path> newFilename = tryRename(target, newVersion.get());
|
||||
if (newFilename.isPresent()) {
|
||||
LOG.info("Move " + target + " to " + newFilename.get());
|
||||
try {
|
||||
Files.move(target, newFilename.get());
|
||||
target = newFilename.get();
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to move target", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG.warning("Failed to find local repository");
|
||||
}
|
||||
|
||||
startJava(target);
|
||||
}
|
||||
|
||||
private static void startJava(Path jar, String... appArgs) throws IOException {
|
||||
List<String> commandline = new ArrayList<>();
|
||||
commandline.add(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath());
|
||||
@@ -159,49 +174,6 @@ public final class UpdateHandler {
|
||||
.start();
|
||||
}
|
||||
|
||||
public static void updateFrom(RemoteVersion version) {
|
||||
checkFxUserThread();
|
||||
|
||||
Task task;
|
||||
try {
|
||||
task = LocalRepository.downloadFromRemote(version);
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to create upgrade download task", e);
|
||||
return;
|
||||
}
|
||||
TaskExecutor executor = task.executor();
|
||||
Region dialog = Controllers.taskDialog(executor, i18n("message.downloading"), "", null);
|
||||
thread(() -> {
|
||||
boolean success = executor.test();
|
||||
Platform.runLater(() -> dialog.fireEvent(new DialogCloseEvent()));
|
||||
if (success) {
|
||||
try {
|
||||
Optional<LocalVersion> current = LocalVersion.current();
|
||||
Optional<LocalVersion> stored = LocalRepository.getStored();
|
||||
if (!current.isPresent()) {
|
||||
throw new IOException("Failed to find current HMCL location");
|
||||
}
|
||||
if (!stored.isPresent()) {
|
||||
throw new IOException("Failed to find local repository, this shouldn't happen");
|
||||
}
|
||||
if (!IntegrityChecker.isSelfVerified()) {
|
||||
throw new IOException("Current JAR is not verified");
|
||||
}
|
||||
requestUpdate(stored.get().getLocation(), current.get().getLocation());
|
||||
System.exit(0);
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to update to " + version, e);
|
||||
Platform.runLater(() -> Controllers.dialog(StringUtils.getStackTrace(e), i18n("update.failed"), MessageBox.ERROR_MESSAGE));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Throwable e = task.getLastException();
|
||||
LOG.log(Level.WARNING, "Failed to update to " + version, e);
|
||||
Platform.runLater(() -> Controllers.dialog(e.toString(), i18n("update.failed"), MessageBox.ERROR_MESSAGE));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Optional<Path> tryRename(Path path, String newVersion) {
|
||||
String filename = path.getFileName().toString();
|
||||
Matcher matcher = Pattern.compile("^(?<prefix>[hH][mM][cC][lL][.-])(?<version>\\d+(?:\\.\\d+)*)(?<suffix>\\.[^.]+)$").matcher(filename);
|
||||
@@ -214,6 +186,10 @@ public final class UpdateHandler {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static Path getCurrentLocation() throws IOException {
|
||||
return JarUtils.thisJar().orElseThrow(() -> new IOException("Failed to find current HMCL location"));
|
||||
}
|
||||
|
||||
// ==== support for old versions ===
|
||||
private static void performMigration() throws IOException {
|
||||
LOG.info("Migrating from old versions");
|
||||
@@ -221,17 +197,7 @@ public final class UpdateHandler {
|
||||
Path location = getParentApplicationLocation()
|
||||
.orElseThrow(() -> new IOException("Failed to get parent application location"));
|
||||
|
||||
Optional<LocalVersion> local = LocalRepository.getStored();
|
||||
if (!local.isPresent() ||
|
||||
asVersion(local.get().getVersion()).compareTo(asVersion(Metadata.VERSION)) < 0) {
|
||||
LocalRepository.downloadFromCurrent();
|
||||
}
|
||||
local = LocalRepository.getStored();
|
||||
if (!local.isPresent()) {
|
||||
throw new IOException("Failed to find local repository");
|
||||
}
|
||||
|
||||
requestUpdate(local.get().getLocation(), location);
|
||||
requestUpdate(getCurrentLocation(), location);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,7 +231,7 @@ public final class UpdateHandler {
|
||||
}
|
||||
|
||||
private static boolean isFirstLaunchAfterUpgrade() {
|
||||
Optional<Path> currentPath = LocalVersion.current().map(LocalVersion::getLocation);
|
||||
Optional<Path> currentPath = JarUtils.thisJar();
|
||||
if (currentPath.isPresent()) {
|
||||
Path updated = Launcher.HMCL_DIRECTORY.toPath().resolve("HMCL-" + Metadata.VERSION + ".jar");
|
||||
if (currentPath.get().toAbsolutePath().equals(updated.toAbsolutePath())) {
|
||||
@@ -274,5 +240,21 @@ public final class UpdateHandler {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void breakForceUpdateFeature() {
|
||||
try {
|
||||
Path hmclVersionJson = Launcher.HMCL_DIRECTORY.toPath().resolve("hmclver.json");
|
||||
if (Files.isRegularFile(hmclVersionJson)) {
|
||||
Map<?, ?> content = new Gson().fromJson(new String(Files.readAllBytes(hmclVersionJson), UTF_8), Map.class);
|
||||
Object ver = content.get("ver");
|
||||
if (ver instanceof String && ((String) ver).startsWith("3.")) {
|
||||
Files.delete(hmclVersionJson);
|
||||
LOG.info("Successfully broke the force update feature");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to break the force update feature", e);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
}
|
||||
@@ -319,7 +319,7 @@ update.checking=Checking for updates
|
||||
update.failed=Failed to perform upgrade
|
||||
update.found=Update Available!
|
||||
update.newest_version=Latest version: %s
|
||||
update.note=Development version contains more functionality and bug fixes as well as more possible bugs. And this will affect all HMCL installations in your computer.
|
||||
update.note=Development version contains more functionality and bug fixes as well as more possible bugs.
|
||||
update.latest=This is latest Version.
|
||||
update.no_browser=Cannot open any browser. The link has been copied to the clipboard. Paste it to a browser address bar to update.
|
||||
update.tooltip=Update
|
||||
|
||||
@@ -14,336 +14,336 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
#
|
||||
#author: huangyuhui
|
||||
# author: huangyuhui
|
||||
about.copyright=版權
|
||||
about.copyright.statement=Copyright (c) 2018 huangyuhui.
|
||||
about.author=作者
|
||||
about.author.statement=huanghongxun ([email protected])
|
||||
about.thanks_to=鳴謝
|
||||
about.thanks_to.statement=bangbang93 (BMCLAPI, https://bmclapi2.bangbang93.com/)\ngamerteam (默認背景圖)\n所有通過 Issues、Pull Requests 等方式參與本項目的貢獻者
|
||||
about.thanks_to.statement=bangbang93 (BMCLAPI, https://bmclapi2.bangbang93.com/)\ngamerteam (預設背景圖)\n所有通過 Issues、Pull Requests 等方式參與本項目的貢獻者
|
||||
about.dependency=依賴
|
||||
# 由於篇幅限制,僅列出第一作者
|
||||
about.dependency.statement=JFoenix (Shadi Shaheen, Apache 2.0)\nGson (Google, Apache 2.0)\nApache Commons Compress (ASF, Apache 2.0)\nXZ for Java (Lasse Collin, Public Domain)\nfx-gson (Joffrey Bion, MIT)
|
||||
about.claim=免責聲明
|
||||
about.claim.statement=Minecraft 版權歸 Mojang AB 所有,使用本軟件產生的版權問題,軟件製作方概不負責。請支持正版。
|
||||
about.claim.statement=Minecraft 版權歸 Mojang AB 所有,使用本軟體產生的版權問題,軟體製作方概不負責。請支援正版。
|
||||
about.open_source=開源
|
||||
about.open_source.statement=GPL v3 (https://github.com/huanghongxun/HMCL/)
|
||||
|
||||
account=賬戶
|
||||
account=帳戶
|
||||
account.character=角色
|
||||
account.choose=選擇一個角色
|
||||
account.create=新建賬戶
|
||||
account.email=郵箱
|
||||
account.failed.connect_authentication_server=無法連接認證服務器,可能是網絡問題
|
||||
account.failed.connect_injector_server=無法連接認證服務器,可能是網絡故障或 URL 輸入錯誤
|
||||
account.failed.invalid_credentials=您的用戶名或密碼錯誤,或者登錄次數過多被暫時禁止登錄,請稍後再試
|
||||
account.create=建立帳戶
|
||||
account.email=電子信箱
|
||||
account.failed.connect_authentication_server=無法連接認證伺服器,可能是網路問題
|
||||
account.failed.connect_injector_server=無法連接認證伺服器,可能是網路故障或 URL 輸入錯誤
|
||||
account.failed.invalid_credentials=您的使用者名稱或密碼錯誤,或者登入次數過多被暫時禁止登入,請稍後再試
|
||||
account.failed.invalid_password=無效的密碼
|
||||
account.failed.invalid_token=請嘗試登出並重新輸入密碼登錄
|
||||
account.failed.invalid_token=請嘗試登出並重新輸入密碼登入
|
||||
account.failed.no_character=該帳號沒有角色
|
||||
account.failed.server_response_malformed=這個服務器不是合法的登錄驗證服務器
|
||||
account.injector.add=添加認證服務器
|
||||
account.injector.manage=管理認證服務器
|
||||
account.injector.manage.title=認證服務器
|
||||
account.injector.http=警告:此服務器使用不安全的 HTTP 協議,您的密碼在登錄時會被明文傳輸。
|
||||
account.injector.server=認證服務器
|
||||
account.injector.server_url=服務器地址
|
||||
account.injector.server_name=服務器名稱
|
||||
account.methods=登錄方式
|
||||
account.methods.authlib_injector=authlib-injector 登錄
|
||||
account.failed.server_response_malformed=這個伺服器不是合法的登入驗證伺服器
|
||||
account.injector.add=新增認證伺服器
|
||||
account.injector.manage=管理認證伺服器
|
||||
account.injector.manage.title=認證伺服器
|
||||
account.injector.http=警告:此伺服器使用不安全的 HTTP 協議,您的密碼在登入時會被明文傳輸。
|
||||
account.injector.server=認證伺服器
|
||||
account.injector.server_url=伺服器位址
|
||||
account.injector.server_name=伺服器名稱
|
||||
account.methods=登入方式
|
||||
account.methods.authlib_injector=authlib-injector 登入
|
||||
account.methods.offline=離線模式
|
||||
account.methods.yggdrasil=正版登錄
|
||||
account.missing=沒有賬戶
|
||||
account.methods.yggdrasil=正版登入
|
||||
account.missing=沒有帳戶
|
||||
account.password=密碼
|
||||
account.username=用戶名
|
||||
account.username=使用者名稱
|
||||
|
||||
archive.author=作者
|
||||
archive.game_version=遊戲版本
|
||||
archive.version=版本
|
||||
|
||||
assets.download=下載資源
|
||||
assets.download_all=檢查資源文件完整性
|
||||
assets.download_all=驗證資源檔案完整性
|
||||
|
||||
button.cancel=取消
|
||||
button.clear=清除
|
||||
button.delete=刪除
|
||||
button.edit=修改
|
||||
button.edit=編輯
|
||||
button.install=安裝
|
||||
button.no=否
|
||||
button.ok=確定
|
||||
button.refresh=刷新
|
||||
button.save=保存
|
||||
button.refresh=重新整理
|
||||
button.save=儲存
|
||||
button.yes=是
|
||||
|
||||
color.recent=推薦
|
||||
color.custom=自定義顏色
|
||||
color.custom=自訂顏色
|
||||
|
||||
crash.NoClassDefFound=請確認 HMCL 本體是否完整,或更新您的 Java。
|
||||
crash.user_fault=您的系統或 Java 環境可能安裝不當導致本軟件崩潰,請檢查您的 Java 環境或您的電腦!可以嘗試重新安裝 Java。
|
||||
crash.user_fault=您的系統或 Java 環境可能安裝不當導致本軟體崩潰,請檢查您的 Java 環境或您的電腦!可以嘗試重新安裝 Java。
|
||||
|
||||
download=下載
|
||||
download.BMCL=BMCLAPI(bangbang93,https://bmclapi2.bangbang93.com/)
|
||||
download.failed=下載失敗
|
||||
download.failed.empty=沒有可供安裝的版本,點擊此處返回。
|
||||
download.failed.refresh=加載版本列表失敗,點擊此處重試。
|
||||
download.mojang=官方
|
||||
download.failed.refresh=載入版本列表失敗,點擊此處重試。
|
||||
download.mojang=官方伺服器
|
||||
|
||||
extension.bat=Windows 腳本
|
||||
extension.mod=模組文件
|
||||
extension.png=圖片文件
|
||||
extension.mod=模組檔案
|
||||
extension.png=圖片檔案
|
||||
extension.sh=Bash 腳本
|
||||
|
||||
fatal.missing_javafx=JavaFX 缺失。\n如果您使用的是 Java 11 或更高版本,請降級到 Java 8 或 10。\n如果您使用的是 OpenJDK,請確保其包含 OpenJFX。
|
||||
fatal.missing_dst_root_ca_x3=當前 Java 平台缺少 DST Root CA X3 證書。\n您依然可以使用 HMCL,但將無法連接到部分站點(如使用 Let's Encrypt 證書的站點),這可能會使 HMCL 無法正常工作。\n請將您的 Java 升級到 8u101 以上以解決此問題。
|
||||
fatal.config_loading_failure=HMCL 無法加載配置文件。\n請確保 HMCL 對 "%s" 目錄及該目錄下的文件擁有讀寫權限。
|
||||
fatal.migration_requires_manual_reboot=HMCL 即將完成升級,請重新打開 HMCL。
|
||||
fatal.apply_update_failure=我們很抱歉 HMCL 無法自動完成升級,因為出現了一些問題。\n但你依然可以從 %s 處手動下載 HMCL 來完成升級。\n請考慮向我們反饋該問題。
|
||||
fatal.missing_javafx=找不到 JavaFX。\n如果您使用的是 Java 11 或更高版本,請降級到 Java 8 或 10。\n如果您使用的是 OpenJDK,請確保其包含 OpenJFX。
|
||||
fatal.missing_dst_root_ca_x3=目前的 Java 平台缺少 DST Root CA X3 憑證。\n您依然可以使用 HMCL,但將無法連線到部分網站(如使用 Lets Encrypt 證書的站點),這可能會使 HMCL 無法正常運作。\n請將您的 Java 升級到 8u101 以上以解決此問題。
|
||||
fatal.config_loading_failure=HMCL 無法載入設定檔案。\n請確保 HMCL 對 "%s" 目錄及該目錄下的檔案擁有讀寫權限。
|
||||
fatal.migration_requires_manual_reboot=HMCL 即將升級完成,請重新打開 HMCL。
|
||||
fatal.apply_update_failure=我們很抱歉 HMCL 無法自動完成升級程序,因為出現了一些問題。\n但你依然可以從 %s 處手動下載 HMCL 來完成升級。\n請考慮向我們回報該問題。
|
||||
|
||||
folder.config=配置文件夾
|
||||
folder.coremod=核心MOD文件夾
|
||||
folder.game=遊戲文件夾
|
||||
folder.mod=MOD文件夾
|
||||
folder.resourcepacks=資源包文件夾
|
||||
folder.saves=存檔文件夾
|
||||
folder.screenshots=截圖文件夾
|
||||
folder.config=設定資料夾
|
||||
folder.coremod=核心 MOD 模組資料夾
|
||||
folder.game=遊戲資料夾
|
||||
folder.mod=MOD 模組資料夾
|
||||
folder.resourcepacks=資源包資料夾
|
||||
folder.saves=遊戲存檔資料夾
|
||||
folder.screenshots=截圖資料夾
|
||||
|
||||
general.prompt.empty=(無)
|
||||
general.prompt.empty=(無)
|
||||
|
||||
input.email=用戶名必須是郵箱
|
||||
input.email=「使用者名稱」必須是電子信箱格式
|
||||
input.number=必須是數字
|
||||
input.not_empty=必填項
|
||||
input.url=必須是合法的鏈接
|
||||
input.not_empty=必填
|
||||
input.url=必須為有效連結
|
||||
|
||||
install=添加遊戲
|
||||
install=新增遊戲
|
||||
install.failed=安裝失敗
|
||||
install.installer.choose=選擇 %s 版本
|
||||
install.installer.forge=Forge
|
||||
install.installer.game=遊戲
|
||||
install.installer.install=安裝 %s
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=暫不安裝 %s,可以點擊此處安裝
|
||||
install.installer.not_installed=暫時不安裝 %s,可以點擊此處安裝
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.version=%s 版本
|
||||
install.modpack=安裝整合包
|
||||
install.new_game=安裝新遊戲版本
|
||||
install.new_game.already_exists=此版本已經存在,請換一個名字
|
||||
install.new_game.current_game_version=當前遊戲版本
|
||||
install.new_game.current_game_version=目前遊戲版本
|
||||
install.select=請選擇安裝方式
|
||||
install.success=安裝成功
|
||||
|
||||
lang=繁體中文
|
||||
lang=正體中文
|
||||
lang.default=跟隨系統語言
|
||||
|
||||
launch.advice.different_platform=您的系統是 64 位的但是 Java 是 32 位的,推薦您安裝 64 位 Java。
|
||||
launch.advice.java8_1_13=Minecraft 1.13 只支持 Java 8 或更高版本,請使用 Java 8 或最新版本。
|
||||
launch.advice.java8_51_1_13=舊於 1.8.0_51 的 Java 可能會導致 Minecraft 1.13 崩潰。建議您到 https://java.com 安裝最新版的Java 8。
|
||||
launch.advice.java9=不高於 1.13 的安裝了 Mod 的 Minecraft 不支持 Java 9 或更高版本,請使用 Java 8。
|
||||
launch.advice.newer_java=檢測到您未使用 Java 8 及更新版本,Java 8 能使遊戲更流暢而且 Minecraft 1.12 及更新版本和很多 Mod 強制需要需要 Java 8。
|
||||
launch.advice.not_enough_space=您設置的內存大小過大,由於超過了系統內存大小 %dMB,所以可能影響遊戲體驗或無法啓動遊戲,啓動器仍會嘗試啓動。
|
||||
launch.advice.too_large_memory_for_32bit=您設置的內存大小過大,由於可能超過了 32 位 Java 的內存分配限制,所以可能無法啓動遊戲,請將內存調至 1024MB 或更小,啓動器仍會嘗試啓動。
|
||||
launch.failed=啓動失敗
|
||||
launch.failed.cannot_create_jvm=截獲到無法創建 Java 虛擬機,可能是 Java 參數有問題,可以在設置中開啓無參數模式啓動。
|
||||
launch.failed.creating_process=啓動失敗,在創建新進程時發生錯誤,可能是 Java 路徑錯誤。
|
||||
launch.failed.decompressing_natives=未能解壓遊戲本地庫。
|
||||
launch.failed.download_library=未能下载游戏依赖 %s.
|
||||
launch.failed.executable_permission=未能爲啓動文件添加執行權限。
|
||||
launch.failed.exited_abnormally=遊戲非正常退出,請查看日志文件,或聯繫他人尋求幫助。
|
||||
launch.advice.different_platform=您的系統為 64 位元,但是 Java 是 32 位元,建議您安裝 64 位 Java。
|
||||
launch.advice.java8_1_13=Minecraft 1.13 只支援 Java 8 或更高版本,請使用 Java 8 或最新版本。
|
||||
launch.advice.java8_51_1_13=低於 1.8.0_51 的 Java 版本可能會導致 Minecraft 1.13 崩潰。建議您到 https://java.com 安裝最新版的 Java 8。
|
||||
launch.advice.java9=低於 (包含) 1.13 的有安裝 Mod Minecraft 版本 不支援 Java 9 或更高版本,請使用 Java 8。
|
||||
launch.advice.newer_java=偵測到您未使用 Java 8 及更新版本,Java 8 能使遊戲更順暢而且 Minecraft 1.12 及更新版本和很多 Mod 強制需要 Java 8 版本。
|
||||
launch.advice.not_enough_space=您設定的記憶體大小過大,由於超過了系統記憶體大小 %dMB,所以可能影響遊戲體驗或無法啟動遊戲。啟動器仍會嘗試啟動。
|
||||
launch.advice.too_large_memory_for_32bit=您設定的記憶體大小過大,由於可能超過了 32 位元 Java 的記憶體分配限制,所以可能無法啟動遊戲,請將記憶體調至低於 1024MB 的值。啟動器仍會嘗試啟動。
|
||||
launch.failed=啟動失敗
|
||||
launch.failed.cannot_create_jvm=偵測到無法建立 Java 虛擬機,可能是 Java 參數有問題。可以在設定中開啟無參數模式啟動。
|
||||
launch.failed.creating_process=啟動失敗,在建立新執行程序時發生錯誤。可能是 Java 路徑錯誤。
|
||||
launch.failed.decompressing_natives=無法解壓縮遊戲資源庫。
|
||||
launch.failed.download_library=無法下載遊戲依賴 %s.
|
||||
launch.failed.executable_permission=無法為啟動檔案新增執行權限。
|
||||
launch.failed.exited_abnormally=遊戲非正常退出,請查看記錄檔案,或聯絡他人尋求幫助。
|
||||
launch.state.dependencies=正在處理遊戲依賴
|
||||
launch.state.done=啓動完成
|
||||
launch.state.logging_in=登錄中
|
||||
launch.state.modpack=正在下載必要文件
|
||||
launch.state.waiting_launching=等待遊戲啓動
|
||||
launch.wrong_javadir=錯誤的 Java 路徑,將自動重置爲默認 Java 路徑。
|
||||
launch.state.done=啟動完成
|
||||
launch.state.logging_in=登入中
|
||||
launch.state.modpack=正在下載必要檔案
|
||||
launch.state.waiting_launching=等待遊戲啟動
|
||||
launch.wrong_javadir=錯誤的 Java 路徑,將自動重設為預設 Java 路徑。
|
||||
|
||||
launcher=啓動器
|
||||
launcher.background=背景地址
|
||||
launcher=啟動器
|
||||
launcher.background=背景位址
|
||||
launcher.background.choose=選擇背景路徑
|
||||
launcher.background.default=默認(自動檢索啓動器同目錄下的 background.png/jpg 及 bg 文件夾內的圖片)
|
||||
launcher.common_directory=公共文件夾
|
||||
launcher.common_directory.choose=選擇公共文件夾
|
||||
launcher.common_directory.default=默認
|
||||
launcher.common_directory.disabled=禁用
|
||||
launcher.contact=聯繫我們
|
||||
launcher.crash=Hello Minecraft! Launcher 遇到了無法處理的錯誤,請複製下列內容並通過 MCBBS、貼吧、GitHub 或 Minecraft Forum 反饋 bug。
|
||||
launcher.crash_out_dated=Hello Minecraft! Launcher 遇到了無法處理的錯誤,已檢測到您的啓動器不是最新版本,請更新後再試!
|
||||
launcher.background.default=預設(自動尋找啟動器同目錄下的 background.png/jpg 及 bg 資料夾內的圖片)
|
||||
launcher.common_directory=公共資料夾
|
||||
launcher.common_directory.choose=選擇公共資料夾
|
||||
launcher.common_directory.default=預設
|
||||
launcher.common_directory.disabled=停用
|
||||
launcher.contact=聯絡我們
|
||||
launcher.crash=Hello Minecraft! Launcher 遇到了無法處理的錯誤,請複製下列內容並透過 MCBBS、貼吧、GitHub 或 Minecraft Forum 回報 bug。
|
||||
launcher.crash_out_dated=Hello Minecraft! Launcher 遇到了無法處理的錯誤,已偵測到您的啟動器不是最新版本,請更新後重試!
|
||||
launcher.update_java=請更新您的 Java
|
||||
|
||||
login.empty_username=你還未設置用戶名!
|
||||
login.empty_username=你還未設定使用者名稱!
|
||||
login.enter_password=請輸入您的密碼
|
||||
|
||||
logwindow.show_lines=顯示行數
|
||||
logwindow.terminate_game=結束遊戲進程
|
||||
logwindow.title=日誌
|
||||
logwindow.terminate_game=結束遊戲執行程序
|
||||
logwindow.title=記錄
|
||||
|
||||
main_page=主頁
|
||||
main_page=首頁
|
||||
|
||||
message.confirm=提示
|
||||
message.doing=請耐心等待
|
||||
message.downloading=正在下載...
|
||||
message.downloading=正在下載…
|
||||
message.error=錯誤
|
||||
message.info=提示
|
||||
message.success=已完成
|
||||
message.info=資訊
|
||||
message.success=完成
|
||||
message.unknown=未知
|
||||
message.warning=警告
|
||||
|
||||
modpack=整合包
|
||||
modpack.choose=選擇要安裝的遊戲整合包文件
|
||||
modpack.desc=描述你要製作的整合包,比如整合包注意事項和更新記錄,支持 Markdown(圖片請用網絡圖)。
|
||||
modpack.enter_name=給遊戲起個你喜歡的名字
|
||||
modpack.export=導出整合包
|
||||
modpack.choose=選擇要安裝的遊戲整合包檔案
|
||||
modpack.desc=描述你要製作的整合包,比如整合包注意事項和更新記錄,支援 Markdown(圖片請上傳至網路)。
|
||||
modpack.enter_name=給遊戲取個你喜歡的名字
|
||||
modpack.export=匯出整合包
|
||||
modpack.files.blueprints=BuildCraft 藍圖
|
||||
modpack.files.config=Mod 配置文件
|
||||
modpack.files.dumps=NEI 調試輸出
|
||||
modpack.files.liteconfig=Mod 配置文件
|
||||
modpack.files.mods=Mod
|
||||
modpack.files.mods.voxelmods=VoxelMods 配置,如小地圖
|
||||
modpack.files.config=Mod 模組設定檔案
|
||||
modpack.files.dumps=NEI 調校輸出
|
||||
modpack.files.liteconfig=Mod 模組設定檔案
|
||||
modpack.files.mods=Mod 模組
|
||||
modpack.files.mods.voxelmods=VoxelMods 設定,如小地圖
|
||||
modpack.files.options_txt=遊戲設定
|
||||
modpack.files.optionsshaders_txt=光影設定
|
||||
modpack.files.resourcepacks=資源包(材質包)
|
||||
modpack.files.resourcepacks=資源包 (材質包)
|
||||
modpack.files.saves=遊戲存檔
|
||||
modpack.files.scripts=MineTweaker 配置
|
||||
modpack.files.servers_dat=多人遊戲服務器列表
|
||||
modpack.install=安裝%s整合包
|
||||
modpack.files.scripts=MineTweaker 設定
|
||||
modpack.files.servers_dat=多人遊戲伺服器列表
|
||||
modpack.install=安裝 %s 整合包
|
||||
modpack.installing=正在安裝整合包
|
||||
modpack.introduction=支持 Curse、MultiMC、HMCL、MCBBS 整合包。
|
||||
modpack.invalid=無效的整合包升級文件,可能是下載時出現問題。
|
||||
modpack.mismatched_type=整合包類型不匹配,當前遊戲是 %s 整合包,但是提供的整合包更新文件是 %s 整合包。
|
||||
modpack.introduction=支援 Curse、MultiMC、HMCL、MCBBS 整合包。
|
||||
modpack.invalid=無效的整合包升級檔案,可能是下載時出現問題。
|
||||
modpack.mismatched_type=整合包類型不匹配,目前遊戲是 %s 整合包,但是提供的整合包更新檔案是 %s 整合包。
|
||||
modpack.name=整合包名稱
|
||||
modpack.not_a_valid_name=不是一個有效的整合包名稱
|
||||
modpack.not_a_valid_name=整合包名稱無效
|
||||
modpack.scan=解析整合包
|
||||
modpack.task.install=導入整合包
|
||||
modpack.task.install.error=安裝失敗,可能是整合包格式不正確或操作文件失敗。
|
||||
modpack.task.install=匯入整合包
|
||||
modpack.task.install.error=安裝失敗,可能是整合包格式錯誤或操作檔案失敗。
|
||||
modpack.task.install.will=將會安裝整合包:
|
||||
modpack.type.curse=Curse
|
||||
modpack.type.curse.completion=下載 Curse 整合包相關文件
|
||||
modpack.type.curse.error=未能完成 Curse 整合包的下载,请多次重试或设置代理
|
||||
modpack.type.curse.completion=下載 Curse 整合包相關檔案
|
||||
modpack.type.curse.error=無法完成 Curse 整合包的下載,請多次重試或設定代理
|
||||
modpack.type.hmcl=HMCL
|
||||
modpack.type.multimc=MultiMC
|
||||
modpack.unsupported=該整合包不被支持。僅 HMCL、MultiMC、Curse 整合包受支持。
|
||||
modpack.unsupported=不支援該整合包。僅 HMCL、MultiMC、Curse 整合包受支援。
|
||||
modpack.update=正在升級整合包
|
||||
modpack.wizard=導出整合包嚮導
|
||||
modpack.wizard.step.1=基本設置
|
||||
modpack.wizard.step.1.title=設置整合包的主要信息
|
||||
modpack.wizard.step.2=文件選擇
|
||||
modpack.wizard.step.2.title=選中你想加到整合包中的文件或文件夾
|
||||
modpack.wizard=匯出整合包引導
|
||||
modpack.wizard.step.1=基本設定
|
||||
modpack.wizard.step.1.title=設定整合包的主要訊息
|
||||
modpack.wizard.step.2=檔案選擇
|
||||
modpack.wizard.step.2.title=選中你想加到整合包中的檔案或資料夾
|
||||
modpack.wizard.step.3=整合包描述
|
||||
modpack.wizard.step.initialization.exported_version=要導出的遊戲版本
|
||||
modpack.wizard.step.initialization.include_launcher=包含啓動器
|
||||
modpack.wizard.step.initialization.save=選擇要導出到的遊戲整合包位置
|
||||
modpack.wizard.step.initialization.warning=在製作整合包前,請您確認您選擇的版本可以正常啓動,\n並保證您的 Minecraft 是正式版而非快照版,\n而且不應當將不允許非官方途徑傳播的 Mod、材質包等納入整合包。\n整合包會保存您目前的下載源設置
|
||||
modpack.wizard.step.initialization.exported_version=要匯出的遊戲版本
|
||||
modpack.wizard.step.initialization.include_launcher=包含啟動器
|
||||
modpack.wizard.step.initialization.save=選擇要匯出到的遊戲整合包位置
|
||||
modpack.wizard.step.initialization.warning=在製作整合包前,請您確認您選擇的版本可以正常啟動,\n並保證您的 Minecraft 是正式版而非快照版,\n而且不應將不允許非官方途徑傳播的 Mod 模組、材質包等納入整合包。\n整合包會儲存您目前的下載來源設定
|
||||
|
||||
mods=模組管理
|
||||
mods.add=添加模組
|
||||
mods.add.failed=添加模組 %s 失敗。
|
||||
mods.add.success=成功添加模組 %s。
|
||||
mods.add=新增模組
|
||||
mods.add.failed=新增模組 %s 失敗。
|
||||
mods.add.success=成功新增模組 %s。
|
||||
mods.choose_mod=選擇模組
|
||||
mods.remove=刪除
|
||||
|
||||
|
||||
profile=配置
|
||||
profile.default=當前目錄
|
||||
profile.home=主文件夾
|
||||
profile=設定
|
||||
profile.default=目前目錄
|
||||
profile.home=主資料夾
|
||||
profile.instance_directory=遊戲路徑
|
||||
profile.instance_directory.choose=選擇遊戲路徑
|
||||
profile.new=新建配置
|
||||
profile.new=建立設定
|
||||
profile.title=遊戲目錄
|
||||
profile.selected=已選中
|
||||
profile.use_relative_path=若可能,遊戲目錄使用相對路徑
|
||||
profile.selected=已選取
|
||||
profile.use_relative_path=若可能,則在遊戲目錄使用相對路徑
|
||||
|
||||
selector.choose=選擇
|
||||
selector.choose_file=選擇文件
|
||||
selector.custom=自定義
|
||||
selector.choose_file=選擇檔案
|
||||
selector.custom=自訂
|
||||
|
||||
settings=普通設置
|
||||
settings=普通設定
|
||||
|
||||
settings.advanced=高級設置
|
||||
settings.advanced=進階設定
|
||||
settings.advanced.dont_check_game_completeness=不檢查遊戲完整性
|
||||
settings.advanced.game_dir.default=默認(.minecraft/)
|
||||
settings.advanced.game_dir.default=預設(.minecraft/)
|
||||
settings.advanced.game_dir.independent=各版本獨立(.minecraft/versions/<版本名>/,除 assets、libraries)
|
||||
settings.advanced.java_args_default=啓動器默認添加的參數(請不要重複添加):-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:-UseAdaptiveSizePolicy -XX:MaxPermSize=???m -Xmx???m -Dfml.ignoreInvalidMinecraftCertificates=true -Dfml.ignorePatchDiscrepancies=true
|
||||
settings.advanced.java_permanent_generation_space=內存永久保存區域(不必填寫,MB)
|
||||
settings.advanced.java_args_default=啟動器預設新增的參數(請勿重複新增):-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:-UseAdaptiveSizePolicy -XX:MaxPermSize=???m -Xmx???m -Dfml.ignoreInvalidMinecraftCertificates=true -Dfml.ignorePatchDiscrepancies=true
|
||||
settings.advanced.java_permanent_generation_space=記憶體永久儲存區域(不必填寫,格式:MB)
|
||||
settings.advanced.jvm_args=Java 虛擬機參數(不必填寫)
|
||||
settings.advanced.launcher_visibility.close=遊戲啓動後結束啓動器
|
||||
settings.advanced.launcher_visibility.hide=遊戲啓動後隱藏啓動器
|
||||
settings.advanced.launcher_visibility.hide_reopen=隱藏啓動器並在遊戲結束後重新打開
|
||||
settings.advanced.launcher_visibility.keep=保持啓動器可見
|
||||
settings.advanced.launcher_visible=啓動器可見性
|
||||
settings.advanced.launcher_visibility.close=遊戲啟動後結束啟動器
|
||||
settings.advanced.launcher_visibility.hide=遊戲啟動後隱藏啟動器
|
||||
settings.advanced.launcher_visibility.hide_reopen=隱藏啟動器並在遊戲結束後重新開啟
|
||||
settings.advanced.launcher_visibility.keep=不隱藏啟動器
|
||||
settings.advanced.launcher_visible=啟動器可見性
|
||||
settings.advanced.minecraft_arguments=Minecraft 額外參數(不必填寫)
|
||||
settings.advanced.no_common=不使用公共路徑
|
||||
settings.advanced.no_jvm_args=不添加默認的 JVM 參數(使用 Java 9 時必勾)
|
||||
settings.advanced.precall_command=啓動前執行命令(不必填寫,將在遊戲啓動前調用)
|
||||
settings.advanced.server_ip=直入服務器 IP 地址(不必填寫,啓動遊戲後直接進入對應服務器)
|
||||
settings.advanced.no_jvm_args=不新增預設的 JVM 參數(使用 Java 9 時必勾)
|
||||
settings.advanced.precall_command=啟動前執行命令(不必填寫,將在遊戲啟動前呼叫使用)
|
||||
settings.advanced.server_ip=直接進入伺服器 IP 位址(不必填寫,啟動遊戲後直接進入對應伺服器)
|
||||
settings.advanced.wrapper_launcher=前置指令(不必填寫,如 optirun)
|
||||
|
||||
settings.custom=自定義
|
||||
settings.custom=自訂
|
||||
|
||||
settings.game=遊戲設置
|
||||
settings.game.dimension=遊戲窗口分辨率
|
||||
settings.game=遊戲設定
|
||||
settings.game.dimension=遊戲介面解析度大小
|
||||
settings.game.exploration=瀏覽
|
||||
settings.game.fullscreen=全屏
|
||||
settings.game.fullscreen=全螢幕
|
||||
settings.game.game_directory=遊戲路徑(版本隔離)
|
||||
settings.game.game_directory.choose=選擇遊戲路徑
|
||||
settings.game.java_directory=Java 路徑
|
||||
settings.game.java_directory.choose=選擇 Java 路徑
|
||||
settings.game.management=管理
|
||||
|
||||
settings.icon=遊戲圖標
|
||||
settings.icon=遊戲圖示
|
||||
|
||||
settings.launcher=啓動器設置
|
||||
settings.launcher.common_path.tooltip=啓動器將所有遊戲資源及依賴庫文件放於此集中管理,如果遊戲文件夾內有現成的將不會使用公共庫文件
|
||||
settings.launcher.download_source=下載源
|
||||
settings.launcher=啟動器設定
|
||||
settings.launcher.common_path.tooltip=啟動器將所有遊戲資源及依賴庫檔案放於此集中管理,如果遊戲資料夾內有現成的將不會使用公共庫檔案
|
||||
settings.launcher.download_source=下載來源
|
||||
settings.launcher.language=語言
|
||||
settings.launcher.log_font=日誌字體
|
||||
settings.launcher.log_font=記錄字體
|
||||
settings.launcher.proxy=代理
|
||||
settings.launcher.proxy.authentication=身份驗證
|
||||
settings.launcher.proxy.disable=使用系統代理
|
||||
settings.launcher.proxy.host=主機
|
||||
settings.launcher.proxy.http=HTTP
|
||||
settings.launcher.proxy.password=密碼
|
||||
settings.launcher.proxy.port=端口
|
||||
settings.launcher.proxy.port=埠 (Port)
|
||||
settings.launcher.proxy.socks=Socks
|
||||
settings.launcher.proxy.username=賬戶
|
||||
settings.launcher.proxy.username=帳戶
|
||||
settings.launcher.theme=主題
|
||||
|
||||
settings.max_memory=最大內存(MB)
|
||||
settings.physical_memory=物理內存大小
|
||||
settings.show_log=查看日誌
|
||||
settings.max_memory=最大記憶體(MB)
|
||||
settings.physical_memory=實體記憶體大小
|
||||
settings.show_log=查看記錄
|
||||
settings.tabs.installers=自動安裝
|
||||
settings.type.global=全局版本設置(使用該設置的版本共用一套設定)
|
||||
settings.type=版本設置類型
|
||||
settings.type.special=單獨版本設置(不會影響到其他版本的設定)
|
||||
settings.type.global=全域版本設定(使用該設定的版本共用一套設定)
|
||||
settings.type=版本設定類型
|
||||
settings.type.special=單獨版本設定(不會影響到其他版本的設定)
|
||||
|
||||
update=啓動器更新
|
||||
update=啟動器更新
|
||||
update.channel.dev=更新到開發版
|
||||
update.channel.stable=更新到推薦版本
|
||||
update.checking=正在檢查更新
|
||||
update.failed=更新失敗
|
||||
update.found=發現更新
|
||||
update.newest_version=最新版本爲:%s
|
||||
update.note=開發版包含更多的功能以及錯誤修復,但也可能會包含其他的問題。選擇更新到開發版導致你電腦中所有的HMCL更新至開發版
|
||||
update.latest=當前版本爲最新版本
|
||||
update.no_browser=無法打開瀏覽器,網址已經複製到剪貼板了,您可以手動粘貼網址打開頁面
|
||||
update.found=發現到更新
|
||||
update.newest_version=最新版本為:%s
|
||||
update.note=開發版包含更多的功能以及錯誤修復,但也可能會包含其他的問題。
|
||||
update.latest=目前版本為最新版本
|
||||
update.no_browser=無法打開瀏覽器,網址已經複製到剪貼簿了,您可以手動複製網址打開頁面
|
||||
update.tooltip=更新
|
||||
|
||||
version.cannot_read=讀取遊戲版本失敗,無法進行自動安裝
|
||||
version.forbidden_name=此版本名稱不受支持,請換一個名字
|
||||
version.game.old=遠古版
|
||||
version.game.release=穩定版
|
||||
version.game.snapshot=測試版
|
||||
version.launch=啓動遊戲
|
||||
version.launch_script=生成啓動腳本
|
||||
version.launch_script.failed=生成啓動腳本失敗
|
||||
version.launch_script.save=保存啓動腳本
|
||||
version.launch_script.success=啓動腳本已生成完畢:%s
|
||||
version.manage.redownload_assets_index=重新下載資源配置(assets_index.json)
|
||||
version.forbidden_name=此版本名稱不受支援,請換一個名字
|
||||
version.game.old=老舊版本
|
||||
version.game.release=穩定版本
|
||||
version.game.snapshot=測試版本
|
||||
version.launch=啟動遊戲
|
||||
version.launch_script=生成啟動腳本
|
||||
version.launch_script.failed=生成啟動腳本失敗
|
||||
version.launch_script.save=儲存啟動腳本
|
||||
version.launch_script.success=啟動腳本已生成完畢:%s
|
||||
version.manage.redownload_assets_index=重新下載資源設定(assets_index.json)
|
||||
version.manage.remove=刪除該版本
|
||||
version.manage.remove.confirm=真的要刪除版本 %s 嗎?你將無法找回被刪除的文件!
|
||||
version.manage.remove.confirm.trash=真的要刪除版本 %s 嗎?你可以在系統的回收站中恢復文件夾 %s 來找回該版本。
|
||||
version.manage.remove.confirm.independent=由於該遊戲使用了版本隔離,所以刪除該版本將導致該遊戲的存檔等數據一同被刪除,真的要刪除版本 %s 嗎?
|
||||
version.manage.remove_libraries=刪除所有庫文件
|
||||
version.manage.rename=重命名該版本
|
||||
version.manage.rename.message=請輸入要改成的名字
|
||||
version.manage.rename.fail=重命名版本失敗,可能文件被佔用或者名字有特殊字符
|
||||
version.settings=遊戲設置
|
||||
version.manage.remove.confirm=真的要刪除版本 %s 嗎?你將無法找回被刪除的檔案!
|
||||
version.manage.remove.confirm.trash=真的要刪除版本 %s 嗎?你可以在系統的資源回收桶 (或垃圾桶) 中還原資料夾 %s 來找回該版本。
|
||||
version.manage.remove.confirm.independent=由於該遊戲使用了版本隔離,所以刪除該版本將導致該遊戲的存檔等資料一同被刪除,真的要刪除版本 %s 嗎?
|
||||
version.manage.remove_libraries=刪除所有庫檔案
|
||||
version.manage.rename=重新命名該版本
|
||||
version.manage.rename.message=請輸入新名稱
|
||||
version.manage.rename.fail=重新命名版本失敗,可能檔案被佔用或者名字有特殊字元
|
||||
version.settings=遊戲設定
|
||||
version.update=更新
|
||||
|
||||
wizard.prev=< 上一步
|
||||
|
||||
@@ -93,13 +93,13 @@ extension.png=图片文件
|
||||
extension.sh=Bash 脚本
|
||||
|
||||
fatal.missing_javafx=JavaFX 缺失。\n如果您使用的是 Java 11 或更高版本,请降级到 Java 8 或 10。\n如果您使用的是 OpenJDK,请确保其包含 OpenJFX。
|
||||
fatal.missing_dst_root_ca_x3=当前 Java 平台缺少 DST Root CA X3 证书。\n您依然可以使用 HMCL,但将无法连接到部分站点(如使用 Let's Encrypt 证书的站点),这可能会使 HMCL 无法正常工作。\n请将您的 Java 升级到 8u101 以上以解决此问题。
|
||||
fatal.missing_dst_root_ca_x3=当前 Java 平台缺少 DST Root CA X3 证书。\n您依然可以使用 HMCL,但将无法连接到部分站点(如使用 Lets Encrypt 证书的站点),这可能会使 HMCL 无法正常工作。\n请将您的 Java 升级到 8u101 以上以解决此问题。
|
||||
fatal.config_loading_failure=HMCL 无法加载配置文件。\n请确保 HMCL 对 "%s" 目录及该目录下的文件拥有读写权限。
|
||||
fatal.migration_requires_manual_reboot=HMCL 即将完成升级,请重新打开 HMCL。
|
||||
fatal.apply_update_failure=我们很抱歉 HMCL 无法自动完成升级,因为出现了一些问题。\n但你依然可以从 %s 处手动下载 HMCL 来完成升级。\n请考虑向我们反馈该问题。
|
||||
|
||||
folder.config=配置文件夹
|
||||
folder.coremod=核心MOD文件夹
|
||||
folder.coremod=核心 MOD 文件夹
|
||||
folder.game=游戏文件夹
|
||||
folder.mod=MOD文件夹
|
||||
folder.resourcepacks=资源包文件夹
|
||||
@@ -133,11 +133,11 @@ install.success=安装成功
|
||||
lang=简体中文
|
||||
lang.default=跟随系统语言
|
||||
|
||||
launch.advice.different_platform=您的系统是 64 位的但是 Java 是 32 位的,推荐您安装 64 位 Java。
|
||||
launch.advice.different_platform=您的系统是 64 位,但是 Java 是 32 位的,建议您安装 64 位 Java。
|
||||
launch.advice.java8_1_13=Minecraft 1.13 只支持 Java 8 或更高版本,请使用 Java 8 或最新版本。
|
||||
launch.advice.java8_51_1_13=旧于 1.8.0_51 的 Java 可能会导致 Minecraft 1.13 崩溃。建议您到 https://java.com 安装最新版的 Java 8。
|
||||
launch.advice.java9=不高于 1.13 的安装了 Mod 的 Minecraft 不支持 Java 9 或更高版本,请使用 Java 8。
|
||||
launch.advice.newer_java=检测到您未使用 Java 8 及更新版本,Java 8 能使游戏更流畅而且 Minecraft 1.12 及更新版本和很多 Mod 强制需要需要 Java 8。
|
||||
launch.advice.java8_51_1_13=低于 1.8.0_51 的 Java 版本可能会导致 Minecraft 1.13 崩溃。建议您到 https://java.com 安装最新版的 Java 8。
|
||||
launch.advice.java9=低于 1.13 的有安装 Mod 的 Minecraft 版本不支持 Java 9 或更高版本,请使用 Java 8。
|
||||
launch.advice.newer_java=检测到您未使用 Java 8 及更新版本,Java 8 能使游戏更流畅,而且 Minecraft 1.12 及更新版本和很多 Mod 强制需要 Java 8。
|
||||
launch.advice.not_enough_space=您设置的内存大小过大,由于超过了系统内存大小 %dMB,所以可能影响游戏体验或无法启动游戏,启动器仍会尝试启动。
|
||||
launch.advice.too_large_memory_for_32bit=您设置的内存大小过大,由于可能超过了 32 位 Java 的内存分配限制,所以可能无法启动游戏,请将内存调至 1024MB 或更小,启动器仍会尝试启动。
|
||||
launch.failed=启动失败
|
||||
@@ -260,7 +260,7 @@ settings.advanced.dont_check_game_completeness=不检查游戏完整性
|
||||
settings.advanced.game_dir.default=默认(.minecraft/)
|
||||
settings.advanced.game_dir.independent=各版本独立(.minecraft/versions/<版本名>/,除 assets、libraries)
|
||||
settings.advanced.java_args_default=启动器默认添加的参数(请不要重复添加):-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:-UseAdaptiveSizePolicy -XX:MaxPermSize=???m -Xmx???m -Dfml.ignoreInvalidMinecraftCertificates=true -Dfml.ignorePatchDiscrepancies=true
|
||||
settings.advanced.java_permanent_generation_space=内存永久保存区域(不必填写,MB)
|
||||
settings.advanced.java_permanent_generation_space=内存永久保存区域(不必填写,单位 MB)
|
||||
settings.advanced.jvm_args=Java 虚拟机参数(不必填写)
|
||||
settings.advanced.launcher_visibility.close=游戏启动后结束启动器
|
||||
settings.advanced.launcher_visibility.hide=游戏启动后隐藏启动器
|
||||
@@ -319,7 +319,7 @@ update.checking=正在检查更新
|
||||
update.failed=更新失败
|
||||
update.found=发现更新
|
||||
update.newest_version=最新版本为:%s
|
||||
update.note=开发版包含更多的功能以及错误修复,但也可能会包含其他的问题。选择更新到开发版导致你电脑中所有的HMCL更新至开发版
|
||||
update.note=开发版包含更多的功能以及错误修复,但也可能会包含其他的问题。
|
||||
update.latest=当前版本为最新版本
|
||||
update.no_browser=无法打开浏览器,网址已经复制到剪贴板了,您可以手动粘贴网址打开页面
|
||||
update.tooltip=更新
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <[email protected]>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public final class LibraryAnalyzer {
|
||||
private final Library forge;
|
||||
private final Library liteLoader;
|
||||
private final Library optiFine;
|
||||
|
||||
public LibraryAnalyzer(Library forge, Library liteLoader, Library optiFine) {
|
||||
this.forge = forge;
|
||||
this.liteLoader = liteLoader;
|
||||
this.optiFine = optiFine;
|
||||
}
|
||||
|
||||
public Optional<Library> getForge() {
|
||||
return Optional.ofNullable(forge);
|
||||
}
|
||||
|
||||
public boolean hasForge() {
|
||||
return forge != null;
|
||||
}
|
||||
|
||||
public Optional<Library> getLiteLoader() {
|
||||
return Optional.ofNullable(liteLoader);
|
||||
}
|
||||
|
||||
public boolean hasLiteLoader() {
|
||||
return liteLoader != null;
|
||||
}
|
||||
|
||||
public Optional<Library> getOptiFine() {
|
||||
return Optional.ofNullable(optiFine);
|
||||
}
|
||||
|
||||
public boolean hasOptiFine() {
|
||||
return optiFine != null;
|
||||
}
|
||||
|
||||
public static LibraryAnalyzer analyze(Version version) {
|
||||
Library forge = null, liteLoader = null, optiFine = null;
|
||||
|
||||
for (Library library : version.getLibraries()) {
|
||||
String groupId = library.getGroupId();
|
||||
String artifactId = library.getArtifactId();
|
||||
if (groupId.equalsIgnoreCase("net.minecraftforge") && artifactId.equalsIgnoreCase("forge"))
|
||||
forge = library;
|
||||
|
||||
if (groupId.equalsIgnoreCase("com.mumfrey") && artifactId.equalsIgnoreCase("liteloader"))
|
||||
liteLoader = library;
|
||||
|
||||
if ((groupId.equalsIgnoreCase("optifine") || groupId.equalsIgnoreCase("net.optifine")) && artifactId.equalsIgnoreCase("optifine"))
|
||||
optiFine = library;
|
||||
}
|
||||
|
||||
return new LibraryAnalyzer(forge, liteLoader, optiFine);
|
||||
}
|
||||
}
|
||||
@@ -17,14 +17,12 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.game.*;
|
||||
import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.CommandBuilder;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class MaintainTask extends TaskResult<Version> {
|
||||
|
||||
@@ -46,57 +44,41 @@ public class MaintainTask extends TaskResult<Version> {
|
||||
}
|
||||
|
||||
public static Version maintain(Version version) {
|
||||
Library forge = null, liteLoader = null, optiFine = null;
|
||||
List<String> args = new ArrayList<>(StringUtils.tokenize(version.getMinecraftArguments().orElse("")));
|
||||
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
|
||||
List<String> mcArgs = version.getMinecraftArguments().map(StringUtils::tokenize).map(ArrayList::new).orElse(null);
|
||||
List<Argument> game = version.getArguments().map(Arguments::getGame).map(ArrayList::new).orElseGet(ArrayList::new);
|
||||
boolean useMcArgs = mcArgs != null;
|
||||
|
||||
for (Library library : version.getLibraries()) {
|
||||
if (library.getGroupId().equalsIgnoreCase("net.minecraftforge") && library.getArtifactId().equalsIgnoreCase("forge"))
|
||||
forge = library;
|
||||
|
||||
if (library.getGroupId().equalsIgnoreCase("com.mumfrey") && library.getArtifactId().equalsIgnoreCase("liteloader"))
|
||||
liteLoader = library;
|
||||
|
||||
if (library.getGroupId().equalsIgnoreCase("net.optifine") && library.getArtifactId().equalsIgnoreCase("optifine"))
|
||||
optiFine = library;
|
||||
|
||||
}
|
||||
|
||||
if (forge == null) {
|
||||
removeTweakClass(args, "forge");
|
||||
if (!libraryAnalyzer.hasForge()) {
|
||||
removeTweakClass(useMcArgs, mcArgs, game, "forge");
|
||||
}
|
||||
|
||||
// Installing Forge will override the Minecraft arguments in json, so LiteLoader and OptiFine Tweaker are being re-added.
|
||||
|
||||
if (liteLoader == null) {
|
||||
removeTweakClass(args, "liteloader");
|
||||
removeTweakClass(useMcArgs, mcArgs, game, "liteloader");
|
||||
if (libraryAnalyzer.hasLiteLoader()) {
|
||||
addArgument(useMcArgs, mcArgs, game, "--tweakClass", "com.mumfrey.liteloader.launch.LiteLoaderTweaker");
|
||||
}
|
||||
|
||||
removeTweakClass(useMcArgs, mcArgs, game, "optifine");
|
||||
if (libraryAnalyzer.hasOptiFine()) {
|
||||
if (!libraryAnalyzer.hasLiteLoader() && !libraryAnalyzer.hasForge()) {
|
||||
addArgument(useMcArgs, mcArgs, game, "--tweakClass", "optifine.OptiFineTweaker");
|
||||
} else {
|
||||
// If forge or LiteLoader installed, OptiFine Forge Tweaker is needed.
|
||||
addArgument(useMcArgs, mcArgs, game, "--tweakClass", "optifine.OptiFineForgeTweaker");
|
||||
}
|
||||
}
|
||||
|
||||
Version result;
|
||||
if (useMcArgs) {
|
||||
// Since $ will be escaped in linux, and our maintain of minecraftArgument will not cause escaping,
|
||||
// so we regenerate the minecraftArgument without escaping.
|
||||
result = version.setMinecraftArguments(new CommandBuilder().addAllWithoutParsing(mcArgs).toString());
|
||||
} else {
|
||||
if (!StringUtils.containsOne(args, "LiteLoaderTweaker")) {
|
||||
args.add("--tweakClass");
|
||||
args.add("com.mumfrey.liteloader.launch.LiteLoaderTweaker");
|
||||
}
|
||||
result = version.setArguments(version.getArguments().map(args -> args.withGame(game)).orElse(new Arguments(game, Collections.emptyList())));
|
||||
}
|
||||
|
||||
if (optiFine == null) {
|
||||
removeTweakClass(args, "optifine");
|
||||
}
|
||||
|
||||
if (liteLoader == null && forge == null && optiFine != null) {
|
||||
if (!StringUtils.containsOne(args, "optifine.OptiFineTweaker")) {
|
||||
args.add("--tweakClass");
|
||||
args.add("optifine.OptiFineTweaker");
|
||||
}
|
||||
}
|
||||
|
||||
if ((liteLoader != null || forge != null) && optiFine != null) {
|
||||
// If forge or LiteLoader installed, OptiFine Forge Tweaker is needed.
|
||||
removeTweakClass(args, "optifine");
|
||||
args.add("--tweakClass");
|
||||
args.add("optifine.OptiFineForgeTweaker");
|
||||
}
|
||||
|
||||
// Since $ will be escaped in linux, and our maintain of minecraftArgument will not cause escaping,
|
||||
// so we regenerate the minecraftArgument without escaping.
|
||||
return version.setMinecraftArguments(new CommandBuilder().addAllWithoutParsing(args).toString());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,17 +86,43 @@ public class MaintainTask extends TaskResult<Version> {
|
||||
return id;
|
||||
}
|
||||
|
||||
private static void removeTweakClass(List<String> args, String target) {
|
||||
for (int i = 0; i < args.size(); ++i) {
|
||||
if (args.get(i).toLowerCase().contains(target)) {
|
||||
if (i > 0 && args.get(i - 1).equals("--tweakClass")) {
|
||||
args.remove(i - 1);
|
||||
args.remove(i - 1);
|
||||
i -= 2;
|
||||
private static void removeTweakClass(boolean useMcArgs, List<String> mcArgs, List<Argument> game, String target) {
|
||||
if (useMcArgs) {
|
||||
for (int i = 0; i + 1 < mcArgs.size(); ++i) {
|
||||
String arg0Str = mcArgs.get(i);
|
||||
String arg1Str = mcArgs.get(i + 1);
|
||||
if (arg0Str.equals("--tweakClass") && arg1Str.toLowerCase().contains(target)) {
|
||||
mcArgs.remove(i);
|
||||
mcArgs.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i + 1 < game.size(); ++i) {
|
||||
Argument arg0 = game.get(i);
|
||||
Argument arg1 = game.get(i + 1);
|
||||
if (arg0 instanceof StringArgument && arg1 instanceof StringArgument) {
|
||||
// We need to preserve the tokens
|
||||
String arg0Str = arg0.toString();
|
||||
String arg1Str = arg1.toString();
|
||||
if (arg0Str.equals("--tweakClass") && arg1Str.toLowerCase().contains(target)) {
|
||||
game.remove(i);
|
||||
game.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addArgument(boolean useMcArgs, List<String> mcArgs, List<Argument> game, String... args) {
|
||||
if (useMcArgs) {
|
||||
mcArgs.addAll(Arrays.asList(args));
|
||||
} else {
|
||||
for (String arg : args)
|
||||
game.add(new StringArgument(arg));
|
||||
}
|
||||
}
|
||||
|
||||
public static final String ID = "version";
|
||||
}
|
||||
@@ -70,7 +70,7 @@ public abstract class VersionList<T extends RemoteVersion> {
|
||||
});
|
||||
}
|
||||
|
||||
private Collection<T> getVersionsImpl(String gameVersion) {
|
||||
protected Collection<T> getVersionsImpl(String gameVersion) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return versions.get(gameVersion);
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -44,6 +45,16 @@ public final class GameVersionList extends VersionList<GameRemoteVersion> {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<GameRemoteVersion> getVersionsImpl(String gameVersion) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return StringUtils.isBlank(gameVersion) ? versions.values() : versions.get(gameVersion);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task refreshAsync(DownloadProvider downloadProvider) {
|
||||
GetTask task = new GetTask(NetworkUtils.toURL(downloadProvider.getVersionListURL()));
|
||||
|
||||
+1
-10
@@ -19,10 +19,7 @@ package org.jackhuang.hmcl.download.liteloader;
|
||||
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.game.LibrariesDownloadInfo;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.LibraryDownloadInfo;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.game.*;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
@@ -76,16 +73,10 @@ public final class LiteLoaderInstallTask extends TaskResult<Version> {
|
||||
|
||||
Version tempVersion = version.setLibraries(Lang.merge(remote.getLibraries(), Collections.singleton(library)));
|
||||
|
||||
String mcArg = version.getMinecraftArguments().orElse("");
|
||||
if (mcArg.contains("--tweakClass optifine.OptiFineTweaker"))
|
||||
mcArg = mcArg.replace("--tweakClass optifine.OptiFineTweaker", "");
|
||||
|
||||
setResult(version
|
||||
.setMainClass("net.minecraft.launchwrapper.Launch")
|
||||
.setLibraries(Lang.merge(tempVersion.getLibraries(), version.getLibraries()))
|
||||
.setLogging(Collections.emptyMap())
|
||||
.setMinecraftArguments(mcArg + " --tweakClass " + remote.getTweakClass())
|
||||
//.setArguments(Arguments.addGameArguments(Lang.get(version.getArguments()), "--tweakClass", remote.getTag().getTweakClass()))
|
||||
);
|
||||
|
||||
dependencies.add(new GameLibrariesTask(dependencyManager, tempVersion));
|
||||
|
||||
+5
-28
@@ -25,7 +25,6 @@ import org.jackhuang.hmcl.task.TaskResult;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -70,46 +69,24 @@ public final class OptiFineInstallTask extends TaskResult<Version> {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
String remoteVersion = remote.getGameVersion() + "-" + remote.getSelfVersion();
|
||||
String remoteVersion = remote.getGameVersion() + "_" + remote.getSelfVersion();
|
||||
|
||||
Library library = new Library(
|
||||
"net.optifine", "optifine", remoteVersion, null, null,
|
||||
"optifine", "OptiFine", remoteVersion, null, null,
|
||||
new LibrariesDownloadInfo(new LibraryDownloadInfo(
|
||||
"net/optifine/optifine/" + remoteVersion + "/optifine-" + remoteVersion + ".jar",
|
||||
"optifine/OptiFine/" + remoteVersion + "/OptiFine-" + remoteVersion + ".jar",
|
||||
remote.getUrl()))
|
||||
);
|
||||
|
||||
List<Library> libraries = new LinkedList<>();
|
||||
libraries.add(library);
|
||||
|
||||
boolean hasFMLTweaker = false;
|
||||
if (version.getMinecraftArguments().isPresent() && version.getMinecraftArguments().get().contains("FMLTweaker"))
|
||||
hasFMLTweaker = true;
|
||||
if (version.getArguments().isPresent()) {
|
||||
List<Argument> game = version.getArguments().get().getGame();
|
||||
if (game.stream().anyMatch(arg -> arg.toString(Collections.emptyMap(), Collections.emptyMap()).contains("FMLTweaker")))
|
||||
hasFMLTweaker = true;
|
||||
}
|
||||
|
||||
/*Arguments arguments = Lang.get(version.getArguments());
|
||||
|
||||
if (!hasFMLTweaker)
|
||||
arguments = Arguments.addGameArguments(arguments, "--tweakClass", "optifine.OptiFineTweaker");
|
||||
*/
|
||||
String minecraftArguments = version.getMinecraftArguments().orElse("");
|
||||
if (!hasFMLTweaker)
|
||||
minecraftArguments = minecraftArguments + " --tweakClass optifine.OptiFineTweaker";
|
||||
else
|
||||
minecraftArguments = minecraftArguments + " --tweakClass optifine.OptiFineForgeTweaker";
|
||||
|
||||
if (version.getMainClass() == null || !version.getMainClass().startsWith("net.minecraft.launchwrapper."))
|
||||
libraries.add(0, new Library("net.minecraft", "launchwrapper", "1.12"));
|
||||
|
||||
setResult(version
|
||||
.setLibraries(Lang.merge(version.getLibraries(), libraries))
|
||||
.setMainClass("net.minecraft.launchwrapper.Launch")
|
||||
.setMinecraftArguments(minecraftArguments)
|
||||
//.setArguments(arguments)
|
||||
.setLibraries(Lang.merge(version.getLibraries(), libraries))
|
||||
.setMainClass("net.minecraft.launchwrapper.Launch")
|
||||
);
|
||||
|
||||
dependencies.add(new GameLibrariesTask(dependencyManager, version.setLibraries(libraries)));
|
||||
|
||||
@@ -50,10 +50,18 @@ public final class Arguments {
|
||||
return game == null ? Collections.emptyList() : Collections.unmodifiableList(game);
|
||||
}
|
||||
|
||||
public Arguments withGame(List<Argument> game) {
|
||||
return new Arguments(game, jvm);
|
||||
}
|
||||
|
||||
public List<Argument> getJvm() {
|
||||
return jvm == null ? Collections.emptyList() : Collections.unmodifiableList(jvm);
|
||||
}
|
||||
|
||||
public Arguments withJvm(List<Argument> jvm) {
|
||||
return new Arguments(game, jvm);
|
||||
}
|
||||
|
||||
public Arguments addGameArguments(String... gameArguments) {
|
||||
return addGameArguments(Arrays.asList(gameArguments));
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class ClassicVersion extends Version {
|
||||
super(true, "Classic", "${auth_player_name} ${auth_session} --workDir ${game_directory}",
|
||||
null, "net.minecraft.client.Minecraft", null, null, null, null,
|
||||
Arrays.asList(new ClassicLibrary("lwjgl"), new ClassicLibrary("jinput"), new ClassicLibrary("lwjgl_util")),
|
||||
null, null, null, ReleaseType.UNKNOWN, new Date(), new Date(), 0);
|
||||
null, null, null, ReleaseType.UNKNOWN, new Date(), new Date(), 0, false);
|
||||
}
|
||||
|
||||
private static class ClassicLibrary extends Library {
|
||||
|
||||
@@ -54,4 +54,8 @@ public final class StringArgument implements Argument {
|
||||
return Collections.singletonList(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return argument;
|
||||
}
|
||||
}
|
||||
@@ -46,10 +46,11 @@ public class Version implements Comparable<Version>, Validation {
|
||||
private final Date time;
|
||||
private final Date releaseTime;
|
||||
private final int minimumLauncherVersion;
|
||||
private final boolean hidden;
|
||||
|
||||
private transient final boolean resolved;
|
||||
|
||||
public Version(boolean resolved, String id, String minecraftArguments, Arguments arguments, String mainClass, String inheritsFrom, String jar, AssetIndexInfo assetIndex, String assets, List<Library> libraries, List<CompatibilityRule> compatibilityRules, Map<DownloadType, DownloadInfo> downloads, Map<DownloadType, LoggingInfo> logging, ReleaseType type, Date time, Date releaseTime, int minimumLauncherVersion) {
|
||||
public Version(boolean resolved, String id, String minecraftArguments, Arguments arguments, String mainClass, String inheritsFrom, String jar, AssetIndexInfo assetIndex, String assets, List<Library> libraries, List<CompatibilityRule> compatibilityRules, Map<DownloadType, DownloadInfo> downloads, Map<DownloadType, LoggingInfo> logging, ReleaseType type, Date time, Date releaseTime, int minimumLauncherVersion, boolean hidden) {
|
||||
this.resolved = resolved;
|
||||
this.id = id;
|
||||
this.minecraftArguments = minecraftArguments;
|
||||
@@ -67,6 +68,7 @@ public class Version implements Comparable<Version>, Validation {
|
||||
this.time = time == null ? new Date() : (Date) time.clone();
|
||||
this.releaseTime = releaseTime == null ? new Date() : (Date) releaseTime.clone();
|
||||
this.minimumLauncherVersion = minimumLauncherVersion;
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
public Optional<String> getMinecraftArguments() {
|
||||
@@ -109,6 +111,10 @@ public class Version implements Comparable<Version>, Validation {
|
||||
return minimumLauncherVersion;
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
|
||||
public Map<DownloadType, LoggingInfo> getLogging() {
|
||||
return logging == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(logging);
|
||||
}
|
||||
@@ -139,10 +145,6 @@ public class Version implements Comparable<Version>, Validation {
|
||||
return CompatibilityRule.appliesToCurrentEnvironment(compatibilityRules);
|
||||
}
|
||||
|
||||
public boolean install(String id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve given version
|
||||
*/
|
||||
@@ -180,43 +182,44 @@ public class Version implements Comparable<Version>, Validation {
|
||||
type,
|
||||
time,
|
||||
releaseTime,
|
||||
Math.max(minimumLauncherVersion, parent.minimumLauncherVersion));
|
||||
Math.max(minimumLauncherVersion, parent.minimumLauncherVersion),
|
||||
hidden);
|
||||
}
|
||||
|
||||
private Version setResolved() {
|
||||
return new Version(true, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(true, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
public Version setId(String id) {
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
public Version setMinecraftArguments(String minecraftArguments) {
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
public Version setArguments(Arguments arguments) {
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
public Version setMainClass(String mainClass) {
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
public Version setInheritsFrom(String inheritsFrom) {
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
public Version setJar(String jar) {
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
public Version setLibraries(List<Library> libraries) {
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
public Version setLogging(Map<DownloadType, LoggingInfo> logging) {
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion);
|
||||
return new Version(resolved, id, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class NetworkUtils {
|
||||
private NetworkUtils() {
|
||||
}
|
||||
|
||||
private static Supplier<String> userAgentSupplier = RandomUserAgent::randomUserAgent;
|
||||
private static Supplier<String> userAgentSupplier = () -> "HMCLCore";
|
||||
|
||||
public static String getUserAgent() {
|
||||
return userAgentSupplier.get();
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user