From d6a106a2336775c36651deadafe6cb8b48e87339 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 | 9 - .../java/org/jackhuang/hmcl/Metadata.java | 2 - .../org/jackhuang/hmcl/countly/Countly.java | 86 ------ .../org/jackhuang/hmcl/ui/Controllers.java | 9 - .../org/jackhuang/hmcl/ui/CrashWindow.java | 3 - .../org/jackhuang/hmcl/ui/UpgradeDialog.java | 76 ----- .../hmcl/ui/account/CreateAccountPane.java | 16 - .../jackhuang/hmcl/ui/main/FeedbackPage.java | 79 ----- .../hmcl/ui/main/LauncherSettingsPage.java | 14 +- .../org/jackhuang/hmcl/ui/main/MainPage.java | 135 +-------- .../org/jackhuang/hmcl/ui/main/RootPage.java | 11 - .../jackhuang/hmcl/ui/main/SettingsPage.java | 60 ---- .../jackhuang/hmcl/ui/main/SettingsView.java | 58 ---- .../hmcl/upgrade/ExecutableHeaderHelper.java | 124 -------- .../hmcl/upgrade/HMCLDownloadTask.java | 68 ----- .../hmcl/upgrade/IntegrityChecker.java | 145 --------- .../jackhuang/hmcl/upgrade/RemoteVersion.java | 103 ------- .../jackhuang/hmcl/upgrade/UpdateChannel.java | 42 --- .../jackhuang/hmcl/upgrade/UpdateChecker.java | 127 -------- .../jackhuang/hmcl/upgrade/UpdateHandler.java | 281 ------------------ .../jackhuang/hmcl/util/CrashReporter.java | 5 - .../hmcl/game/GameDumpGenerator.java | 6 +- 22 files changed, 3 insertions(+), 1456 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/upgrade/ExecutableHeaderHelper.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IntegrityChecker.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChannel.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateHandler.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java index 494dda7b3..de7786921 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java @@ -30,8 +30,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.UpdateChecker; -import org.jackhuang.hmcl.upgrade.UpdateHandler; import org.jackhuang.hmcl.util.CrashReporter; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.StringUtils; @@ -111,8 +109,6 @@ public final class Launcher extends Application { Platform.setImplicitExit(false); Controllers.initialize(primaryStage); - UpdateChecker.init(); - primaryStage.show(); }); } catch (Throwable e) { @@ -212,11 +208,6 @@ public final class Launcher extends Application { } public static void main(String[] args) { - if (UpdateHandler.processArguments(args)) { - LOG.shutdown(); - 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 06198bfb9..b8d0d50f1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Metadata.java @@ -37,7 +37,6 @@ public final class Metadata { public static final String TITLE = NAME + " " + VERSION; public static final String FULL_TITLE = FULL_NAME + " v" + VERSION; - public static final String HMCL_UPDATE_URL = System.getProperty("hmcl.update_source.override", "https://hmcl.huangyuhui.net/api/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/"; @@ -45,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 f18b19685..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/countly/Countly.java +++ /dev/null @@ -1,86 +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.time.ZonedDateTime; -import java.util.Calendar; -import java.util.Locale; - -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(getTimezoneOffset())), - 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 ZonedDateTime.now().getOffset().getTotalSeconds() / 60; - } - - 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 af9c01d4a..82758c65e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -386,15 +386,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 c1f7158d4..60215297a 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.UpdateChecker; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -41,8 +40,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 e8602e394..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/UpgradeDialog.java +++ /dev/null @@ -1,76 +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.RemoteVersion; - - -import static org.jackhuang.hmcl.Metadata.CHANGELOG_URL; -import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; -import static org.jackhuang.hmcl.util.logging.Logger.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.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 9a17ba55c..606bf4465 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 @@ -57,7 +57,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.IntegrityChecker; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter; import org.jackhuang.hmcl.util.javafx.BindingMapping; @@ -322,12 +321,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); @@ -399,15 +392,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 ec9932bcd..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/icon.png")); - users.setTitle(i18n("feedback.qq_group")); - users.setSubtitle(i18n("feedback.qq_group.statement")); - users.setExternalLink("https://docs.hmcl.net/groups.html"); - - 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 dbcba03c0..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,7 +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 TransitionPane transitionPane = new TransitionPane(); public LauncherSettingsPage() { @@ -54,9 +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); aboutTab.setNodeSupplier(AboutPage::new); - tab = new TabHeader(gameTab, settingsTab, personalizationTab, downloadTab, helpTab, feedbackTab, aboutTab); + tab = new TabHeader(gameTab, settingsTab, personalizationTab, downloadTab, helpTab, aboutTab); tab.select(gameTab); gameTab.initializeIfNeeded(); @@ -100,12 +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(aboutItem -> { aboutItem.setTitle(i18n("about")); aboutItem.setLeftGraphic(wrap(SVG.INFORMATION_OUTLINE)); @@ -134,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 6f1cf7f17..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.RemoteVersion; -import org.jackhuang.hmcl.upgrade.UpdateChecker; -import org.jackhuang.hmcl.upgrade.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 abf24d6ce..c892a4180 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 @@ -42,7 +42,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.UpdateChecker; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.TaskCancellationAction; @@ -109,8 +108,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(); @@ -174,13 +171,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { launcherSettingsItem.setTitle(i18n("settings")); launcherSettingsItem.setOnAction(e -> Controllers.navigate(Controllers.getSettingsPage())); - // sixth item in left sidebar - AdvancedListItem chatItem = new AdvancedListItem(); - chatItem.setLeftGraphic(wrap(SVG.CHAT)); - chatItem.setActionButtonVisible(false); - chatItem.setTitle(i18n("chat")); - chatItem.setOnAction(e -> FXUtils.openLink("https://docs.hmcl.net/groups.html")); - // the left sidebar AdvancedListBox sideBar = new AdvancedListBox() .startCategory(i18n("account").toUpperCase(Locale.ROOT)) @@ -191,7 +181,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { .add(downloadItem) .startCategory(i18n("settings.launcher.general").toUpperCase(Locale.ROOT)) .add(launcherSettingsItem) - .add(chatItem) ; // 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 90df9e610..2de8c21d2 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.RemoteVersion; -import org.jackhuang.hmcl.upgrade.UpdateChannel; -import org.jackhuang.hmcl.upgrade.UpdateChecker; -import org.jackhuang.hmcl.upgrade.UpdateHandler; import org.jackhuang.hmcl.util.StringUtils; 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://github.com/HMCL-dev/HMCL"); - } - @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 39bd0ae17..4eb1fd25b 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 @@ -50,11 +50,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() { @@ -70,11 +65,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(); @@ -97,51 +87,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); } { @@ -205,11 +151,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/upgrade/ExecutableHeaderHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/ExecutableHeaderHelper.java deleted file mode 100644 index 7c47f586d..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/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; - -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/HMCLDownloadTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java deleted file mode 100644 index 8b6fdc06c..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/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; - -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/IntegrityChecker.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IntegrityChecker.java deleted file mode 100644 index 510a59c8a..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IntegrityChecker.java +++ /dev/null @@ -1,145 +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; - -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.zip.ZipEntry; -import java.util.zip.ZipFile; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.jackhuang.hmcl.util.logging.Logger.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.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/RemoteVersion.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java deleted file mode 100644 index 81947320e..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java +++ /dev/null @@ -1,103 +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; - -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); - boolean force = Optional.ofNullable(response.get("force")).map(JsonElement::getAsBoolean).orElse(false); - if (Pack200Utils.isSupported() && packXZUrl != null && packXZHash != null) { - return new RemoteVersion(channel, version, packXZUrl, Type.PACK_XZ, new IntegrityCheck("SHA-1", packXZHash), force); - } else if (jarUrl != null && jarHash != null) { - return new RemoteVersion(channel, version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash), force); - } 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; - private final boolean force; - - public RemoteVersion(UpdateChannel channel, String version, String url, Type type, IntegrityCheck integrityCheck, boolean force) { - this.channel = channel; - this.version = version; - this.url = url; - this.type = type; - this.integrityCheck = integrityCheck; - this.force = force; - } - - 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; - } - - public boolean isForce() { - return force; - } - - @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/UpdateChannel.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChannel.java deleted file mode 100644 index 998a3da7d..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/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; - -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/UpdateChecker.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java deleted file mode 100644 index b4663b0f2..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java +++ /dev/null @@ -1,127 +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; - -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 org.jackhuang.hmcl.util.versioning.VersionNumber; - -import java.io.IOException; - -import static org.jackhuang.hmcl.util.Lang.mapOf; -import static org.jackhuang.hmcl.util.Lang.thread; -import static org.jackhuang.hmcl.util.logging.Logger.LOG; -import static org.jackhuang.hmcl.util.Pair.pair; - -public final class UpdateChecker { - private UpdateChecker() {} - - private static final ObjectProperty latestVersion = new SimpleObjectProperty<>(); - private static final BooleanBinding outdated = Bindings.createBooleanBinding( - () -> { - RemoteVersion latest = latestVersion.get(); - if (latest == null || isDevelopmentVersion(Metadata.VERSION)) { - return false; - } else if (latest.isForce() - || Metadata.isNightly() - || latest.getChannel() == UpdateChannel.NIGHTLY - || latest.getChannel() != UpdateChannel.getChannel()) { - return !latest.getVersion().equals(Metadata.VERSION); - } else { - return VersionNumber.compare(Metadata.VERSION, latest.getVersion()) < 0; - } - }, - latestVersion); - private static final 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.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/UpdateHandler.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateHandler.java deleted file mode 100644 index d0dccc4f7..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateHandler.java +++ /dev/null @@ -1,281 +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; - -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.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.Logger.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.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.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.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()); - Main.exit(0); - } catch (IOException e) { - LOG.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.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.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.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/util/CrashReporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java index ad3121b5b..434a6433a 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.IntegrityChecker; -import org.jackhuang.hmcl.upgrade.UpdateChecker; import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.IOException; @@ -102,9 +100,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 36ab72ee2..eae748add 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameDumpGenerator.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameDumpGenerator.java @@ -164,10 +164,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.45.1