From 6124732f8ef59b0b1e05641f70c4180644d20cf8 Mon Sep 17 00:00:00 2001 From: Aviana Cruz Date: Sun, 6 Nov 2022 13:33:14 +0800 Subject: [PATCH 2/2] Cleanup Co-authored-by: zhaose Signed-off-by: Aviana Cruz --- .../java/org/jackhuang/hmcl/Launcher.java | 13 - .../java/org/jackhuang/hmcl/Metadata.java | 4 - .../org/jackhuang/hmcl/countly/Countly.java | 87 ------ .../org/jackhuang/hmcl/ui/Controllers.java | 9 - .../org/jackhuang/hmcl/ui/CrashWindow.java | 3 - .../org/jackhuang/hmcl/ui/UpgradeDialog.java | 77 ----- .../hmcl/ui/account/CreateAccountPane.java | 16 - .../jackhuang/hmcl/ui/main/FeedbackPage.java | 79 ----- .../hmcl/ui/main/LauncherSettingsPage.java | 22 +- .../org/jackhuang/hmcl/ui/main/MainPage.java | 135 +-------- .../org/jackhuang/hmcl/ui/main/RootPage.java | 17 -- .../jackhuang/hmcl/ui/main/SettingsPage.java | 60 ---- .../jackhuang/hmcl/ui/main/SettingsView.java | 58 ---- .../jackhuang/hmcl/ui/main/SponsorPage.java | 174 ----------- .../hmcl/ui/versions/ModTranslations.java | 18 +- .../upgrade/hmcl/ExecutableHeaderHelper.java | 124 -------- .../hmcl/upgrade/hmcl/HMCLDownloadTask.java | 68 ----- .../hmcl/upgrade/hmcl/IntegrityChecker.java | 146 --------- .../hmcl/upgrade/hmcl/RemoteVersion.java | 96 ------ .../hmcl/upgrade/hmcl/UpdateChannel.java | 42 --- .../hmcl/upgrade/hmcl/UpdateChecker.java | 125 -------- .../hmcl/upgrade/hmcl/UpdateHandler.java | 282 ------------------ .../resource/RemoteResourceManager.java | 204 ------------- .../jackhuang/hmcl/util/CrashReporter.java | 5 - .../hmcl/game/GameDumpGenerator.java | 6 +- 25 files changed, 4 insertions(+), 1866 deletions(-) delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/main/FeedbackPage.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SponsorPage.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/ExecutableHeaderHelper.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/HMCLDownloadTask.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/IntegrityChecker.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/RemoteVersion.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateChannel.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateChecker.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateHandler.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/resource/RemoteResourceManager.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java index 489d77999..794602dfe 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java @@ -33,9 +33,6 @@ import org.jackhuang.hmcl.setting.SambaException; import org.jackhuang.hmcl.task.AsyncTaskExecutor; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.ui.Controllers; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateChecker; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateHandler; -import org.jackhuang.hmcl.upgrade.resource.RemoteResourceManager; import org.jackhuang.hmcl.util.CrashReporter; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Logging; @@ -121,12 +118,6 @@ public final class Launcher extends Application { Platform.setImplicitExit(false); Controllers.initialize(primaryStage); - UpdateChecker.init(); - - RemoteResourceManager.init(); - - RemoteResourceManager.register(); - primaryStage.show(); }); } catch (Throwable e) { @@ -265,10 +256,6 @@ public final class Launcher extends Application { } public static void main(String[] args) { - if (UpdateHandler.processArguments(args)) { - return; - } - Thread.setDefaultUncaughtExceptionHandler(CRASH_REPORTER); AsyncTaskExecutor.setUncaughtExceptionHandler(new CrashReporter(false)); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java b/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java index 0a599934f..a26b1ca45 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java @@ -37,9 +37,6 @@ public final class Metadata { public static final String TITLE = NAME + " " + VERSION; public static final String FULL_TITLE = FULL_NAME + " v" + VERSION; - // hmcl.update_source.override is deprecated. If it is used, a warning message will be printed in org.jackhuang.hmcl.Launcher.main . - public static final String HMCL_UPDATE_URL = System.getProperty("hmcl.hmcl_update_source.override", System.getProperty("hmcl.update_source.override", "https://hmcl.huangyuhui.net/api/update_link")); - public static final String RESOURCE_UPDATE_URL = System.getProperty("hmcl.resource_update_source.override", "https://hmcl.huangyuhui.net/api/dynamic_remote_resource/update_link"); public static final String CONTACT_URL = "https://docs.hmcl.net/help.html"; public static final String HELP_URL = "https://docs.hmcl.net"; public static final String CHANGELOG_URL = "https://docs.hmcl.net/changelog/"; @@ -47,7 +44,6 @@ public final class Metadata { public static final String EULA_URL = "https://docs.hmcl.net/eula/hmcl.html"; public static final String BUILD_CHANNEL = JarUtils.getManifestAttribute("Build-Channel", "nightly"); - public static final String GITHUB_SHA = JarUtils.getManifestAttribute("GitHub-SHA", null); public static final Path MINECRAFT_DIRECTORY = OperatingSystem.getWorkingDirectory("minecraft"); public static final Path HMCL_DIRECTORY; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java b/HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java deleted file mode 100644 index f22dd1d0c..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.countly; - -import org.jackhuang.hmcl.util.io.HttpRequest; - -import java.io.IOException; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -import static org.jackhuang.hmcl.util.Pair.pair; - -public class Countly { - - private String deviceId; - private String endpoint; - private String serverURL; - - public void sendMetric(String metrics) throws IOException { - HttpRequest.GET(serverURL + endpoint, - pair("begin_session", "1"), - pair("session_id", "1"), - pair("metrics", metrics), - pair("device_id", deviceId), - pair("timestamp", Long.toString(System.currentTimeMillis())), - pair("tz", Integer.toString(TimeZone.getDefault().getOffset(new Date().getTime()) / 60000)), - pair("hour", Integer.toString(currentHour())), - pair("dow", Integer.toString(currentDayOfWeek())), - pair("app_key", APP_KEY), - pair("sdk_name", "java-native"), - pair("sdk_version", "20.11.1")) - .getString(); - } - - private static int getTimezoneOffset() { - return TimeZone.getDefault().getOffset(new Date().getTime()) / 60000; - } - - private static String getLocale() { - final Locale locale = Locale.getDefault(); - return locale.getLanguage() + "_" + locale.getCountry(); - } - - private static int currentHour() { - return Calendar.getInstance().get(Calendar.HOUR_OF_DAY); - } - - private int currentDayOfWeek() { - int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); - switch (day) { - case Calendar.SUNDAY: - return 0; - case Calendar.MONDAY: - return 1; - case Calendar.TUESDAY: - return 2; - case Calendar.WEDNESDAY: - return 3; - case Calendar.THURSDAY: - return 4; - case Calendar.FRIDAY: - return 5; - case Calendar.SATURDAY: - return 6; - } - return 0; - } - - private static final String APP_KEY = ""; -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java index acedb629c..94c28acad 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -385,15 +385,6 @@ public final class Controllers { public static void onHyperlinkAction(String href) { if (href.startsWith("hmcl://")) { - switch (href) { - case "hmcl://settings/feedback": - Controllers.getSettingsPage().showFeedback(); - Controllers.navigate(Controllers.getSettingsPage()); - break; - case "hmcl://hide-announcement": - Controllers.getRootPage().getMainPage().hideAnnouncementPane(); - break; - } } else { FXUtils.openLink(href); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/CrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/CrashWindow.java index 6761ad986..8f4b2b880 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/CrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/CrashWindow.java @@ -28,7 +28,6 @@ import javafx.scene.layout.StackPane; import javafx.stage.Stage; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.countly.CrashReport; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateChecker; import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -42,8 +41,6 @@ public class CrashWindow extends Stage { Label lblCrash = new Label(); if (report.getThrowable() instanceof InternalError) lblCrash.setText(i18n("launcher.crash.java_internal_error")); - else if (UpdateChecker.isOutdated()) - lblCrash.setText(i18n("launcher.crash.hmcl_out_dated")); else lblCrash.setText(i18n("launcher.crash")); lblCrash.setWrapText(true); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java deleted file mode 100644 index 733e393da..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2021 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.ui; - -import com.jfoenix.controls.JFXButton; -import com.jfoenix.controls.JFXDialogLayout; -import javafx.concurrent.Worker; -import javafx.scene.control.Label; -import javafx.scene.web.WebEngine; -import javafx.scene.web.WebView; -import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; -import org.jackhuang.hmcl.upgrade.hmcl.RemoteVersion; - -import java.util.logging.Level; - -import static org.jackhuang.hmcl.Metadata.CHANGELOG_URL; -import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; -import static org.jackhuang.hmcl.util.Logging.LOG; -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; - -public class UpgradeDialog extends JFXDialogLayout { - public UpgradeDialog(RemoteVersion remoteVersion, Runnable updateRunnable) { - { - setHeading(new Label(i18n("update.changelog"))); - } - - { - String url = CHANGELOG_URL + remoteVersion.getChannel().channelName + ".html#nowchange"; - try { - WebView webView = new WebView(); - webView.getEngine().setUserDataDirectory(Metadata.HMCL_DIRECTORY.toFile()); - WebEngine engine = webView.getEngine(); - engine.load(url); - engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> { - if (newValue == Worker.State.FAILED) { - LOG.warning("Failed to load update log, trying to open it in browser"); - FXUtils.openLink(url); - setBody(); - } - }); - setBody(webView); - } catch (NoClassDefFoundError | UnsatisfiedLinkError e) { - LOG.log(Level.WARNING, "WebView is missing or initialization failed", e); - FXUtils.openLink(url); - } - } - - { - JFXButton updateButton = new JFXButton(i18n("update.accept")); - updateButton.getStyleClass().add("dialog-accept"); - updateButton.setOnMouseClicked(e -> updateRunnable.run()); - - JFXButton cancelButton = new JFXButton(i18n("button.cancel")); - cancelButton.getStyleClass().add("dialog-cancel"); - cancelButton.setOnMouseClicked(e -> fireEvent(new DialogCloseEvent())); - - setActions(updateButton, cancelButton); - onEscPressed(this, cancelButton::fire); - } - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java index dfa578cc2..cac871f81 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java @@ -58,7 +58,6 @@ import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.WeakListenerHolder; import org.jackhuang.hmcl.ui.construct.*; -import org.jackhuang.hmcl.upgrade.hmcl.IntegrityChecker; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter; import org.jackhuang.hmcl.util.javafx.BindingMapping; @@ -323,12 +322,6 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware { box.getChildren().setAll(profileLink, birthLink, purchaseLink, deauthorizeLink, forgotpasswordLink, createProfileLink); GridPane.setColumnSpan(box, 2); - if (!IntegrityChecker.isOfficial()) { - HintPane unofficialHint = new HintPane(MessageDialogPane.MessageType.WARNING); - unofficialHint.setText(i18n("unofficial.hint")); - vbox.getChildren().add(unofficialHint); - } - vbox.getChildren().addAll(hintPane, box); btnAccept.setDisable(false); @@ -418,15 +411,6 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware { int rowIndex = 0; - if (!IntegrityChecker.isOfficial() && !(factory instanceof OfflineAccountFactory)) { - HintPane hintPane = new HintPane(MessageDialogPane.MessageType.WARNING); - hintPane.setSegment(i18n("unofficial.hint")); - GridPane.setColumnSpan(hintPane, 2); - add(hintPane, 0, rowIndex); - - rowIndex++; - } - if (factory instanceof BoundAuthlibInjectorAccountFactory) { this.server = ((BoundAuthlibInjectorAccountFactory) factory).getServer(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/FeedbackPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/FeedbackPage.java deleted file mode 100644 index a71c1d5d5..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/FeedbackPage.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2021 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.ui.main; - -import javafx.geometry.Insets; -import javafx.scene.control.ScrollPane; -import javafx.scene.layout.VBox; -import org.jackhuang.hmcl.ui.FXUtils; -import org.jackhuang.hmcl.ui.construct.ComponentList; -import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem; -import org.jackhuang.hmcl.ui.construct.SpinnerPane; - -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; - -public class FeedbackPage extends SpinnerPane { - - public FeedbackPage() { - VBox content = new VBox(); - content.setPadding(new Insets(10)); - content.setSpacing(10); - content.setFillWidth(true); - ScrollPane scrollPane = new ScrollPane(content); - scrollPane.setFitToWidth(true); - FXUtils.smoothScrolling(scrollPane); - setContent(scrollPane); - - ComponentList community = new ComponentList(); - { - IconedTwoLineListItem users = new IconedTwoLineListItem(); - users.setImage(FXUtils.newBuiltinImage("/assets/img/craft_table.png")); - users.setTitle(i18n("feedback.qq_group")); - users.setSubtitle(i18n("feedback.qq_group.statement")); - users.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/sponsor"); - - IconedTwoLineListItem github = new IconedTwoLineListItem(); - github.setImage(FXUtils.newBuiltinImage("/assets/img/github.png")); - github.setTitle(i18n("feedback.github")); - github.setSubtitle(i18n("feedback.github.statement")); - github.setExternalLink("https://github.com/HMCL-dev/HMCL/issues/new/choose"); - - IconedTwoLineListItem discord = new IconedTwoLineListItem(); - discord.setImage(FXUtils.newBuiltinImage("/assets/img/discord.png")); - discord.setTitle(i18n("feedback.discord")); - discord.setSubtitle(i18n("feedback.discord.statement")); - discord.setExternalLink("https://discord.gg/jVvC7HfM6U"); - - IconedTwoLineListItem kookapp = new IconedTwoLineListItem(); - kookapp.setImage(FXUtils.newBuiltinImage("/assets/img/kookapp.png")); - kookapp.setTitle(i18n("feedback.kookapp")); - kookapp.setSubtitle(i18n("feedback.kookapp.statement")); - kookapp.setExternalLink("https://kook.top/Kx7n3t"); - - community.getContent().setAll(users, github, discord, kookapp); - } - - content.getChildren().addAll( - ComponentList.createComponentListTitle(i18n("feedback.channel")), - community - ); - - this.setContent(content); - } - -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java index 3e80594cc..32ca4b1db 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java @@ -45,8 +45,6 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor private final TabHeader.Tab downloadTab = new TabHeader.Tab<>("downloadSettingsPage"); private final TabHeader.Tab helpTab = new TabHeader.Tab<>("helpPage"); private final TabHeader.Tab aboutTab = new TabHeader.Tab<>("aboutPage"); - private final TabHeader.Tab feedbackTab = new TabHeader.Tab<>("feedbackPage"); - private final TabHeader.Tab sponsorTab = new TabHeader.Tab<>("sponsorPage"); private final TransitionPane transitionPane = new TransitionPane(); public LauncherSettingsPage() { @@ -55,10 +53,8 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor personalizationTab.setNodeSupplier(PersonalizationPage::new); downloadTab.setNodeSupplier(DownloadSettingsPage::new); helpTab.setNodeSupplier(HelpPage::new); - feedbackTab.setNodeSupplier(FeedbackPage::new); - sponsorTab.setNodeSupplier(SponsorPage::new); aboutTab.setNodeSupplier(AboutPage::new); - tab = new TabHeader(gameTab, settingsTab, personalizationTab, downloadTab, helpTab, feedbackTab, sponsorTab, aboutTab); + tab = new TabHeader(gameTab, settingsTab, personalizationTab, downloadTab, helpTab, aboutTab); tab.select(gameTab); gameTab.initializeIfNeeded(); @@ -102,18 +98,6 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor helpItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(helpTab)); helpItem.setOnAction(e -> tab.select(helpTab)); }) - .addNavigationDrawerItem(feedbackItem -> { - feedbackItem.setTitle(i18n("feedback")); - feedbackItem.setLeftGraphic(wrap(SVG.MESSAGE_ALERT_OUTLINE)); - feedbackItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(feedbackTab)); - feedbackItem.setOnAction(e -> tab.select(feedbackTab)); - }) - .addNavigationDrawerItem(sponsorItem -> { - sponsorItem.setTitle(i18n("sponsor")); - sponsorItem.setLeftGraphic(wrap(SVG.HAND_HEAR_OUTLINE)); - sponsorItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(sponsorTab)); - sponsorItem.setOnAction(e -> tab.select(sponsorTab)); - }) .addNavigationDrawerItem(aboutItem -> { aboutItem.setTitle(i18n("about")); aboutItem.setLeftGraphic(wrap(SVG.INFORMATION_OUTLINE)); @@ -142,10 +126,6 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor tab.select(gameTab); } - public void showFeedback() { - tab.select(feedbackTab); - } - @Override public ReadOnlyObjectProperty stateProperty() { return state.getReadOnlyProperty(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java index f613d8fb3..c63d73ce9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java @@ -53,9 +53,6 @@ import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.ui.versions.GameItem; import org.jackhuang.hmcl.ui.versions.Versions; -import org.jackhuang.hmcl.upgrade.hmcl.RemoteVersion; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateChecker; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateHandler; import org.jackhuang.hmcl.util.javafx.BindingMapping; import org.jackhuang.hmcl.util.javafx.MappedObservableList; @@ -77,14 +74,10 @@ public final class MainPage extends StackPane implements DecoratorPage { private final JFXPopup popup = new JFXPopup(menu); private final StringProperty currentGame = new SimpleStringProperty(this, "currentGame"); - private final BooleanProperty showUpdate = new SimpleBooleanProperty(this, "showUpdate"); - private final ObjectProperty latestVersion = new SimpleObjectProperty<>(this, "latestVersion"); private final ObservableList versions = FXCollections.observableArrayList(); private final ObservableList versionNodes; private Profile profile; - private VBox announcementPane; - private final StackPane updatePane; private final JFXButton menuButton; { @@ -101,54 +94,6 @@ public final class MainPage extends StackPane implements DecoratorPage { setPadding(new Insets(20)); - if (Metadata.isNightly() || (Metadata.isDev() && !Objects.equals(Metadata.VERSION, config().getShownTips().get(ANNOUNCEMENT)))) { - announcementPane = new VBox(16); - if (Metadata.isNightly()) { - announcementPane.getChildren().add(new AnnouncementCard(i18n("update.channel.nightly.title"), i18n("update.channel.nightly.hint"))); - } else if (Metadata.isDev()) { - announcementPane.getChildren().add(new AnnouncementCard(i18n("update.channel.dev.title"), i18n("update.channel.dev.hint"))); - } - getChildren().add(announcementPane); - } - - updatePane = new StackPane(); - updatePane.setVisible(false); - updatePane.getStyleClass().add("bubble"); - FXUtils.setLimitWidth(updatePane, 230); - FXUtils.setLimitHeight(updatePane, 55); - StackPane.setAlignment(updatePane, Pos.TOP_RIGHT); - updatePane.setOnMouseClicked(e -> onUpgrade()); - FXUtils.onChange(showUpdateProperty(), this::showUpdate); - - { - HBox hBox = new HBox(); - hBox.setSpacing(12); - hBox.setAlignment(Pos.CENTER_LEFT); - StackPane.setAlignment(hBox, Pos.CENTER_LEFT); - StackPane.setMargin(hBox, new Insets(9, 12, 9, 16)); - { - Label lblIcon = new Label(); - lblIcon.setGraphic(SVG.UPDATE.createIcon(Theme.whiteFill(), 20, 20)); - - TwoLineListItem prompt = new TwoLineListItem(); - prompt.setSubtitle(i18n("update.bubble.subtitle")); - prompt.setPickOnBounds(false); - prompt.titleProperty().bind(BindingMapping.of(latestVersionProperty()).map(latestVersion -> - latestVersion == null ? "" : i18n("update.bubble.title", latestVersion.getVersion()))); - - hBox.getChildren().setAll(lblIcon, prompt); - } - - JFXButton closeUpdateButton = new JFXButton(); - closeUpdateButton.setGraphic(SVG.CLOSE.createIcon(Theme.whiteFill(), 10, 10)); - StackPane.setAlignment(closeUpdateButton, Pos.TOP_RIGHT); - closeUpdateButton.getStyleClass().add("toggle-icon-tiny"); - StackPane.setMargin(closeUpdateButton, new Insets(5)); - closeUpdateButton.setOnMouseClicked(e -> closeUpdateBubble()); - - updatePane.getChildren().setAll(hBox, closeUpdateButton); - } - StackPane launchPane = new StackPane(); launchPane.getStyleClass().add("launch-pane"); launchPane.setMaxWidth(230); @@ -219,7 +164,7 @@ public final class MainPage extends StackPane implements DecoratorPage { launchPane.getChildren().setAll(launchButton, separator, menuButton); } - getChildren().addAll(updatePane, launchPane); + getChildren().addAll(launchPane); menu.setMaxHeight(365); menu.setMaxWidth(545); @@ -232,37 +177,6 @@ public final class MainPage extends StackPane implements DecoratorPage { }); Bindings.bindContent(menu.getContent(), versionNodes); } - - private void showUpdate(boolean show) { - doAnimation(show); - - if (show && getLatestVersion() != null && !Objects.equals(config().getPromptedVersion(), getLatestVersion().getVersion())) { - Controllers.dialog("", i18n("update.bubble.title", getLatestVersion().getVersion()), MessageDialogPane.MessageType.INFO, () -> { - config().setPromptedVersion(getLatestVersion().getVersion()); - onUpgrade(); - }); - } - } - - private void doAnimation(boolean show) { - if (AnimationUtils.isAnimationEnabled()) { - Duration duration = Duration.millis(320); - Timeline nowAnimation = new Timeline(); - nowAnimation.getKeyFrames().addAll( - new KeyFrame(Duration.ZERO, - new KeyValue(updatePane.translateXProperty(), show ? 260 : 0, SINE)), - new KeyFrame(duration, - new KeyValue(updatePane.translateXProperty(), show ? 0 : 260, SINE))); - if (show) nowAnimation.getKeyFrames().add( - new KeyFrame(Duration.ZERO, e -> updatePane.setVisible(true))); - else nowAnimation.getKeyFrames().add( - new KeyFrame(duration, e -> updatePane.setVisible(false))); - nowAnimation.play(); - } else { - updatePane.setVisible(show); - } - } - private void launch() { Versions.launch(Profiles.getSelectedProfile()); } @@ -271,29 +185,6 @@ public final class MainPage extends StackPane implements DecoratorPage { popup.show(menuButton, JFXPopup.PopupVPosition.BOTTOM, JFXPopup.PopupHPosition.RIGHT, 0, -menuButton.getHeight()); } - private void onUpgrade() { - RemoteVersion target = UpdateChecker.getLatestVersion(); - if (target == null) { - return; - } - UpdateHandler.updateFrom(target); - } - - private void closeUpdateBubble() { - showUpdate.unbind(); - showUpdate.set(false); - } - - public void hideAnnouncementPane() { - if (announcementPane != null) { - config().getShownTips().put(ANNOUNCEMENT, Metadata.VERSION); - Pane parent = (Pane) announcementPane.getParent(); - if (parent != null) - parent.getChildren().remove(announcementPane); - announcementPane = null; - } - } - @Override public ReadOnlyObjectWrapper stateProperty() { return state; @@ -311,30 +202,6 @@ public final class MainPage extends StackPane implements DecoratorPage { this.currentGame.set(currentGame); } - public boolean isShowUpdate() { - return showUpdate.get(); - } - - public BooleanProperty showUpdateProperty() { - return showUpdate; - } - - public void setShowUpdate(boolean showUpdate) { - this.showUpdate.set(showUpdate); - } - - public RemoteVersion getLatestVersion() { - return latestVersion.get(); - } - - public ObjectProperty latestVersionProperty() { - return latestVersion; - } - - public void setLatestVersion(RemoteVersion latestVersion) { - this.latestVersion.set(latestVersion); - } - public void initVersions(Profile profile, List versions) { FXUtils.checkFxUserThread(); this.profile = profile; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java index d6dd1c5fb..391432d1f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java @@ -43,7 +43,6 @@ import org.jackhuang.hmcl.ui.nbt.NBTEditorPage; import org.jackhuang.hmcl.ui.nbt.NBTHelper; import org.jackhuang.hmcl.ui.versions.GameAdvancedListItem; import org.jackhuang.hmcl.ui.versions.Versions; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateChecker; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.io.CompressingUtils; @@ -110,8 +109,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { }); FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), mainPage::setCurrentGame); - mainPage.showUpdateProperty().bind(UpdateChecker.outdatedProperty()); - mainPage.latestVersionProperty().bind(UpdateChecker.latestVersionProperty()); Profiles.registerVersionsListener(profile -> { HMCLGameRepository repository = profile.getRepository(); @@ -169,19 +166,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { downloadItem.setOnAction(e -> Controllers.navigate(Controllers.getDownloadPage())); runInFX(() -> FXUtils.installFastTooltip(downloadItem, i18n("download.hint"))); - // fifth item in left sidebar - AdvancedListItem multiplayerItem = new AdvancedListItem(); - multiplayerItem.setLeftGraphic(wrap(SVG.LAN)); - multiplayerItem.setActionButtonVisible(false); - multiplayerItem.setTitle(i18n("multiplayer")); - JFXHyperlink link = new JFXHyperlink(i18n("multiplayer.hint.details")); - link.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/multiplayer-migrate"); - multiplayerItem.setOnAction(e -> Controllers.dialog( - new MessageDialogPane.Builder(i18n("multiplayer.hint"), null, MessageDialogPane.MessageType.INFO) - .addAction(link) - .ok(null) - .build())); - // sixth item in left sidebar AdvancedListItem launcherSettingsItem = new AdvancedListItem(); launcherSettingsItem.setLeftGraphic(wrap(SVG.GEAR_OUTLINE)); @@ -198,7 +182,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { .add(gameItem) .add(downloadItem) .startCategory(i18n("settings.launcher.general").toUpperCase(Locale.ROOT)) - .add(multiplayerItem) .add(launcherSettingsItem); // the root page, with the sidebar in left, navigator in center. diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java index a76070c1c..622b21e6b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java @@ -27,10 +27,6 @@ import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; -import org.jackhuang.hmcl.upgrade.hmcl.RemoteVersion; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateChannel; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateChecker; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateHandler; import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.i18n.Locales; import org.jackhuang.hmcl.util.io.FileUtils; @@ -68,57 +64,6 @@ public final class SettingsPage extends SettingsView { Bindings.createObjectBinding(() -> Optional.ofNullable(Settings.instance().getCommonDirectory()) .orElse(i18n("launcher.cache_directory.disabled")), config().commonDirectoryProperty(), config().commonDirTypeProperty())); - - // ==== Update ==== - FXUtils.installFastTooltip(btnUpdate, i18n("update.tooltip")); - updateListener = any -> { - btnUpdate.setVisible(UpdateChecker.isOutdated()); - - if (UpdateChecker.isOutdated()) { - lblUpdateSub.setText(i18n("update.newest_version", UpdateChecker.getLatestVersion().getVersion())); - lblUpdateSub.getStyleClass().setAll("update-label"); - - lblUpdate.setText(i18n("update.found")); - lblUpdate.getStyleClass().setAll("update-label"); - } else if (UpdateChecker.isCheckingUpdate()) { - lblUpdateSub.setText(i18n("update.checking")); - lblUpdateSub.getStyleClass().setAll("subtitle-label"); - - lblUpdate.setText(i18n("update")); - lblUpdate.getStyleClass().setAll(); - } else { - lblUpdateSub.setText(i18n("update.latest")); - lblUpdateSub.getStyleClass().setAll("subtitle-label"); - - lblUpdate.setText(i18n("update")); - lblUpdate.getStyleClass().setAll(); - } - }; - UpdateChecker.latestVersionProperty().addListener(new WeakInvalidationListener(updateListener)); - UpdateChecker.outdatedProperty().addListener(new WeakInvalidationListener(updateListener)); - UpdateChecker.checkingUpdateProperty().addListener(new WeakInvalidationListener(updateListener)); - updateListener.invalidated(null); - - ToggleGroup updateChannelGroup = new ToggleGroup(); - chkUpdateDev.setToggleGroup(updateChannelGroup); - chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT); - chkUpdateStable.setToggleGroup(updateChannelGroup); - chkUpdateStable.setUserData(UpdateChannel.STABLE); - ObjectProperty updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class); - updateChannel.set(UpdateChannel.getChannel()); - updateChannel.addListener((a, b, newValue) -> { - UpdateChecker.requestCheckUpdate(newValue); - }); - // ==== - } - - @Override - protected void onUpdate() { - RemoteVersion target = UpdateChecker.getLatestVersion(); - if (target == null) { - return; - } - UpdateHandler.updateFrom(target); } @Override @@ -142,11 +87,6 @@ public final class SettingsPage extends SettingsView { }); } - @Override - protected void onSponsor() { - FXUtils.openLink("https://hmcl.huangyuhui.net/api/redirect/sponsor"); - } - @Override protected void clearCacheDirectory() { FileUtils.cleanDirectoryQuietly(new File(Settings.instance().getCommonDirectory(), "cache")); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java index 132ea76f6..44b6dfed7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java @@ -49,11 +49,6 @@ public abstract class SettingsView extends StackPane { protected final JFXComboBox cboLanguage; protected final MultiFileItem fileCommonLocation; protected final ComponentSublist fileCommonLocationSublist; - protected final Label lblUpdate; - protected final Label lblUpdateSub; - protected final JFXRadioButton chkUpdateStable; - protected final JFXRadioButton chkUpdateDev; - protected final JFXButton btnUpdate; protected final ScrollPane scroll; public SettingsView() { @@ -69,11 +64,6 @@ public abstract class SettingsView extends StackPane { ComponentList settingsPane = new ComponentList(); { { - StackPane sponsorPane = new StackPane(); - sponsorPane.setCursor(Cursor.HAND); - sponsorPane.setOnMouseClicked(e -> onSponsor()); - sponsorPane.setPadding(new Insets(8, 0, 8, 0)); - GridPane gridPane = new GridPane(); ColumnConstraints col = new ColumnConstraints(); @@ -96,51 +86,7 @@ public abstract class SettingsView extends StackPane { GridPane.setColumnIndex(label, 0); gridPane.getChildren().add(label); } - - sponsorPane.getChildren().setAll(gridPane); - settingsPane.getContent().add(sponsorPane); - } - } - - { - ComponentSublist updatePane = new ComponentSublist(); - updatePane.setTitle(i18n("update")); - updatePane.setHasSubtitle(true); - { - VBox headerLeft = new VBox(); - - lblUpdate = new Label(i18n("update")); - lblUpdateSub = new Label(); - lblUpdateSub.getStyleClass().add("subtitle-label"); - - headerLeft.getChildren().setAll(lblUpdate, lblUpdateSub); - updatePane.setHeaderLeft(headerLeft); - } - - { - btnUpdate = new JFXButton(); - btnUpdate.setOnMouseClicked(e -> onUpdate()); - btnUpdate.getStyleClass().add("toggle-icon4"); - btnUpdate.setGraphic(SVG.UPDATE.createIcon(Theme.blackFill(), 20, 20)); - - updatePane.setHeaderRight(btnUpdate); } - - { - VBox content = new VBox(); - content.setSpacing(8); - - chkUpdateStable = new JFXRadioButton(i18n("update.channel.stable")); - chkUpdateDev = new JFXRadioButton(i18n("update.channel.dev")); - - TextFlow noteWrapper = new TextFlow(new Text(i18n("update.note"))); - VBox.setMargin(noteWrapper, new Insets(10, 0, 0, 0)); - - content.getChildren().setAll(chkUpdateStable, chkUpdateDev, noteWrapper); - - updatePane.getContent().add(content); - } - settingsPane.getContent().add(updatePane); } { @@ -204,11 +150,7 @@ public abstract class SettingsView extends StackPane { } } - protected abstract void onUpdate(); - protected abstract void onExportLogs(); - protected abstract void onSponsor(); - protected abstract void clearCacheDirectory(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SponsorPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SponsorPage.java deleted file mode 100644 index 07716990b..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SponsorPage.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2021 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.ui.main; - -import com.google.gson.annotations.SerializedName; -import com.google.gson.reflect.TypeToken; -import com.jfoenix.controls.JFXListCell; -import com.jfoenix.controls.JFXListView; -import javafx.geometry.Insets; -import javafx.geometry.VPos; -import javafx.scene.Cursor; -import javafx.scene.control.Label; -import javafx.scene.layout.*; -import javafx.scene.text.TextAlignment; -import org.jackhuang.hmcl.task.Schedulers; -import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.ui.FXUtils; -import org.jackhuang.hmcl.util.Holder; -import org.jackhuang.hmcl.util.io.HttpRequest; - -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; - -public class SponsorPage extends StackPane { - private final JFXListView listView; - - public SponsorPage() { - VBox content = new VBox(); - content.setPadding(new Insets(10)); - content.setSpacing(10); - content.setFillWidth(true); - - { - StackPane sponsorPane = new StackPane(); - sponsorPane.getStyleClass().add("card"); - sponsorPane.setCursor(Cursor.HAND); - sponsorPane.setOnMouseClicked(e -> onSponsor()); - - GridPane gridPane = new GridPane(); - - ColumnConstraints col = new ColumnConstraints(); - col.setHgrow(Priority.SOMETIMES); - col.setMaxWidth(Double.POSITIVE_INFINITY); - - gridPane.getColumnConstraints().setAll(col); - - RowConstraints row = new RowConstraints(); - row.setMinHeight(Double.NEGATIVE_INFINITY); - row.setValignment(VPos.TOP); - row.setVgrow(Priority.SOMETIMES); - gridPane.getRowConstraints().setAll(row); - - { - Label label = new Label(i18n("sponsor.hmcl")); - label.setWrapText(true); - label.setTextAlignment(TextAlignment.JUSTIFY); - GridPane.setRowIndex(label, 0); - GridPane.setColumnIndex(label, 0); - gridPane.getChildren().add(label); - } - - sponsorPane.getChildren().setAll(gridPane); - content.getChildren().add(sponsorPane); - } - - { - StackPane pane = new StackPane(); - pane.getStyleClass().add("card"); - listView = new JFXListView<>(); - Holder lastCell = new Holder<>(); - listView.setCellFactory((listView) -> new JFXListCell() { - @Override - public void updateItem(Sponsor item, boolean empty) { - super.updateItem(item, empty); - - // https://mail.openjdk.org/pipermail/openjfx-dev/2022-July/034764.html - if (this == lastCell.value && !isVisible()) - return; - lastCell.value = this; - - if (!empty) { - setText(item.getName()); - setGraphic(null); - } - } - }); - VBox.setVgrow(pane, Priority.ALWAYS); - pane.getChildren().setAll(listView); - content.getChildren().add(pane); - } - - loadSponsorList(); - - getChildren().setAll(content); - } - - private void onSponsor() { - FXUtils.openLink("https://hmcl.huangyuhui.net/api/redirect/sponsor"); - } - - private void loadSponsorList() { - Task.>supplyAsync(() -> HttpRequest.GET("https://hmcl.huangyuhui.net/api/sponsor").getJson(new TypeToken>() { - }.getType())).thenAcceptAsync(Schedulers.javafx(), sponsors -> { - listView.getItems().setAll(sponsors); - }).start(); - } - - private static class Sponsor { - @SerializedName("name") - private final String name; - - @SerializedName("create_time") - private final Date createTime; - - @SerializedName("money") - private final BigDecimal money; - - @SerializedName("contact") - private final String contact; - - @SerializedName("afdian_id") - private final String afdianId; - - public Sponsor() { - this("", new Date(), BigDecimal.ZERO, "", ""); - } - - public Sponsor(String name, Date createTime, BigDecimal money, String contact, String afdianId) { - this.name = name; - this.createTime = createTime; - this.money = money; - this.contact = contact; - this.afdianId = afdianId; - } - - public String getName() { - return name; - } - - public Date getCreateTime() { - return createTime; - } - - public BigDecimal getMoney() { - return money; - } - - public String getContact() { - return contact; - } - - public String getAfdianId() { - return afdianId; - } - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java index 7d7a22cb4..36b380e85 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java @@ -18,7 +18,6 @@ package org.jackhuang.hmcl.ui.versions; import org.jackhuang.hmcl.mod.RemoteModRepository; -import org.jackhuang.hmcl.upgrade.resource.RemoteResourceManager; import org.jackhuang.hmcl.util.Pair; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.io.IOUtils; @@ -69,7 +68,6 @@ public enum ModTranslations { } private final String defaultResourceName; - private final RemoteResourceManager.RemoteResourceKey remoteResourceKey; private List mods; private Map modIdMap; // mod id -> mod private Map curseForgeMap; // curseforge id -> mod @@ -78,8 +76,6 @@ public enum ModTranslations { ModTranslations(String defaultResourceName, String namespace, String name, String version) { this.defaultResourceName = defaultResourceName; - - remoteResourceKey = RemoteResourceManager.get(namespace, name, version, () -> ModTranslations.class.getResourceAsStream(defaultResourceName)); } @Nullable @@ -127,19 +123,7 @@ public enum ModTranslations { return true; } - try { - InputStream inputStream = remoteResourceKey.getResource(); - if (inputStream == null) { - return false; - } - - String modData = IOUtils.readFullyAsString(inputStream); - mods = Arrays.stream(modData.split("\n")).filter(line -> !line.startsWith("#")).map(Mod::new).collect(Collectors.toList()); - return true; - } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to load " + defaultResourceName, e); - return false; - } + return false; } private boolean loadCurseForgeMap() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/ExecutableHeaderHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/ExecutableHeaderHelper.java deleted file mode 100644 index e5c9ccb5f..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/ExecutableHeaderHelper.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.upgrade.hmcl; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.FileChannel.MapMode; -import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.jackhuang.hmcl.util.io.IOUtils; - -import static java.nio.file.StandardOpenOption.*; -import static org.jackhuang.hmcl.util.Lang.mapOf; -import static org.jackhuang.hmcl.util.Pair.pair; - -/** - * Helper class for adding/removing executable header from HMCL file. - * - * @author yushijinhun - */ -final class ExecutableHeaderHelper { - private ExecutableHeaderHelper() {} - - private static Map suffix2header = mapOf( - pair("exe", "assets/HMCLauncher.exe"), - pair("sh", "assets/HMCLauncher.sh") - ); - - private static Optional getSuffix(Path file) { - String filename = file.getFileName().toString(); - int idxDot = filename.lastIndexOf('.'); - if (idxDot < 0) { - return Optional.empty(); - } else { - return Optional.of(filename.substring(idxDot + 1)); - } - } - - private static Optional readHeader(ZipFile zip, String suffix) throws IOException { - String location = suffix2header.get(suffix); - if (location != null) { - ZipEntry entry = zip.getEntry(location); - if (entry != null && !entry.isDirectory()) { - try (InputStream in = zip.getInputStream(entry)) { - return Optional.of(IOUtils.readFullyAsByteArray(in)); - } - } - } - return Optional.empty(); - } - - private static int detectHeaderLength(ZipFile zip, FileChannel channel) throws IOException { - ByteBuffer buf = channel.map(MapMode.READ_ONLY, 0, channel.size()); - suffixLoop: for (String suffix : suffix2header.keySet()) { - Optional header = readHeader(zip, suffix); - if (header.isPresent()) { - ((Buffer) buf).rewind(); - for (byte b : header.get()) { - if (!buf.hasRemaining() || b != buf.get()) { - continue suffixLoop; - } - } - return header.get().length; - } - } - return 0; - } - - /** - * Copies the executable and removes its header. - */ - public static void copyWithoutHeader(Path from, Path to) throws IOException { - try ( - FileChannel in = FileChannel.open(from, READ); - FileChannel out = FileChannel.open(to, CREATE, WRITE, TRUNCATE_EXISTING); - ZipFile zip = new ZipFile(from.toFile()) - ) { - in.transferTo(detectHeaderLength(zip, in), Long.MAX_VALUE, out); - } - } - - /** - * Copies the executable and appends the header according to the suffix. - */ - public static void copyWithHeader(Path from, Path to) throws IOException { - try ( - FileChannel in = FileChannel.open(from, READ); - FileChannel out = FileChannel.open(to, CREATE, WRITE, TRUNCATE_EXISTING); - ZipFile zip = new ZipFile(from.toFile()) - ) { - Optional suffix = getSuffix(to); - if (suffix.isPresent()) { - Optional header = readHeader(zip, suffix.get()); - if (header.isPresent()) { - out.write(ByteBuffer.wrap(header.get())); - } - } - - in.transferTo(detectHeaderLength(zip, in), Long.MAX_VALUE, out); - } - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/HMCLDownloadTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/HMCLDownloadTask.java deleted file mode 100644 index 0ae8358a5..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/HMCLDownloadTask.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.upgrade.hmcl; - -import org.jackhuang.hmcl.task.FileDownloadTask; -import org.jackhuang.hmcl.util.Pack200Utils; -import org.jackhuang.hmcl.util.io.NetworkUtils; -import org.tukaani.xz.XZInputStream; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.jar.JarOutputStream; - -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))) { - Pack200Utils.unpack(in, out); - } - break; - - default: - throw new IllegalArgumentException("Unknown format: " + archiveFormat); - } - } catch (Throwable e) { - getFile().delete(); - throw e; - } - } - -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/IntegrityChecker.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/IntegrityChecker.java deleted file mode 100644 index 8833f94c0..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/IntegrityChecker.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.upgrade.hmcl; - -import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.util.DigestUtils; -import org.jackhuang.hmcl.util.Lang; -import org.jackhuang.hmcl.util.io.IOUtils; -import org.jackhuang.hmcl.util.io.JarUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Path; -import java.security.*; -import java.security.spec.X509EncodedKeySpec; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; -import java.util.logging.Level; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.jackhuang.hmcl.util.Logging.LOG; - -/** - * A class that checks the integrity of HMCL. - * - * @author yushijinhun - */ -public final class IntegrityChecker { - private IntegrityChecker() {} - - public static final boolean DISABLE_SELF_INTEGRITY_CHECK = "true".equals(System.getProperty("hmcl.self_integrity_check.disable")); - - private static final String SIGNATURE_FILE = "META-INF/hmcl_signature"; - private static final String PUBLIC_KEY_FILE = "assets/hmcl_signature_publickey.der"; - - private static PublicKey getPublicKey() throws IOException { - try (InputStream in = IntegrityChecker.class.getResourceAsStream("/" + PUBLIC_KEY_FILE)) { - if (in == null) { - throw new IOException("Public key not found"); - } - return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(IOUtils.readFullyAsByteArray(in))); - } catch (GeneralSecurityException e) { - throw new IOException("Failed to load public key", e); - } - } - - static void verifyJar(Path jarPath) throws IOException { - PublicKey publickey = getPublicKey(); - MessageDigest md = DigestUtils.getDigest("SHA-512"); - - byte[] signature = null; - Map fileFingerprints = new TreeMap<>(); - try (ZipFile zip = new ZipFile(jarPath.toFile())) { - for (ZipEntry entry : Lang.toIterable(zip.entries())) { - String filename = entry.getName(); - try (InputStream in = zip.getInputStream(entry)) { - if (in == null) { - throw new IOException("entry is null"); - } - - if (SIGNATURE_FILE.equals(filename)) { - signature = IOUtils.readFullyAsByteArray(in); - } else { - md.reset(); - fileFingerprints.put(filename, DigestUtils.digest(md, in)); - } - } - } - } - - if (signature == null) { - throw new IOException("Signature is missing"); - } - - try { - Signature verifier = Signature.getInstance("SHA512withRSA"); - verifier.initVerify(publickey); - for (Entry entry : fileFingerprints.entrySet()) { - md.reset(); - verifier.update(md.digest(entry.getKey().getBytes(UTF_8))); - verifier.update(entry.getValue()); - } - if (!verifier.verify(signature)) { - throw new IOException("Invalid signature: " + jarPath); - } - } catch (GeneralSecurityException e) { - throw new IOException("Failed to verify signature", e); - } - } - - private static volatile Boolean selfVerified = null; - - /** - * Checks whether the current application is verified. - * This method is blocking. - */ - public static boolean isSelfVerified() { - if (selfVerified != null) { - return selfVerified; - } - - synchronized (IntegrityChecker.class) { - if (selfVerified != null) { - return selfVerified; - } - - try { - Path jarPath = JarUtils.thisJarPath(); - if (jarPath == null) { - throw new IOException("Failed to find current HMCL location"); - } - - verifyJar(jarPath); - LOG.info("Successfully verified current JAR"); - selfVerified = true; - } catch (IOException e) { - LOG.log(Level.WARNING, "Failed to verify myself, is the JAR corrupt?", e); - selfVerified = false; - } - - return selfVerified; - } - } - - public static boolean isOfficial() { - return isSelfVerified() || (Metadata.GITHUB_SHA != null && Metadata.BUILD_CHANNEL.equals("nightly")); - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/RemoteVersion.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/RemoteVersion.java deleted file mode 100644 index 776881aca..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/RemoteVersion.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.upgrade.hmcl; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck; -import org.jackhuang.hmcl.util.Pack200Utils; -import org.jackhuang.hmcl.util.gson.JsonUtils; -import org.jackhuang.hmcl.util.io.NetworkUtils; - -import java.io.IOException; -import java.util.Optional; - -public class RemoteVersion { - - public static RemoteVersion fetch(UpdateChannel channel, String url) throws IOException { - try { - JsonObject response = JsonUtils.fromNonNullJson(NetworkUtils.doGet(NetworkUtils.toURL(url)), JsonObject.class); - String version = Optional.ofNullable(response.get("version")).map(JsonElement::getAsString).orElseThrow(() -> new IOException("version is missing")); - String jarUrl = Optional.ofNullable(response.get("jar")).map(JsonElement::getAsString).orElse(null); - String jarHash = Optional.ofNullable(response.get("jarsha1")).map(JsonElement::getAsString).orElse(null); - String packXZUrl = Optional.ofNullable(response.get("packxz")).map(JsonElement::getAsString).orElse(null); - String packXZHash = Optional.ofNullable(response.get("packxzsha1")).map(JsonElement::getAsString).orElse(null); - if (Pack200Utils.isSupported() && packXZUrl != null && packXZHash != null) { - return new RemoteVersion(channel, version, packXZUrl, Type.PACK_XZ, new IntegrityCheck("SHA-1", packXZHash)); - } else if (jarUrl != null && jarHash != null) { - return new RemoteVersion(channel, version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash)); - } else { - throw new IOException("No download url is available"); - } - } catch (JsonParseException e) { - throw new IOException("Malformed response", e); - } - } - - private final UpdateChannel channel; - private final String version; - private final String url; - private final Type type; - private final IntegrityCheck integrityCheck; - - public RemoteVersion(UpdateChannel channel, String version, String url, Type type, IntegrityCheck integrityCheck) { - this.channel = channel; - this.version = version; - this.url = url; - this.type = type; - this.integrityCheck = integrityCheck; - } - - public UpdateChannel getChannel() { - return channel; - } - - public String getVersion() { - return version; - } - - public String getUrl() { - return url; - } - - public Type getType() { - return type; - } - - public IntegrityCheck getIntegrityCheck() { - return integrityCheck; - } - - @Override - public String toString() { - return "[" + version + " from " + url + "]"; - } - - public enum Type { - PACK_XZ, - JAR - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateChannel.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateChannel.java deleted file mode 100644 index f56d645dd..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateChannel.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.upgrade.hmcl; - -import org.jackhuang.hmcl.Metadata; - -public enum UpdateChannel { - STABLE("stable"), - DEVELOPMENT("dev"), - NIGHTLY("nightly"); - - public final String channelName; - - UpdateChannel(String channelName) { - this.channelName = channelName; - } - - public static UpdateChannel getChannel() { - if (Metadata.isDev()) { - return DEVELOPMENT; - } else if (Metadata.isNightly()) { - return NIGHTLY; - } else { - return STABLE; - } - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateChecker.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateChecker.java deleted file mode 100644 index d26c10a0b..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateChecker.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.upgrade.hmcl; - -import javafx.application.Platform; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.property.*; -import javafx.beans.value.ObservableBooleanValue; -import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.util.io.NetworkUtils; - -import java.io.IOException; -import java.util.logging.Level; - -import static org.jackhuang.hmcl.util.Lang.mapOf; -import static org.jackhuang.hmcl.util.Lang.thread; -import static org.jackhuang.hmcl.util.Logging.LOG; -import static org.jackhuang.hmcl.util.Pair.pair; -import static org.jackhuang.hmcl.util.versioning.VersionNumber.asVersion; - -public final class UpdateChecker { - private UpdateChecker() {} - - private static ObjectProperty latestVersion = new SimpleObjectProperty<>(); - private static BooleanBinding outdated = Bindings.createBooleanBinding( - () -> { - RemoteVersion latest = latestVersion.get(); - if (latest == null || isDevelopmentVersion(Metadata.VERSION)) { - return false; - } else { - // We can update from development version to stable version, - // which can be downgrading. - return asVersion(latest.getVersion()).compareTo(asVersion(Metadata.VERSION)) != 0; - } - }, - latestVersion); - private static ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false); - - public static void init() { - requestCheckUpdate(UpdateChannel.getChannel()); - } - - public static RemoteVersion getLatestVersion() { - return latestVersion.get(); - } - - public static ReadOnlyObjectProperty latestVersionProperty() { - return latestVersion; - } - - public static boolean isOutdated() { - return outdated.get(); - } - - public static ObservableBooleanValue outdatedProperty() { - return outdated; - } - - public static boolean isCheckingUpdate() { - return checkingUpdate.get(); - } - - public static ReadOnlyBooleanProperty checkingUpdateProperty() { - return checkingUpdate.getReadOnlyProperty(); - } - - private static RemoteVersion checkUpdate(UpdateChannel channel) throws IOException { - if (!IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK && !IntegrityChecker.isSelfVerified()) { - throw new IOException("Self verification failed"); - } - - String url = NetworkUtils.withQuery(Metadata.HMCL_UPDATE_URL, mapOf( - pair("version", Metadata.VERSION), - pair("channel", channel.channelName))); - - return RemoteVersion.fetch(channel, url); - } - - private static boolean isDevelopmentVersion(String version) { - return version.contains("@") || // eg. @develop@ - version.contains("SNAPSHOT"); // eg. 3.5.SNAPSHOT - } - - public static void requestCheckUpdate(UpdateChannel channel) { - Platform.runLater(() -> { - if (isCheckingUpdate()) - return; - checkingUpdate.set(true); - - thread(() -> { - RemoteVersion result = null; - try { - result = checkUpdate(channel); - LOG.info("Latest version (" + channel + ") is " + result); - } catch (IOException e) { - LOG.log(Level.WARNING, "Failed to check for update", e); - } - - RemoteVersion finalResult = result; - Platform.runLater(() -> { - checkingUpdate.set(false); - if (finalResult != null) { - latestVersion.set(finalResult); - } - }); - }, "Update Checker", true); - }); - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateHandler.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateHandler.java deleted file mode 100644 index f027fff1e..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/hmcl/UpdateHandler.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.upgrade.hmcl; - -import com.google.gson.Gson; -import com.google.gson.JsonParseException; -import javafx.application.Platform; - -import org.jackhuang.hmcl.Main; -import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskExecutor; -import org.jackhuang.hmcl.ui.Controllers; -import org.jackhuang.hmcl.ui.UpgradeDialog; -import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; -import org.jackhuang.hmcl.util.StringUtils; -import org.jackhuang.hmcl.ui.SwingUtils; -import org.jackhuang.hmcl.util.TaskCancellationAction; -import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.io.JarUtils; -import org.jackhuang.hmcl.util.platform.JavaVersion; -import org.jackhuang.hmcl.util.platform.OperatingSystem; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.concurrent.CancellationException; -import java.util.logging.Level; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static org.jackhuang.hmcl.ui.FXUtils.checkFxUserThread; -import static org.jackhuang.hmcl.util.Lang.thread; -import static org.jackhuang.hmcl.util.Logging.LOG; -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; - -public final class UpdateHandler { - private UpdateHandler() { - } - - /** - * @return whether to exit - */ - public static boolean processArguments(String[] args) { - breakForceUpdateFeature(); - - if (isNestedApplication()) { - // updated from old versions - try { - performMigration(); - } catch (IOException e) { - LOG.log(Level.WARNING, "Failed to perform migration", e); - SwingUtils.showErrorDialog(i18n("fatal.apply_update_failure", Metadata.PUBLISH_URL) + "\n" + StringUtils.getStackTrace(e)); - } - return true; - } - - if (args.length == 2 && args[0].equals("--apply-to")) { - if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && !OperatingSystem.isWindows7OrLater()) { - SwingUtils.showErrorDialog(i18n("fatal.apply_update_need_win7", Metadata.PUBLISH_URL)); - return true; - } - - try { - applyUpdate(Paths.get(args[1])); - } catch (IOException e) { - LOG.log(Level.WARNING, "Failed to apply update", e); - SwingUtils.showErrorDialog(i18n("fatal.apply_update_failure", Metadata.PUBLISH_URL) + "\n" + StringUtils.getStackTrace(e)); - } - return true; - } - - if (isFirstLaunchAfterUpgrade()) { - SwingUtils.showInfoDialog(i18n("fatal.migration_requires_manual_reboot")); - return true; - } - - return false; - } - - public static void updateFrom(RemoteVersion version) { - checkFxUserThread(); - - if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && !OperatingSystem.isWindows7OrLater()) { - Controllers.dialog(i18n("fatal.apply_update_need_win7", Metadata.PUBLISH_URL), i18n("message.error"), MessageType.ERROR); - return; - } - - Controllers.dialog(new UpgradeDialog(version, () -> { - Path downloaded; - try { - downloaded = Files.createTempFile("hmcl-update-", ".jar"); - } catch (IOException e) { - LOG.log(Level.WARNING, "Failed to create temp file", e); - return; - } - - Task task = new HMCLDownloadTask(version, downloaded); - - TaskExecutor executor = task.executor(false); - Controllers.taskDialog(executor, i18n("message.downloading"), TaskCancellationAction.NORMAL); - executor.start(); - thread(() -> { - boolean success = executor.test(); - - if (success) { - try { - if (!IntegrityChecker.isSelfVerified() && !IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK) { - 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"), MessageType.ERROR)); - } - - } else { - Exception e = executor.getException(); - LOG.log(Level.WARNING, "Failed to update to " + version, e); - if (e instanceof CancellationException) { - Platform.runLater(() -> Controllers.showToast(i18n("message.cancelled"))); - } else { - Platform.runLater(() -> Controllers.dialog(e.toString(), i18n("update.failed"), MessageType.ERROR)); - } - } - }); - })); - } - - private static void applyUpdate(Path target) throws IOException { - LOG.info("Applying update to " + target); - - Path self = getCurrentLocation(); - if (!IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK && !IntegrityChecker.isSelfVerified()) { - throw new IOException("Self verification failed"); - } - ExecutableHeaderHelper.copyWithHeader(self, target); - - Optional 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 { - if (!IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK) { - IntegrityChecker.verifyJar(updateTo); - } - startJava(updateTo, "--apply-to", self.toString()); - } - - private static void startJava(Path jar, String... appArgs) throws IOException { - List commandline = new ArrayList<>(); - commandline.add(JavaVersion.fromCurrentEnvironment().getBinary().toString()); - for (Map.Entry entry : System.getProperties().entrySet()) { - Object key = entry.getKey(); - if (key instanceof String && ((String) key).startsWith("hmcl.")) { - commandline.add("-D" + key + "=" + entry.getValue()); - } - } - commandline.add("-jar"); - commandline.add(jar.toAbsolutePath().toString()); - commandline.addAll(Arrays.asList(appArgs)); - LOG.info("Starting process: " + commandline); - new ProcessBuilder(commandline) - .directory(Paths.get("").toAbsolutePath().toFile()) - .inheritIO() - .start(); - } - - private static Optional tryRename(Path path, String newVersion) { - String filename = path.getFileName().toString(); - Matcher matcher = Pattern.compile("^(?[hH][mM][cC][lL][.-])(?\\d+(?:\\.\\d+)*)(?\\.[^.]+)$").matcher(filename); - if (matcher.find()) { - String newFilename = matcher.group("prefix") + newVersion + matcher.group("suffix"); - if (!newFilename.equals(filename)) { - return Optional.of(path.resolveSibling(newFilename)); - } - } - return Optional.empty(); - } - - private static Path getCurrentLocation() throws IOException { - Path path = JarUtils.thisJarPath(); - if (path == null) { - throw new IOException("Failed to find current HMCL location"); - } - return path; - } - - // ==== support for old versions === - private static void performMigration() throws IOException { - LOG.info("Migrating from old versions"); - - Path location = getParentApplicationLocation() - .orElseThrow(() -> new IOException("Failed to get parent application location")); - - requestUpdate(getCurrentLocation(), location); - } - - /** - * This method must be called from the main thread. - */ - private static boolean isNestedApplication() { - StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace(); - for (int i = 0; i < stacktrace.length; i++) { - StackTraceElement element = stacktrace[i]; - if (Main.class.getName().equals(element.getClassName()) && "main".equals(element.getMethodName())) { - // we've reached the main method - return i + 1 != stacktrace.length; - } - } - return false; - } - - private static Optional getParentApplicationLocation() { - String command = System.getProperty("sun.java.command"); - if (command != null) { - Path path = Paths.get(command); - if (Files.isRegularFile(path)) { - return Optional.of(path.toAbsolutePath()); - } - } - return Optional.empty(); - } - - private static boolean isFirstLaunchAfterUpgrade() { - Path currentPath = JarUtils.thisJarPath(); - if (currentPath != null) { - Path updated = Metadata.HMCL_DIRECTORY.resolve("HMCL-" + Metadata.VERSION + ".jar"); - if (currentPath.equals(updated.toAbsolutePath())) { - return true; - } - } - return false; - } - - private static void breakForceUpdateFeature() { - Path hmclVersionJson = Metadata.HMCL_DIRECTORY.resolve("hmclver.json"); - if (Files.isRegularFile(hmclVersionJson)) { - try { - Map content = new Gson().fromJson(FileUtils.readText(hmclVersionJson), 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); - } catch (JsonParseException e) { - hmclVersionJson.toFile().delete(); - } - } - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/resource/RemoteResourceManager.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/resource/RemoteResourceManager.java deleted file mode 100644 index b9c4a31db..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/resource/RemoteResourceManager.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * 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 . - */ -package org.jackhuang.hmcl.upgrade.resource; - -import com.google.gson.annotations.SerializedName; -import com.google.gson.reflect.TypeToken; -import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.task.FileDownloadTask; -import org.jackhuang.hmcl.task.Schedulers; -import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.ui.versions.ModTranslations; -import org.jackhuang.hmcl.upgrade.hmcl.IntegrityChecker; -import org.jackhuang.hmcl.util.DigestUtils; -import org.jackhuang.hmcl.util.function.ExceptionalSupplier; -import org.jackhuang.hmcl.util.io.HttpRequest; -import org.jackhuang.hmcl.util.io.IOUtils; -import org.jackhuang.hmcl.util.io.NetworkUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -public final class RemoteResourceManager { - private RemoteResourceManager() { - } - - private static final class RemoteResource { - @SerializedName("sha1") - private final String sha1; - - @SerializedName("urls") - private final String[] urls; - - private transient byte[] data = null; - - private RemoteResource(String sha1, String[] urls) { - this.sha1 = sha1; - this.urls = urls; - } - - public void download(Path path, Runnable callback) { - if (data != null) { - return; - } - - new FileDownloadTask(Arrays.stream(urls).map(NetworkUtils::toURL).collect(Collectors.toList()), path.toFile(), new FileDownloadTask.IntegrityCheck("SHA-1", sha1)) - .whenComplete(Schedulers.defaultScheduler(), (result, exception) -> { - if (exception != null) { - data = Files.readAllBytes(path); - callback.run(); - } - }).start(); - } - } - - public static final class RemoteResourceKey { - private final String namespace; - private final String name; - private final String version; - private final Path cachePath; - private final ExceptionalSupplier localResourceSupplier; - private String localResourceSha1 = null; - - public RemoteResourceKey(String namespace, String name, String version, ExceptionalSupplier localResourceSupplier) { - this.namespace = namespace; - this.name = name; - this.version = version; - this.localResourceSupplier = localResourceSupplier; - - this.cachePath = Metadata.HMCL_DIRECTORY.resolve("remoteResources").resolve(namespace).resolve(name).resolve(version).resolve(String.format("%s-%s-%s.resource", namespace, name, version)); - } - - private InputStream getLocalResource() throws IOException { - if (Files.isReadable(cachePath)) { - return Files.newInputStream(cachePath); - } - return localResourceSupplier.get(); - } - - private String getLocalResourceSha1() throws IOException { - if (localResourceSha1 == null) { - localResourceSha1 = DigestUtils.digestToString("SHA-1", IOUtils.readFullyAsByteArray(getLocalResource())); - } - - return localResourceSha1; - } - - @Nullable - private RemoteResource getRemoteResource() { - return Optional.ofNullable(remoteResources.get(namespace)).map(map -> map.get(name)).map(map -> map.get(version)).orElse(null); - } - - @Nullable - public InputStream getResource() throws IOException { - RemoteResource remoteResource = getRemoteResource(); - - if (remoteResource == null) { - return getLocalResource(); - } - - if (remoteResource.sha1.equals(getLocalResourceSha1())) { - return getLocalResource(); - } - - if (remoteResource.data == null) { - return null; - } - - return new ByteArrayInputStream(remoteResource.data); - } - - public void downloadRemoteResourceIfNecessary() throws IOException { - RemoteResource remoteResource = getRemoteResource(); - - if (remoteResource == null) { - return; - } - - if (remoteResource.sha1.equals(getLocalResourceSha1())) { - return; - } - - remoteResource.download(cachePath, () -> localResourceSha1 = null); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - RemoteResourceKey that = (RemoteResourceKey) o; - - if (!namespace.equals(that.namespace)) return false; - if (!name.equals(that.name)) return false; - return version.equals(that.version); - } - - @Override - public int hashCode() { - int result = namespace.hashCode(); - result = 31 * result + name.hashCode(); - result = 31 * result + version.hashCode(); - return result; - } - } - - private static final Map>> remoteResources = new ConcurrentHashMap<>(); - - private static final Map keys = new ConcurrentHashMap<>(); - - public static void init() { - Task.>>>supplyAsync(() -> - IntegrityChecker.isSelfVerified() ? HttpRequest.GET(Metadata.RESOURCE_UPDATE_URL).getJson( - new TypeToken>>>() { - }.getType() - ) : null - ).whenComplete(Schedulers.defaultScheduler(), (result, exception) -> { - if (exception == null && result != null) { - remoteResources.clear(); - remoteResources.putAll(result); - - for (RemoteResourceKey key : keys.values()) { - key.downloadRemoteResourceIfNecessary(); - } - } - }).start(); - } - - public static void register() { - ModTranslations.values(); - } - - public static RemoteResourceKey get(@NotNull String namespace, @NotNull String name, @NotNull String version, ExceptionalSupplier defaultSupplier) { - String stringKey = String.format("%s:%s:%s", namespace, name, version); - RemoteResourceKey key = keys.containsKey(stringKey) ? keys.get(stringKey) : new RemoteResourceKey(namespace, name, version, defaultSupplier); - Task.runAsync(key::downloadRemoteResourceIfNecessary).start(); - keys.put(stringKey, key); - return key; - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java index 5e5e28fe5..ba2158ac2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java @@ -23,8 +23,6 @@ import javafx.scene.control.Alert.AlertType; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.countly.CrashReport; import org.jackhuang.hmcl.ui.CrashWindow; -import org.jackhuang.hmcl.upgrade.hmcl.IntegrityChecker; -import org.jackhuang.hmcl.upgrade.hmcl.UpdateChecker; import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.IOException; @@ -103,9 +101,6 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler { if (showCrashWindow) { new CrashWindow(report).show(); } - if (!UpdateChecker.isOutdated() && IntegrityChecker.isSelfVerified()) { - reportToServer(report); - } } }); } catch (Throwable handlingException) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameDumpGenerator.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameDumpGenerator.java index 984cdfd79..7fd482fca 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameDumpGenerator.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameDumpGenerator.java @@ -165,10 +165,6 @@ public final class GameDumpGenerator { } private static InputStream executeJVMCommand(VirtualMachine vm, String command) throws IOException, AttachNotSupportedException { - if (vm instanceof sun.tools.attach.HotSpotVirtualMachine) { - return ((sun.tools.attach.HotSpotVirtualMachine) vm).executeJCmd(command); - } else { - throw new AttachNotSupportedException("Unsupported VM implementation " + vm.getClass().getName()); - } + throw new AttachNotSupportedException("Unsupported VM implementation " + vm.getClass().getName()); } } -- 2.43.0