diff --git a/Apache License 2.0~ b/Apache License 2.0~ new file mode 100644 index 000000000..e69de29bb diff --git a/HMCL/build.gradle b/HMCL/build.gradle index 58e11892e..4b8ce3dcb 100644 --- a/HMCL/build.gradle +++ b/HMCL/build.gradle @@ -80,8 +80,8 @@ jar { } launch4j { - //launch4jCmd = 'D:\\Develop\\Java\\Launch4j\\launch4j.exe' - launch4jCmd = '/home/huangyuhui/softwares/launch4j/launch4j' + launch4jCmd = 'D:\\Develop\\Java\\Launch4j\\launch4j.exe' + //launch4jCmd = '/home/huangyuhui/softwares/launch4j/launch4j' supportUrl = 'http://www.mcbbs.net/thread-142335-1-1.html' jreMinVersion = '1.6.0' diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Main.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Main.java index 175422b72..d76b4cd37 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Main.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Main.java @@ -17,34 +17,21 @@ */ package org.jackhuang.hellominecraft.launcher; -import java.awt.Toolkit; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.Authenticator; import java.net.PasswordAuthentication; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; import java.security.GeneralSecurityException; import java.security.cert.X509Certificate; import java.text.ParseException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Map; -import java.util.jar.JarFile; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; import javax.swing.ImageIcon; -import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import org.jackhuang.hellominecraft.C; import org.jackhuang.hellominecraft.HMCLog; import org.jackhuang.hellominecraft.launcher.launch.GameLauncher; import org.jackhuang.hellominecraft.launcher.utils.CrashReporter; @@ -53,18 +40,13 @@ import org.jackhuang.hellominecraft.logging.appender.ConsoleAppender; import org.jackhuang.hellominecraft.logging.layout.DefaultLayout; import org.jackhuang.hellominecraft.views.LogWindow; import org.jackhuang.hellominecraft.launcher.settings.Settings; -import org.jackhuang.hellominecraft.launcher.utils.upgrade.Upgrader; +import org.jackhuang.hellominecraft.launcher.utils.upgrade.IUpgrader; import org.jackhuang.hellominecraft.launcher.views.MainFrame; import org.jackhuang.hellominecraft.lookandfeel.HelloMinecraftLookAndFeel; -import org.jackhuang.hellominecraft.tasks.TaskWindow; -import org.jackhuang.hellominecraft.utils.ArrayUtils; import org.jackhuang.hellominecraft.utils.MathUtils; -import org.jackhuang.hellominecraft.utils.MessageBox; import org.jackhuang.hellominecraft.utils.StrUtils; import org.jackhuang.hellominecraft.utils.VersionNumber; -import org.jackhuang.hellominecraft.utils.system.FileUtils; -import org.jackhuang.hellominecraft.utils.system.IOUtils; -import org.jackhuang.hellominecraft.utils.system.OS; +import rx.concurrency.Schedulers; /** * @@ -104,7 +86,7 @@ public final class Main implements Runnable { } public static String launcherName = "Hello Minecraft! Launcher"; - public static byte firstVer = 2, secondVer = 3, thirdVer = 5, forthVer = 6; + public static byte firstVer = 2, secondVer = 3, thirdVer = 1, forthVer = 6; public static int minimumLauncherVersion = 16; //public static Proxy PROXY; @@ -131,34 +113,8 @@ public final class Main implements Runnable { @SuppressWarnings( {"CallToPrintStackTrace", "UseSpecificCatch"}) public static void main(String[] args) { { - if (!ArrayUtils.contains(args, "nofound")) - try { - File f = Upgrader.HMCL_VER_FILE; - if (f.exists()) { - Map m = C.gson.fromJson(FileUtils.readFileToString(f), Map.class); - String s = m.get("ver"); - if (s != null && VersionNumber.check(s).compareTo(new VersionNumber(firstVer, secondVer, thirdVer)) > 0) { - String j = m.get("loc"); - if (j != null) { - File jar = new File(j); - if (jar.exists()) { - JarFile jarFile = new JarFile(jar); - String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class"); - if (mainClass != null) { - ArrayList al = new ArrayList<>(Arrays.asList(args)); - al.add("notfound"); - new URLClassLoader(new URL[] {jar.toURI().toURL()}, - URLClassLoader.getSystemClassLoader().getParent()).loadClass(mainClass) - .getMethod("main", String[].class).invoke(null, new Object[] {al.toArray(new String[0])}); - return; - } - } - } - } - } - } catch (Throwable t) { - t.printStackTrace(); - } + if (IUpgrader.NOW_UPGRADER.parseArguments(new VersionNumber(firstVer, secondVer, thirdVer), args)) + return; System.setProperty("sun.java2d.noddraw", "true"); @@ -185,7 +141,9 @@ public final class Main implements Runnable { HMCLog.warn("Failed to set look and feel...", ex); } - Settings.UPDATE_CHECKER.start(); + Settings.UPDATE_CHECKER.outdated.register(IUpgrader.NOW_UPGRADER); + Settings.UPDATE_CHECKER.process(false).subscribeOn(Schedulers.newThread()).subscribe(t -> + Main.invokeUpdate()); if (StrUtils.isNotBlank(Settings.getInstance().getProxyHost()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPort()) && MathUtils.canParseInt(Settings.getInstance().getProxyPort())) { HMCLog.log("Initializing customized proxy"); @@ -198,9 +156,6 @@ public final class Main implements Runnable { return new PasswordAuthentication(Settings.getInstance().getProxyUserName(), Settings.getInstance().getProxyPassword().toCharArray()); } }); - //PROXY = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(Settings.getInstance().getProxyHost(), Integer.parseInt(Settings.getInstance().getProxyPort()))); - } else { - //PROXY = Proxy.NO_PROXY; } try { @@ -217,44 +172,6 @@ public final class Main implements Runnable { GameLauncher.PROCESS_MANAGER.stopAllProcesses(); } - public static void update() { - Settings.UPDATE_CHECKER.requestDownloadLink(() -> { - SwingUtilities.invokeLater(() -> { - Map map = Settings.UPDATE_CHECKER.download_link; - if (map != null && map.containsKey("pack")) - try { - if (TaskWindow.getInstance().addTask(new Upgrader(map.get("pack"), Settings.UPDATE_CHECKER.versionString)).start()) { - new ProcessBuilder(new String[] {IOUtils.getJavaDir(), "-jar", Upgrader.getSelf(Settings.UPDATE_CHECKER.versionString).getAbsolutePath()}).directory(new File(".")).start(); - System.exit(0); - } - } catch (IOException ex) { - HMCLog.warn("Failed to create upgrader", ex); - } - if (MessageBox.Show(C.i18n("update.newest_version") + Settings.UPDATE_CHECKER.getNewVersion().firstVer + "." + Settings.UPDATE_CHECKER.getNewVersion().secondVer + "." + Settings.UPDATE_CHECKER.getNewVersion().thirdVer + "\n" - + C.i18n("update.should_open_link"), - MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) { - String url = C.URL_PUBLISH; - if (map != null) - if (map.containsKey(OS.os().checked_name)) - url = map.get(OS.os().checked_name); - else if (map.containsKey(OS.UNKOWN.checked_name)) - url = map.get(OS.UNKOWN.checked_name); - if (url == null) - url = C.URL_PUBLISH; - try { - java.awt.Desktop.getDesktop().browse(new URI(url)); - } catch (URISyntaxException | IOException e) { - HMCLog.warn("Failed to browse uri: " + url, e); - - Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); - cb.setContents(new StringSelection(url), null); - MessageBox.Show(C.i18n("update.no_browser")); - } - } - }); - }); - } - public static void invokeUpdate() { MainFrame.INSTANCE.invokeUpdate(); } diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/AbstractMinecraftLoader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/AbstractMinecraftLoader.java index 38b96de3c..2f4056123 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/AbstractMinecraftLoader.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/AbstractMinecraftLoader.java @@ -159,7 +159,9 @@ public abstract class AbstractMinecraftLoader implements IMinecraftLoader { res.add(v.getWidth()); } - if (StrUtils.isNotBlank(v.getServerIp())) { + String serverIp = v.getServerIp(); + if (lr.getServerIp() != null) serverIp = lr.getServerIp(); + if (StrUtils.isNotBlank(serverIp)) { String[] args = v.getServerIp().split(":"); res.add("--server"); res.add(args[0]); diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/settings/Settings.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/settings/Settings.java index 4c1120862..b013fc251 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/settings/Settings.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/settings/Settings.java @@ -70,7 +70,7 @@ public final class Settings { e.checkFormat(); UPDATE_CHECKER = new UpdateChecker(new VersionNumber(Main.firstVer, Main.secondVer, Main.thirdVer), - "hmcl", Main::invokeUpdate); + "hmcl"); List temp = new ArrayList<>(); temp.add(new Java("Default", System.getProperty("java.home"))); @@ -119,7 +119,8 @@ public final class Settings { } public static Profile getProfile(String name) { - if (name == null) return getProfiles().get("Default"); + if (name == null) + return getProfiles().get("Default"); return getProfiles().get(name); } diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/CrashReporter.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/CrashReporter.java index 91aff6a60..9928153bd 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/CrashReporter.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/CrashReporter.java @@ -26,8 +26,8 @@ import javax.swing.SwingUtilities; import org.jackhuang.hellominecraft.C; import org.jackhuang.hellominecraft.HMCLog; import org.jackhuang.hellominecraft.launcher.Main; +import org.jackhuang.hellominecraft.launcher.settings.Settings; import org.jackhuang.hellominecraft.utils.NetUtils; -import org.jackhuang.hellominecraft.utils.UpdateChecker; import org.jackhuang.hellominecraft.utils.MessageBox; import org.jackhuang.hellominecraft.utils.StrUtils; import org.jackhuang.hellominecraft.views.LogWindow; @@ -105,8 +105,8 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler { System.out.println(text); if (checkThrowable(e) && !System.getProperty("java.vm.name").contains("OpenJDK")) { - SwingUtilities.invokeLater(() -> LogWindow.INSTANCE.showAsCrashWindow(UpdateChecker.OUT_DATED)); - if (!UpdateChecker.OUT_DATED) + SwingUtilities.invokeLater(() -> LogWindow.INSTANCE.showAsCrashWindow(Settings.UPDATE_CHECKER.OUT_DATED)); + if (!Settings.UPDATE_CHECKER.OUT_DATED) reportToServer(text, s); } } catch (Throwable ex) { diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/auth/UserProfileProvider.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/auth/UserProfileProvider.java index ece464a82..e7f1e3145 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/auth/UserProfileProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/auth/UserProfileProvider.java @@ -52,7 +52,8 @@ public final class UserProfileProvider { } public void setAccessToken(String accessToken) { - if (accessToken == null) accessToken = "0"; + if (accessToken == null) + accessToken = "0"; this.accessToken = accessToken; } @@ -114,4 +115,13 @@ public final class UserProfileProvider { private String otherInfo = ""; private String clientIdentifier = ""; private String userType = "Offline"; + private String serverIp = ""; + + public String getServerIp() { + return serverIp; + } + + public void setServerIp(String serverIp) { + this.serverIp = serverIp; + } } diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/installers/InstallerService.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/installers/InstallerService.java index 86d8d0f93..a4829301c 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/installers/InstallerService.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/installers/InstallerService.java @@ -19,7 +19,6 @@ package org.jackhuang.hellominecraft.launcher.utils.installers; import java.io.File; import org.jackhuang.hellominecraft.launcher.settings.Profile; -import org.jackhuang.hellominecraft.launcher.settings.Settings; import org.jackhuang.hellominecraft.launcher.utils.installers.InstallerVersionList.InstallerVersion; import org.jackhuang.hellominecraft.launcher.utils.installers.forge.ForgeInstaller; import org.jackhuang.hellominecraft.launcher.utils.installers.liteloader.LiteLoaderInstaller; @@ -64,7 +63,7 @@ public final class InstallerService { File filepath = IOUtils.tryGetCanonicalFile(IOUtils.currentDirWithSeparator() + "forge-installer.jar"); if (v.installer != null) TaskWindow.getInstance() - .addTask(new FileDownloadTask(Settings.getInstance().getDownloadSource().getProvider().getParsedLibraryDownloadURL(v.installer), filepath).setTag("forge")) + .addTask(new FileDownloadTask(p.getDownloadType().getProvider().getParsedLibraryDownloadURL(v.installer), filepath).setTag("forge")) .addTask(new ForgeInstaller(p.getMinecraftProvider(), filepath, v)) .start(); } diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/AppDataUpgrader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/AppDataUpgrader.java new file mode 100644 index 000000000..2ad5db2fe --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/AppDataUpgrader.java @@ -0,0 +1,180 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hellominecraft.launcher.utils.upgrade; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Pack200; +import java.util.zip.GZIPInputStream; +import org.jackhuang.hellominecraft.C; +import org.jackhuang.hellominecraft.HMCLog; +import org.jackhuang.hellominecraft.launcher.utils.MCUtils; +import org.jackhuang.hellominecraft.tasks.Task; +import org.jackhuang.hellominecraft.tasks.TaskWindow; +import org.jackhuang.hellominecraft.tasks.download.FileDownloadTask; +import org.jackhuang.hellominecraft.utils.ArrayUtils; +import org.jackhuang.hellominecraft.utils.MessageBox; +import org.jackhuang.hellominecraft.utils.UpdateChecker; +import org.jackhuang.hellominecraft.utils.VersionNumber; +import org.jackhuang.hellominecraft.utils.system.FileUtils; +import org.jackhuang.hellominecraft.utils.system.IOUtils; +import org.jackhuang.hellominecraft.utils.system.OS; +import rx.concurrency.Schedulers; + +/** + * + * @author huangyuhui + */ +public class AppDataUpgrader extends IUpgrader { + + @Override + public boolean parseArguments(VersionNumber nowVersion, String[] args) { + if (!ArrayUtils.contains(args, "nofound")) + try { + File f = AppDataUpgraderTask.HMCL_VER_FILE; + if (f.exists()) { + Map m = C.gson.fromJson(FileUtils.readFileToString(f), Map.class); + String s = m.get("ver"); + if (s != null && VersionNumber.check(s).compareTo(nowVersion) > 0) { + String j = m.get("loc"); + if (j != null) { + File jar = new File(j); + if (jar.exists()) { + JarFile jarFile = new JarFile(jar); + String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class"); + if (mainClass != null) { + ArrayList al = new ArrayList<>(Arrays.asList(args)); + al.add("notfound"); + new URLClassLoader(new URL[] {jar.toURI().toURL()}, + URLClassLoader.getSystemClassLoader().getParent()).loadClass(mainClass) + .getMethod("main", String[].class).invoke(null, new Object[] {al.toArray(new String[0])}); + return true; + } + } + } + } + } + } catch (Throwable t) { + t.printStackTrace(); + } + return false; + } + + @Override + public boolean call(Object sender, VersionNumber number) { + ((UpdateChecker) sender).requestDownloadLink().subscribeOn(Schedulers.newThread()).observeOn(Schedulers.eventQueue()).subscribe(map -> { + if (map != null && map.containsKey("pack")) + try { + if (TaskWindow.getInstance().addTask(new AppDataUpgraderTask(map.get("pack"), number.version)).start()) { + new ProcessBuilder(new String[] {IOUtils.getJavaDir(), "-jar", AppDataUpgraderTask.getSelf(number.version).getAbsolutePath()}).directory(new File(".")).start(); + System.exit(0); + } + } catch (IOException ex) { + HMCLog.err("Failed to create upgrader", ex); + } + if (MessageBox.Show(C.i18n("update.newest_version") + number.firstVer + "." + number.secondVer + "." + number.thirdVer + "\n" + + C.i18n("update.should_open_link"), + MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) { + String url = C.URL_PUBLISH; + if (map != null) + if (map.containsKey(OS.os().checked_name)) + url = map.get(OS.os().checked_name); + else if (map.containsKey(OS.UNKOWN.checked_name)) + url = map.get(OS.UNKOWN.checked_name); + if (url == null) + url = C.URL_PUBLISH; + try { + java.awt.Desktop.getDesktop().browse(new URI(url)); + } catch (URISyntaxException | IOException e) { + HMCLog.warn("Failed to browse uri: " + url, e); + + Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); + cb.setContents(new StringSelection(url), null); + MessageBox.Show(C.i18n("update.no_browser")); + } + } + }); + return true; + } + + public static class AppDataUpgraderTask extends Task { + + public static final File BASE_FOLDER = MCUtils.getWorkingDirectory("hmcl"); + public static final File HMCL_VER_FILE = new File(BASE_FOLDER, "hmclver.json"); + + public static File getSelf(String ver) { + return new File(BASE_FOLDER, "HMCL-" + ver + ".jar"); + } + + private final String downloadLink, newestVersion; + File tempFile; + + public AppDataUpgraderTask(String downloadLink, String newestVersion) throws IOException { + this.downloadLink = downloadLink; + this.newestVersion = newestVersion; + tempFile = File.createTempFile("hmcl", ".pack.xz"); + } + + @Override + public Collection getDependTasks() { + return Arrays.asList(new FileDownloadTask(downloadLink, tempFile)); + } + + @Override + public void executeTask() throws Exception { + HashMap json = new HashMap<>(); + File f = getSelf(newestVersion); + if (!f.getParentFile().exists()) + f.getParentFile().mkdirs(); + + for (int i = 0; f.exists(); i++) + f = new File(BASE_FOLDER, "HMCL-" + newestVersion + (i > 0 ? "-" + i : "") + ".jar"); + f.createNewFile(); + + try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(f))) { + Pack200.newUnpacker().unpack(new GZIPInputStream(new FileInputStream(tempFile)), jos); + } + json.put("ver", newestVersion); + json.put("loc", f.getAbsolutePath()); + String result = C.gson.toJson(json); + FileUtils.write(HMCL_VER_FILE, result); + } + + @Override + public String getInfo() { + return "Upgrade"; + } + + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/IUpgrader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/IUpgrader.java new file mode 100644 index 000000000..182d513bc --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/IUpgrader.java @@ -0,0 +1,50 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hellominecraft.launcher.utils.upgrade; + +import org.jackhuang.hellominecraft.utils.Event; +import org.jackhuang.hellominecraft.utils.VersionNumber; + +/** + * + * @author huangyuhui + */ +public abstract class IUpgrader implements Event { + + public static final IUpgrader NOW_UPGRADER = new AppDataUpgrader(); + + /** + * Paring arguments to decide on whether the upgrade is needed. + * + * @param nowVersion now launcher version + * @param args Application CommandLine Arguments + * @return true if it is needed to break the main thread to shutdown this + * application. + */ + public abstract boolean parseArguments(VersionNumber nowVersion, String[] args); + + /** + * Just download the new app. + * + * @param sender Should be VersionChecker + * @param number the newest version + * @return should return true + */ + @Override + public abstract boolean call(Object sender, VersionNumber number); +} diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/NewFileUpgrader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/NewFileUpgrader.java new file mode 100644 index 000000000..170e70b29 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/NewFileUpgrader.java @@ -0,0 +1,68 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hellominecraft.launcher.utils.upgrade; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.jackhuang.hellominecraft.HMCLog; +import org.jackhuang.hellominecraft.tasks.TaskWindow; +import org.jackhuang.hellominecraft.tasks.download.FileDownloadTask; +import org.jackhuang.hellominecraft.utils.ArrayUtils; +import org.jackhuang.hellominecraft.utils.VersionNumber; +import org.jackhuang.hellominecraft.utils.system.FileUtils; +import org.jackhuang.hellominecraft.utils.system.IOUtils; + +/** + * + * @author huangyuhui + */ +public class NewFileUpgrader extends IUpgrader { + + @Override + public boolean parseArguments(VersionNumber nowVersion, String[] args) { + int i = ArrayUtils.indexOf(args, "--removeOldLauncher"); + if (i != -1 && i < args.length - 1) { + File f = new File(args[i + 1]); + if (f.exists()) + f.deleteOnExit(); + } + return false; + } + + @Override + public boolean call(Object sender, VersionNumber number) { + String str = requestDownloadLink(); + File newf = new File(FileUtils.getName(str)); + if (TaskWindow.getInstance().addTask(new FileDownloadTask(str, newf)).start()) { + try { + new ProcessBuilder(new String[] {IOUtils.tryGetCanonicalFilePath(newf), "--removeOldLauncher", IOUtils.getRealPath()}).directory(new File(".")).start(); + } catch (IOException ex) { + HMCLog.err("Failed to start new app", ex); + } + System.exit(0); + } + return true; + } + + private String requestDownloadLink() { + return null; + } + +} diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/Upgrader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/Upgrader.java deleted file mode 100644 index a31bb81a1..000000000 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/upgrade/Upgrader.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2013 huangyuhui - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hellominecraft.launcher.utils.upgrade; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.jar.JarOutputStream; -import java.util.jar.Pack200; -import org.jackhuang.hellominecraft.C; -import org.jackhuang.hellominecraft.launcher.utils.MCUtils; -import org.jackhuang.hellominecraft.tasks.Task; -import org.jackhuang.hellominecraft.tasks.download.FileDownloadTask; -import org.jackhuang.hellominecraft.utils.system.FileUtils; -import org.tukaani.xz.XZInputStream; - -/** - * - * @author huangyuhui - */ -public class Upgrader extends Task { - - public static final File BASE_FOLDER = MCUtils.getWorkingDirectory("hmcl"); - public static final File HMCL_VER_FILE = new File(BASE_FOLDER, "hmclver.json"); - - public static File getSelf(String ver) { - return new File(BASE_FOLDER, "HMCL-" + ver + ".jar"); - } - - private final String downloadLink, newestVersion; - File tempFile; - - public Upgrader(String downloadLink, String newestVersion) throws IOException { - this.downloadLink = downloadLink; - this.newestVersion = newestVersion; - tempFile = File.createTempFile("hmcl", ".pack.xz"); - } - - @Override - public Collection getDependTasks() { - return Arrays.asList(new FileDownloadTask(downloadLink, tempFile)); - } - - @Override - public void executeTask() throws Exception { - HashMap json = new HashMap<>(); - File f = getSelf(newestVersion); - if (!f.getParentFile().exists()) - f.getParentFile().mkdirs(); - - for (int i = 0; f.exists(); i++) - f = new File(BASE_FOLDER, "HMCL-" + newestVersion + (i > 0 ? "-" + i : "") + ".jar"); - f.createNewFile(); - - try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(f))) { - Pack200.newUnpacker().unpack(new XZInputStream(new FileInputStream(tempFile)), jos); - } - json.put("ver", newestVersion); - json.put("loc", f.getAbsolutePath()); - String result = C.gson.toJson(json); - FileUtils.write(HMCL_VER_FILE, result); - } - - @Override - public String getInfo() { - return "Upgrade"; - } - -} diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/AnimatedPanel.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/AnimatedPanel.java index f468d1728..35f125bd0 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/AnimatedPanel.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/AnimatedPanel.java @@ -18,7 +18,6 @@ package org.jackhuang.hellominecraft.launcher.views; import java.awt.AlphaComposite; -import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/InstallerPanel.form b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/InstallerPanel.form index a1a14ea5e..50e6f4b35 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/InstallerPanel.form +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/InstallerPanel.form @@ -28,7 +28,7 @@ - + diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/InstallerPanel.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/InstallerPanel.java index e66e923c5..59ee9f7d4 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/InstallerPanel.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/InstallerPanel.java @@ -18,7 +18,6 @@ package org.jackhuang.hellominecraft.launcher.views; import java.util.List; -import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.table.DefaultTableModel; import org.jackhuang.hellominecraft.C; @@ -104,7 +103,7 @@ public class InstallerPanel extends AnimatedPanel { ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane12, javax.swing.GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE) + .addComponent(jScrollPane12, javax.swing.GroupLayout.DEFAULT_SIZE, 147, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(btnInstall) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/MainFrame.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/MainFrame.java index 13a8980f9..c4d2298ca 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/MainFrame.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/MainFrame.java @@ -41,7 +41,6 @@ import org.jackhuang.hellominecraft.C; import org.jackhuang.hellominecraft.HMCLog; import org.jackhuang.hellominecraft.launcher.Main; import org.jackhuang.hellominecraft.launcher.settings.Settings; -import org.jackhuang.hellominecraft.utils.UpdateChecker; import org.jackhuang.hellominecraft.utils.Utils; import org.jackhuang.hellominecraft.views.DropShadowBorder; import org.jackhuang.hellominecraft.views.TintablePanel; @@ -187,8 +186,7 @@ public final class MainFrame extends DraggableFrame { @Override public void mouseClicked(MouseEvent e) { - if (UpdateChecker.OUT_DATED) - Main.update(); + Settings.UPDATE_CHECKER.checkOutdate(); } @Override @@ -314,7 +312,7 @@ public final class MainFrame extends DraggableFrame { isShowedMessage = false; reloadColor(); windowTitle.setText(defaultTitle); - windowTitle.setForeground(UpdateChecker.OUT_DATED ? Color.red : Color.white); + windowTitle.setForeground(Settings.UPDATE_CHECKER.OUT_DATED ? Color.red : Color.white); } } @@ -354,14 +352,15 @@ public final class MainFrame extends DraggableFrame { } private void paintImpl(Graphics g) { - super.paint(g); - g.setColor(borderColor); int off = enableShadow ? 16 : 0; int width = 800; int height = header.getHeight() + 480 - 1; + super.paint(g); + g.setColor(borderColor); g.drawLine(off, off, off, height + off + 1); g.drawLine(off + width + 1, off, off + width + 1, height + off + 1); g.drawLine(off, height + off + 1, off + width + 1, height + off + 1); + g.dispose(); } @Override diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/tasks/TaskWindow.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/tasks/TaskWindow.java index e1a8bbc40..6fd194171 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/tasks/TaskWindow.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/tasks/TaskWindow.java @@ -17,7 +17,6 @@ */ package org.jackhuang.hellominecraft.tasks; -import java.awt.EventQueue; import java.util.ArrayList; import java.util.LinkedList; import javax.swing.SwingUtilities; @@ -300,28 +299,16 @@ public class TaskWindow extends javax.swing.JDialog } public boolean start() { - Runnable r = () -> { + return SwingUtils.invokeAndWait(() -> { synchronized (INSTANCE) { - if (INSTANCE.isVisible()) { - flag = false; - return; - } + if (INSTANCE.isVisible()) + return false; TaskWindow tw = inst(); for (Task t : ll) tw.addTask(t); - flag = tw.start(); + return tw.start(); } - }; - if (EventQueue.isDispatchThread()) - r.run(); - else - try { - EventQueue.invokeAndWait(r); - } catch (Exception e) { - HMCLog.err("Failed to invokeAndWait, the UI will work abnormally.", e); - r.run(); - } - return flag; + }); } } } diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/IUpdateChecker.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/IUpdateChecker.java new file mode 100644 index 000000000..02cc8e526 --- /dev/null +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/IUpdateChecker.java @@ -0,0 +1,55 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hellominecraft.utils; + +import java.util.Map; +import rx.Observable; + +/** + * + * @author huangyuhui + */ +public interface IUpdateChecker { + + /** + * + */ + void checkOutdate(); + + /** + * Get the cached newest version number, use "process" method to download! + * @return the newest version number + * @see process + */ + VersionNumber getNewVersion(); + + /** + * Download the version number synchronously. + * When you execute this method first, should leave "showMessage" false. + * @param showMessage If it is requested to warn the user that there is a new version. + * @return the process observable. + */ + Observable process(boolean showMessage); + + /** + * Get the download links. + * @return a JSON, which contains the server response. + */ + Observable> requestDownloadLink(); + +} diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/MessageBox.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/MessageBox.java index 9df71981e..1c652a3d8 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/MessageBox.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/MessageBox.java @@ -97,9 +97,9 @@ public class MessageBox { case YES_NO_OPTION: case YES_NO_CANCEL_OPTION: case OK_CANCEL_OPTION: - return JOptionPane.showConfirmDialog(null, Msg, Title, Option - 10); + return SwingUtils.invokeAndWait(() -> JOptionPane.showConfirmDialog(null, Msg, Title, Option - 10)); default: - JOptionPane.showMessageDialog(null, Msg, Title, Option); + SwingUtils.invokeAndWait(() -> JOptionPane.showMessageDialog(null, Msg, Title, Option)); } return 0; } diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/Pair.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/Pair.java index f1ed387a0..d7371ddc2 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/Pair.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/Pair.java @@ -18,6 +18,7 @@ package org.jackhuang.hellominecraft.utils; import java.util.Map; +import java.util.Objects; /** * @@ -52,4 +53,28 @@ public class Pair implements Map.Entry { return t; } + @Override + public int hashCode() { + int hash = 5; + hash = 29 * hash + Objects.hashCode(this.key); + hash = 29 * hash + Objects.hashCode(this.value); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final Pair other = (Pair) obj; + if (!Objects.equals(this.key, other.key)) + return false; + if (!Objects.equals(this.value, other.value)) + return false; + return true; + } + } diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/SwingUtils.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/SwingUtils.java index 55cff9bdc..dd601d981 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/SwingUtils.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/SwingUtils.java @@ -17,6 +17,7 @@ */ package org.jackhuang.hellominecraft.utils; +import java.awt.EventQueue; import java.awt.FontMetrics; import java.net.URI; import javax.swing.DefaultListModel; @@ -28,6 +29,7 @@ import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.table.DefaultTableModel; import org.jackhuang.hellominecraft.HMCLog; +import org.jackhuang.hellominecraft.utils.functions.NonFunction; /** * @@ -47,8 +49,8 @@ public class SwingUtils { */ public static DefaultTableModel makeDefaultTableModel(String[] titleA, final Class[] typesA, final boolean[] canEditA) { return new DefaultTableModel( - new Object[][] {}, - titleA) { + new Object[][] {}, + titleA) { Class[] types = typesA; boolean[] canEdit = canEditA; @@ -131,7 +133,7 @@ public class SwingUtils { * Clear the JTable * * @param table JTable with DefaultTableModel. - * + * * @return To make the code succinct */ public static DefaultTableModel clearDefaultTable(JTable table) { @@ -177,4 +179,24 @@ public class SwingUtils { } return builder.toString(); } + + private static final ThreadLocal THREAD_LOCAL = new ThreadLocal<>(); + + public static T invokeAndWait(NonFunction x) { + Runnable r = () -> THREAD_LOCAL.set(x.apply()); + invokeAndWait(r); + return (T) THREAD_LOCAL.get(); + } + + public static void invokeAndWait(Runnable r) { + if (EventQueue.isDispatchThread()) + r.run(); + else + try { + EventQueue.invokeAndWait(r); + } catch (Exception e) { + HMCLog.err("Failed to invokeAndWait, the UI will work abnormally.", e); + r.run(); + } + } } diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/UpdateChecker.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/UpdateChecker.java index 23f741452..02b56ef77 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/UpdateChecker.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/UpdateChecker.java @@ -20,66 +20,74 @@ package org.jackhuang.hellominecraft.utils; import java.util.Map; import org.jackhuang.hellominecraft.C; import org.jackhuang.hellominecraft.HMCLog; +import rx.Observable; /** * * @author huangyuhui */ -public final class UpdateChecker extends Thread { - - public static boolean OUT_DATED = false; +public final class UpdateChecker implements IUpdateChecker { + + public boolean OUT_DATED = false; public VersionNumber base; public String versionString; public String type; - public Runnable dl; - public Map download_link = null; - - public UpdateChecker(VersionNumber base, String type, Runnable dl) { - super("UpdateChecker"); + private Map download_link = null; + + public UpdateChecker(VersionNumber base, String type) { this.base = base; this.type = type; - this.dl = dl; } - + VersionNumber value; - + @Override - public void run() { - - try { - versionString = NetUtils.get("http://huangyuhui.duapp.com/info.php?type=" + type); - } catch (Exception e) { - HMCLog.warn("Failed to get update url.", e); - return; - } - value = VersionNumber.check(versionString); - process(false); - if (OUT_DATED) - dl.run(); + public Observable process(boolean showMessage) { + return Observable.createWithEmptySubscription(t -> { + if (value == null) { + try { + versionString = NetUtils.get("http://huangyuhui.duapp.com/info.php?type=" + type); + } catch (Exception e) { + HMCLog.warn("Failed to get update url.", e); + return; + } + value = VersionNumber.check(versionString); + } + + if (value == null) { + HMCLog.warn("Failed to check update..."); + if (showMessage) + MessageBox.Show(C.i18n("update.failed")); + } else if (VersionNumber.isOlder(base, value)) + OUT_DATED = true; + if (OUT_DATED) + t.onNext(value); + }); } - - public void process(boolean showMessage) { - if (value == null) { - HMCLog.warn("Failed to check update..."); - if (showMessage) - MessageBox.Show(C.i18n("update.failed")); - } else if (VersionNumber.isOlder(base, value)) - OUT_DATED = true; - } - + + @Override public VersionNumber getNewVersion() { return value; } - - public synchronized void requestDownloadLink(Runnable finish) { - new Thread(() -> { + + @Override + public synchronized Observable> requestDownloadLink() { + return Observable.createWithEmptySubscription(t -> { if (download_link == null) try { download_link = C.gson.fromJson(NetUtils.get("http://huangyuhui.duapp.com/update_link.php?type=" + type), Map.class); } catch (Exception e) { HMCLog.warn("Failed to get update link.", e); } - finish.run(); - }).start(); + t.onNext(download_link); + }); + } + + public final EventHandler outdated = new EventHandler<>(this); + + @Override + public void checkOutdate() { + if (OUT_DATED) + outdated.execute(getNewVersion()); } } diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/VersionNumber.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/VersionNumber.java index 285d501ad..2e26fe110 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/VersionNumber.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/VersionNumber.java @@ -25,12 +25,18 @@ import org.jackhuang.hellominecraft.HMCLog; */ public final class VersionNumber implements Comparable { - public byte firstVer, secondVer, thirdVer; + public final byte firstVer, secondVer, thirdVer; + public final String version; public VersionNumber(byte a, byte b, byte c) { + this(a, b, c, null); + } + + public VersionNumber(byte a, byte b, byte c, String version) { firstVer = a; secondVer = b; thirdVer = c; + this.version = version; } public static VersionNumber check(String data) { @@ -46,7 +52,7 @@ public final class VersionNumber implements Comparable { v1 = Byte.parseByte(ver[0]); v2 = Byte.parseByte(ver[1]); v3 = Byte.parseByte(ver[2]); - ur = new VersionNumber(v1, v2, v3); + ur = new VersionNumber(v1, v2, v3, data); return ur; } catch (Exception e) { HMCLog.warn("Failed to parse the version", e); diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/system/IOUtils.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/system/IOUtils.java index 685de775f..896d09c37 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/system/IOUtils.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/system/IOUtils.java @@ -112,6 +112,18 @@ public class IOUtils { return arr; } + public static String getRealPath() { + String realPath = IOUtils.class.getClassLoader().getResource("").getFile(); + java.io.File file = new java.io.File(realPath); + realPath = file.getAbsolutePath(); + try { + realPath = java.net.URLDecoder.decode(realPath, "utf-8"); + } catch (Exception e) { + e.printStackTrace(); + } + return realPath; + } + public static File currentDir() { return new File("."); } @@ -219,19 +231,19 @@ public class IOUtils { } public static void write(byte[] data, OutputStream output) - throws IOException { + throws IOException { if (data != null) output.write(data); } public static void write(String data, OutputStream output, String encoding) - throws IOException { + throws IOException { if (data != null) output.write(data.getBytes(encoding)); } public static FileInputStream openInputStream(File file) - throws IOException { + throws IOException { if (file.exists()) { if (file.isDirectory()) throw new IOException("File '" + file + "' exists but is a directory"); diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/DropShadowBorder.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/DropShadowBorder.java index 04a48f4d9..7f63a18fe 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/DropShadowBorder.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/DropShadowBorder.java @@ -26,7 +26,9 @@ import java.awt.Graphics2D; import java.awt.Insets; import java.awt.RenderingHints; import java.awt.image.BufferedImage; +import java.util.HashMap; import javax.swing.border.AbstractBorder; +import org.jackhuang.hellominecraft.utils.Pair; public class DropShadowBorder extends AbstractBorder { @@ -61,29 +63,37 @@ public class DropShadowBorder extends AbstractBorder { return getBorderInsets(c); } + private static final HashMap, BufferedImage> CACHE = new HashMap<>(); + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - BufferedImage shadow = new BufferedImage(width, height, 2); + Pair pair = new Pair<>(width, height); + if (CACHE.containsKey(pair)) + g.drawImage(CACHE.get(pair), x, y, width, height, null); + else { + BufferedImage shadow = new BufferedImage(width, height, 2); - Graphics2D g2 = shadow.createGraphics(); - g2.setRenderingHints(this.hints); - Composite oldComposite = g2.getComposite(); - AlphaComposite composite = AlphaComposite.getInstance(1, 0.0F); - g2.setComposite(composite); - g2.setColor(new Color(0, 0, 0, 0)); - g2.fillRect(0, 0, width, height); - g2.setComposite(oldComposite); - g2.setColor(this.color); - int border = (int) (this.thickness * 4); - g2.fillRect(border, border + border / 6, width - border * 2, height - border * 2); - g2.dispose(); + Graphics2D g2 = shadow.createGraphics(); + g2.setRenderingHints(this.hints); + Composite oldComposite = g2.getComposite(); + AlphaComposite composite = AlphaComposite.getInstance(1, 0.0F); + g2.setComposite(composite); + g2.setColor(new Color(0, 0, 0, 0)); + g2.fillRect(0, 0, width, height); + g2.setComposite(oldComposite); + g2.setColor(this.color); + int border = (int) (this.thickness * 4); + g2.fillRect(border, border + border / 6, width - border * 2, height - border * 2); + g2.dispose(); - FastBlurFilter blur = new FastBlurFilter(this.thickness); - shadow = blur.filter(shadow, null); - shadow = blur.filter(shadow, null); - shadow = blur.filter(shadow, null); - shadow = blur.filter(shadow, null); + FastBlurFilter blur = new FastBlurFilter(this.thickness); + shadow = blur.filter(shadow, null); + shadow = blur.filter(shadow, null); + shadow = blur.filter(shadow, null); + shadow = blur.filter(shadow, null); - g.drawImage(shadow, x, y, width, height, null); + CACHE.put(pair, shadow); + g.drawImage(shadow, x, y, width, height, null); + } } }