Merge pull request #438 from yushijinhun/force-update
移除「更新一次 HMCL,电脑上所有 HMCL 都得到更新」的功能
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2018 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* 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,153 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2018 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* 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");
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <huanghongxun2008@126.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -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=更新
|
||||
|
||||
@@ -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=更新
|
||||
|
||||
Reference in New Issue
Block a user