Compare commits

..
854 Commits
Author SHA1 Message Date
huanghongxun 8b52c46664 Merge resources.zip to allow multiple datapack zip containing resources.zip 2018-09-20 00:12:41 +08:00
huanghongxun aa8c386cdd Support zip file in datapacks folder 2018-09-19 23:02:27 +08:00
huanghongxun bafe17107c Fix loading empty repository 2018-09-19 16:31:17 +08:00
huanghongxun 9c169fb560 Add a separator to separate launch button and popup button 2018-09-19 10:46:14 +08:00
huanghongxun 61ab8a6769 Fix NPE when first start 2018-09-19 00:20:32 +08:00
huanghongxun b1cd7057db Add a convenient entrance to launch other version 2018-09-19 00:16:21 +08:00
huanghongxun d426952d47 Fix Minecraft jar does not exist when renaming a version 2018-09-19 00:12:44 +08:00
huanghongxun 67b6a60382 Fix bugs with world. 2018-09-17 16:30:27 +08:00
huanghongxun 9d5da5a39d Try again when decorator is not initialized. 2018-09-17 16:28:52 +08:00
huanghongxun efb14572d6 Fix selected profile automatically changes to Home 2018-09-17 16:28:01 +08:00
huanghongxun bc3ae5cc7d Add link to hmcl documentation page 2018-09-16 14:12:52 +08:00
huanghongxun 9752dea0e1 Merge pull request #454 from yushijinhun/javafx
重构
2018-09-16 13:46:31 +08:00
huanghongxun 9afdc99157 Support single datapack zip 2018-09-16 13:15:54 +08:00
huanghongxun 07febc18d4 World and datapacks management 2018-09-16 12:38:15 +08:00
yushijinhun 68fdfb36fd Add selectedItemPropertyFor(ComboBox) 2018-09-16 00:52:03 +08:00
yushijinhun 09287f9c72 Rename WeakListenerHelper to WeakListenerHolder 2018-09-15 23:24:42 +08:00
yushijinhun 4a5ac1b899 Remove Settings.logLines 2018-09-15 23:18:59 +08:00
yushijinhun afad520669 Move ProxyManager.proxyProperty initialization to init() 2018-09-15 23:13:25 +08:00
yushijinhun 9950bef260 Change type of downloadType to string 2018-09-15 23:05:37 +08:00
Yuhui Huang 1753b4d27e Datapack resolving 2018-09-14 15:44:40 +08:00
Yellow Fish 2bfc85b18f Fixed NPE mentioned in #451 2018-09-13 01:13:20 +08:00
Yellow Fish 24f3dec453 Fixed #450 2018-09-12 21:37:27 +08:00
huangyuhui 4e6237c062 Fixed #448 2018-09-11 19:26:36 +08:00
huangyuhui 5cbde9cc33 Fix not on FX user thread 2018-09-09 19:38:14 +08:00
huangyuhui 25d79a94f8 Move specialize and globalize VersionSetting to HMCLGameRepository 2018-09-09 18:55:01 +08:00
huangyuhui a5997be9c4 Fix crash when selectedVersion set to empty string 2018-09-09 18:35:10 +08:00
huangyuhui c679667079 Fix crash when the game version is too long 2018-09-09 18:24:05 +08:00
huangyuhui 6b311c679d Fixed #446 2018-09-08 22:14:06 +08:00
huangyuhui 0f1f881367 Add BuildNumberOffset in gradle build config 2018-09-08 19:41:02 +08:00
huangyuhui 090665528f Improve UI 2018-09-08 19:34:51 +08:00
huangyuhui 387beb8484 Fix not saving profile configurations 2018-09-08 01:03:36 +08:00
huanghongxun daa1a38a63 Refactor ModListPage and InstallerListPage 2018-09-08 00:36:57 +08:00
huangyuhui d8a34aac1c Widen task dialog 2018-09-07 15:16:09 +08:00
huangyuhui ce9d882c9f Add total progress of task execution 2018-09-07 15:12:41 +08:00
huanghongxun 84c18c8693 Move cache repository to HMCLCore 2018-09-07 11:27:14 +08:00
huangyuhui 9360854150 Use ReadWriteLock instead of synchronized 2018-09-07 01:58:43 +08:00
huangyuhui ada63f1452 Fix not selecting the version just downloaded 2018-09-07 01:58:22 +08:00
huangyuhui c3cd0dd8a0 Refactor ProfileList & AccountList 2018-09-07 01:03:59 +08:00
huangyuhui 60143d5299 Refactor FileDownloadTask 2018-09-07 00:35:28 +08:00
huangyuhui 1019c891e2 Cache asset files 2018-09-06 17:47:44 +08:00
huangyuhui 1392ad413a Only cache verified files and copy cached files to current directory 2018-09-06 00:13:16 +08:00
huangyuhui 61aee90c8d Refactor DecoratorPage 2018-09-05 23:25:51 +08:00
huangyuhui 19725012fb Refactor AccountList and ProfileList 2018-09-05 23:20:20 +08:00
huangyuhui 94a71dc88f Fix unclosing file 2018-09-05 22:17:58 +08:00
huangyuhui d8cb93c36a Add Task.preExecute and Task.postExecute 2018-09-05 20:38:00 +08:00
huangyuhui 151097a884 Removed the text that notices user to enable disabling jvm args when using Java 9 2018-09-04 21:42:27 +08:00
huanghongxun e97bad88c6 Fix not syncing observable list 2018-09-04 14:25:18 +08:00
huangyuhui 9f494a35ec Add a button for deleting the game icon 2018-09-03 23:58:23 +08:00
huangyuhui d9d20c969a Refactor ComponentList 2018-09-03 23:42:42 +08:00
huangyuhui 7e08cfedd6 Add Constant Pool Scanner to open source code dependencies 2018-09-03 22:35:25 +08:00
huangyuhui 1145e31162 Extract IconedMenuItem 2018-09-03 22:30:22 +08:00
huangyuhui e4e521c2ef Change Controllers.navigate(null) to PageCloseEvent/onEnd 2018-09-03 21:27:39 +08:00
huangyuhui d01c9a425a Fix crash when removed all profiles 2018-09-03 18:38:40 +08:00
huangyuhui a9be348ddf Add prompt warning user that no game installed 2018-09-03 18:38:39 +08:00
huangyuhui 07079ee295 Fix image mis-positioned in AccountAdvancedListItem 2018-09-03 18:38:39 +08:00
huangyuhui eb1bab453b Cancel the option enabling game list in main page 2018-09-03 18:38:39 +08:00
huangyuhui fd3c496a3d Fix crash when first launch 2018-09-03 18:38:39 +08:00
huanghongxun 35e1e0bdd4 Change Java to 64bit automatically. 2018-09-03 17:33:45 +08:00
huangyuhui 28aa137dc1 Use iconedItem instead of ListView in popup menu 2018-09-03 10:58:45 +08:00
huangyuhui 16ee0a040a optimize import 2018-09-03 00:25:56 +08:00
huangyuhui 437391a860 Merge branch '3.2' into javafx 2018-09-03 00:11:16 +08:00
huangyuhui f61181438f allow displaying game list in main page 2018-09-03 00:10:21 +08:00
huangyuhui d74ab35279 Move package 2018-09-02 23:30:27 +08:00
huangyuhui bbc2b251dd Change the way to determine whether use global settings or the specific one 2018-09-02 23:24:32 +08:00
huangyuhui 222e39dc48 Remove decorator.fxml 2018-09-02 21:58:03 +08:00
huangyuhui f5b310d959 Move AdvancedListItem & Skin to new package 2018-09-02 21:57:25 +08:00
huangyuhui 5fb0035b2f Refactor decorator as well as navigation 2018-09-02 21:53:34 +08:00
huangyuhui b8793f7575 Prevent horizontal scroll bar in settings page 2018-09-02 21:52:45 +08:00
huangyuhui 5c5f091769 Fails game installing when unable to download game jar 2018-09-01 23:41:13 +08:00
huangyuhui cf6485aea8 Make exception message more understandable in FileDownloadTask 2018-09-01 23:38:32 +08:00
huangyuhui f2f0c96e62 Notice user to add authentication server 2018-09-01 23:38:05 +08:00
huangyuhui 64e7cc74b2 ProfileList 2018-09-01 00:36:18 +08:00
huangyuhui 531fd87ff3 Profiles 2018-09-01 00:19:25 +08:00
huangyuhui efa280b839 Move profile management to Profiles 2018-08-31 22:28:06 +08:00
huangyuhui b3d84c4f99 Refactor 2018-08-31 22:21:15 +08:00
huangyuhui 015a1e3482 Fix #441 2018-08-31 12:21:08 +08:00
huangyuhui 5efc8d6fa9 Refactor View and ViewModel to Control and Skin 2018-08-31 12:13:47 +08:00
huangyuhui bb1654828f Change "Run Directory" to "Working Directory" 2018-08-31 10:44:01 +08:00
huangyuhui 93cabde9f4 clean up HMCLCore 2018-08-30 22:20:18 +08:00
huangyuhui aeb5eb9129 clean up HMCL 2018-08-30 22:19:49 +08:00
huangyuhui e9e8b8a1ad Change contact URL 2018-08-30 22:15:12 +08:00
huangyuhui 08564e5ea2 Add account list view 2018-08-30 22:14:30 +08:00
huangyuhui 1695619ef5 Move account ui class to a new package 2018-08-30 22:13:53 +08:00
huangyuhui 8f2f57c543 cut off the version name if too long 2018-08-30 22:13:13 +08:00
huangyuhui 60454c6af3 New game list page 2018-08-30 22:12:39 +08:00
huangyuhui 40c7c72973 Move operations on version to new class 2 2018-08-30 22:11:58 +08:00
huangyuhui f9127272b1 Split download wizard into { new game, install modpack } 2018-08-30 22:11:49 +08:00
huangyuhui ec295664d9 Move operations on version to new class 2018-08-30 22:11:00 +08:00
huangyuhui ec2b9b19be Add an entrance to game list page 2018-08-30 22:09:54 +08:00
huangyuhui 1566e069ed Add selectedMinecraftVersion 2018-08-30 22:09:05 +08:00
huangyuhui 9c149f3529 Postpone loading fonts 2018-08-29 21:05:07 +08:00
huangyuhui 2f35baef39 Convert settings.fxml to Java code 2018-08-29 20:28:43 +08:00
huangyuhui 7c77c317df Improve finalizedTask log 2018-08-29 00:03:50 +08:00
huangyuhui ed3a04d531 Fix animation twinkling 2018-08-28 00:23:49 +08:00
huangyuhui c3ec7741dc Change "Game directory" to "Run directory" 2018-08-28 00:22:12 +08:00
huanghongxun f4f89fac1f Merge pull request #438 from yushijinhun/force-update
移除「更新一次 HMCL,电脑上所有 HMCL 都得到更新」的功能
2018-08-26 19:51:20 +08:00
yushijinhun 5262150d3c Prevent 2.x being updated to 3.x 2018-08-26 19:34:10 +08:00
yushijinhun b5f56eb2b5 Remove force update feature 2018-08-26 19:02:47 +08:00
huangyuhui 9a375fd0d1 Add hiding versions. Closes #437 2018-08-26 11:50:42 +08:00
huangyuhui 6ca4aeb5a2 Support 1.13 auto-installing 2018-08-26 11:48:27 +08:00
huangyuhui 8ed4a9a5f2 Fix not showing Optifine 1.13 alpha 2018-08-25 19:53:29 +08:00
huangyuhui a4578405cf Remove RandomUserAgent 2018-08-25 19:39:00 +08:00
huangyuhui 73f147b7e2 Update Chinese localization 2018-08-23 21:45:56 +08:00
huangyuhui 5c3d735315 Prevent HMCL 2.x updating 2018-08-23 21:45:47 +08:00
huanghongxun 200621996d Merge pull request #431 from pan93412/javafx
Update Chinese (Taiwan) Translation
2018-08-22 20:56:12 +08:00
byStarTW a912a0a07e Update Chinese (Taiwan) Translation 2018-08-22 20:54:49 +08:00
huangyuhui 4146ceb048 Fix not downloading the correct game version 2018-08-22 04:25:35 +08:00
huangyuhui ad568d2b9f Fix #429 2018-08-22 02:08:49 +08:00
huangyuhui c7bfb9a11d Suggest user to install latest Java 8 to avoid potentional game crashing 2018-08-21 21:12:05 +08:00
huangyuhui c9391181bd Display empty message when loading 1.13 forge version list 2018-08-21 19:31:04 +08:00
huangyuhui b08eb519bf Remove logging support which is meaningless 2018-08-21 11:48:19 +08:00
huangyuhui 47c4fc2f7e Fix #426 2018-08-20 11:53:02 +08:00
huangyuhui dfd177433a Fix not replacing tokens metioned in #426 2018-08-20 11:38:06 +08:00
huanghongxun 27381e9696 Merge pull request #425 from yushijinhun/yushijinhun/javafx
修复 UpdateChecker 潜在问题 & 弃用 ImmediateXXXProperty
2018-08-19 19:47:30 +08:00
yushijinhun 1c7827c53c Deprecate and partially remove ImmediateProperty 2018-08-19 15:55:18 +08:00
yushijinhun 9512bdb5d6 Remove UpdateChecker.updateChannel & Fix concurrent problems in update checking 2018-08-19 15:43:34 +08:00
huangyuhui 33d1f1d692 Not showing 'unknown' in mod info 2018-08-19 12:19:11 +08:00
huangyuhui c6b49545ff Fix #424 2018-08-19 12:13:39 +08:00
huangyuhui a4a833bfdb Fix auto-installing: missing checksums in game json 2018-08-19 11:58:02 +08:00
huangyuhui 2e1b6e4630 Fix not correctly loading remote game version list 2018-08-19 11:56:39 +08:00
huangyuhui 6911cfa387 try to move deleting version to trash 2018-08-19 11:34:07 +08:00
huangyuhui aa29f890de Log memory size and metaspace 2018-08-19 02:03:05 +08:00
huangyuhui 0f4e6a01bc Fix unable to install more than one libraries 2018-08-19 01:18:57 +08:00
huangyuhui 1d3d8d6710 Show OptiFine versions in dividually 2018-08-19 00:39:47 +08:00
huangyuhui 005e06c56f Always download Optifine from BMCLAPI 2018-08-19 00:35:37 +08:00
huangyuhui 0a7c32b3cb Friendly prompt warning user about independent version deletion 2018-08-18 22:40:08 +08:00
huangyuhui 82916a04ea Check if forge libraries' checksums are valid 2018-08-18 22:25:13 +08:00
huangyuhui ba2e419894 Fix #422 2018-08-18 22:09:16 +08:00
huangyuhui 0812c9025d Do not check game asset hash code for every launching 2018-08-18 02:00:00 +08:00
huangyuhui 4c59ed3ccf Fix installing MultiMC modpack 2018-08-18 01:12:22 +08:00
huangyuhui 43d8d96608 Add doublequotes when doublequotes exist in windows batch 2018-08-18 00:43:55 +08:00
huangyuhui 26a6a7d883 Add doublequotes when special characters exist in launch script. Closes #420 2018-08-18 00:32:37 +08:00
huangyuhui 2e9c237367 Use system proxy by default 2018-08-17 23:48:01 +08:00
huangyuhui 99d2816ea7 Suppress RuntimeException since -1 is possible 2018-08-17 22:11:46 +08:00
huangyuhui 7c3853b0e6 Not logging command line in ProcessStoppedEvent 2018-08-17 22:10:11 +08:00
huangyuhui 53aecf38e0 Support displaying Rift mod information 2018-08-17 22:09:37 +08:00
huangyuhui 41fab0a781 Log launching game version name 2018-08-17 21:56:52 +08:00
huangyuhui 3df35aa373 Translate ZipError into ZipException since ZipError is not IOException 2018-08-17 21:53:29 +08:00
huangyuhui 543eaa4f66 Force cancel using custom log4j config 2018-08-17 21:52:35 +08:00
huangyuhui 3a851b7f1a Fix unable to launch 1.13 with Rift 2018-08-17 21:51:25 +08:00
huangyuhui 089ae1e313 Suppress InterruptedException 2018-08-17 21:51:12 +08:00
huangyuhui bfe5802d02 Remove roboto font 2018-08-16 02:46:49 +08:00
huangyuhui 3ec6c97380 Replace 2.x with existent 3.x 2018-08-15 01:40:18 +08:00
huangyuhui e376da208d Fix duplicate JavaVersions in Windows. Closes #419 2018-08-14 10:44:24 +08:00
huangyuhui 3b02c5e4e0 Merge branch 'javafx' of https://github.com/huanghongxun/HMCL into javafx 2018-08-14 00:10:48 +08:00
huangyuhui 1bcc79c415 Fix always trying to close launcher when game version cannot be obtained 2018-08-14 00:09:20 +08:00
huangyuhui 9e2cb25d01 Convert old offline account setings 2018-08-14 00:08:35 +08:00
yushijinhun 7e820ba2a5 Fix closeDialog() throws NPE 2018-08-13 22:18:18 +08:00
huanghongxun b079940cd9 Fix uniquing text2speech and its native library. Closes #418 2018-08-11 09:45:31 +08:00
huanghongxun 593ee24429 Merge branch 'javafx' of https://github.com/huanghongxun/HMCL into javafx 2018-08-10 19:05:26 +08:00
huanghongxun f7a91bf10c Fix version setting not saved 2018-08-10 19:04:33 +08:00
huanghongxun dad7ac706f Add update channel selection 2018-08-10 12:53:49 +08:00
Haowei Wen 13c48ce78c Merge pull request #417 from tsl0922/osx-maximized
Mac 下恢复使用自定义窗口边框按钮
2018-08-10 08:26:56 +08:00
Shuanglei Tao 8ecbba1003 Remove native window border on osx 2018-08-09 23:41:56 +08:00
huanghongxun 8bf6a9ec9d Rename AdvancedListItem 2018-08-09 20:22:57 +08:00
huanghongxun 64092a4bd4 Merge branch 'yushijinhun-java' into javafx 2018-08-09 13:54:54 +08:00
yushijinhun 8e6bcd969e Refactor JavaVersion 2018-08-09 13:49:16 +08:00
yushijinhun 6777dd7ea7 Fix UnsupportedOperationException in java lookup
Mentioned in #412
2018-08-09 13:22:49 +08:00
yushijinhun f16885568e Make config files hidden 2018-08-09 12:56:03 +08:00
huanghongxun ab109bcfcc Merge pull request #414 from yushijinhun/javafx
Fixes FileSystemNotFoundException in createZipFileSystem
2018-08-09 11:41:27 +08:00
yushijinhun 17f71eaa21 Fixes FileSystemNotFoundException in createZipFileSystem 2018-08-09 11:34:38 +08:00
huanghongxun 3a294e354a ExeLauncher: Search Java in C:/Program Files 2018-08-08 21:16:57 +08:00
huanghongxun 54814181b9 Change xz compressing level to 6 since CI server does not have enough memory 2018-08-08 12:57:42 +08:00
huanghongxun 935c2bd6e5 Merge branch 'rewrite-upgrade' into javafx 2018-08-08 10:03:14 +08:00
huanghongxun a2b74b8e78 Fix getImplementationVersion returning null on Java 9. 2018-08-08 10:02:34 +08:00
huanghongxun 09730d74e0 Merge branch 'rewrite-upgrade' of https://github.com/yushijinhun/HMCL into rewrite-upgrade 2018-08-07 22:18:58 +08:00
huanghongxun 2bf03291ce Try Java8 for Minecraft 1.12.2 or older modded game 2018-08-07 22:10:34 +08:00
huanghongxun 93e5851167 Improve config compatibility with HMCL 2.x. Fix #411 2018-08-07 18:40:23 +08:00
huanghongxun 61fd581ef5 Hide the separator line between refreshNavButton and window buttons when refreshNavButton is hidden 2018-08-07 18:08:20 +08:00
huanghongxun 51afcf2dee Use ZipFileSystem instead of commons-compress 2018-08-07 11:53:05 +08:00
huanghongxun cadafe13e1 Remove IOUtils.closeQuietly 2018-08-07 11:53:05 +08:00
Haowei Wen 47031cb70e Merge pull request #413 from tsl0922/osx
修复在 OSX 下使用的一些问题
2018-08-06 18:36:53 +08:00
Shuanglei Tao b3e776b4bc Use native window border on osx (workaround for #403) 2018-08-06 14:17:41 +08:00
Shuanglei Tao e57a1a8da6 Make gradlew executable 2018-08-05 23:08:27 +08:00
yushijinhun 7f2a392a33 Use com.github.johnrengelman.shadow plugin 2018-08-05 11:06:50 +08:00
yushijinhun 055379f569 Add .pack.gz build back 2018-08-05 09:37:55 +08:00
yushijinhun 2b8843ca19 Replace .pack.gz with .pack.xz 2018-08-05 01:02:42 +08:00
yushijinhun ace830bced Refactor build.gradle 2018-08-05 00:42:05 +08:00
yushijinhun 3c2f232acb Rename PACK -> PACK_GZ 2018-08-04 23:11:31 +08:00
yushijinhun 86030e64ca Extract writeToStorage() 2018-08-04 23:10:14 +08:00
huanghongxun b1ce3c31f5 Build packed archive 2018-08-04 22:12:02 +08:00
huanghongxun 04553c2c56 Support packed update archive 2018-08-04 22:04:59 +08:00
yushijinhun bdb7afa860 Replace updateSource with updateChannel 2018-08-04 21:39:19 +08:00
yushijinhun 7096135cdf Change update source to hmcl.huangyuhui.net 2018-08-04 21:26:46 +08:00
yushijinhun be37014206 Use Paths.get(url.toURI()) in LocalVersion.current() 2018-08-04 21:17:52 +08:00
yushijinhun b78beb3305 Copy downloaded HMCL to .hmcl only after it's verified 2018-08-01 15:54:52 +08:00
yushijinhun 38f27d134d Change task.test() to executor.test() 2018-08-01 15:54:52 +08:00
yushijinhun 3b42ba9375 Add version query when checking for update 2018-08-01 15:54:52 +08:00
yushijinhun 4f52bb2ffe Add option hmcl.update_source.override 2018-07-31 19:41:50 +08:00
yushijinhun dd45e1b3db Add JAR integrity check 2018-07-31 19:39:21 +08:00
yushijinhun e38bfdfc73 Refactor build.gradle 2018-07-31 15:48:29 +08:00
yushijinhun 73caebff00 Remove unnecessary saveConfig() call 2018-07-31 14:33:03 +08:00
yushijinhun e0608cdf3e Remove unused files 2018-07-31 14:32:42 +08:00
yushijinhun c815fa80e8 Prevent /build being created 2018-07-31 14:06:54 +08:00
yushijinhun e91e1cab47 Remove coreCompile/Runtime.extendsFrom 2018-07-31 14:04:36 +08:00
yushijinhun b791878651 Remove generateSources task 2018-07-31 14:02:26 +08:00
yushijinhun 8192ffec03 Remove duplicated HMCLauncher.exe 2018-07-31 13:59:48 +08:00
yushijinhun afa6eb3bad Refactor build.gradle 2018-07-31 13:46:31 +08:00
yushijinhun 6f7d22518e Remove pack.gz build 2018-07-31 13:34:17 +08:00
yushijinhun 2663312dfb Auto-rename after upgrade 2018-07-31 13:28:39 +08:00
yushijinhun 1332517a9f Rewrite upgrade feature 2018-07-30 23:32:01 +08:00
yushijinhun 13e227851f Refactor IconedItem 2018-07-29 21:10:04 +08:00
yushijinhun e1b6c18017 Remove HELLO_MINECRAFT_LAUNCHER_VERSION_FOR_GRADLE_REPLACING 2018-07-29 19:07:48 +08:00
yushijinhun a88c8ed85f Extract class Metadata 2018-07-29 19:03:49 +08:00
yushijinhun 25a90fc481 Remove upgrade feature 2018-07-29 18:42:31 +08:00
huangyuhui 1371206323 Pack with exe launcher 2018-07-29 16:34:15 +08:00
huanghongxun 129f6bb5cc Merge pull request #407 from yushijinhun/config-permission
重构 Config
2018-07-29 14:44:23 +08:00
yushijinhun 545c17d052 Print current directory & hmcl directory when bootstrap 2018-07-29 14:27:50 +08:00
yushijinhun add00ddba1 Use configured locale as soon as possible 2018-07-29 14:21:43 +08:00
yushijinhun d9aeb0cc2b Use SupportedLocale in Config 2018-07-29 14:15:32 +08:00
yushijinhun 49e70e7195 Add ConfigHolder.isNewlyCreated() 2018-07-29 14:02:32 +08:00
yushijinhun f8abebf110 Remove isFirstLaunch 2018-07-29 13:45:22 +08:00
yushijinhun 8e2dfc7341 Show error dialog when hmcl.json is not accessible 2018-07-29 13:40:59 +08:00
yushijinhun e650ffffce Initialize ConfigHolder & Settings manually 2018-07-29 13:40:59 +08:00
yushijinhun d549a300ab Replace Settings.INSTANCE with Settings.instance() 2018-07-29 13:40:59 +08:00
yushijinhun 82a62e73c1 Replace CONFIG with config() 2018-07-29 13:40:57 +08:00
yushijinhun 45c7e0c231 Remove Settings.save() 2018-07-29 13:39:32 +08:00
huangyuhui b98a4b11a3 Fix #406 2018-07-29 13:31:18 +08:00
huangyuhui 484a103f27 Fix always showing the welcome page when upgrading from old versions 2018-07-29 13:25:15 +08:00
huangyuhui e31120be21 Friendly prompt that it cannot download some libraries successfully. 2018-07-22 18:50:44 +08:00
huangyuhui 247f02d423 Friendly prompt to ServerResponseMalformedException 2018-07-22 18:22:28 +08:00
huangyuhui 3da0c1d8e3 Abandon Launch4j which will not find Java inst in PATH or JAVA_HOME 2018-07-22 18:15:39 +08:00
huangyuhui c830bbc703 reorder version in main page 2018-07-21 21:58:46 +08:00
huangyuhui 7b619fef1d Fix always using BMCLAPIDownloadProvider 2018-07-21 20:24:54 +08:00
huanghongxun bac265a077 Merge pull request #399 from yushijinhun/refactor-account
重构账户部分
2018-07-21 19:50:46 +08:00
huanghongxun 39df0f8d43 Merge branch 'javafx' into refactor-account 2018-07-21 19:50:16 +08:00
huangyuhui 6af7f916ee Add an option to disable common directory globally 2018-07-21 19:45:59 +08:00
yushijinhun ae64097edf Automatically select the newly added account 2018-07-21 12:34:12 +08:00
yushijinhun cb6d8a88f1 Fix the old account isn't replaced when adding a same account 2018-07-21 12:31:08 +08:00
huangyuhui 12838994ad Reconstruct MultiFileItem 2018-07-21 11:39:41 +08:00
yushijinhun d30758a2a8 Throw NPE when selected server is null 2018-07-21 09:57:47 +08:00
yushijinhun b820aad358 Use MappedObservableList in AuthlibInjectorServersPage 2018-07-20 20:26:27 +08:00
yushijinhun 170189c344 Refactor accounts 2018-07-20 20:26:27 +08:00
yushijinhun f9e9c9d38b Use LinkedHashMap for mapOf 2018-07-20 20:26:27 +08:00
yushijinhun 088af981df Turn properties in SettingsPage from local variables into fields 2018-07-20 20:26:27 +08:00
yushijinhun 357fef8672 Call initProxy() manually 2018-07-20 20:26:27 +08:00
yushijinhun c38848ea0e Rename fields in Accounts 2018-07-20 20:26:27 +08:00
yushijinhun be8cd13b08 Throw IAE when getAccountType() receives an unexpected param 2018-07-20 20:26:27 +08:00
yushijinhun 487816ab74 Use AccountFactory in cboType 2018-07-20 20:26:27 +08:00
yushijinhun bcd9f8240c Extract account factories to static fields 2018-07-20 20:26:27 +08:00
huangyuhui 1b62972f06 Fix 1.13 version parsing 2018-07-20 11:44:50 +08:00
huangyuhui 1117c3bfab Add missing data binding 2018-07-19 18:30:47 +08:00
huangyuhui 748d195db5 launch4j 2018-07-19 00:55:23 +08:00
huanghongxun 3a9017adb8 Merge pull request #396 from yushijinhun/fix
支持背景热替换
2018-07-18 23:05:56 +08:00
yushijinhun eff3186ab5 Background hot replacement 2018-07-18 22:51:02 +08:00
yushijinhun e5f5fe878e Use bindBidirectional for background type 2018-07-18 21:59:12 +08:00
yushijinhun a47f0f6ecf Use databind for theme subtitle 2018-07-18 21:47:30 +08:00
yushijinhun 9896165b68 Remove theme in Settings 2018-07-18 21:36:44 +08:00
huanghongxun 5e3adcee93 Merge pull request #395 from yushijinhun/fix
Fix ExportWizardProvider leaks proxy config
2018-07-18 20:42:42 +08:00
yushijinhun b252266a46 Fix ExportWizardProvider leaks proxy config 2018-07-18 20:40:18 +08:00
huanghongxun 1d5adea114 Merge pull request #394 from yushijinhun/refactor-settings
重构 Settings
2018-07-18 20:17:12 +08:00
yushijinhun a64a51c7df Refactor proxy UI 2018-07-18 20:07:13 +08:00
yushijinhun ec41c13b45 Update docs for tasks in org.jackhuang.hmcl.download.game 2018-07-18 20:05:54 +08:00
yushijinhun 486ca434ff Remove proxy HMCLDependencyManager 2018-07-18 20:05:54 +08:00
yushijinhun fe87a899c8 Remove proxy from AccountHelper 2018-07-18 20:05:54 +08:00
yushijinhun 06806bd383 Remove proxy from FileDownloadTask/GetTask/NetworkUtils 2018-07-18 20:05:54 +08:00
yushijinhun 2f6c7e1ce2 Remove proxy from AccountFactory 2018-07-18 20:05:54 +08:00
yushijinhun 141cda13f1 Add proxyProperty() 2018-07-18 20:05:54 +08:00
yushijinhun 3e8c8afcd1 Add get/set/property methods for Config 2018-07-18 20:05:16 +08:00
yushijinhun 8236f613e0 Use static import for ConfigHolder.CONFIG 2018-07-18 20:03:34 +08:00
yushijinhun ea6108dca7 Use bindBidirectional 2018-07-18 20:02:33 +08:00
yushijinhun 985a4f07e0 Use Authenticator to set proxy username/password 2018-07-18 20:02:28 +08:00
yushijinhun 5642c579a4 Add ProxyManager 2018-07-17 22:57:33 +08:00
yushijinhun 8e0559fb3b Remove proxyType 2018-07-17 22:56:00 +08:00
yushijinhun a6a1755fee Remove getRawConfig 2018-07-17 22:56:00 +08:00
yushijinhun 846f383f7b Remove backgroundImageTypeProperty 2018-07-17 22:56:00 +08:00
yushijinhun bbbe3726f2 Remove backgroundImageProperty 2018-07-17 22:56:00 +08:00
yushijinhun 6d83fd9903 Remove simple properties in Settings 2018-07-17 22:56:00 +08:00
yushijinhun fac62a8d24 Replace save() with observer pattern 2018-07-17 22:56:00 +08:00
yushijinhun b0d71a5511 Let Config implement Observable 2018-07-17 22:56:00 +08:00
huangyuhui 124ba34d48 Prevent appearance of the horizontal slide bar in install type page 2018-07-17 21:00:22 +08:00
huangyuhui 75270b8ad6 Fix wrong relativized path 2018-07-17 20:56:49 +08:00
yushijinhun 5cf6ef88a6 Let Account implement Observable 2018-07-17 17:04:27 +08:00
huangyuhui b5f72af513 Friendly hint of failing to rename game version 2018-07-16 20:39:21 +08:00
huangyuhui 1532893c5f Change current directory to run directory for launching scripts 2018-07-16 19:51:12 +08:00
huanghongxun a3fbc9595a Merge pull request #385 from yushijinhun/relative-path
添加设置项:若可能,游戏目录使用相对路径
2018-07-15 18:51:34 +08:00
yushijinhun f789343b6e Add game dir option: use relative path 2018-07-14 14:40:59 +08:00
yushijinhun ff74417352 [FileItem]Replace setProperty with bindBidirectional 2018-07-14 14:40:34 +08:00
huanghongxun a0ff843d0c Merge pull request #383 from yushijinhun/fix-382
Fix #382
2018-07-13 18:39:02 +08:00
yushijinhun da93cb0dbb Fix #382 2018-07-13 18:19:18 +08:00
huangyuhui 0de446c608 Update JFoenix 2018-07-11 22:33:29 +08:00
huangyuhui 03bccf16d4 Remove replacement of logs 2018-07-11 20:56:36 +08:00
huangyuhui 635ae8c11e Remove unused preset themes 2018-07-11 20:55:56 +08:00
huangyuhui dfd5a82112 Fix #365 by blocking all hacked Minecraft logs text as XML 2018-07-11 20:11:09 +08:00
huangyuhui 7dad8d452f Filter preview version of OptiFine 2018-07-11 13:08:08 +08:00
huangyuhui 07f8294876 Fixed mis-unbound data. GH-377 2018-07-11 12:46:02 +08:00
huanghongxun 7185cc410b Merge pull request #376 from yushijinhun/fix
Fix selected account is not loaded
2018-07-09 21:41:44 +08:00
yushijinhun 2d985af60d Fix selected account is not loaded 2018-07-09 21:34:43 +08:00
huanghongxun bee2e64482 Merge pull request #373 from yushijinhun/account-page
完善账户信息页的显示
2018-07-09 19:14:26 +08:00
huanghongxun d5dd43c0c1 Merge pull request #372 from yushijinhun/bmclapi
支持从 BMCLAPI 下载 authlib-injector
2018-07-09 19:14:00 +08:00
yushijinhun 09470eeb8a Use auto layout instead of manual sizing 2018-07-09 14:35:30 +08:00
yushijinhun 094249a6fa Set margin of fields in AccountPage 2018-07-09 14:31:41 +08:00
yushijinhun 6b5302907a [AccountPage]Display auth server url in tooltip of auth server name 2018-07-09 14:09:45 +08:00
yushijinhun adc5b08765 Fix account page overflow 2018-07-09 14:04:30 +08:00
yushijinhun 0150e2a8d7 Support downloading authlib-injector from BMCLAPI 2018-07-09 13:17:19 +08:00
huanghongxun 45eaa0c60f Merge pull request #371 from yushijinhun/fix
Refactor(WIP) & Fixes
2018-07-08 20:06:32 +08:00
yushijinhun 66ed683196 Move config load/save code to ConfigHolder(WIP) 2018-07-08 19:32:43 +08:00
yushijinhun aa4239721e Use NIO api to load/save config 2018-07-08 19:19:37 +08:00
yushijinhun 5b0b926cbd Move config serialization/deserialization to Config class 2018-07-08 19:17:53 +08:00
yushijinhun 929ce398eb AddAccountPane 使用数据绑定 & 登录时设置disable为true 2018-07-08 18:33:37 +08:00
yushijinhun b3fdbe021d 添加验证服务器界面回车代表下一步 2018-07-08 17:47:37 +08:00
huanghongxun 423bd68ce8 Merge pull request #369 from yushijinhun/fix
Fixes
2018-07-08 12:36:29 +08:00
yushijinhun 9bffc68c70 Do not reuse dialog 2018-07-08 12:20:38 +08:00
yushijinhun b7a5a60091 Improve English translations 2018-07-08 10:25:41 +08:00
yushijinhun 333b11c19f Fix uncaught JsonParseException, mentioned in #367 2018-07-08 10:11:14 +08:00
huanghongxun fbd4d1b772 Merge pull request #368 from yushijinhun/dnd
支持 DnD 方式添加验证服务器
2018-07-07 23:28:53 +08:00
yushijinhun 06a58514b3 Fix black ComboBox 2018-07-07 23:06:44 +08:00
yushijinhun 80815fc3a0 authlib-injector DnD support 2018-07-07 23:04:56 +08:00
huanghongxun b97c277a3f Merge pull request #364 from yushijinhun/refactor-ui
UI 重构 & bug 修复
2018-07-07 20:53:22 +08:00
yushijinhun 310d693e2b Remove some error cause inferences
Trampoline - High frequency of false positives.
java.lang.OutOfMemoryError - It's more likely to be a memory leak.
2018-07-07 20:51:28 +08:00
yushijinhun c1596f6a11 Replace Controllers.closeDialog with DialogCloseEvent 2018-07-07 20:50:54 +08:00
yushijinhun 76a04343d9 Use Controllers.dialog for AddAuthlibInjectorServerDialog 2018-07-07 20:30:48 +08:00
yushijinhun 25261c99f1 Remove 'class ' prefix in error messages 2018-07-07 20:30:48 +08:00
yushijinhun d0b994fa9d Move add authentication server dialog to a new file 2018-07-07 20:30:48 +08:00
yushijinhun f259601397 Each TransitionHandler instance uses its own empty pane
Using shared empty pane may cause some probleams
2018-07-07 20:30:47 +08:00
yushijinhun 87904109ca [TransitionHandler]Set mouseTransparent of the whole view
, fix bug introduced in 3fb5048f10
2018-07-07 20:30:47 +08:00
yushijinhun 785790ccc4 Move promptText of cboServers to FXML 2018-07-07 20:29:03 +08:00
yushijinhun 759921d00e Fix missing license headers 2018-07-07 20:28:59 +08:00
huangyuhui e9db183d54 Fix blank page of add authlib-injector server dialog 2018-07-07 20:08:40 +08:00
huangyuhui a853374a88 Support new MultiMC modpack 2018-07-07 00:48:48 +08:00
huangyuhui 3fb5048f10 Fix IllegalStateException in DownloadWizardProvider 2018-07-04 21:41:07 +08:00
huangyuhui 0dd2e758e8 Update READMD.md 2018-07-03 13:02:35 +08:00
huanghongxun d1a562452a Merge pull request #362 from yushijinhun/dst-x3
Add the prompt indicating the miss of DST Root CA X3.
2018-07-01 22:55:01 +08:00
yushijinhun 9205a6cbf4 Show warning when DST Root CA X3 is missing 2018-07-01 22:51:48 +08:00
yushijinhun 4c8961f39a Fix NPE when calling i18n during its initialization 2018-07-01 22:50:28 +08:00
huanghongxun 22bdc23a09 Merge pull request #361 from yushijinhun/i18n
Reconstruct I18N.
2018-07-01 22:11:23 +08:00
yushijinhun 764cd16e21 I18n for missing JavaFX error 2018-07-01 22:00:22 +08:00
yushijinhun 7583f4651d Remove I18nException 2018-07-01 21:59:16 +08:00
yushijinhun 13e931cda4 Fallback to use Locales.DEFAULT when Settings has not been initialized 2018-07-01 21:59:12 +08:00
yushijinhun 9743cf8351 Use static import for I18n.i18n 2018-07-01 21:27:30 +08:00
yushijinhun e5ee5702f8 Move i18n things to util.i18n package 2018-07-01 21:27:28 +08:00
huangyuhui 5bd5b25b77 Add debug message of system details 2018-07-01 19:18:55 +08:00
huangyuhui 55d59f3779 Fix not on FX thread 2018-07-01 19:02:32 +08:00
huangyuhui 7d2ea0b77e Add Tranditional Chinese translation 2018-07-01 13:37:09 +08:00
huangyuhui 1f30c299a5 Fix #360 2018-07-01 13:34:52 +08:00
huanghongxun c887d7e649 Merge pull request #358 from yushijinhun/authlib-injector
重构 authlib-injector 下载,并切换到新 API
2018-07-01 11:54:55 +08:00
yushijinhun 3fc7743a14 Add missing license header 2018-06-30 22:45:57 +08:00
yushijinhun 2a232f70db Refactor authlib-injector downloading, switch to new API 2018-06-30 22:45:57 +08:00
yushijinhun 6fae131287 Display (None) instead of empty string if no Yggdrasil server is available when adding account 2018-06-30 22:44:26 +08:00
yushijinhun 7ee7ef25f9 Refactor integrity check in FileDownloadTask, support multi algorithms 2018-06-30 22:43:57 +08:00
huangyuhui 2bd4bc1472 Add debug message in Task.run 2018-06-30 22:24:46 +08:00
huanghongxun aa170b647e Merge pull request #359 from yushijinhun/fixes
Fix bugs with yggdrasil authentication.
2018-06-30 22:12:06 +08:00
huangyuhui 4fa01216b1 Add debug message for tracing EmptyStackException and IllegalStateException 2018-06-30 22:09:35 +08:00
yushijinhun a82eb996a4 Add missing license header 2018-06-30 21:54:31 +08:00
yushijinhun 9315684ee3 Use CredentialExpiredException to indicate password login
instead of Non-ServerDisconnectException
2018-06-30 21:53:11 +08:00
huangyuhui 34f7774ce9 Fix NPE when the game launched and suddenly crashes 2018-06-30 21:36:57 +08:00
huangyuhui 75031a04cc Fix not on FX application thread 2018-06-30 21:28:41 +08:00
yushijinhun cfb0526cbb Fix potential NPE in YggdrasilAccount(selectedProfile is null) 2018-06-30 20:54:27 +08:00
yushijinhun 9fa56a9cd4 Regard token to be invalid only when remote throws ForbiddenOperationException 2018-06-30 18:52:37 +08:00
huangyuhui c4db9c9e12 Always show the advanced version setting pane as some people cannot find the options 2018-06-27 01:06:43 +08:00
huangyuhui 71272371e4 Fix #356 2018-06-26 21:55:29 +08:00
huangyuhui 91c6c4d233 Reduce size of welcome.png 2018-06-23 22:37:41 +08:00
huangyuhui 8a6653a926 Only show welcome page to Chinese 2018-06-23 22:25:39 +08:00
huangyuhui 76caf84e39 Welcome page 2018-06-23 22:15:23 +08:00
huangyuhui 0fee286b84 Use BMCLAPI as default ownload provider 2018-06-23 19:42:36 +08:00
huangyuhui 4af18a1575 Change build status icon in README.md 2018-06-23 13:03:28 +08:00
huangyuhui d9293f4da8 Display remote error message when RemoteAuthenticationException thrown 2018-06-21 19:31:16 +08:00
huangyuhui db29f97397 Update the link for crash reports 2018-06-17 18:22:22 +08:00
huangyuhui 573f41611d Force using Java 8 when launching Minecraft 1.13 or later 2018-06-17 18:13:47 +08:00
huanghongxun 28ed103ec0 Merge pull request #353 from yushijinhun/translations
完善 UI 提示消息
2018-06-17 17:45:59 +08:00
huanghongxun 5e37750f00 Merge pull request #352 from yushijinhun/refactor-update
添加 hmcl.version.override 选项用于调试更新功能
2018-06-17 17:40:07 +08:00
yushijinhun 5fe3cd9406 移除input.url.http错误提示 2018-06-17 17:28:12 +08:00
yushijinhun b00cc99408 BMCLAPI的链接使用https 2018-06-17 17:27:44 +08:00
yushijinhun 9a66c3bba9 完善翻译
中英文间补白、更正大小写、调整措辞
2018-06-17 17:25:22 +08:00
yushijinhun 546921b445 删除未被使用过的i18n条目 2018-06-17 16:40:22 +08:00
yushijinhun 8b698d3a4c 更新设置页面中依赖信息 2018-06-17 15:33:35 +08:00
yushijinhun c4608a949b 处理未捕获异常时立即进行log,防止异常被忽略
THROWABLE_SET改名为CAUGHT_EXCEPTIONS,使用并发安全集合
2018-06-17 15:04:31 +08:00
yushijinhun bba1c559a3 为连接authlib-injector服务器失败添加错误消息 2018-06-17 14:41:26 +08:00
yushijinhun bdee9ea72f 将获取验证服务器信息的代码移入AuthlibInjectorServer 2018-06-17 14:26:38 +08:00
yushijinhun 520923ba08 跳过更新时记录日志 2018-06-17 13:44:04 +08:00
yushijinhun 936a74597f 若版本号包含SNAPSHOT则也不更新
通过Gradle构建出来的JAR版本号为3.1.SNAPSHOT这样的
2018-06-17 13:40:09 +08:00
yushijinhun 97132745cc 增加hmcl.version.override选项用于覆写HMCL版本 2018-06-17 13:30:05 +08:00
yushijinhun 2bb30f65f3 在AppDataUpgrader中使用ReflectiveOperationException替代具体反射异常 2018-06-17 13:11:56 +08:00
huangyuhui ec04d55793 Fix transition 2018-06-17 12:05:39 +08:00
huangyuhui 88671db566 Use spinner instead of indeterminate progress bar 2018-06-17 12:05:25 +08:00
huanghongxun 538f501bc0 Merge pull request #351 from yushijinhun/refactor-yggdrasil
authlib-injector 部分重构
2018-06-17 10:34:47 +08:00
huangyuhui 3b75d41a2f 修改更新服务器连接 2018-06-17 10:34:13 +08:00
yushijinhun 110149d0e6 AuthlibInjectorAccountFactory的addtionalData改为AuthlibInjectorServer类型 2018-06-16 23:14:04 +08:00
yushijinhun 89b68781fa 修复添加验证服务器页面的错误信息不会被清除 2018-06-16 23:09:16 +08:00
yushijinhun 4cdc54b9c1 修复添加账号时未选中验证服务器会NPE 2018-06-16 23:06:21 +08:00
yushijinhun 7673595a43 AddAccountPane中服务器列表数据视图分离 2018-06-16 22:58:39 +08:00
yushijinhun 76a259c107 AuthlibInjectorAccount中存储AuthlibInjectorServer对象而不是url 2018-06-16 21:26:36 +08:00
yushijinhun 5f40d01fb4 在AuthlibInjectorAccountFactory中使用AuthlibInjectorServer而不是url 2018-06-16 21:26:36 +08:00
yushijinhun df29d47c0a workaround: 将Settings中的Config字段改为静态 2018-06-16 21:26:36 +08:00
yushijinhun 10d4084dde AuthlibInjectorServerInfo重命名为AuthlibInjectorServer
更正其它措辞:ip->url
2018-06-16 21:26:34 +08:00
yushijinhun ba8cdb1b42 移除AuthlibInjectorServersPage的spinner 2018-06-16 21:25:25 +08:00
yushijinhun 22732fee6a 存储AuthlibInjectorServerInfo对象而不是url字符串 2018-06-16 21:24:30 +08:00
yushijinhun bfbc4613b9 在添加authlib-injector服务器的过程中,传递AuthlibInjectorServerInfo而不是url 2018-06-16 20:33:48 +08:00
yushijinhun 92e5eecaf2 将Settings中DEFAULT_PROFILE, HOME_PROFILE字段移至Profiles 2018-06-16 20:30:14 +08:00
yushijinhun 593159f4a6 将DEFAULT_ICON移至Constants, 并使用懒加载
当类初始化时, JavaFX可能还未启动, 这将使图像加载失败
2018-06-16 20:10:10 +08:00
yushijinhun 53cad0e56a 在因无法读取而移除账户时记录日志 2018-06-16 20:10:10 +08:00
huangyuhui d61006dd67 Fix uncaught IOException 2018-06-13 23:40:16 +08:00
huangyuhui eb565285b2 Fix curse mod downloading 2018-06-10 20:05:36 +08:00
huangyuhui 630f164877 Continue load old version if the newer version cannot launch 2018-06-10 00:10:17 +08:00
huangyuhui 38c6bce2c0 Change log folder to ~/.hmcl 2018-06-09 17:37:43 +08:00
huanghongxun 034734ec66 Merge pull request #348 from yushijinhun/fxgson
使用 FxGson
2018-06-09 01:12:50 +08:00
yushijinhun d875eeb22a 将Config中属性替换为JavaFX Property 2018-06-09 00:32:33 +08:00
yushijinhun 61db6b8fb2 添加FxGson依赖 2018-06-09 00:28:23 +08:00
huanghongxun 945d4cf20d Merge pull request #347 from yushijinhun/merge-head
重构
2018-06-08 21:34:36 +08:00
yushijinhun 631337c451 YggdrasilAccount记录角色uuid而不是名称
注:旧版本无法读取此版本配置(移除了character)。
2018-06-08 21:13:33 +08:00
yushijinhun 4f51e377ae 移除canPlayOffline() 2018-06-08 21:09:35 +08:00
yushijinhun e71c06a0d0 Arguments.addXXX改为链式调用 2018-06-08 21:09:35 +08:00
yushijinhun 13aabde5d9 完善Account文档 2018-06-08 21:09:35 +08:00
huanghongxun e3f371f457 Merge pull request #344 from yushijinhun/javafx
修复YggdrasilAccount读取到了错误的character
2018-06-08 16:36:50 +08:00
yushijinhun 6ee99b5736 修复YggdrasilAccount读取到了错误的character
引入:https://github.com/huanghongxun/HMCL/commit/6c4231a6b242c2a11af9768e424593cc6cc14bc5#diff-839dd42e51cd641828b00c5302c02b12R50
2018-06-08 16:31:56 +08:00
huangyuhui 895188b25f Merge branch 'javafx' of https://github.com/huanghongxun/HMCL into javafx 2018-06-08 16:06:31 +08:00
huanghongxun 9fba923a51 Merge pull request #343 from yushijinhun/javafx
修复 defaultJavaPath 不能保存的问题
2018-06-08 16:06:01 +08:00
huangyuhui 37a39098f8 Try to fix VersionNotFoundException. Closes #298 2018-06-08 16:05:33 +08:00
yushijinhun 6fb548e6c3 修复defaultJavaPath不能保存的问题(未添加监听器) 2018-06-08 15:19:47 +08:00
huangyuhui 110b7cb06f Should fix 'Never get to here' 2018-06-08 13:55:38 +08:00
huangyuhui e9070a77c3 Fixed java.lang.IllegalStateException: stream has already been operated upon or closed 2018-06-08 13:40:12 +08:00
huangyuhui 475e6e5511 Remove redundant URLs that download providers provide. Mentioned in #242 2018-06-08 13:13:42 +08:00
huangyuhui eed4c7c11a Load skin when added new account 2018-06-08 12:58:01 +08:00
huangyuhui d986d7ac03 Apply spinner instead of intermediate progress bar 2018-06-08 12:47:46 +08:00
huangyuhui f640922a50 Optimize imports 2018-06-08 12:47:34 +08:00
huangyuhui 118a6cf0d1 Fasten version item construction 2018-06-08 12:45:44 +08:00
huanghongxun 72871e6d9a Merge pull request #342 from yushijinhun/refactor-skin
Yggdrasil 部分重构及 bug 修复
2018-06-08 10:41:46 +08:00
yushijinhun 61acbcec0d 移除GameProfile类的TypeAdapter 2018-06-07 22:28:17 +08:00
yushijinhun 06af79e2b4 移除对legcay账户的支持 2018-06-07 22:25:31 +08:00
yushijinhun 6782602141 重构YggdrasilService相关代码 2018-06-07 21:12:38 +08:00
yushijinhun 8df17ae38a 使用静态方法pair()替代new Pair<>() 2018-06-07 21:08:25 +08:00
huanghongxun 1645a93adf Merge pull request #341 from yushijinhun/cleanup
清理冗余代码
2018-06-07 12:41:51 +08:00
yushijinhun 6a04ab37d7 清理Hex 2018-06-07 12:17:58 +08:00
yushijinhun 27c9abd9ed 清理DigestUtils 2018-06-07 12:16:34 +08:00
yushijinhun a08be2e11d 移除Charsets类 2018-06-07 11:47:36 +08:00
huanghongxun 17615b1791 Merge pull request #340 from yushijinhun/javafx
修复 Java 选择相关 bug
2018-06-07 01:15:44 +08:00
yushijinhun d75c3b584a 修复加载JREs时可能的并发修改异常 2018-06-07 01:06:13 +08:00
huangyuhui 20f919b93e Merge branch 'javafx' of https://github.com/huanghongxun/HMCL into javafx 2018-06-07 00:53:56 +08:00
huangyuhui 20244fe5cc Fasten versions loading 2018-06-07 00:50:15 +08:00
yushijinhun 6a89f0a661 将当前Java版本包含在getJREs()中 2018-06-07 00:28:33 +08:00
huanghongxun 3a9efdb03e Merge pull request #339 from yushijinhun/multiple-java
Linux下自动检测Java + 允许多个相同版本的JRE
2018-06-06 23:57:24 +08:00
huangyuhui 2ae00db94b Removed MultiFileItem tooltips 2018-06-06 23:54:19 +08:00
huangyuhui a9261b759b Shutdown Now to prevent NPE when task executed after app closed 2018-06-06 23:52:23 +08:00
yushijinhun 6b02dc3cd5 允许多个相同版本的Java共存 2018-06-06 23:43:58 +08:00
yushijinhun afa37c0d2f 自动检测Linux下的Java 2018-06-06 23:01:27 +08:00
huangyuhui 2575f10497 Fixed #336 2018-06-06 19:45:39 +08:00
huanghongxun 27c4a68a13 Merge pull request #338 from yushijinhun/openjdk
对 OpenJDK 更好的支持
2018-06-06 14:02:14 +08:00
yushijinhun f09cb54894 当JavaFX缺失时弹窗提示 2018-06-06 13:52:23 +08:00
yushijinhun 5431cfef79 对OpenJDK上出现的错误同样进行上报 2018-06-06 13:31:53 +08:00
huanghongxun 35c0f3cddc Merge pull request #337 from yushijinhun/javafx
完善 authlib-injector 功能
2018-06-03 03:12:19 +08:00
yushijinhun efe22ca613 防止执行平移动画时组件溢出面板 2018-06-02 20:09:36 +08:00
yushijinhun 3408a8ffcf 更改措辞:添加认证服务器->管理认证服务器 2018-06-02 19:59:00 +08:00
yushijinhun 60a140efb3 修复删除验证服务器时可能出现ConcurrentModificationException
初始化块执行时字段并不一定都完成了初始化,应当避免使用。
利用ConcurrentHashMap的弱一致性防止迭代中删除账户造成ConcurrentModificationException。
2018-06-02 19:38:03 +08:00
yushijinhun bbe584bd91 修复无法显示未设置皮肤的Yggdrasil账户的皮肤的问题 2018-06-02 19:21:41 +08:00
yushijinhun 3866377a28 使用UUID而不是角色名来标识皮肤 2018-06-02 18:15:41 +08:00
yushijinhun ebc0b4b2b0 移除AccountHelper未使用的单例 2018-06-02 18:06:32 +08:00
huanghongxun d6c65a320d Merge pull request #334 from yushijinhun/java9
移除对Unsafe的使用
2018-05-29 22:47:35 +08:00
yushijinhun 2e46d76165 移除Lang.get(Map,Object,Class) 2018-05-27 12:40:45 +08:00
yushijinhun 23037da406 移除对Unsafe的使用 2018-05-27 12:13:27 +08:00
yushijinhun 617261c74d 不使用ReflectionHelper来安装Tooltip 2018-05-27 12:09:04 +08:00
yushijinhun 6c0d6ee0cf 通过非反射方法获取总物理内存 2018-05-27 11:04:39 +08:00
huanghongxun 663e1ef7ab Merge pull request #332 from xfl03/javafx
Fix #325 #296
2018-05-20 19:40:39 +08:00
Alexander Xia 1a47d355f0 Fix #325 #296 2018-05-20 19:12:12 +08:00
huangyuhui e407994103 Fixed #331 2018-05-17 16:46:16 +08:00
huangyuhui bda2149c02 Fix #326 2018-04-30 01:59:33 +08:00
huangyuhui b925423d61 Fixded #324 2018-04-26 22:15:27 +08:00
huangyuhui f3906a37bf Fixed #321 2018-04-26 13:14:14 +08:00
huangyuhui a1e115ea6b Ignore some exceptions 2018-03-09 16:54:28 +08:00
huangyuhui 03383510ef Disable accept button in AddAccountPage 2018-03-09 16:45:12 +08:00
huangyuhui e8cf9644eb Fix IllegalArgumentException: Invalid UUID String 2018-03-09 16:31:39 +08:00
huangyuhui dbfcf1facc Try to fix empty stack of StackContainerPane 2018-03-09 16:24:02 +08:00
huangyuhui 44aff94937 Remove error 2018-03-06 11:25:15 +08:00
huangyuhui fb1fc92b7c Fix optifine 2018-03-06 11:19:21 +08:00
huangyuhui 71cfa64b16 Fix StackContainerPane 2018-03-06 10:19:37 +08:00
huangyuhui b200105a85 Fix Liteloader installing of BMCLAPI 2018-03-06 10:13:48 +08:00
huanghongxun ce83f3c5e1 Merge pull request #297 from andylizi/switch-to-https
Switch to Https for most links.
2018-03-05 20:57:30 +08:00
huanghongxun 57d3275856 Merge branch 'javafx' into switch-to-https 2018-03-05 20:56:26 +08:00
huangyuhui eb1a109afc Fix IllegalArgumentException: Folder parameter must be a valid folder 2018-03-05 20:36:38 +08:00
huangyuhui a03e3fea12 Logs stopApplication stack trace 2018-03-05 20:23:23 +08:00
huangyuhui c60ae111ef Progress bar in account page 2018-03-05 20:07:30 +08:00
huangyuhui 5eb46395ae Close popup when deleted an account 2018-03-05 19:13:58 +08:00
huangyuhui db08b61cfa Fix #301 2018-03-05 19:02:13 +08:00
huangyuhui 41d313baff Fix #303 2018-03-04 23:35:42 +08:00
huangyuhui 58c3ed9254 Fixed #302 2018-03-04 23:33:08 +08:00
huangyuhui affe36a568 Fix update again 2018-03-04 23:29:27 +08:00
huangyuhui 9ba6cddde7 Fix update 2018-03-04 19:09:11 +08:00
huangyuhui 5656c9f351 update update_link.php 2018-03-04 16:54:35 +08:00
huangyuhui ecf24a746e Fix crashing when unable to save version setting 2018-03-04 15:33:54 +08:00
huangyuhui 5b5a58a867 Fixed not terminating the process when closed window 2018-03-03 22:56:42 +08:00
huangyuhui c6ab7878e7 Optimize code 2018-03-02 23:42:38 +08:00
huangyuhui 99e85eba37 Fix NPE in LauncherHelper.executor.onFinish: executor.getRunningTasks 2018-03-02 23:11:17 +08:00
huangyuhui 3bf92e6f12 Fix process not exited when pressed Alt+F4 2018-03-02 22:54:36 +08:00
huangyuhui ba359305f6 Hide refresh and add button in MainPage 2018-03-02 19:22:10 +08:00
huangyuhui f826eb224c AccountPage maintainence 2018-03-02 10:41:25 +08:00
huangyuhui a675f4cb68 Upgrade message 2018-03-02 00:56:16 +08:00
huangyuhui 5e1e2c6047 Remove accountsPage 2018-03-02 00:43:33 +08:00
huangyuhui eba0990538 Collect log when launcher crashed 2018-03-01 01:02:05 +08:00
huangyuhui 1bcef2bab0 Added event logs. Cloese #244 2018-03-01 00:27:07 +08:00
huangyuhui f83777e1d2 Terminate when exclaimation mark is in the path 2018-02-28 23:34:31 +08:00
huangyuhui 9fa48090ce Show indeterminate progress bar when loading versions in MainPage 2018-02-28 22:15:46 +08:00
huangyuhui 7c8ac4fee8 more precise warning in authlib injector add server page 2018-02-28 20:36:32 +08:00
andylizi 76c254ee98 Switch the download links to HTTPS 2018-02-28 17:23:49 +08:00
huangyuhui e75ad64483 Fixed IllegalStateException when clicked the empty space of list in InstallTypePage 2018-02-27 23:27:26 +08:00
huangyuhui 17d1af181d Profile page title changed to display name 2018-02-27 23:25:10 +08:00
huangyuhui a72d27a431 May fix VersionNotFoundException when building main page version items 2018-02-27 23:18:19 +08:00
huangyuhui 4e9fc57aa4 Fix NullPointerException when launcher launched two game at the same time 2018-02-27 23:12:53 +08:00
huangyuhui 494b27cc22 May fix RemoteVersion not found exception 2018-02-27 23:05:05 +08:00
huangyuhui 3606186975 Fix NullPointerException when selected an version item in download.VersionsPage 2018-02-27 20:05:05 +08:00
huangyuhui 41dbdfc016 Fix NullPointerException when refreshing versions again 2018-02-27 19:58:43 +08:00
huangyuhui 655e5ca7e0 Fixed missed encoding in Log4jHandler 2018-02-27 11:13:07 +08:00
huangyuhui 3067d323de Fixed NullPointerException when switched profile 2018-02-26 20:16:14 +08:00
huangyuhui 1404a080ad library download optimization 2018-02-26 19:56:06 +08:00
huangyuhui cbb2a1b575 Unique duplicated libraries in minecraft json file 2018-02-26 11:21:34 +08:00
huangyuhui 30b276ec1a Forge xz library supported 2018-02-26 11:14:53 +08:00
huangyuhui 13a24d5b00 try to fix RejectedExecutionException 2018-02-25 11:10:31 +08:00
huangyuhui 40360cf18a Fixed installing game 2018-02-25 10:59:48 +08:00
huangyuhui 139e2ee78d try fix ConcurrentModificationException 2018-02-25 10:48:07 +08:00
huangyuhui 3ff466462c Better theme selection UI 2018-02-24 23:46:20 +08:00
huanghongxun 9ff2442789 Foreground text fill auto detected 2018-02-23 17:40:32 +08:00
huanghongxun b11e4ab1db Fixed font in dialog accept and cancel button. Closes #291 2018-02-23 14:53:08 +08:00
huanghongxun a52cc8c093 Fixed crash when launching 1.7.10 forge version 2018-02-23 11:36:44 +08:00
huanghongxun 506c409303 log4jHandler maintainence 2018-02-23 11:22:20 +08:00
huanghongxun 53a8446f4a Curse CDN download provider 2018-02-23 09:54:57 +08:00
huanghongxun ab5bb8ea6c customized theme 2018-02-22 21:54:20 +08:00
huanghongxun d097b84c82 Fixed #285 2018-02-22 16:26:47 +08:00
huanghongxun f285635e76 Add multiple mods. Closes #287 2018-02-22 16:16:25 +08:00
huanghongxun 0f7b5299e9 Fixed incorrect format of userProperties. Closes #286 2018-02-22 15:46:48 +08:00
huanghongxun 7a788d1e6e cleanup 2018-02-22 15:02:12 +08:00
huanghongxun 6c4231a6b2 authentication reconstruction 2018-02-22 14:12:55 +08:00
huanghongxun 6e202341ad clean up 2018-02-20 18:03:34 +08:00
huanghongxun 95a509b86c ToStringBuilder 2018-02-20 12:11:31 +08:00
huanghongxun 602114af55 UI maintainence 2018-02-20 10:48:59 +08:00
huanghongxun e5ccc40358 clear cached skin records when refrshing account state 2018-02-18 18:35:05 +08:00
huanghongxun 2310f6e1c0 Fix http warning not being hidden if https used 2018-02-18 18:29:22 +08:00
huanghongxun 9ae952bb78 Add comments 2018-02-18 18:26:01 +08:00
huanghongxun 57a7eaccf5 Optimize imports 2018-02-18 17:16:42 +08:00
huanghongxun 1934bfa962 Merge pull request #282 from yushijinhun/javafx
重构
2018-02-18 17:12:16 +08:00
yushijinhun a5f3ec7b9b fix indents 2018-02-18 17:07:54 +08:00
yushijinhun 3cfcf1e772 用定义的类型代替FXUtils.addListener中的Pair 2018-02-18 16:47:00 +08:00
yushijinhun b45907a9f6 Polish, 处理部分警告 2018-02-18 16:23:12 +08:00
yushijinhun 8fd9395e23 删除对SSL的干涉(出于安全考虑) 2018-02-18 16:03:13 +08:00
yushijinhun 126b2a19e7 ReflectionHelper中使用参数化类型 2018-02-18 16:01:21 +08:00
yushijinhun bde01af89d help compilers to infer types
ecc cannot infer it
2018-02-18 15:49:11 +08:00
yushijinhun 65491ef18e Remove 3-arg Lang.merge() 2018-02-18 15:44:32 +08:00
huanghongxun 44a9470613 Fixed same skin among characters in one account 2018-02-18 15:42:18 +08:00
yushijinhun 470045f228 Rename Lang.getOrPut() to computeIfAbsent()
See Map.computeIfAbsent() in java9
2018-02-18 15:33:58 +08:00
yushijinhun d081a6ee92 Remove Lang.requireJsonNonNull(), use JsonUtils.fromNonNullJson() instead 2018-02-18 15:32:00 +08:00
yushijinhun 95f404bb64 move emptyConsumer() to Constants 2018-02-18 15:20:00 +08:00
yushijinhun dcea76bcd3 Add missing @SafeVarargs in Lang 2018-02-18 15:17:17 +08:00
yushijinhun e9b816fb87 Change Lang.EMPTY_CONSUMER to emptyConsumer() 2018-02-18 15:15:28 +08:00
huanghongxun 20a7039f59 GC after game launched 2018-02-18 13:54:13 +08:00
huanghongxun 4ad172dda4 authlib-injector prefetch support 2018-02-18 09:39:56 +08:00
huanghongxun adf6c19996 Cache session profile response. Closes #280 2018-02-17 23:38:40 +08:00
huanghongxun 24ec0adacf Authlib Injector support 2018-02-17 23:28:05 +08:00
huanghongxun 83bc6748a3 HMCLCore authlib injector support 2018-02-17 11:01:08 +08:00
huangyuhui bfed651263 hmcl.log in normal format 2018-02-15 01:29:19 +08:00
huangyuhui 8bd4f2b5b5 hmcl.log in normal format 2018-02-14 23:42:08 +08:00
huangyuhui 3d7bc0b593 Will not wait for launching if launching rd versions 2018-02-14 23:01:23 +08:00
huangyuhui 473c6f2b3c Additional information on main page 2018-02-14 22:54:28 +08:00
huangyuhui 484ce6c895 try javafx static attributes 2018-02-14 22:19:25 +08:00
huangyuhui eeccdbca72 proxy settings ui optimization 2018-02-14 20:57:48 +08:00
huangyuhui 552238676c Fixed activation of mods not working. Closes #259 2018-02-14 15:16:42 +08:00
huangyuhui c9e7bf7ca5 Yggdrasil account offline logging in 2018-02-14 14:51:42 +08:00
huangyuhui 8d1e335abf Downloading snapshot versions 2018-02-14 14:15:34 +08:00
huangyuhui c76bcb5d15 show retry link when failed to fetch version list 2018-02-14 13:29:08 +08:00
huangyuhui 7732b21ca2 add introduction to installing modpacks 2018-02-14 01:45:21 +08:00
huangyuhui 123d9b791c Unify the font of tab header 2018-02-14 01:19:29 +08:00
huangyuhui a237ca799f Fixed darker color of title bar 2018-02-14 00:34:50 +08:00
huangyuhui f850c2461a Current account tip 2018-02-14 00:19:25 +08:00
huangyuhui 0fb248e6be theme selection 2018-02-14 00:15:27 +08:00
huangyuhui 7fca697234 current directory for selected profile 2018-02-13 22:28:27 +08:00
huangyuhui 4004525d3a english i18n 2018-02-13 22:23:59 +08:00
huangyuhui 4f67788d4a modifiable theme color 2018-02-13 21:36:19 +08:00
huangyuhui 69ea41056d background customizing 2018-02-13 18:37:33 +08:00
huangyuhui 6443770670 update prompt 2018-02-13 12:16:53 +08:00
huangyuhui 46917af37c Renaming profile 2018-02-12 23:52:10 +08:00
huangyuhui 47a4a0eaf5 Add profile button move to category title 2018-02-12 23:23:39 +08:00
huangyuhui 03dbecd5ae About 2018-02-12 23:02:33 +08:00
huangyuhui f6c95e3095 Show alex or steve portrait for offline account 2018-02-12 21:25:47 +08:00
huangyuhui 6823291eb0 Ignoring IOExceptions in log4j handler 2018-02-08 00:04:02 +08:00
huangyuhui 98b43945ed Global and special version settings. Fixed property bindings 2018-02-07 22:33:52 +08:00
huangyuhui 8792c423d5 Disabling launcher checking game completion 2018-02-07 21:05:58 +08:00
huangyuhui 5607298898 reduce 'return null' 2018-02-07 21:01:09 +08:00
huangyuhui 35047477fe Fixed crash when a version inherits from a nonexistent version. Closes #269 2018-02-06 16:40:31 +08:00
huanghongxun 08a31a92f2 Merge pull request #267 from mslxl/javafx
Fix `Unable to move temp file`, `File::renameTo` is problematic.
2018-02-06 09:54:08 +08:00
huangyuhui 6e2fc7ff97 Maintains minecraft arguments when installing or uninstalling Forge, OptiFine, LiteLoader 2018-02-06 00:07:32 +08:00
huangyuhui 44d1f9cf7d LiteLoader installing 2018-02-05 23:53:57 +08:00
mslxl 826a6bf868 Fix Unable move temp file on Arch Linux 2018-02-05 16:24:44 +08:00
huangyuhui 3abb96e5b9 Temporarily fix spacing missing. Closes #264 2018-02-05 00:23:58 +08:00
huangyuhui 228fddf902 Fix always throwing IOException when downloading game asset index 2018-02-04 21:26:55 +08:00
huangyuhui 1516802a8d Fix the layout of task executor pane 2018-02-04 21:26:25 +08:00
huangyuhui c7589e4e3c Fix official optifine download 2018-02-04 12:33:09 +08:00
huangyuhui a502785209 character selection 2018-02-03 16:48:30 +08:00
huangyuhui c923ed69a0 Update & Crash 2018-02-02 17:45:29 +08:00
huangyuhui e4bd1c758f Delete version folder when installing canceled 2018-02-02 15:38:55 +08:00
huangyuhui ad175fd2f2 Fixed duplicated but different version libraries casuing crash when Forge and OptiFine installed. Closes #261 2018-02-02 15:31:42 +08:00
huangyuhui 190cc18b11 Fixed no forge when install a version with its name not the default one. Closes #208 2018-02-02 14:40:59 +08:00
huangyuhui 55e7b8901a Forbids interrupted exception shown 2018-02-02 14:25:21 +08:00
huangyuhui 2efb5d7f8f MainPage popup menu: open game directory 2018-02-02 13:51:29 +08:00
huangyuhui f144dd888d Launching messages 2018-02-02 13:44:53 +08:00
huangyuhui 0a4944f120 decompress natives to system temp directory 2018-02-02 11:13:10 +08:00
huangyuhui 7675347889 decompress natives when making launch script 2018-02-02 10:53:59 +08:00
huangyuhui 7ea2b57ece Unable to launch dialog 2018-02-02 10:46:27 +08:00
huangyuhui cec8249b24 Removed -XstartOnFirstThread to fix freezed launched game. GH-257 2018-02-01 15:57:55 +08:00
huangyuhui 31c05c9b20 Fixed incomplete GUI. Closes #253 2018-01-29 20:44:58 +08:00
huangyuhui f7aeef3ffc Fix malformd version settings leading to unmodifiable configuration 2018-01-28 15:03:18 +08:00
huangyuhui ccb1ff7f0e Warns user before launching 2018-01-28 14:59:53 +08:00
huangyuhui b707388134 Fix NullPointerException when upgrade from 2.x 2018-01-28 14:16:05 +08:00
huangyuhui 538cc2b75e Attempt to fix #253 2018-01-27 21:27:15 +08:00
huangyuhui b783f3bae9 Install initial modpack 2018-01-27 21:23:24 +08:00
huangyuhui b776015b36 sort i18n 2018-01-27 18:57:54 +08:00
huangyuhui be4ea59984 about 2018-01-27 17:03:06 +08:00
huangyuhui 2f92b65400 installTooltip for java9 2018-01-27 16:25:41 +08:00
huangyuhui 2c7510fe5f Crash and upgrade 2018-01-27 16:16:38 +08:00
huangyuhui 1ff36552e0 Yggdrasil account requries email to be username 2018-01-27 14:14:42 +08:00
huangyuhui 418be689f2 Cached Minecraft jars 2018-01-27 14:05:39 +08:00
huangyuhui 1a572be52e Modpack updates UI 2018-01-27 12:56:45 +08:00
huangyuhui e8316de160 Modpack updates 2018-01-27 01:19:13 +08:00
huangyuhui 12fa94627d TransitionHandler update 2018-01-25 22:41:15 +08:00
huangyuhui 056c0901f2 make launch script 2018-01-24 19:42:04 +08:00
huangyuhui 6db41431ed localization 2018-01-20 11:18:59 +08:00
huangyuhui b90d6b7b8c Update Readme.md for HMCLCore introduction 2018-01-16 19:34:53 +08:00
huangyuhui 4b39c046a7 Prepare for MCBBS modpack 2018-01-12 21:30:09 +08:00
huangyuhui 8edfe7bc9c MessageBox 2018-01-09 21:37:04 +08:00
huangyuhui 9e21e02791 G1GC more options 2018-01-09 17:17:41 +08:00
huangyuhui 8e6b56b2d6 upgrader 2018-01-09 17:14:50 +08:00
huangyuhui 4b65d4da06 Make background transparent? 2018-01-09 00:03:34 +08:00
huangyuhui a40c5fdd40 Turn to java 2018-01-01 23:12:59 +08:00
huangyuhui d8be9abcc5 nothing 2018-01-01 16:21:54 +08:00
huangyuhui d2529cfc23 Merge 'arguments' 2017-11-16 00:13:49 +08:00
huangyuhui b81b38f7e4 remove -Xincgc for Java 9 2017-11-04 11:07:36 +08:00
huangyuhui d9225b9529 Launching 1.13 2017-11-03 13:38:38 +08:00
huangyuhui 4bde509708 Update Gradle 2017-10-23 13:09:50 +08:00
huanghongxun 22877e96c7 Update build.gradle 2017-09-17 16:55:05 +08:00
huanghongxun ae473a0d1a Merge pull request #207 from hellckt/javafx
Fixed invalid forge download url
2017-09-17 16:46:24 +08:00
keteZeng 807f42ad65 Fixed invalid forge download url 2017-09-17 12:08:02 +08:00
曾科特 026986c956 Merge pull request #1 from huanghongxun/javafx
Fixed finding asset objects. Closes #205
2017-09-17 10:40:53 +08:00
huanghongxun 621562a17e Fixed finding asset objects. Closes #205 2017-09-16 20:42:08 +08:00
huanghongxun 5f7f885d99 Added custom game directory. Closes #199 2017-09-04 15:55:18 +08:00
huangyuhui 41337f66a8 Upgrader 2017-08-27 14:23:27 +08:00
huangyuhui 8c61bc1a5e Prepare for proguard 2017-08-27 12:49:56 +08:00
huangyuhui b07144278b Task chain exception catching 2017-08-26 19:09:21 +08:00
huangyuhui c775e8368e Try to asynchronize some time-costly tasks 2017-08-26 10:53:05 +08:00
huangyuhui 008f07cacc Removed wrong imports 2017-08-25 20:22:27 +08:00
huangyuhui ff1a566bf4 Profiles editing and selecting 2017-08-25 20:18:27 +08:00
huangyuhui 3b4359f7eb Fixed logging spaces and tabs missing, unclickable version item, removing 'logging' element when installing forge and liteloader 2017-08-25 13:22:10 +08:00
huangyuhui e70226afba Apache common-compress 2017-08-25 10:12:56 +08:00
huangyuhui cc2c186e7f Load mod list asynchronously 2017-08-25 09:28:55 +08:00
huangyuhui 833247d133 Icon selection 2017-08-25 08:54:33 +08:00
huangyuhui f532df20e6 MultiMC modpack support 2017-08-24 23:53:27 +08:00
huangyuhui 0fa601ad5e Auto-installing 2017-08-24 19:20:15 +08:00
huangyuhui 6da1dc5372 HMCL modpack export 2017-08-24 13:57:01 +08:00
huangyuhui 2e3d9c22e3 Tooltip reflection for advanced options 2017-08-23 12:07:08 +08:00
huangyuhui 86cef86fc9 HMCL modpack output model 2017-08-22 21:07:56 +08:00
huangyuhui d83291eac0 HMCL modpack import 2017-08-22 20:15:26 +08:00
huangyuhui 0cc7d621bc Javadoc 2017-08-22 14:31:35 +08:00
huangyuhui b40b0ec47c Version setting pane context menu 2017-08-21 22:57:45 +08:00
huangyuhui a67bfabea4 Log window category and show lines 2017-08-21 20:59:32 +08:00
huangyuhui be202a6e1a Log Window refined 2017-08-21 13:40:16 +08:00
huangyuhui f92275fa50 orignal log window 2017-08-21 00:37:53 +08:00
huangyuhui 563ea993c6 Minecraft Logging 2017-08-20 19:47:28 +08:00
huangyuhui cbf2a4e7a8 Allow draging files to mod pane 2017-08-20 09:25:37 +08:00
huangyuhui bc53e944af Add mod button in Mod page 2017-08-20 00:20:41 +08:00
huangyuhui 432fd287c9 Fix yggdrasil login. 2017-08-19 23:44:12 +08:00
huangyuhui 383453f9af Launching progress 2017-08-19 21:51:46 +08:00
huangyuhui 27939c6b61 Skin portrait 2017-08-18 22:42:11 +08:00
huangyuhui dc468f1a76 Java Selection 2017-08-18 13:58:49 +08:00
huangyuhui 99f60ea6e5 CurseForge modpack support. Random UserAgent for OptiFine. Fixed mis-repositioning of maronry pane 2017-08-17 13:14:34 +08:00
huangyuhui 1394034160 Settings page refined 2017-08-16 12:02:04 +08:00
huangyuhui 45ac758b52 Mods page refined 2017-08-16 11:06:11 +08:00
huangyuhui bf13c5ff40 ComponentList for settings view 2017-08-16 10:29:59 +08:00
huangyuhui 6179bcdf5b UI improvement 2017-08-14 18:09:02 +08:00
huangyuhui 6121a0cade Version item width limited 2017-08-14 13:11:26 +08:00
huangyuhui a9b044b4d2 localization 2017-08-11 18:16:23 +08:00
huangyuhui 54c4ca4180 Hamburger and drawer 2017-08-10 20:48:18 +08:00
huangyuhui 301130bc0c Clear warnings 2017-08-10 19:56:27 +08:00
huangyuhui 36b23d072c Add files 2017-08-10 19:34:19 +08:00
huangyuhui 66ad048053 Remove tests 2017-08-10 19:08:05 +08:00
huangyuhui 9bd7071297 emmmmm 2017-08-10 18:44:21 +08:00
huangyuhui da66102bc0 Able to launch game now 2017-08-08 23:57:17 +08:00
huangyuhui f1ffa5ca03 Scheduler JavaFX and Swing now have Future 2017-08-06 11:45:12 +08:00
huangyuhui 736a8c1b30 FXML for decorator 2017-08-03 23:54:15 +08:00
huangyuhui 41498b5d93 UI works 2017-08-02 00:33:24 +08:00
huangyuhui 3c32ef39c7 Fixed compile error 2017-08-01 18:56:13 +08:00
huangyuhui 726f92a9c9 Fixed untracked files 2017-08-01 18:12:39 +08:00
huangyuhui f6adbe435e .gitignore 2017-08-01 18:11:47 +08:00
huangyuhui 1410b3b5b1 LICENSE 2017-08-01 18:10:36 +08:00
huangyuhui 6dc2b36d14 HMCLKotlin project 2017-08-01 13:51:48 +08:00
huangyuhui 34d560b75e Now OptionPane Yes No are translated 2017-07-28 09:44:29 +08:00
huangyuhui caa77387df Fixed reseting the color at warning mode 2017-07-28 08:45:36 +08:00
huangyuhui a0b19cfd1b Russian Lang 2017-07-19 23:28:56 +08:00
huangyuhui 6afcf8d0d7 Support liteloader snapshots 2017-07-03 19:43:36 +08:00
huangyuhui b8591007cf Fixed wrong username when already logged in. Closes #158 2017-07-03 08:52:41 +08:00
huangyuhui 7fe3e28a2d Add default log4j config file for better performance 2017-07-03 08:46:35 +08:00
huangyuhui 72a1d4f186 Initial version here 2017-07-02 23:08:26 +08:00
huangyuhui 472658293f 2.7.8 2017-07-02 16:31:24 +08:00
huangyuhui 4ecdefc14e Added searching log texts. Closes #69 2017-07-02 16:24:50 +08:00
huangyuhui 38eff7e59c Supported 'logging' item in minecraft.json 2017-07-02 13:12:41 +08:00
huangyuhui 7d8a66b71a Fixed not downloading when a library and an native library have the same name 2017-07-01 23:38:07 +08:00
huangyuhui 29f53d574c add log lines limitation 2017-07-01 21:31:24 +08:00
huangyuhui 979a1a9810 Prevent too much memory used by logging system 2017-06-29 08:30:01 +08:00
huangyuhui 2f3c8285c8 Fixed #153 2017-06-24 15:52:28 +08:00
huangyuhui cfa7b4832a try to avoid not supporting translucent 2017-06-11 21:46:54 +08:00
huangyuhui 091898551e Force to disable shadows in Mac and Linux in order to close issue #122 #124 #131 #136 #145 2017-06-11 13:15:38 +08:00
huangyuhui fbeabfcad2 Fix spinner UI 2017-06-11 13:11:44 +08:00
huangyuhui 5a6c64377a Fix console font coloring 2017-06-11 12:24:50 +08:00
huangyuhui faa806fc9f New console font options 2017-06-11 12:17:41 +08:00
huangyuhui 4fdafecf77 add STDOUT & STDERR highlight 2017-06-08 22:59:21 +08:00
huangyuhui a8bc4eb352 Change version to 2.7.7 2017-05-20 19:10:38 +08:00
huangyuhui 532ff88ea4 Fixed not aborting launching when not having successfully downloaded all libraries 2017-05-20 19:01:32 +08:00
huangyuhui 30ee33cd66 Now component animations and MainPagePanel animation can be disabled 2017-05-20 18:44:26 +08:00
huangyuhui 3462123877 Fixed not turn to state 'done' when game crashes at the beginning 2017-05-20 18:24:42 +08:00
huangyuhui 0d8bd2569f Fixed warning when renaming a game version 2017-04-09 20:09:11 +08:00
huangyuhui a68aa84e2f An alert to suggest users to use Java 8 2017-04-04 18:10:05 +08:00
huangyuhui ebadbb0f18 Fixed #130 2017-04-04 13:58:14 +08:00
huangyuhui 4f03ec503f Fixed outputing crash advice twice 2017-03-12 13:50:20 +08:00
huangyuhui fd2a5a07a1 Try to fix concurrentModificationException 2017-03-10 19:38:51 +08:00
huangyuhui 0f390e63d3 Add progress of installing and game downloading 2017-03-02 13:18:25 +08:00
huangyuhui 57c6ae5e04 Animations on TextField 2017-02-28 13:27:28 +08:00
huangyuhui f4303a0480 Animations on Scroll Bar 2017-02-27 21:13:43 +08:00
huangyuhui 61afad30c8 Animations on buttons and comboboxes 2017-02-27 20:36:14 +08:00
huangyuhui d8086b7337 Decrease the border width of scroll pane 2017-02-27 12:45:32 +08:00
huangyuhui ea7eb72cce Fixed #123: Disable translucent when it is not supported 2017-02-27 12:41:22 +08:00
huangyuhui 0fc7eb6316 will not take operations when cancel the file chooser 2017-02-26 21:45:39 +08:00
huangyuhui 926e276167 InstallerPanel: show loading in the table instead of showing a task window 2017-02-26 21:38:38 +08:00
huangyuhui a34875e804 New launcher visibility mode: hide and reopen later 2017-02-26 21:19:21 +08:00
huangyuhui 7436736040 Modify logging system 2017-02-26 20:21:35 +08:00
huangyuhui 0dfd8af7d5 show white page when the image files in jar are missing 2017-02-25 19:14:08 +08:00
huangyuhui b4658463e1 Init log before checking updates 2017-02-25 12:59:37 +08:00
huangyuhui 99c7fb997b Sign jar 2017-02-25 12:26:07 +08:00
huangyuhui dc78eead09 Fixed #120 2017-02-25 10:57:27 +08:00
huangyuhui 63d483d4ec Fixed NullPointerException when failed to check newest version 2017-02-24 22:56:15 +08:00
huangyuhui 6e685a2aa1 support jar upgrading 2017-02-24 19:42:42 +08:00
huangyuhui 4b435d4ac3 Try to fix auto update 2017-02-24 19:22:06 +08:00
huangyuhui 17eca9dd2f mac os app 2017-02-24 19:08:12 +08:00
huangyuhui 0a853ca8a5 Scroll Bar 2017-02-24 19:04:19 +08:00
huangyuhui c67caafdb4 Fixed forge not downloading from BMCL 2017-02-24 13:13:55 +08:00
huangyuhui 0bda79c0d5 Fixed typesafe again and again 2017-02-24 12:57:18 +08:00
huangyuhui 44735b3d4e try to fix memory over flow 2017-02-23 18:19:14 +08:00
huangyuhui a6768c361f Make java dir text field text clearer 2017-02-23 13:31:18 +08:00
huangyuhui d1c4dee7f7 New LaF 2017-02-22 20:12:21 +08:00
huangyuhui f4d148b042 version 2.7.3 2017-02-19 16:45:55 +08:00
huangyuhui 184bcc2e40 Gradle 3.3 and wrapper 2017-02-19 16:38:25 +08:00
huangyuhui 445367532a Fixed #119 2017-02-19 16:30:27 +08:00
huangyuhui fa5ff14ff1 missing files 2017-02-18 18:41:00 +08:00
huangyuhui f4c5fbf9dd May fixed: length must be positive when logging 2017-02-18 18:29:46 +08:00
huangyuhui 9df351a2f0 Add #111: wrapper launch options and login result processing event 2017-02-18 13:02:19 +08:00
huangyuhui 00143de42b Fixed #113: when switch to launcher settings page, the theme changes to orange 2017-02-18 12:50:37 +08:00
huangyuhui 65e5677788 Fixed #114: no lwjgl64 in java.library.path 2017-02-18 12:41:56 +08:00
huangyuhui 0bd1b404aa Update I18N_zh.land and I18N_zh.properties 2017-02-17 20:16:44 +08:00
huangyuhui 5f65496500 Load plugins from jar file 2017-02-17 20:00:45 +08:00
huangyuhui 413854d1f1 Add an option to disable common path 2017-02-16 20:34:31 +08:00
huangyuhui f836afa2ea Api 2017-02-15 20:28:01 +08:00
huangyuhui 55b36e734d Fixed not automatically downloading a new version file when it is malformed 2017-02-13 22:07:58 +08:00
huangyuhui 0a2129aeab installers support common path 2017-02-13 21:04:23 +08:00
huangyuhui c1208563cd Add some javadoc 2017-02-13 18:59:04 +08:00
huangyuhui 5a6e1ffcd9 Fix gradle file 2017-02-13 18:46:30 +08:00
huangyuhui 33ef03ef71 Fixed saving common path setting 2017-02-13 14:02:13 +08:00
huangyuhui 1b81c1e221 Try travis 2017-02-13 13:32:42 +08:00
huangyuhui 7418ef21ac Fixed compile errors in HMCSM 2017-02-13 13:20:52 +08:00
huangyuhui 20be2f76c6 Add: Common folder to save libraries and assets 2017-02-13 13:10:11 +08:00
huangyuhui eb311abe83 Add: Load plugins by command line 2017-02-12 23:05:43 +08:00
huangyuhui 80599013f2 Fixed not showing prompt when no version here 2017-02-12 22:56:44 +08:00
huangyuhui f756f32bda Download libraries from aliyun 2017-02-12 00:01:14 +08:00
huangyuhui 273744bb7e Added check validity when refreshing authenticated token 2017-02-11 23:51:24 +08:00
huangyuhui bbfd8db190 Fixed library download source 2017-02-11 23:47:19 +08:00
huangyuhui b415a2c2fa Switching tabs animation optimization 2017-02-11 22:00:07 +08:00
huangyuhui a11ca8b720 Now a version setting can be linked to the global setting or its specialized setting 2017-02-11 21:38:10 +08:00
huangyuhui 4f88b26c0b Now OptionPane.border has been set 2017-02-11 19:26:22 +08:00
huangyuhui 2fa0a182ff WideComboBox is now more intelligent 2017-02-11 19:03:01 +08:00
huangyuhui 25fb73809e Restored animations 2017-02-11 18:18:43 +08:00
huangyuhui b8a7b489cc Now the person who are using OpenJDK will be warned. 2017-02-10 22:06:46 +08:00
huangyuhui 92219189a9 Fixed forge installing 2017-02-10 13:59:16 +08:00
huangyuhui afe3f84c4a Update zh_TW lang 2017-02-09 22:51:36 +08:00
huangyuhui a29a5b0bbf Merge branch 'master' of https://github.com/huanghongxun/HMCL 2017-02-09 13:15:30 +08:00
huangyuhui 2553ce82ec Fixed #82 2017-02-09 13:10:30 +08:00
huangyuhui f6bdb986dd Fixed dragging mod files to UI 2017-02-09 12:59:09 +08:00
huangyuhui 6fe451c247 Fixed messy reading caused by charset. 2017-02-09 12:31:57 +08:00
huangyuhui 2ece71aae3 Ignore IllegalStateException(Shutdown in Progress) 2017-02-05 16:59:59 +08:00
huangyuhui ac66dfe476 Temporarily blocked ArrayIndexOutOfBoundsException when refreshing game downloads. It should not happen 2017-02-05 16:54:18 +08:00
huanghongxun b5f8c4fb6d Merge pull request #100 from InfinityStudio/master
Rollback Changes
2017-02-01 12:22:38 +08:00
huangyuhui 9ab853d0ea Revert 2017-02-01 12:21:19 +08:00
huangyuhui 02d3bd36fe Now zh_HK, zh_MO are redirected to zh_TW 2017-01-30 23:18:57 +08:00
huangyuhui 899c825813 Change default language from zh_CN to en_US 2017-01-30 16:20:41 +08:00
huangyuhui 89efa71ced Supported BMCL Liteloader downloads 2017-01-29 12:23:38 +08:00
huangyuhui 88c46ba9ee Fixed #3 2017-01-29 11:33:43 +08:00
huangyuhui 972c4758b1 Clean up again 2017-01-27 22:41:34 +08:00
huangyuhui 809d7378e2 Clean up 2017-01-27 16:26:02 +08:00
huangyuhui 68cfa3a5da Added Vietnamese lang. 2017-01-27 14:09:08 +08:00
huanghongxun 6e79450558 Merge pull request #5 from dxNeil/patch-1
Update I18N_en.lang
2017-01-27 14:04:27 +08:00
dxNeil 0fd29ac223 Update I18N_en.lang
Fixed a few grammar issues.
Fixed the spelling mistake on the word 'Texutre' changed to 'Texture'.
2017-01-27 14:08:00 +11:00
huangyuhui 627e632120 Fixed handshake failed connecting with minecraft asset site 2017-01-26 15:07:57 +08:00
huangyuhui 574532f10c Fixed NPE downloading assets and there is no version 2017-01-25 18:07:22 +08:00
huangyuhui 74ad750d1d missing files 2017-01-25 12:56:00 +08:00
huangyuhui 67a61493dd Fixed #1 2017-01-23 10:25:16 +08:00
huangyuhui 0d03e965d2 allow tasks being hidden in task window 2017-01-22 17:01:02 +08:00
huangyuhui db4615a2d3 Fixed NullPointerException when fail to get forge list. 2017-01-20 12:44:14 +08:00
huangyuhui da2f0b234f Merge branch 'master' of https://github.com/huanghongxun/HMCL 2017-01-19 20:46:57 +08:00
huangyuhui 3896b2511c Merge branch 'master' of https://github.com/huanghongxun/HMCL 2017-01-19 20:46:11 +08:00
unknown 7c316f8c88 Merge branch 'master' of https://github.com/huanghongxun/HMCL 2017-01-19 20:36:20 +08:00
unknown ed7c52f09f Added Gaussion Blur 2017-01-19 20:33:24 +08:00
南宫临风 130b950878 update version 2016-08-29 17:13:00 +08:00
南宫临风 c0b935e3f1 迁移崩溃收集
改进推荐内容关闭策略
2016-08-25 14:33:40 +08:00
南宫临风 90451e6da9 最大限度的捕获异常,防止客户端崩溃
添加关闭推荐内容按钮
2016-08-24 13:46:06 +08:00
南宫临风 6db34fcdc7 修正地址解析问题 2016-08-22 10:23:27 +08:00
南宫临风 5bb53622ca Update HMCL version 2016-08-18 11:36:36 +08:00
南宫临风 b9308f060f oschina的Maven下载失效 2016-08-18 11:25:03 +08:00
南宫临风 f715367849 Update HMCL version 2016-07-12 19:07:15 +08:00
南宫临风 07b757b3c1 try fix travis 2016-07-12 18:03:04 +08:00
南宫临风 3325e393bc try fix travis file 2016-07-12 17:51:07 +08:00
南宫临风 48a8c99c83 Update travis 2016-07-12 16:17:09 +08:00
南宫临风 8d687158f6 Update travis 2016-07-12 15:28:55 +08:00
南宫临风 f966793490 Fix travis 2016-07-12 15:06:03 +08:00
南宫临风 d824122219 Fix travis-ci file 2016-07-12 14:49:32 +08:00
南宫临风 65900b5881 update tag style 2016-07-12 14:37:13 +08:00
南宫临风 e6ed1eab71 难用的travis-ci 2016-07-12 14:34:14 +08:00
南宫临风 1a3c31a141 Fix Library resolve bug 2016-07-12 14:17:17 +08:00
南宫临风 c0ef592f72 Restore icon and must manually add tag 2016-07-12 10:37:18 +08:00
南宫临风 5d2b4d435f Modify download type 2016-07-11 16:59:06 +08:00
南宫临风 fd5b5ebd8d Try test travis 2016-07-11 15:23:10 +08:00
南宫临风 2f42873793 Fix gradle build file 2016-07-11 11:54:22 +08:00
南宫临风 3b4b63e57b Modify publish link 2016-07-11 11:47:12 +08:00
南宫临风 c33a99d9ed show update log 2016-07-09 22:04:43 +08:00
南宫临风 b6be41e5c5 update git ignore file 2016-07-09 21:02:57 +08:00
南宫临风 bd4c07a013 read buildNumber from travis 2016-07-09 21:01:37 +08:00
南宫临风 ba763b2d2a Synchronize version.properties 2016-07-08 20:40:55 +08:00
南宫临风 c15ec71be9 update travis 2016-07-08 20:31:25 +08:00
南宫临风 93273d555d update README.md 2016-07-08 19:54:48 +08:00
南宫临风 793f81e287 update travis 2016-07-08 19:49:06 +08:00
南宫临风 d87b768fc0 修正模组信息解析问题 2016-07-07 18:01:58 +08:00
南宫临风 c07d2dc6d3 update link 2016-07-07 16:53:46 +08:00
南宫临风 95af0222f3 update dynamic provider 2016-07-07 14:32:35 +08:00
南宫临风 3f15eddb0c 修正使用java 8 API导致启动失败 2016-07-06 16:24:33 +08:00
南宫临风 c39f1ad75f 使用gradle管理buildNumber 2016-07-05 12:03:34 +08:00
南宫临风 f27b60e031 udpate version 2016-07-05 11:25:36 +08:00
南宫临风 5f1d0a5936 强制更新的时候不刷新标题栏 2016-07-04 18:22:01 +08:00
南宫临风 4fdadd5474 统计版本号 2016-07-04 18:16:34 +08:00
南宫临风 b2ea6d449e 忽略版本更新功能 2016-07-04 17:29:22 +08:00
南宫临风 3afff687b2 修改版本升级地址 2016-07-04 14:34:04 +08:00
evilwk 37ddecf629 加入强制升级和升级提示 2016-07-03 18:33:53 +08:00
南宫临风 27e58edb1f MainPagePanel content 2016-06-30 20:05:12 +08:00
南宫临风 3dd421a2bf fix library url parse 2016-06-29 16:54:29 +08:00
南宫临风 4537f9e48f 修正library补全Bug 2016-06-29 15:47:40 +08:00
南宫临风 94b6cda86e 添加可以在线控制的下载源 2016-06-28 20:48:27 +08:00
南宫临风 9ae010a391 改进自动下载数据排序
自动下载表格加入表头排序
2016-06-27 17:43:34 +08:00
南宫临风 13c105472e Update README.md 2016-06-27 10:23:39 +08:00
huanghongxun 88194e479e Update README.md 2016-06-07 23:00:07 +08:00
huangyuhui b36c194f67 Merge branch 'master' of https://github.com/huanghongxun/HMCL 2016-05-28 23:19:21 +08:00
huangyuhui 7c7b6e0fd9 Fixed #73 2016-05-28 23:17:49 +08:00
huanghongxun 01b77f1f5f Merge pull request #71 from Cat7373/master
Windows 启动脚本中允许跨分区 cd
2016-05-23 19:28:18 +08:00
Cat73 840a0ad840 Windows 启动脚本中允许跨分区 cd
修复跨分区的情况下一些文件如 logs 仍然生成在脚本所在目录,而不是 .minecraft 目录
2016-05-23 13:25:58 +08:00
huangyuhui ab1ca18488 Fixed NullPointerException when minecraftArguments=null 2016-05-23 13:09:30 +08:00
huangyuhui 75e0fa2def Fixed mainClass of macAppBundle 2016-05-16 18:10:30 +08:00
huangyuhui ca3ed47d21 Applied macosapp. Closes #63 2016-05-16 12:55:35 +08:00
huangyuhui 61a8ab5199 Supplements: 'SerializedName' 2016-05-14 20:24:42 +08:00
huangyuhui ce721c2e09 Reconstruct codes 2016-05-13 18:25:55 +08:00
huangyuhui 2862e3a6ee TWords in title bar can be dragged now 2016-05-11 13:42:46 +08:00
huangyuhui 75c4a24cbd Fixed #68 2016-05-10 13:24:06 +08:00
huanghongxun 1cf7d791cc Changes logo. Closes #67 2016-05-08 22:46:11 +08:00
huangyuhui 62fecc08ac Fixed #65 2016-05-08 10:04:23 +08:00
huangyuhui 491ca63342 Merge branch 'master' of https://github.com/huanghongxun/HMCL 2016-05-08 09:42:00 +08:00
huangyuhui b232a255e7 Fixed #66 2016-05-08 09:41:27 +08:00
huanghongxun 0870f42557 Merge pull request #64 from Cat7373/master
在 Windows 的启动脚本里增加一行 cd %appdata%
2016-05-03 19:12:59 +08:00
Cat73 85237eac7e 在 Windows 的启动脚本里增加一行 cd %appdata%
这样可以避免一些文件如 logs 生成在脚本所在目录,而不是 .minecraft 目录
2016-05-03 09:41:55 +08:00
849 changed files with 43213 additions and 69699 deletions

No files matched your search

Executable → Regular
+25 -16
View File
@@ -1,27 +1,36 @@
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
.gradle
.nb-gradle
*.bat
*.lck
*.1
*.2
*.log
.mine*
NVIDIA
*.json
*.hmd
HMCLAPI/build/
HMCL/build/
HMCLServer/
HMCSM/build/
MetroLookAndFeel/build/
# gradle build
/build/
/HMCL/build/
/HMCLCore/build/
# idea
.idea
/out/
/HMCL/out/
/HMCLCore/out/
# eclipse
/bin/
/HMCL/bin/
/HMCLCore/bin/
.classpath
.project
.settings
# netbeans
.nb-gradle
-27
View File
@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<gradle-project-properties>
<!--DO NOT EDIT THIS FILE! - Used by the Gradle plugin of NetBeans.-->
<target-platform-name>j2se</target-platform-name>
<target-platform>1.8</target-platform>
<source-level>1.8</source-level>
<common-tasks>
<task>
<display-name>launch4j</display-name>
<non-blocking>no</non-blocking>
<task-names>
<name must-exist="yes">launch4j</name>
</task-names>
<task-args/>
<task-jvm-args/>
</task>
</common-tasks>
<script-platform>
<spec-name>j2se</spec-name>
<spec-version>1.8</spec-version>
</script-platform>
<license-header>
<name>GNU General Public License</name>
<template>license-header.txt</template>
<property name="organization">huangyuhui</property>
</license-header>
</gradle-project-properties>
-32
View File
@@ -1,32 +0,0 @@
language: java
jdk:
- oraclejdk8
branches:
only:
- master
before_deploy:
- git config --global user.email ${GITHUB_EMAIL}
- git config --global user.name ${GITHUB_NAME}
- git tag ${TRAVIS_BUILD_NUMBER}
- git push -q ${REPO} --tags
deploy:
provider: releases
api_key:
secure: lfFEwKtij/s9Ao/SKL7oVdsWcfASshZuwT27gllMrTx1ZQqLCG2I5mGJOp5ukx7lb3y4Tu316nFasLjy9NI3eLXSx9f0w4q+wMf0K5Yj9iOwu/TIn7JkLyHDMQ20qRwGxZplS2WUb669gIRg+l6jUHeTBW+dlTxr0mMa6WHIl8UDpHwfFrGC3i6dL4y6WlDwGl2rYktvOoA/iqvtglBcHuXaL2sDfhp5MXRcYULTIw+b9zmiQXP665DQN+Su5I3gwB4y5X8RH72GAacZn13fEIo5i8UUoHM7UQxM8y8DKSO3avyFCfpUle9+9sErQVW7b6JV1c+AoLWuAhNJLMlUTKarZE7UMqfjvoQHxX5hp2B2WHLEON/UJiGf25HJWx6VhJitE0/odujqnG/umesqki2jMTs6gPcxbc9iBjzUg+ZmFztdtC+Emnni7lpqVVl+Y5hsJRn3Z6rIiNgwmaE0r2OQgAm1vRYFc7jvOdRfyFG+uCRZF6nS56BzJ7dLc0WW8dTgSft6YFll4ZYL6hiI9qiIaBAK948y5HV+6VBWuO3xf/G2CUFbE1Y9qUCjToh3ahxNDzZvXB+rXqvlvNQOi5l8n594oQ61n45qIHSKlMBn9Bxhw29oWT5mo1aYIaNXbpzKam2w4mK0T3VrgTszu/3282wRbNr+VAwdGMfwW1s=
file:
- HMCL/build/libs/HMCL-${HMCL_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}.jar
- HMCL/build/libs/HMCL-${HMCL_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}.exe
- HMCSM/build/libs/HMCSM-${HMCSM_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}.jar
- HMCSM/build/libs/HMCSM-${HMCSM_VERSION_ROOT}.${TRAVIS_BUILD_NUMBER}.exe
on:
repo: huanghongxun/HMCL
tags: false
skip_cleanup: true
install: echo "skip 'gradle assemble' step"
script: gradle build --continue
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
cache:
directories:
- "$HOME/.gradle/caches/"
- "$HOME/.gradle/wrapper/"
+14
View File
@@ -0,0 +1,14 @@
language: java
jdk:
- oraclejdk8
branches:
only:
- master
before_install:
- chmod +x gradlew
script: "bash ./gradlew clean build --stacktrace"
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
cache:
directories:
- "$HOME/.gradle/caches/"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.
Executable → Regular
+119 -105
View File
@@ -1,125 +1,139 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
plugins {
id 'com.github.johnrengelman.shadow' version '2.0.4'
}
import java.nio.file.FileSystems
import java.security.KeyFactory
import java.security.MessageDigest
import java.security.Signature
import java.security.spec.PKCS8EncodedKeySpec
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
import java.util.jar.Pack200
import java.util.zip.GZIPOutputStream
import java.util.zip.ZipFile
import java.nio.file.Files
apply plugin: 'launch4j'
apply plugin: 'me.tatarka.retrolambda'
import org.tukaani.xz.LZMA2Options
import org.tukaani.xz.XZOutputStream
if (!hasProperty('mainClass')) {
ext.mainClass = 'org.jackhuang.hellominecraft.launcher.Main'
}
def buildnumber = System.getenv("TRAVIS_BUILD_NUMBER")
if (buildnumber == null)
buildnumber = System.getenv("BUILD_NUMBER")
if (buildnumber == null)
buildnumber = "233"
def versionroot = System.getenv("VERSION_ROOT")
if (versionroot == null)
versionroot = "2.4.1"
String mavenGroupId = 'HMCL'
String mavenVersion = versionroot + '.' + buildnumber
String bundleName = "Hello Minecraft! Launcher"
group = mavenGroupId
version = mavenVersion
String mavenArtifactId = name
task generateSources(type: Copy) {
from 'src/main/java'
into "$buildDir/generated-src"
filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: [
'HELLO_MINECRAFT_LAUNCHER_VERSION_FOR_GRADLE_REPLACING': mavenVersion
])
}
compileJava.setSource "$buildDir/generated-src"
compileJava.dependsOn generateSources
buildscript {
repositories {
mavenCentral();
maven {
url "https://libraries.minecraft.net"
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:4.10'
classpath 'edu.sc.seis.gradle:launch4j:1.0.6'
classpath 'me.tatarka:gradle-retrolambda:3.1.0'
}
}
}
configure(install.repositories.mavenInstaller) {
pom.project {
groupId = mavenGroupId
artifactId = mavenArtifactId
version = mavenVersion
}
}
def buildnumber = System.getenv("BUILD_NUMBER") ?: "SNAPSHOT"
if (System.getenv("BUILD_NUMBER") != null && System.getenv("BUILD_NUMBER_OFFSET") != null)
buildnumber = (Integer.parseInt(System.getenv("BUILD_NUMBER")) - Integer.parseInt(System.getenv("BUILD_NUMBER_OFFSET"))).toString()
def versionroot = System.getenv("VERSION_ROOT") ?: "3.2"
version = versionroot + '.' + buildnumber
dependencies {
compile project(":MetroLookAndFeel")
compile project(":HMCLAPI")
compile group: "org.commonjava.googlecode.markdown4j", name: "markdown4j", version: "2.2-cj-1.0"
compile project(":HMCLCore")
compile rootProject.files("lib/JFoenix.jar")
}
retrolambda {
javaVersion = JavaVersion.VERSION_1_6
def digest(String algorithm, byte[] bytes) {
return MessageDigest.getInstance(algorithm).digest(bytes)
}
def createChecksum(File file) {
def algorithm = "SHA-1"
def suffix = "sha1"
new File(file.parentFile, file.name + "." + suffix).text = digest(algorithm, file.bytes).encodeHex().toString() + "\n"
}
def attachSignature(File jar) {
def keyLocation = System.getenv("HMCL_SIGNATURE_KEY");
if (keyLocation == null)
return
def privatekey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(new File(keyLocation).bytes))
def signer = Signature.getInstance("SHA512withRSA")
signer.initSign(privatekey)
new ZipFile(jar).withCloseable { zip ->
zip.stream()
.sorted(Comparator.comparing { it.name })
.filter { it.name != "META-INF/hmcl_signature" }
.forEach {
signer.update(digest("SHA-512", it.name.getBytes("UTF-8")))
signer.update(digest("SHA-512", zip.getInputStream(it).bytes))
}
}
def signature = signer.sign()
FileSystems.newFileSystem(URI.create("jar:" + jar.toURI()), [:]).withCloseable { zipfs ->
Files.newOutputStream(zipfs.getPath("META-INF/hmcl_signature")).withCloseable { it << signature }
}
}
ext.packer = Pack200.newPacker()
packer.properties()["pack.effort"] = "9"
ext.unpacker = Pack200.newUnpacker()
def repack(File file) {
def packed = new ByteArrayOutputStream()
new JarFile(file).withCloseable { packer.pack(it, packed) }
new JarOutputStream(file.newOutputStream()).withCloseable { unpacker.unpack(new ByteArrayInputStream(packed.toByteArray()), it) }
}
jar {
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
manifest {
attributes 'Created-By' : 'Copyright(c) 2013-2016 huangyuhui.',
'Main-Class' : mainClass
attributes 'Created-By': 'Copyright(c) 2013-2018 huangyuhui.',
'Main-Class': 'org.jackhuang.hmcl.Main',
'Multi-Release': 'true',
'Implementation-Version': version
}
finalizedBy shadowJar
}
shadowJar {
classifier = null
exclude 'META-INF/maven/**'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/LICENSE.txt'
dependencies {
exclude(dependency('org.jetbrains:annotations'))
}
doLast {
repack(jar.archivePath)
attachSignature(jar.archivePath)
createChecksum(jar.archivePath)
}
}
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'
mainClassName = mainClass
icon = new File(project.buildDir, '../icon.ico').absolutePath
version = mavenVersion
downloadUrl = 'http://java.com/download'
copyright = "Copyright(c) 2013-2015 huangyuhui."
jar = new File(project.buildDir, 'libs/' + mavenGroupId + '-' + mavenVersion + '.jar').absolutePath
outfile = mavenGroupId + '-' + mavenVersion + '.exe'
messagesJreVersionError = 'This application requires a Java Runtime Environment installation, or the runtime is corrupted.\n\u6ca1\u6709\u627e\u5230\u004a\u0061\u0076\u0061\u8fd0\u884c\u65f6\uff0c\u8bf7\u4e0d\u8981\u4f7f\u7528\u7eff\u8272\u004a\u0061\u0076\u0061\uff0c\u8bf7\u4f7f\u7528\u5b89\u88c5\u7248\u7684\u004a\u0061\u0076\u0061\uff0c\u70b9\u51fb\u786e\u5b9a\u8fdb\u5165\u004a\u0061\u0076\u0061\u5b89\u88c5\u9875\u9762\u3002'
def createExecutable(String suffix, String header) {
def output = new File(jar.archivePath.parentFile, jar.archivePath.name[0..-4] + suffix)
output.bytes = new File(project.projectDir, header).bytes
output << jar.archivePath.bytes
createChecksum(output)
}
processResources {
from(sourceSets.main.resources.srcDirs) {
exclude 'icon.icns'
task makePack(dependsOn: jar) {
ext.outputPath = new File(jar.archivePath.parentFile, jar.archivePath.name[0..-4] + "pack")
doLast {
outputPath.newOutputStream().withCloseable { out ->
new JarFile(jar.archivePath).withCloseable { jarFile -> packer.pack(jarFile, out) }
}
createChecksum(outputPath)
}
}
build.dependsOn makeExecutable
build.dependsOn makePackGZ
task makePackXz(dependsOn: makePack) doLast {
def packXz = new File(makePack.outputPath.parentFile, makePack.outputPath.name + ".xz")
new XZOutputStream(packXz.newOutputStream(), new LZMA2Options(6)).withCloseable { it << makePack.outputPath.bytes }
createChecksum(packXz)
}
task makePackGz(dependsOn: makePack) doLast {
def packGz = new File(makePack.outputPath.parentFile, makePack.outputPath.name + ".gz")
new GZIPOutputStream(packGz.newOutputStream()).withCloseable { it << makePack.outputPath.bytes }
createChecksum(packGz)
}
task makeExecutables(dependsOn: jar) doLast {
createExecutable("exe", "src/main/resources/assets/HMCLauncher.exe")
}
build.dependsOn makePackXz
build.dependsOn makePackGz
build.dependsOn makeExecutables
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

-81
View File
@@ -1,81 +0,0 @@
-libraryjars <java.home>/lib/rt.jar
-libraryjars <java.home>/lib/jce.jar
-libraryjars <java.home>/lib/jsse.jar
-dontoptimize
-dontshrink
-dontwarn java.lang.invoke.*
-overloadaggressively
-repackageclasses 'org.jackhuang.hellominecraft.launcher'
-allowaccessmodification
-renamesourcefileattribute SourceFile
-keepattributes *Annotation*,SourceFile,LineNumberTable,Signature
-keep class com.** { *; }
-keep class org.jackhuang.hellominecraft.lookandfeel.* { *; }
-keep class org.jackhuang.hellominecraft.lookandfeel.painters.* { *; }
-keep class org.jackhuang.hellominecraft.lookandfeel.ui.* { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.Agent { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.UserType { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.properties.Property { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.minecraft.MinecraftProfileTexture$Type { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.minecraft.MinecraftProfileTexture { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.request.AuthenticationRequest { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.request.InvalidateRequest { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.request.JoinMinecraftServerRequest { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.request.RefreshRequest { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.response.AuthenticationResponse { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.response.HasJoinedMinecraftServerResponse { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.response.ProfileSearchResultsResponse { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.response.RefreshResponse { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.response.Response { *; }
-keepclassmembers class org.jackhuang.mojang.authlib.yggdrasil.response.User { *; }
-keep class org.jackhuang.hellominecraft.launcher.Main { public static void main(java.lang.String[]); }
-keep class org.jackhuang.hellominecraft.launcher.Launcher { public static void main(java.lang.String[]); }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.settings.Profile { private <fields>; public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.settings.Config { private <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.version.MinecraftLibrary { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.version.IMinecraftLibrary { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.version.Natives { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.version.OS { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.version.Rules { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.version.MinecraftVersion { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.assets.AssetsObject { <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.assets.AssetsIndex { <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.ModInfo { <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.forge.InstallProfile { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.forge.Install { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.forge.vanilla.MinecraftForgeVersionRoot { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.forge.vanilla.MinecraftForgeVersion { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.forge.bmcl.ForgeVersion { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.forge.bmcl.Downloads { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.optifine.OptiFineVersion { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.liteloader.LiteLoaderVersionsRoot { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.liteloader.LiteLoaderMCVersions { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.liteloader.LiteLoaderVersion { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.launcher.utils.installers.liteloader.LiteLoaderVersionsMeta { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.utils.system.JdkVersion { private <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.version.MinecraftRemoteLatestVersion { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.version.MinecraftRemoteVersion { public <fields>; }
-keepclassmembers class org.jackhuang.hellominecraft.version.MinecraftRemoteVersions { public <fields>; }
+2
View File
@@ -0,0 +1,2 @@
rootProject.name = 'HMCL'
Binary file not shown.
@@ -1,201 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.api.PluginManager;
import org.jackhuang.hellominecraft.launcher.core.launch.GameLauncher;
import org.jackhuang.hellominecraft.launcher.util.CrashReporter;
import org.jackhuang.hellominecraft.util.logging.Configuration;
import org.jackhuang.hellominecraft.util.logging.appender.ConsoleAppender;
import org.jackhuang.hellominecraft.util.logging.layout.DefaultLayout;
import org.jackhuang.hellominecraft.util.ui.LogWindow;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
import org.jackhuang.hellominecraft.launcher.util.upgrade.IUpgrader;
import org.jackhuang.hellominecraft.launcher.ui.MainFrame;
import org.jackhuang.hellominecraft.lookandfeel.HelloMinecraftLookAndFeel;
import org.jackhuang.hellominecraft.util.MathUtils;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.lang.SupportedLocales;
import org.jackhuang.hellominecraft.util.VersionNumber;
/**
*
* @author huangyuhui
*/
public final class Main implements Runnable {
private static final X509TrustManager XTM = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
private static final HostnameVerifier HNV = (hostname, session) -> true;
static {
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
X509TrustManager[] xtmArray = new X509TrustManager[] { XTM };
sslContext.init(null, xtmArray, new java.security.SecureRandom());
} catch (GeneralSecurityException gse) {
}
if (sslContext != null)
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(HNV);
}
public static final String LAUNCHER_NAME = "Hello Minecraft! Launcher";
public static final String LAUNCHER_VERSION = "@HELLO_MINECRAFT_LAUNCHER_VERSION_FOR_GRADLE_REPLACING@";
public static final int MINIMUM_LAUNCHER_VERSION = 16;
public static VersionNumber getVersionNumber() {
return VersionNumber.check(LAUNCHER_VERSION);
}
/**
* Make the main window title.
*
* @return the MainWindow title.
*/
public static String makeTitle() {
return LAUNCHER_NAME + ' ' + LAUNCHER_VERSION;
}
public static String shortTitle() {
return "HMCL" + ' ' + LAUNCHER_VERSION;
}
public static final Main INSTANCE = new Main();
private static HelloMinecraftLookAndFeel LOOK_AND_FEEL;
private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
@SuppressWarnings({ "CallToPrintStackTrace", "UseSpecificCatch" })
public static void main(String[] args) throws IOException {
{
//PluginManager.getServerPlugin();
if (IUpgrader.NOW_UPGRADER.parseArguments(getVersionNumber(), args))
return;
System.setProperty("awt.useSystemAAFontSettings", "on");
System.setProperty("swing.aatext", "true");
System.setProperty("sun.java2d.noddraw", "true");
System.setProperty("sun.java2d.dpiaware", "false");
Thread.setDefaultUncaughtExceptionHandler(new CrashReporter(true));
try {
File file = new File("hmcl.log");
if (!file.exists() && !file.createNewFile())
HMCLog.warn("Failed to create log file " + file);
Configuration.DEFAULT.appenders.add(new ConsoleAppender("File", new DefaultLayout(), true, new FileOutputStream(file), true));
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Failed to add log appender File because an error occurred while creating or opening hmcl.log", ex);
}
HMCLog.log("*** " + Main.makeTitle() + " ***");
String s = Settings.getInstance().getLocalization();
for (SupportedLocales sl : SupportedLocales.values())
if (sl.name().equals(s)) {
SupportedLocales.NOW_LOCALE = sl;
Locale.setDefault(sl.self);
}
LogWindow.INSTANCE.clean();
LogWindow.INSTANCE.setTerminateGame(GameLauncher.PROCESS_MANAGER::stopAllProcesses);
try {
LOOK_AND_FEEL = new HelloMinecraftLookAndFeel(Settings.getInstance().getTheme().settings);
UIManager.setLookAndFeel(LOOK_AND_FEEL);
} catch (ParseException | UnsupportedLookAndFeelException ex) {
HMCLog.warn("Failed to set look and feel...", ex);
}
Settings.UPDATE_CHECKER.outdated.register(IUpgrader.NOW_UPGRADER);
Settings.UPDATE_CHECKER.process(false).reg(t -> Main.invokeUpdate()).execute();
if (StrUtils.isNotBlank(Settings.getInstance().getProxyHost()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPort()) && MathUtils.canParseInt(Settings.getInstance().getProxyPort())) {
HMCLog.log("Initializing customized proxy");
System.setProperty("http.proxyHost", Settings.getInstance().getProxyHost());
System.setProperty("http.proxyPort", Settings.getInstance().getProxyPort());
if (StrUtils.isNotBlank(Settings.getInstance().getProxyUserName()) && StrUtils.isNotBlank(Settings.getInstance().getProxyPassword()))
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(Settings.getInstance().getProxyUserName(), Settings.getInstance().getProxyPassword().toCharArray());
}
});
}
try {
PluginManager.plugin().showUI();
} catch (Throwable t) {
new CrashReporter(false).uncaughtException(Thread.currentThread(), t);
System.exit(1);
}
}
}
@Override
public void run() {
GameLauncher.PROCESS_MANAGER.stopAllProcesses();
}
public static void invokeUpdate() {
MainFrame.INSTANCE.invokeUpdate();
}
public static ImageIcon getIcon(String path) {
try {
return new ImageIcon(Main.class.getResource("/org/jackhuang/hellominecraft/launcher/" + path));
} catch (Exception e) {
HMCLog.err("Failed to load icon", e);
return null;
}
}
}
@@ -1,65 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.api;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.launcher.setting.Profile;
import org.jackhuang.hellominecraft.launcher.core.auth.AuthenticationException;
import org.jackhuang.hellominecraft.launcher.core.auth.IAuthenticator;
import org.jackhuang.hellominecraft.launcher.core.auth.UserProfileProvider;
import org.jackhuang.hellominecraft.launcher.core.launch.LaunchOptions;
import org.jackhuang.hellominecraft.util.func.Consumer;
/**
*
* @author huangyuhui
*/
public interface IPlugin {
/**
* You can modify the application actions by this method.
*
* @param profile info to the Minecraft Loader
*
* @return For example, you can implement IMinecraftProvider to support
* MultiMC
*/
IMinecraftService provideMinecraftService(Profile profile);
/**
* Register authenticators by calling IAuthenticator.LOGINS.add.
*
* @param apply call apply.accept(your authenticator)
*/
void onRegisterAuthenticators(Consumer<IAuthenticator> apply);
/**
* Open your customized UI.
*/
void showUI();
/**
* Add your server ip or modify the access token.
*
* @param result What you want.
*/
void onProcessingLoginResult(UserProfileProvider result) throws AuthenticationException;
void onProcessingLaunchOptions(LaunchOptions p) throws GameException;
}
@@ -1,47 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.api;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.util.DefaultPlugin;
/**
*
* @author huangyuhui
*/
public class PluginManager {
private static IPlugin NOW_PLUGIN = new DefaultPlugin();
public static void getServerPlugin() {
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class c = cl.loadClass("org.jackhuang.hellominecraft.launcher.server.ServerPlugin");
IPlugin p = (IPlugin) c.newInstance();
NOW_PLUGIN = p;
} catch (ClassNotFoundException ignore) {
} catch (Exception e) {
HMCLog.err("Failed to new instance");
}
}
public static IPlugin plugin() {
return NOW_PLUGIN;
}
}
@@ -1,85 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core;
import java.io.File;
import java.io.IOException;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.system.OS;
/**
*
* @author huang
*/
public final class MCUtils {
public static File getWorkingDirectory(String baseName) {
String userhome = System.getProperty("user.home", ".");
File file;
switch (OS.os()) {
case LINUX:
file = new File(userhome, '.' + baseName + '/');
break;
case WINDOWS:
String appdata = System.getenv("APPDATA");
if (appdata != null)
file = new File(appdata, "." + baseName + '/');
else
file = new File(userhome, '.' + baseName + '/');
break;
case OSX:
file = new File(userhome, "Library/Application Support/" + baseName);
break;
default:
file = new File(userhome, baseName + '/');
}
return file;
}
public static File getLocation() {
return getWorkingDirectory("minecraft");
}
public static String minecraft() {
if (OS.os() == OS.OSX)
return "minecraft";
return ".minecraft";
}
public static File getInitGameDir() {
File gameDir = IOUtils.currentDir();
if (gameDir.exists()) {
gameDir = new File(gameDir, MCUtils.minecraft());
if (!gameDir.exists()) {
File newFile = MCUtils.getLocation();
if (newFile.exists())
gameDir = newFile;
}
}
return gameDir;
}
public static final String PROFILE = "{\"selectedProfile\": \"(Default)\",\"profiles\": {\"(Default)\": {\"name\": \"(Default)\"}},\"clientToken\": \"88888888-8888-8888-8888-888888888888\"}";
public static void tryWriteProfile(File gameDir) throws IOException {
File file = new File(gameDir, "launcher_profiles.json");
if (!file.exists())
FileUtils.writeStringToFile(file, PROFILE);
}
}
@@ -1,111 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.asset;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftAssetService;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.launcher.core.download.IDownloadProvider;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.Utils;
import org.jackhuang.hellominecraft.util.VersionNumber;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
/**
*
* @author huangyuhui
*/
public class AssetsMojangLoader extends IAssetsHandler {
public AssetsMojangLoader(String name) {
super(name);
}
@Override
public Task getList(final MinecraftVersion mv, final IMinecraftAssetService mp) {
Utils.requireNonNull(mv);
String assetsId = mv.getAssetsIndex().getId();
File assets = mp.getAssets();
HMCLog.log("Gathering asset index: " + assetsId);
File f = IOUtils.tryGetCanonicalFile(new File(assets, "indexes/" + assetsId + ".json"));
return new TaskInfo("Gather asset index") {
@Override
public Collection<Task> getDependTasks() {
if (!f.exists())
return Arrays.asList(mp.downloadMinecraftAssetsIndex(mv.getAssetsIndex()));
else
return null;
}
@Override
public void executeTask() throws Throwable {
if (!areDependTasksSucceeded)
throw new IllegalStateException("Failed to get asset index");
String result = FileUtils.readFileToString(f);
if (StrUtils.isBlank(result))
throw new IllegalStateException("Index json is empty, please redownload it!");
AssetsIndex o = C.GSON.fromJson(result, AssetsIndex.class);
assetsDownloadURLs = new ArrayList<>();
assetsLocalNames = new ArrayList<>();
ArrayList<String> al = new ArrayList<>();
contents = new ArrayList<>();
HashSet<String> loadedHashes = new HashSet<>();
int pgs = 0;
if (o != null && o.getFileMap() != null)
for (Map.Entry<String, AssetsObject> e : o.getFileMap().entrySet()) {
if (loadedHashes.contains(e.getValue().getHash()))
continue;
loadedHashes.add(e.getValue().getHash());
Contents c = new Contents();
c.eTag = e.getValue().getHash();
c.key = c.eTag.substring(0, 2) + "/" + e.getValue().getHash();
c.size = e.getValue().getSize();
contents.add(c);
assetsDownloadURLs.add(c.key);
assetsLocalNames.add(new File(assets, "objects" + File.separator + c.key.replace("/", File.separator)));
al.add(e.getKey());
if (ppl != null)
ppl.setProgress(this, ++pgs, o.getFileMap().size());
}
}
};
}
@Override
public Task getDownloadTask(IDownloadProvider sourceType) {
return new AssetsTask(sourceType.getAssetsDownloadURL());
}
@Override
public boolean isVersionAllowed(String formattedVersion) {
VersionNumber ur = VersionNumber.check(formattedVersion);
if (ur == null)
return false;
return VersionNumber.check("1.6.0").compareTo(ur) <= 0;
}
}
@@ -1,71 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.asset;
/**
*
* @author huangyuhui
*/
public class AssetsObject {
private String hash;
private long size;
public AssetsObject(String hash, long size) {
this.hash = hash;
this.size = size;
}
public void setHash(String hash) {
this.hash = hash;
}
public void setSize(long size) {
this.size = size;
}
public AssetsObject() {
}
public String getHash() {
return this.hash;
}
public long getSize() {
return this.size;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
AssetsObject that = (AssetsObject) o;
if (this.size != that.size)
return false;
return this.hash.equals(that.hash);
}
@Override
public int hashCode() {
int result = this.hash.hashCode();
result = 31 * result + (int) (this.size ^ this.size >>> 32);
return result;
}
}
@@ -1,81 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.asset;
/**
*
* @author huangyuhui
*/
public class Contents {
public String key, eTag, lastModified, storageClass;
public Contents() {
}
public Contents(String key, String eTag, String lastModified, String storageClass, long size) {
this();
this.key = key;
this.eTag = eTag;
this.lastModified = lastModified;
this.storageClass = storageClass;
this.size = size;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String geteTag() {
return eTag;
}
public void seteTag(String eTag) {
this.eTag = eTag;
}
public String getLastModified() {
return lastModified;
}
public void setLastModified(String lastModified) {
this.lastModified = lastModified;
}
public String getStorageClass() {
return storageClass;
}
public void setStorageClass(String storageClass) {
this.storageClass = storageClass;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public long size;
}
@@ -1,143 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.asset;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftAssetService;
import org.jackhuang.hellominecraft.launcher.core.download.IDownloadProvider;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.download.FileDownloadTask;
import org.jackhuang.hellominecraft.util.code.DigestUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.NetUtils;
import org.jackhuang.hellominecraft.util.OverridableSwingWorker;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
/**
* Assets
*
* @author huangyuhui
*/
public abstract class IAssetsHandler {
protected ArrayList<String> assetsDownloadURLs;
protected ArrayList<File> assetsLocalNames;
protected final String name;
protected List<Contents> contents;
public IAssetsHandler(String name) {
this.name = name;
}
public static final IAssetsHandler ASSETS_HANDLER;
static {
ASSETS_HANDLER = new AssetsMojangLoader(C.i18n("assets.list.1_7_3_after"));
}
/**
* interface name
*
* @return
*/
public String getName() {
return name;
}
/**
* All the files assets needed
*
* @param mv The version that needs assets
* @param mp Asset Service
* @param x finished event
*/
public abstract Task getList(MinecraftVersion mv, IMinecraftAssetService mp);
/**
* Will be invoked when the user invoked "Download all assets".
*
* @param sourceType Download Source
*
* @return Download File Task
*/
public abstract Task getDownloadTask(IDownloadProvider sourceType);
public abstract boolean isVersionAllowed(String formattedVersion);
protected class AssetsTask extends TaskInfo {
ArrayList<Task> al;
String u;
public AssetsTask(String url) {
super(C.i18n("assets.download"));
this.u = url;
}
@Override
public void executeTask() {
if (assetsDownloadURLs == null || assetsLocalNames == null || contents == null)
throw new IllegalStateException(C.i18n("assets.not_refreshed"));
int max = assetsDownloadURLs.size();
al = new ArrayList<>();
int hasDownloaded = 0;
for (int i = 0; i < max; i++) {
String mark = assetsDownloadURLs.get(i);
String url = u + mark;
File location = assetsLocalNames.get(i);
if (!location.getParentFile().exists() && !location.getParentFile().mkdirs())
HMCLog.warn("Failed to make directories: " + location.getParent());
if (location.isDirectory())
continue;
boolean need = true;
try {
if (location.exists()) {
FileInputStream fis = new FileInputStream(location);
String sha = DigestUtils.sha1Hex(NetUtils.getBytesFromStream(fis));
IOUtils.closeQuietly(fis);
if (contents.get(i).geteTag().equals(sha)) {
++hasDownloaded;
HMCLog.log("File " + assetsLocalNames.get(i) + " has been downloaded successfully, skipped downloading.");
if (ppl != null)
ppl.setProgress(this, hasDownloaded, max);
continue;
}
}
} catch (IOException e) {
HMCLog.warn("Failed to get hash: " + location, e);
need = !location.exists();
}
if (need)
al.add(new FileDownloadTask(url, location).setTag(mark));
}
}
@Override
public Collection<Task> getAfterTasks() {
return al;
}
}
}
@@ -1,218 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.asset;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftAssetService;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.launcher.core.version.AssetIndexDownloadInfo;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.func.BiFunction;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.TaskWindow;
import org.jackhuang.hellominecraft.util.tasks.download.FileDownloadTask;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
/**
*
* @author huangyuhui
*/
public class MinecraftAssetService extends IMinecraftAssetService {
public MinecraftAssetService(IMinecraftService service) {
super(service);
}
@Override
public Task downloadAssets(final String mcVersion) {
return downloadAssets(service.version().getVersionById(mcVersion));
}
public Task downloadAssets(final MinecraftVersion mv) {
if (mv == null)
return null;
return IAssetsHandler.ASSETS_HANDLER.getList(mv, service.asset()).after(IAssetsHandler.ASSETS_HANDLER.getDownloadTask(service.getDownloadType().getProvider()));
}
@Override
public boolean refreshAssetsIndex(String id) {
MinecraftVersion mv = service.version().getVersionById(id);
if (mv == null)
return false;
return downloadMinecraftAssetsIndexAsync(mv.getAssetsIndex());
}
@Override
public Task downloadMinecraftAssetsIndex(AssetIndexDownloadInfo assets) {
File assetsLocation = getAssets();
if (!assetsLocation.exists() && !assetsLocation.mkdirs())
HMCLog.warn("Failed to make directories: " + assetsLocation);
File assetsIndex = new File(assetsLocation, "indexes/" + assets.getId() + ".json");
File renamed = null;
if (assetsIndex.exists()) {
renamed = new File(assetsLocation, "indexes/" + assets.getId() + "-renamed.json");
if (assetsIndex.renameTo(renamed))
HMCLog.warn("Failed to rename " + assetsIndex + " to " + renamed);
}
File renamedFinal = renamed;
return new TaskInfo("Download Asset Index") {
@Override
public Collection<Task> getDependTasks() {
return Arrays.asList(new FileDownloadTask(assets.getUrl(service.getDownloadType()), IOUtils.tryGetCanonicalFile(assetsIndex), assets.sha1).setTag(assets.getId() + ".json"));
}
@Override
public void executeTask() throws Throwable {
if (areDependTasksSucceeded) {
if (renamedFinal != null && !renamedFinal.delete())
HMCLog.warn("Failed to delete " + renamedFinal + ", maybe you should do it.");
} else if (renamedFinal != null && !renamedFinal.renameTo(assetsIndex))
HMCLog.warn("Failed to rename " + renamedFinal + " to " + assetsIndex);
}
};
}
@Override
public boolean downloadMinecraftAssetsIndexAsync(AssetIndexDownloadInfo assets) {
File assetsLocation = getAssets();
if (!assetsLocation.exists() && !assetsLocation.mkdirs())
HMCLog.warn("Failed to make directories: " + assetsLocation);
File assetsIndex = new File(assetsLocation, "indexes/" + assets.getId() + ".json");
File renamed = null;
if (assetsIndex.exists()) {
renamed = new File(assetsLocation, "indexes/" + assets.getId() + "-renamed.json");
if (assetsIndex.renameTo(renamed))
HMCLog.warn("Failed to rename " + assetsIndex + " to " + renamed);
}
if (TaskWindow.factory()
.append(new FileDownloadTask(assets.getUrl(service.getDownloadType()), IOUtils.tryGetCanonicalFile(assetsIndex), assets.sha1).setTag(assets.getId() + ".json"))
.create()) {
if (renamed != null && !renamed.delete())
HMCLog.warn("Failed to delete " + renamed + ", maybe you should do it.");
return true;
}
if (renamed != null && !renamed.renameTo(assetsIndex))
HMCLog.warn("Failed to rename " + renamed + " to " + assetsIndex);
return false;
}
@Override
public File getAssets() {
return new File(service.baseDirectory(), "assets");
}
@Override
public File getAssetObject(String assetVersion, String name) throws IOException {
File assetsDir = getAssets();
File indexDir = new File(assetsDir, "indexes");
File objectsDir = new File(assetsDir, "objects");
File indexFile = new File(indexDir, assetVersion + ".json");
try {
AssetsIndex index = (AssetsIndex) C.GSON.fromJson(FileUtils.readFileToString(indexFile, "UTF-8"), AssetsIndex.class);
String hash = ((AssetsObject) index.getFileMap().get(name)).getHash();
return new File(objectsDir, hash.substring(0, 2) + "/" + hash);
} catch (JsonSyntaxException e) {
throw new IOException("Assets file format malformed.", e);
}
}
private boolean checkAssetsExistance(AssetIndexDownloadInfo assetIndex) {
File assetsDir = getAssets();
File indexDir = new File(assetsDir, "indexes");
File objectDir = new File(assetsDir, "objects");
File indexFile = new File(indexDir, assetIndex.getId() + ".json");
if (!assetsDir.exists() || !indexFile.isFile())
return false;
try {
String assetIndexContent = FileUtils.readFileToString(indexFile, "UTF-8");
AssetsIndex index = (AssetsIndex) C.GSON.fromJson(assetIndexContent, AssetsIndex.class);
if (index == null)
return false;
for (Map.Entry entry : index.getFileMap().entrySet())
if (!new File(new File(objectDir, ((AssetsObject) entry.getValue()).getHash().substring(0, 2)), ((AssetsObject) entry.getValue()).getHash()).exists())
return false;
return true;
} catch (IOException | JsonSyntaxException e) {
return false;
}
}
private File reconstructAssets(AssetIndexDownloadInfo assetIndex) {
File assetsDir = getAssets();
File indexDir = new File(assetsDir, "indexes");
File objectDir = new File(assetsDir, "objects");
String assetVersion = assetIndex.getId();
File indexFile = new File(indexDir, assetVersion + ".json");
File virtualRoot = new File(new File(assetsDir, "virtual"), assetVersion);
if (!indexFile.isFile()) {
HMCLog.warn("No assets index file " + virtualRoot + "; can't reconstruct assets");
return assetsDir;
}
try {
String assetIndexContent = FileUtils.readFileToString(indexFile, "UTF-8");
AssetsIndex index = (AssetsIndex) C.GSON.fromJson(assetIndexContent, AssetsIndex.class);
if (index == null)
return assetsDir;
if (index.isVirtual()) {
int cnt = 0;
HMCLog.log("Reconstructing virtual assets folder at " + virtualRoot);
int tot = index.getFileMap().entrySet().size();
for (Map.Entry entry : index.getFileMap().entrySet()) {
File target = new File(virtualRoot, (String) entry.getKey());
File original = new File(new File(objectDir, ((AssetsObject) entry.getValue()).getHash().substring(0, 2)), ((AssetsObject) entry.getValue()).getHash());
if (original.exists()) {
cnt++;
if (!target.isFile())
FileUtils.copyFile(original, target, false);
}
}
// If the scale new format existent file is lower then 0.1, use the old format.
if (cnt * 10 < tot)
return assetsDir;
}
} catch (IOException | JsonSyntaxException e) {
HMCLog.warn("Failed to create virutal assets.", e);
}
return virtualRoot;
}
public final BiFunction<MinecraftVersion, Boolean, String> ASSET_PROVIDER_IMPL = (t, allow) -> {
if (allow && !checkAssetsExistance(t.getAssetsIndex()))
if (MessageBox.Show(C.i18n("assets.no_assets"), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
TaskWindow.execute(downloadAssets(t));
return reconstructAssets(t.getAssetsIndex()).getAbsolutePath();
};
}
@@ -1,106 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;
import org.jackhuang.hellominecraft.util.code.DigestUtils;
/**
*
* @author huangyuhui
*/
public final class BestLogin extends IAuthenticator {
public BestLogin(String clientToken) {
super(clientToken);
}
@Override
public UserProfileProvider login(LoginInfo info) throws AuthenticationException {
try {
String request = "bl:l:" + info.username + ":" + DigestUtils.sha1Hex(info.password);
Socket socket = new Socket("auth.zhh0000zhh.com", 8);
OutputStream os = socket.getOutputStream();
os.write(request.length());
os.write(request.getBytes(Charset.forName("UTF-8")));
UserProfileProvider lr = new UserProfileProvider();
InputStream is = socket.getInputStream();
int code = is.read();
switch (code) {
case -1:
throw new AuthenticationException("internet error.");
case 200:
throw new AuthenticationException("server restarting.");
case 255:
throw new AuthenticationException("unknown error");
case 3:
throw new AuthenticationException("unregistered.");
case 50:
throw new AuthenticationException("please update your launcher and act your account.");
case 2:
throw new AuthenticationException("wrong password.");
case 100:
throw new AuthenticationException("server reloading.");
case 0:
byte[] b = new byte[64];
int x = is.read(b, 0, b.length);
if (x != -1)
throw new AuthenticationException("server response does not follow the protocol.");
String[] ss = new String(b, Charset.forName("UTF-8")).split(":");
lr.setUserName(info.username);
lr.setUserId(ss[1]);
lr.setSession(ss[0]);
lr.setAccessToken(ss[0]);
break;
default:
break;
}
lr.setUserType("Legacy");
return lr;
} catch (IOException t) {
throw new AuthenticationException(t);
}
}
@Override
public String id() {
return "best";
}
@Override
public String getName() {
return "BestLogin";
}
@Override
public UserProfileProvider loginBySettings() {
return null;
}
@Override
public void logOut() {
}
}
@@ -1,118 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jackhuang.hellominecraft.launcher.api.PluginManager;
/**
* Login interface
*
* @author huangyuhui
*/
public abstract class IAuthenticator {
public static final List<IAuthenticator> LOGINS = new ArrayList<>();
static {
PluginManager.plugin().onRegisterAuthenticators(LOGINS::add);
}
protected String clientToken, username, password;
public IAuthenticator(String clientToken) {
this.clientToken = clientToken;
}
public String getClientToken() {
return clientToken;
}
/**
* Login Method
*
* @param info username & password
*
* @return login result
*
* @throws
* org.jackhuang.hellominecraft.launcher.core.auth.AuthenticationException
*/
public abstract UserProfileProvider login(LoginInfo info) throws AuthenticationException;
public abstract String id();
/**
*
* @return the name of login method.
*/
public abstract String getName();
/**
* Has password?
*
* @return has password?
*/
public boolean hasPassword() {
return true;
}
public boolean isLoggedIn() {
return false;
}
public void setRememberMe(boolean is) {
}
public abstract UserProfileProvider loginBySettings() throws AuthenticationException;
public abstract void logOut();
public Map onSaveSettings() {
HashMap<String, String> m = new HashMap<>();
m.put("IAuthenticator_UserName", username);
return m;
}
public void onLoadSettings(Map m) {
if (m == null)
return;
Object o = m.get("IAuthenticator_UserName");
username = o instanceof String ? (String) o : "";
}
public String getUserName() {
return username;
}
public void setUserName(String s) {
username = s;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
@@ -1,104 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth;
import java.util.HashMap;
import java.util.Map;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.code.DigestUtils;
/**
*
* @author huangyuhui
*/
public final class OfflineAuthenticator extends IAuthenticator {
Map<String, String> uuidMap = new HashMap<>();
public OfflineAuthenticator(String clientToken) {
super(clientToken);
}
@Override
public void onLoadSettings(Map m) {
super.onLoadSettings(m);
if (m == null)
return;
Object o = m.get("uuidMap");
if (o != null && o instanceof Map)
uuidMap = (Map<String, String>) o;
}
@Override
public Map onSaveSettings() {
Map m = super.onSaveSettings();
m.put("uuidMap", uuidMap);
return m;
}
@Override
public UserProfileProvider login(LoginInfo info) throws AuthenticationException {
if (StrUtils.isBlank(info.username))
throw new AuthenticationException(C.i18n("login.no_Player007"));
UserProfileProvider result = new UserProfileProvider();
result.setUserName(info.username);
String uuid = getUUIDFromUserName(info.username);
if (uuidMap != null && uuidMap.containsKey(uuid))
uuid = uuidMap.get(info.username);
else {
if (uuidMap == null)
uuidMap = new HashMap<>();
uuidMap.put(info.username, uuid);
}
result.setSession(uuid);
result.setUserId(uuid);
result.setAccessToken(uuid);
result.setUserType("Legacy");
return result;
}
public static String getUUIDFromUserName(String str) {
return DigestUtils.md5Hex(str);
}
@Override
public String id() {
return "offline";
}
@Override
public String getName() {
return C.i18n("login.methods.offline");
}
@Override
public boolean hasPassword() {
return false;
}
@Override
public UserProfileProvider loginBySettings() {
return null;
}
@Override
public void logOut() {
}
}
@@ -1,123 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.code.DigestUtils;
import org.jackhuang.hellominecraft.util.NetUtils;
import org.jackhuang.hellominecraft.util.lang.SupportedLocales;
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public final class SkinmeAuthenticator extends IAuthenticator {
public SkinmeAuthenticator(String clientToken) {
super(clientToken);
}
public String[] parseType1(String s) {
return s.split(",");
}
public String getCharacter(String user, String hash, String $char) throws Exception {
return NetUtils.get(
"http://www.skinme.cc/api/login.php?user=" + user + "&hash=" + hash + (($char == null) ? "" : ("&char=" + $char)));
}
@Override
public UserProfileProvider login(LoginInfo info) throws AuthenticationException {
UserProfileProvider req = new UserProfileProvider();
if (info.username == null || !info.username.contains("@"))
throw new AuthenticationException(C.i18n("login.not_email"));
try {
String usr = info.username.toLowerCase(SupportedLocales.NOW_LOCALE.self);
String pwd = info.password;
String str = DigestUtils.sha1Hex(usr);
String hashCode = DigestUtils.sha1Hex(DigestUtils.md5Hex(DigestUtils.sha1Hex(pwd) + pwd) + str);
String data = getCharacter(usr, hashCode, null);
String[] sl = data.split(":");
if (null != sl[0])
switch (sl[0]) {
case "0":
if (sl[1].contains("No Valid Character"))
sl[1] = C.i18n("login.no_valid_character");
throw new AuthenticationException(sl[1]);
case "1":
String[] s = parseType1(sl[1]);
req.setUserName(s[0]);
req.setSession(s[1]);
req.setUserId(s[1]);
req.setAccessToken(s[1]);
break;
case "2":
String[] charators = sl[1].split(";");
int len = charators.length;
String[] $char = new String[len];
String[] user = new String[len];
System.out.println(sl[1]);
for (int i = 0; i < len; i++) {
String[] charator = charators[i].split(",");
$char[i] = charator[0];
user[i] = charator[1];
}
int index = SwingUtils.select(user, C.i18n("login.choose_charactor"));
if (index == -1)
throw new AuthenticationException(C.i18n("message.cancelled"));
else {
String character = $char[index];
sl = getCharacter(usr, hashCode, character).split(":");
String[] s2 = parseType1(sl[1]);
req.setUserName(s2[0]);
req.setSession(s2[1]);
req.setUserId(s2[1]);
req.setAccessToken(s2[1]);
}
break;
}
req.setUserType("Legacy");
return req;
} catch (Exception e) {
throw new AuthenticationException(e);
}
}
@Override
public String id() {
return "skinme";
}
@Override
public String getName() {
return "Skinme";
}
@Override
public UserProfileProvider loginBySettings() {
return null;
}
@Override
public void logOut() {
}
}
@@ -1,109 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth;
/**
*
* @author huangyuhui
*/
public final class UserProfileProvider {
public String getUserName() {
return username;
}
public void setUserName(String username) {
this.username = username;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getSession() {
return session;
}
public void setSession(String session) {
this.session = session;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
if (accessToken == null)
accessToken = "0";
this.accessToken = accessToken;
}
public String getUserProperties() {
return userProperties;
}
public void setUserProperties(String userProperties) {
this.userProperties = userProperties;
}
public String getUserPropertyMap() {
return userPropertyMap;
}
public void setUserPropertyMap(String userPropertyMap) {
this.userPropertyMap = userPropertyMap;
}
public String getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(String otherInfo) {
this.otherInfo = otherInfo;
}
public String getClientIdentifier() {
return clientIdentifier;
}
public void setClientIdentifier(String clientIdentifier) {
this.clientIdentifier = clientIdentifier;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
private String username = "";
private String userId = "";
private String session = "";
private String accessToken = "";
private String userProperties = "{}";
private String userPropertyMap = "{}";
private String otherInfo = "";
private String clientIdentifier = "";
private String userType = "Offline";
}
@@ -1,143 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth;
import com.google.gson.GsonBuilder;
import java.net.Proxy;
import java.util.Map;
import javax.swing.JOptionPane;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.ArrayUtils;
import org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil.GameProfile;
import org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil.PropertyMap;
import org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil.YggdrasilAuthentication;
import org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil.UUIDTypeAdapter;
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public final class YggdrasilAuthenticator extends IAuthenticator {
YggdrasilAuthentication ua;
public YggdrasilAuthenticator(String clientToken) {
super(clientToken);
ua = new YggdrasilAuthentication(Proxy.NO_PROXY, clientToken);
}
@Override
public UserProfileProvider login(LoginInfo info) throws AuthenticationException {
UserProfileProvider result = new UserProfileProvider();
result.setUserType("mojang");
if (ua.canPlayOnline()) {
result.setUserName(info.username);
result.setUserId(UUIDTypeAdapter.fromUUID(ua.getSelectedProfile().id));
} else {
String usr = info.username;
if (info.username == null || !info.username.contains("@"))
throw new AuthenticationException(C.i18n("login.not_email"));
String pwd = info.password;
if (!ua.isLoggedIn())
ua.setPassword(pwd);
ua.setUserName(usr);
ua.logIn();
if (!ua.isLoggedIn())
throw new AuthenticationException(C.i18n("login.wrong_password"));
GameProfile selectedProfile = ua.getSelectedProfile();
GameProfile[] profiles = ua.getAvailableProfiles();
String username;
if (selectedProfile == null)
if (ArrayUtils.isNotEmpty(profiles)) {
String[] names = new String[profiles.length];
for (int i = 0; i < profiles.length; i++)
names[i] = profiles[i].name;
int sel = SwingUtils.select(names, C.i18n("login.choose_charactor"));
if (sel == -1)
throw new AuthenticationException("No selection");
selectedProfile = profiles[sel];
username = names[sel];
} else
username = JOptionPane.showInputDialog(C.i18n("login.no_charactor"));
else
username = selectedProfile.name;
if (username == null)
throw new AuthenticationException("No player");
result.setUserName(username);
result.setUserId(selectedProfile == null ? OfflineAuthenticator.getUUIDFromUserName(username) : UUIDTypeAdapter.fromUUID(selectedProfile.id));
}
result.setUserProperties(new GsonBuilder().registerTypeAdapter(PropertyMap.class, new PropertyMap.LegacySerializer()).create().toJson(ua.getUserProperties()));
result.setUserPropertyMap(new GsonBuilder().registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()).create().toJson(ua.getUserProperties()));
result.setAccessToken(ua.getAuthenticatedToken());
result.setSession(ua.getAuthenticatedToken());
return result;
}
@Override
public boolean isLoggedIn() {
return ua.isLoggedIn();
}
@Override
public String id() {
return "yggdrasil";
}
@Override
public String getName() {
return C.i18n("login.methods.yggdrasil");
}
@Override
public Map onSaveSettings() {
Map m = ua.saveForStorage();
m.putAll(super.onSaveSettings());
return m;
}
@Override
public void onLoadSettings(Map settings) {
super.onLoadSettings(settings);
if (settings == null)
return;
ua.loadFromStorage(settings);
}
@Override
public UserProfileProvider loginBySettings() throws AuthenticationException {
UserProfileProvider result = new UserProfileProvider();
ua.logIn();
if (!ua.isLoggedIn())
throw new AuthenticationException(C.i18n("login.wrong_password"));
GameProfile profile = ua.getSelectedProfile();
result.setUserName(profile.name);
result.setUserId(profile.id.toString());
result.setUserProperties(new GsonBuilder().registerTypeAdapter(PropertyMap.class, new PropertyMap.LegacySerializer()).create().toJson(ua.getUserProperties()));
result.setUserPropertyMap(new GsonBuilder().registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()).create().toJson(ua.getUserProperties()));
result.setAccessToken(ua.getAuthenticatedToken());
result.setSession(ua.getAuthenticatedToken());
return result;
}
@Override
public void logOut() {
ua.logOut();
}
}
@@ -1,77 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil;
import java.util.HashMap;
public class AuthenticationRequest {
private HashMap<String, Object> agent;
private String username, password, clientToken;
private boolean requestUser = true;
public HashMap<String, Object> getAgent() {
return agent;
}
public void setAgent(HashMap<String, Object> agent) {
this.agent = agent;
}
public String getUserName() {
return username;
}
public void setUserName(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getClientToken() {
return clientToken;
}
public void setClientToken(String clientToken) {
this.clientToken = clientToken;
}
public boolean isRequestUser() {
return requestUser;
}
public void setRequestUser(boolean requestUser) {
this.requestUser = requestUser;
}
public AuthenticationRequest(String username, String password, String clientToken) {
agent = new HashMap<>();
agent.put("name", "Minecraft");
agent.put("version", 1);
this.username = username;
this.password = password;
this.clientToken = clientToken;
}
}
@@ -1,94 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.UUID;
import org.jackhuang.hellominecraft.util.StrUtils;
public class GameProfile {
public final UUID id;
public final String name;
public final PropertyMap properties = new PropertyMap();
public GameProfile(UUID id, String name) {
if (id == null && StrUtils.isBlank(name))
throw new IllegalArgumentException("Name and ID cannot both be blank");
this.id = id;
this.name = name;
}
public boolean isComplete() {
return id != null && StrUtils.isNotBlank(name);
}
@Override
public int hashCode() {
int hash = 7;
hash = 29 * hash + Objects.hashCode(this.id);
hash = 29 * hash + Objects.hashCode(this.name);
return hash;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
GameProfile that = (GameProfile) o;
if (id != null ? !id.equals(that.id) : that.id != null)
return false;
return name != null ? name.equals(that.name) : that.name == null;
}
public static class GameProfileSerializer implements JsonSerializer<GameProfile>, JsonDeserializer<GameProfile> {
@Override
public GameProfile deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (!(json instanceof JsonObject))
throw new JsonParseException("The json element is not a JsonObject.");
JsonObject object = (JsonObject) json;
UUID id = object.has("id") ? (UUID) context.deserialize(object.get("id"), UUID.class) : null;
String name = object.has("name") ? object.getAsJsonPrimitive("name").getAsString() : null;
return new GameProfile(id, name);
}
@Override
public JsonElement serialize(GameProfile src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
if (src.id != null)
result.add("id", context.serialize(src.id));
if (src.name != null)
result.addProperty("name", src.name);
return result;
}
}
}
@@ -1,116 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
public class PropertyMap extends HashMap<String, Property> {
private static final long serialVersionUID = 362498820763181265L;
public List<Map<String, String>> list() {
List<Map<String, String>> properties = new ArrayList<>();
for (Property profileProperty : values()) {
Map<String, String> property = new HashMap<>();
property.put("name", profileProperty.name);
property.put("value", profileProperty.value);
properties.add(property);
}
return properties;
}
public void fromList(List<Map<String, String>> list) {
try {
for (Map<String, String> propertyMap : list) {
String name = propertyMap.get("name");
String value = propertyMap.get("value");
put(name, new Property(name, value));
}
} catch (Throwable t) {
HMCLog.warn("Failed to deserialize properties", t);
}
}
public static class Serializer implements JsonSerializer<PropertyMap>, JsonDeserializer<PropertyMap> {
@Override
public PropertyMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
PropertyMap result = new PropertyMap();
if ((json instanceof JsonObject)) {
JsonObject object = (JsonObject) json;
for (Map.Entry<String, JsonElement> entry : object.entrySet())
if (entry.getValue() instanceof JsonArray)
for (JsonElement element : (JsonArray) entry.getValue())
result.put(entry.getKey(),
new Property((String) entry.getKey(), element.getAsString()));
} else if ((json instanceof JsonArray))
for (JsonElement element : (JsonArray) json)
if ((element instanceof JsonObject)) {
JsonObject object = (JsonObject) element;
String name = object.getAsJsonPrimitive("name").getAsString();
String value = object.getAsJsonPrimitive("value").getAsString();
result.put(name, new Property(name, value));
}
return result;
}
@Override
public JsonElement serialize(PropertyMap src, Type typeOfSrc, JsonSerializationContext context) {
JsonArray result = new JsonArray();
for (Property property : src.values()) {
JsonObject object = new JsonObject();
object.addProperty("name", property.name);
object.addProperty("value", property.value);
result.add(object);
}
return result;
}
}
public static class LegacySerializer
implements JsonSerializer<PropertyMap> {
@Override
public JsonElement serialize(PropertyMap src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
for (PropertyMap.Entry<String, Property> entry : src.entrySet()) {
JsonArray values = new JsonArray();
values.add(new JsonPrimitive(entry.getValue().value));
result.add(entry.getKey(), values);
}
return result;
}
}
}
@@ -1,64 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil;
public class RefreshRequest {
private String clientToken;
private String accessToken;
private GameProfile selectedProfile;
private boolean requestUser = true;
public RefreshRequest(String accessToken, String clientToken) {
this.clientToken = clientToken;
this.accessToken = accessToken;
}
public String getClientToken() {
return clientToken;
}
public void setClientToken(String clientToken) {
this.clientToken = clientToken;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public GameProfile getSelectedProfile() {
return selectedProfile;
}
public void setSelectedProfile(GameProfile selectedProfile) {
this.selectedProfile = selectedProfile;
}
public boolean isRequestUser() {
return requestUser;
}
public void setRequestUser(boolean requestUser) {
this.requestUser = requestUser;
}
}
@@ -1,237 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.auth.yggdrasil;
import org.jackhuang.hellominecraft.launcher.core.auth.AuthenticationException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.NetUtils;
import org.jackhuang.hellominecraft.util.StrUtils;
public class YggdrasilAuthentication {
public static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(GameProfile.class, new GameProfile.GameProfileSerializer())
.registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer())
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
protected static final String BASE_URL = "https://authserver.mojang.com/";
protected static final URL ROUTE_AUTHENTICATE = NetUtils.constantURL(BASE_URL + "authenticate");
protected static final URL ROUTE_REFRESH = NetUtils.constantURL(BASE_URL + "refresh");
protected static final String STORAGE_KEY_ACCESS_TOKEN = "accessToken";
protected static final String STORAGE_KEY_PROFILE_NAME = "displayName";
protected static final String STORAGE_KEY_PROFILE_ID = "uuid";
protected static final String STORAGE_KEY_PROFILE_PROPERTIES = "profileProperties";
protected static final String STORAGE_KEY_USER_NAME = "username";
protected static final String STORAGE_KEY_USER_ID = "userid";
protected static final String STORAGE_KEY_USER_PROPERTIES = "userProperties";
private final Proxy proxy;
private final String clientToken;
private final PropertyMap userProperties = new PropertyMap();
private String userid, username, password, accessToken;
private GameProfile selectedProfile;
private GameProfile[] profiles;
private boolean isOnline;
public YggdrasilAuthentication(Proxy proxy, String clientToken) {
this.proxy = proxy;
this.clientToken = clientToken;
}
// <editor-fold defaultstate="collapsed" desc="Get/Set">
public void setUserName(String username) {
if ((isLoggedIn()) && (canPlayOnline()))
throw new IllegalStateException("Cannot change username while logged in & online");
this.username = username;
}
public void setPassword(String password) {
if ((isLoggedIn()) && (canPlayOnline()) && (StrUtils.isNotBlank(password)))
throw new IllegalStateException("Cannot set password while logged in & online");
this.password = password;
}
public GameProfile getSelectedProfile() {
return this.selectedProfile;
}
public String getUserId() {
return this.userid;
}
public PropertyMap getUserProperties() {
if (isLoggedIn())
return (PropertyMap) userProperties.clone();
return new PropertyMap();
}
public GameProfile[] getAvailableProfiles() {
if (profiles == null)
return null;
else
return profiles.clone();
}
public String getAuthenticatedToken() {
return this.accessToken;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Log In/Out">
public boolean canPlayOnline() {
return isLoggedIn() && getSelectedProfile() != null && this.isOnline;
}
public boolean canLogIn() {
return !canPlayOnline() && StrUtils.isNotBlank(username) && (StrUtils.isNotBlank(password) || StrUtils.isNotBlank(getAuthenticatedToken()));
}
public boolean isLoggedIn() {
return StrUtils.isNotBlank(this.accessToken);
}
public void logIn() throws AuthenticationException {
if (StrUtils.isBlank(username))
throw new AuthenticationException(C.i18n("login.invalid_username"));
if (StrUtils.isNotBlank(getAuthenticatedToken())) {
if (StrUtils.isBlank(getUserId()))
if (StrUtils.isBlank(username))
userid = username;
else
throw new AuthenticationException(C.i18n("login.invalid_uuid_and_username"));
loggedIn(ROUTE_REFRESH, new RefreshRequest(getAuthenticatedToken(), clientToken));
} else if (StrUtils.isNotBlank(password))
loggedIn(ROUTE_AUTHENTICATE, new AuthenticationRequest(username, password, clientToken));
else
throw new AuthenticationException(C.i18n("login.invalid_password"));
}
private void loggedIn(URL url, Object input) throws AuthenticationException {
try {
String jsonResult = input == null ? NetUtils.get(url) : NetUtils.post(url, GSON.toJson(input), "application/json", proxy);
Response response = (Response) GSON.fromJson(jsonResult, Response.class);
if (response == null)
throw new AuthenticationException("No valid response here");
if (StrUtils.isNotBlank(response.error)) {
HMCLog.err("Failed to log in, the auth server returned an error: " + response.error + ", message: " + response.errorMessage + ", cause: " + response.cause);
if (response.errorMessage.contains("Invalid token"))
response.errorMessage = C.i18n("login.invalid_token");
throw new AuthenticationException("Request error: " + response.errorMessage);
}
if (!clientToken.equals(response.clientToken))
throw new AuthenticationException(C.i18n("login.changed_client_token"));
User user = response.user;
userid = user != null && user.getId() != null ? user.getId() : username;
isOnline = true;
profiles = response.availableProfiles;
selectedProfile = response.selectedProfile;
userProperties.clear();
this.accessToken = response.accessToken;
if (user != null && user.getProperties() != null)
userProperties.putAll(user.getProperties());
} catch (IOException | IllegalStateException | JsonParseException e) {
throw new AuthenticationException(C.i18n("login.failed.connect_authentication_server"), e);
}
}
public void logOut() {
password = null;
userid = null;
selectedProfile = null;
userProperties.clear();
accessToken = null;
profiles = null;
isOnline = false;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Settings Storage">
public void loadFromStorage(Map<String, Object> credentials) {
logOut();
setUserName((String) credentials.get(STORAGE_KEY_USER_NAME));
if (credentials.containsKey(STORAGE_KEY_USER_ID))
userid = (String) credentials.get(STORAGE_KEY_USER_ID);
else
userid = username;
if (credentials.containsKey(STORAGE_KEY_USER_PROPERTIES))
userProperties.fromList((List<Map<String, String>>) credentials.get(STORAGE_KEY_USER_PROPERTIES));
if ((credentials.containsKey(STORAGE_KEY_PROFILE_NAME)) && (credentials.containsKey(STORAGE_KEY_PROFILE_ID))) {
GameProfile profile = new GameProfile(UUIDTypeAdapter.fromString((String) credentials.get(STORAGE_KEY_PROFILE_ID)), (String) credentials.get(STORAGE_KEY_PROFILE_NAME));
if (credentials.containsKey(STORAGE_KEY_PROFILE_PROPERTIES))
profile.properties.fromList((List<Map<String, String>>) credentials.get(STORAGE_KEY_PROFILE_PROPERTIES));
selectedProfile = profile;
}
this.accessToken = (String) credentials.get(STORAGE_KEY_ACCESS_TOKEN);
}
public Map<String, Object> saveForStorage() {
Map<String, Object> result = new HashMap<>();
if (username != null)
result.put(STORAGE_KEY_USER_NAME, username);
if (getUserId() != null)
result.put(STORAGE_KEY_USER_ID, getUserId());
if (!getUserProperties().isEmpty())
result.put(STORAGE_KEY_USER_PROPERTIES, getUserProperties().list());
GameProfile sel = getSelectedProfile();
if (sel != null) {
result.put(STORAGE_KEY_PROFILE_NAME, sel.name);
result.put(STORAGE_KEY_PROFILE_ID, sel.id);
if (!sel.properties.isEmpty())
result.put(STORAGE_KEY_PROFILE_PROPERTIES, sel.properties.list());
}
if (StrUtils.isNotBlank(getAuthenticatedToken()))
result.put(STORAGE_KEY_ACCESS_TOKEN, getAuthenticatedToken());
return result;
}
// </editor-fold>
}
@@ -1,82 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
/**
*
* @author huangyuhui
*/
public class BMCLAPIDownloadProvider extends IDownloadProvider {
@Override
public InstallerVersionList getForgeInstaller() {
return org.jackhuang.hellominecraft.launcher.core.install.forge.MinecraftForgeVersionList.getInstance();
}
@Override
public InstallerVersionList getLiteLoaderInstaller() {
return org.jackhuang.hellominecraft.launcher.core.install.liteloader.LiteLoaderVersionList.getInstance();
}
@Override
public InstallerVersionList getOptiFineInstaller() {
return org.jackhuang.hellominecraft.launcher.core.install.optifine.bmcl.OptiFineBMCLVersionList.getInstance();
}
@Override
public String getLibraryDownloadURL() {
return "http://bmclapi2.bangbang93.com/libraries";
}
@Override
public String getVersionsDownloadURL() {
return "http://bmclapi2.bangbang93.com/versions/";
}
@Override
public String getIndexesDownloadURL() {
return "http://bmclapi2.bangbang93.com/indexes/";
}
@Override
public String getVersionsListDownloadURL() {
return "http://bmclapi2.bangbang93.com/mc/game/version_manifest.json";
}
@Override
public String getAssetsDownloadURL() {
return "http://bmclapi2.bangbang93.com/assets/";
}
@Override
public String getParsedDownloadURL(String str) {
return str == null ? null
: str.replace("https://launchermeta.mojang.com", "http://bmclapi2.bangbang93.com")
.replace("https://launcher.mojang.com", "http://bmclapi2.bangbang93.com")
.replace("https://libraries.minecraft.net", "http://bmclapi2.bangbang93.com/libraries")
.replace("http://files.minecraftforge.net/maven", "http://bmclapi2.bangbang93.com/maven");
}
@Override
public boolean isAllowedToUseSelfURL() {
return true;
}
}
@@ -1,63 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.tasks.TaskWindow;
/**
*
* @author huangyuhui
*/
public enum DownloadType {
Mojang("download.mojang", new MojangDownloadProvider()),
BMCL("download.BMCL", new BMCLAPIDownloadProvider()),
//RapidData("download.rapid_data", new RapidDataDownloadProvider()),
Curse("Curse CDN", new CurseDownloadProvider());
private final String name;
private final IDownloadProvider provider;
DownloadType(String a, IDownloadProvider provider) {
name = a;
this.provider = provider;
}
public IDownloadProvider getProvider() {
return provider;
}
public String getName() {
return C.i18n(name);
}
private static DownloadType suggestedDownloadType = Mojang;
public static DownloadType getSuggestedDownloadType() {
return suggestedDownloadType;
}
public static void setSuggestedDownloadType(DownloadType suggestedDownloadType) {
if (suggestedDownloadType == null)
throw new IllegalArgumentException("download type should not be null.");
TaskWindow.downloadSource = suggestedDownloadType.getName();
DownloadType.suggestedDownloadType = suggestedDownloadType;
}
}
@@ -1,69 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerType;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
/**
*
* @author huangyuhui
*/
public abstract class IDownloadProvider {
public InstallerVersionList getInstallerByType(InstallerType type) {
switch (type) {
case Forge:
return getForgeInstaller();
case LiteLoader:
return getLiteLoaderInstaller();
case OptiFine:
return getOptiFineInstaller();
default:
return null;
}
}
public abstract InstallerVersionList getForgeInstaller();
public abstract InstallerVersionList getLiteLoaderInstaller();
public abstract InstallerVersionList getOptiFineInstaller();
public abstract String getLibraryDownloadURL();
public abstract String getVersionsDownloadURL();
public abstract String getIndexesDownloadURL();
public abstract String getVersionsListDownloadURL();
public abstract String getAssetsDownloadURL();
/**
* For example, minecraft.json/assetIndex/url or
* minecraft.json/downloads/client/url
*
* @param str baseURL
*
* @return parsedURL
*/
public abstract String getParsedDownloadURL(String str);
public abstract boolean isAllowedToUseSelfURL();
}
@@ -1,163 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftDownloadService;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.launcher.core.version.GameDownloadInfo;
import org.jackhuang.hellominecraft.launcher.core.version.IMinecraftLibrary;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.tasks.download.FileDownloadTask;
import org.jackhuang.hellominecraft.util.func.Function;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
/**
*
* @author huangyuhui
*/
public class MinecraftDownloadService extends IMinecraftDownloadService {
public MinecraftDownloadService(IMinecraftService service) {
super(service);
}
@Override
public List<DownloadLibraryJob> getDownloadLibraries(MinecraftVersion mv) throws GameException {
ArrayList<DownloadLibraryJob> downloadLibraries = new ArrayList<>();
if (mv == null)
return downloadLibraries;
MinecraftVersion v = mv.resolve(service.version());
for (IMinecraftLibrary l : v.getLibraries())
if (l != null && l.allow() && l.getDownloadInfo() != null) {
File ff = l.getFilePath(service.baseDirectory());
if (!ff.exists()) {
String libURL = l.getDownloadInfo().getUrl(service.getDownloadType());
if (libURL != null)
downloadLibraries.add(new DownloadLibraryJob(l, libURL, ff));
}
}
return downloadLibraries;
}
@Override
public Task downloadMinecraft(String id) {
return new TaskInfo("Download Minecraft") {
@Override
public Collection<Task> getDependTasks() {
return Arrays.asList(downloadMinecraftVersionJson(id));
}
@Override
public void executeTask() throws Throwable {
File vpath = new File(service.baseDirectory(), "versions/" + id);
if (!areDependTasksSucceeded) {
FileUtils.deleteDirectory(vpath);
throw new RuntimeException("Cannot continue because of download failing.");
}
File mvj = new File(vpath, id + ".jar");
if (mvj.exists() && !mvj.delete())
HMCLog.warn("Failed to delete " + mvj);
try {
MinecraftVersion mv = C.GSON.fromJson(FileUtils.readFileToStringQuietly(new File(vpath, id + ".json")), MinecraftVersion.class);
if (mv == null)
throw new JsonSyntaxException("incorrect version");
afters.add(downloadMinecraftJar(mv, mvj));
} catch (JsonSyntaxException ex) {
HMCLog.err("Failed to parse minecraft version json.", ex);
FileUtils.deleteDirectory(vpath);
}
}
Collection<Task> afters = new HashSet<>();
@Override
public Collection<Task> getAfterTasks() {
return afters;
}
};
}
private static class DownloadTypeSwitcher implements Function<Integer, String> {
String suffix;
public DownloadTypeSwitcher(String suffix) {
this.suffix = suffix;
}
@Override
public String apply(Integer t) {
return DownloadType.values()[t / 2].getProvider().getVersionsDownloadURL() + suffix;
}
}
@Override
public Task downloadMinecraftJar(MinecraftVersion mv, File mvj) {
GameDownloadInfo i = mv.getClientDownloadInfo();
return new FileDownloadTask(i.getUrl(service.getDownloadType()), mvj, i.sha1)
.setFailedCallbackReturnsNewURL(new DownloadTypeSwitcher(mv.id + "/" + mv.id + ".jar")).setTag(mv.id + ".jar");
}
@Override
public Task downloadMinecraftVersionJson(String id) {
return new TaskInfo("Download Minecraft Json") {
@Override
public void executeTask() throws Throwable {
List<MinecraftRemoteVersion> versions = MinecraftRemoteVersions.getRemoteVersions(service.getDownloadType()).justDo();
MinecraftRemoteVersion currentVersion = null;
for (MinecraftRemoteVersion v : versions)
if (id.equals(v.id)) {
currentVersion = v;
break;
}
if (currentVersion == null)
throw new RuntimeException("Cannot find version: " + id + " in remote repository.");
String jsonURL = currentVersion.getUrl(service.getDownloadType());
File vpath = new File(service.baseDirectory(), "versions/" + id);
File mvt = new File(vpath, id + ".json");
if (!vpath.exists() && !vpath.mkdirs())
HMCLog.warn("Failed to make directories: " + vpath);
if (mvt.exists() && !mvt.delete())
HMCLog.warn("Failed to delete " + mvt);
afters.add(new FileDownloadTask(jsonURL, mvt).setTag(id + ".json"));
}
Collection<Task> afters = new HashSet<>();
@Override
public Collection<Task> getAfterTasks() {
return afters;
}
};
}
}
@@ -1,28 +0,0 @@
/*
* Hello Minecraft!.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
/**
*
* @author huangyuhui
*/
public class MinecraftRemoteLatestVersion {
public String snapshot, release;
}
@@ -1,34 +0,0 @@
/*
* Hello Minecraft!.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
/**
*
* @author huangyuhui
*/
public class MinecraftRemoteVersion {
public String id, time, releaseTime, type;
private String url;
public String getUrl(DownloadType type) {
if (url == null)
return type.getProvider().getVersionsDownloadURL() + id + "/" + id + ".json";
return type.getProvider().getParsedDownloadURL(url);
}
}
@@ -1,74 +0,0 @@
/*
* Hello Minecraft!.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
import java.util.ArrayList;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.NetUtils;
import org.jackhuang.hellominecraft.util.OverridableSwingWorker;
/**
*
* @author huangyuhui
*/
public class MinecraftRemoteVersions {
public ArrayList<MinecraftRemoteVersion> versions;
public MinecraftRemoteLatestVersion latest;
private static volatile MinecraftRemoteVersions INSTANCE = null;
private static final Object INSTANCE_LOCK = new Object();
public static RemoteVersionsTask getRemoteVersions(DownloadType type) {
return new RemoteVersionsTask(type) {
@Override
public void work() throws Exception {
synchronized (INSTANCE_LOCK) {
if (INSTANCE != null)
send(INSTANCE.versions.toArray(new MinecraftRemoteVersion[INSTANCE.versions.size()]));
else
super.work();
}
}
};
}
public static RemoteVersionsTask refreshRomoteVersions(DownloadType type) {
return new RemoteVersionsTask(type);
}
public static class RemoteVersionsTask extends OverridableSwingWorker<MinecraftRemoteVersion> {
DownloadType type;
public RemoteVersionsTask(DownloadType type) {
this.type = type;
}
@Override
public void work() throws Exception {
MinecraftRemoteVersions r = C.GSON.fromJson(NetUtils.get(type.getProvider().getVersionsListDownloadURL()), MinecraftRemoteVersions.class);
if (r != null && r.versions != null) {
INSTANCE = r;
send(r.versions.toArray(new MinecraftRemoteVersion[r.versions.size()]));
}
}
}
}
@@ -1,89 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
import java.util.Locale;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
import org.jackhuang.hellominecraft.util.lang.SupportedLocales;
/**
*
* @author huangyuhui
*/
public class MojangDownloadProvider extends IDownloadProvider {
@Override
public InstallerVersionList getForgeInstaller() {
return org.jackhuang.hellominecraft.launcher.core.install.forge.MinecraftForgeVersionList.getInstance();
}
@Override
public InstallerVersionList getLiteLoaderInstaller() {
return org.jackhuang.hellominecraft.launcher.core.install.liteloader.LiteLoaderVersionList.getInstance();
}
@Override
public InstallerVersionList getOptiFineInstaller() {
return org.jackhuang.hellominecraft.launcher.core.install.optifine.vanilla.OptiFineVersionList.getInstance();
}
@Override
public String getLibraryDownloadURL() {
return "https://libraries.minecraft.net";
}
@Override
public String getVersionsDownloadURL() {
return "http://s3.amazonaws.com/Minecraft.Download/versions/";
}
@Override
public String getIndexesDownloadURL() {
return "http://s3.amazonaws.com/Minecraft.Download/indexes/";
}
@Override
public String getVersionsListDownloadURL() {
return "https://launchermeta.mojang.com/mc/game/version_manifest.json";
}
@Override
public String getAssetsDownloadURL() {
return "https://resources.download.minecraft.net/";
}
@Override
public boolean isAllowedToUseSelfURL() {
return true;
}
@Override
public String getParsedDownloadURL(String str) {
if (str == null)
return null;
else if (str.contains("scala-swing") || str.contains("scala-xml") || str.contains("scala-parser-combinators"))
return str.replace("http://files.minecraftforge.net/maven", "http://ftb.cursecdn.com/FTB2/maven/");
else if (str.contains("typesafe") || str.contains("scala"))
if (SupportedLocales.NOW_LOCALE.self == Locale.CHINA)
return str.replace("http://files.minecraftforge.net/maven", "http://maven.oschina.net/content/groups/public");
else
return str.replace("http://files.minecraftforge.net/maven", "http://repo1.maven.org/maven2");
else
return str;
}
}
@@ -1,56 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.download;
/**
*
* @author huangyuhui
*/
public class RapidDataDownloadProvider extends MojangDownloadProvider {
@Override
public String getAssetsDownloadURL() {
return "http://mirrors.rapiddata.org/resources.download.minecraft.net/";
}
@Override
public String getLibraryDownloadURL() {
return "http://mirrors.rapiddata.org/libraries.minecraft.net";
}
@Override
public String getIndexesDownloadURL() {
return "http://mirrors.rapiddata.org/Minecraft.Download/indexes/";
}
@Override
public String getVersionsDownloadURL() {
return "http://mirrors.rapiddata.org/Minecraft.Download/versions/";
}
@Override
public String getVersionsListDownloadURL() {
return "http://mirrors.rapiddata.org/Minecraft.Download/versions/versions.json";
}
@Override
public String getParsedDownloadURL(String str) {
return str == null ? null : str.replace("http://files.minecraftforge.net/maven", "http://mirrors.rapiddata.org/forge/maven");
}
}
@@ -1,120 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import org.jackhuang.hellominecraft.util.tasks.Task;
/**
*
* @author huangyuhui
*/
public abstract class InstallerVersionList {
/**
* Refresh installer versions list from the downloaded content.
*
* @param versions Minecraft versions you need to refresh
*
* @throws java.lang.Exception including network exceptions, IO exceptions.
*/
public abstract Task refresh(String[] versions);
/**
* Installer name.
*
* @return installer name.
*/
public abstract String getName();
/**
* Get installers you want.
*
* @param mcVersion the installers to this Minecraft version.
*
* @return cached result.
*/
protected abstract List<InstallerVersion> getVersionsImpl(String mcVersion);
/**
* Get installers you want, please cache this method's result to save time.
*
* @param mcVersion the installers to this Minecraft version.
*
* @return a copy of the cached data to prevent
* ConcurrentModificationException.
*/
public List<InstallerVersion> getVersions(String mcVersion) {
List<InstallerVersion> a = getVersionsImpl(mcVersion);
if (a == null)
return null;
else
return new ArrayList<>(a);
}
public static class InstallerVersion implements Comparable<InstallerVersion> {
public String selfVersion, mcVersion;
public String installer, universal;
public String changelog;
public InstallerVersion(String selfVersion, String mcVersion) {
this.selfVersion = selfVersion;
this.mcVersion = mcVersion;
}
@Override
public int compareTo(InstallerVersion o) {
return selfVersion.compareTo(o.selfVersion);
}
@Override
public int hashCode() {
return selfVersion.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final InstallerVersion other = (InstallerVersion) obj;
return Objects.equals(this.selfVersion, other.selfVersion);
}
}
public static class InstallerVersionComparator implements Comparator<InstallerVersion>, Serializable {
private static final long serialVersionUID = 3276198781795213723L;
public static final InstallerVersionComparator INSTANCE = new InstallerVersionComparator();
@Override
public int compare(InstallerVersion o1, InstallerVersion o2) {
return o2.compareTo(o1);
}
}
}
@@ -1,87 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftInstallerService;
import java.io.File;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList.InstallerVersion;
import org.jackhuang.hellominecraft.launcher.core.install.forge.ForgeInstaller;
import org.jackhuang.hellominecraft.launcher.core.install.liteloader.LiteLoaderInstaller;
import org.jackhuang.hellominecraft.launcher.core.install.liteloader.LiteLoaderVersionList;
import org.jackhuang.hellominecraft.launcher.core.install.optifine.OptiFineInstaller;
import org.jackhuang.hellominecraft.launcher.core.install.optifine.vanilla.OptiFineDownloadFormatter;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.download.FileDownloadTask;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.tasks.DeleteFileTask;
/**
*
* @author huangyuhui
*/
public final class MinecraftInstallerService extends IMinecraftInstallerService {
public MinecraftInstallerService(IMinecraftService service) {
super(service);
}
@Override
public Task download(String installId, InstallerVersion v, InstallerType type) {
switch (type) {
case Forge:
return downloadForge(installId, v);
case OptiFine:
return downloadOptiFine(installId, v);
case LiteLoader:
return downloadLiteLoader(installId, v);
default:
return null;
}
}
@Override
public Task downloadForge(String installId, InstallerVersion v) {
File filepath = IOUtils.tryGetCanonicalFile(IOUtils.currentDirWithSeparator() + "forge-installer.jar");
if (v.installer == null)
return null;
else
return new FileDownloadTask(service.getDownloadType().getProvider().getParsedDownloadURL(v.installer), filepath).setTag("forge")
.after(new ForgeInstaller(service, filepath))
.after(new DeleteFileTask(filepath));
}
@Override
public Task downloadOptiFine(String installId, InstallerVersion v) {
File filepath = IOUtils.tryGetCanonicalFile(IOUtils.currentDirWithSeparator() + "optifine-installer.jar");
if (v.installer == null)
return null;
OptiFineDownloadFormatter task = new OptiFineDownloadFormatter(v.installer);
return task.after(new FileDownloadTask(filepath).registerPreviousResult(task).setTag("optifine"))
.after(new OptiFineInstaller(service, installId, v, filepath))
.after(new DeleteFileTask(filepath));
}
@Override
public Task downloadLiteLoader(String installId, InstallerVersion v) {
File filepath = IOUtils.tryGetCanonicalFile(IOUtils.currentDirWithSeparator() + "liteloader-universal.jar");
FileDownloadTask task = (FileDownloadTask) new FileDownloadTask(v.universal, filepath).setTag("LiteLoader");
return task.after(new LiteLoaderInstaller(service, installId, (LiteLoaderVersionList.LiteLoaderInstallerVersion) v).registerPreviousResult(task))
.after(new DeleteFileTask(filepath));
}
}
@@ -1,51 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.system.Compressor;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
/**
*
* @author huangyuhui
*/
public class PackMinecraftInstaller {
File dest;
ArrayList<String> src;
public PackMinecraftInstaller(ArrayList<String> src, File dest) {
this.dest = dest;
this.src = src;
}
public void install() throws IOException {
File file = new File(IOUtils.currentDir(), "HMCL-MERGE-TEMP");
if (!file.exists() && !file.mkdirs())
HMCLog.warn("Failed to make directories: " + file);
for (String src1 : src)
Compressor.unzip(new File(src1), file);
Compressor.zip(file.getAbsolutePath(), dest.getAbsolutePath());
FileUtils.deleteDirectory(file);
}
}
@@ -1,96 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.forge;
import org.jackhuang.hellominecraft.launcher.core.install.InstallProfile;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.NetUtils;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftLibrary;
import org.jackhuang.hellominecraft.util.MessageBox;
/**
*
* @author huangyuhui
*/
public class ForgeInstaller extends Task {
public File gameDir;
public File forgeInstaller;
public IMinecraftService mp;
public ForgeInstaller(IMinecraftService mp, File forgeInstaller) {
this.gameDir = mp.baseDirectory();
this.forgeInstaller = forgeInstaller;
this.mp = mp;
}
@Override
public void executeTask() throws Exception {
HMCLog.log("Extracting install profiles...");
try (ZipFile zipFile = new ZipFile(forgeInstaller)) {
ZipEntry entry = zipFile.getEntry("install_profile.json");
String content = NetUtils.getStreamContent(zipFile.getInputStream(entry));
InstallProfile profile = C.GSON.fromJson(content, InstallProfile.class);
File from = new File(gameDir, "versions" + File.separator + profile.install.getMinecraft());
if (!from.exists())
if (MessageBox.Show(C.i18n("install.no_version_if_intall")) == MessageBox.YES_OPTION) {
if (!mp.version().install(profile.install.getMinecraft(), null))
throw new IllegalStateException(C.i18n("install.no_version"));
} else
throw new IllegalStateException(C.i18n("install.no_version"));
File to = new File(gameDir, "versions" + File.separator + profile.install.getTarget());
if (!to.exists() && !to.mkdirs())
HMCLog.warn("Failed to make new version folder " + to);
HMCLog.log("Copying jar..." + profile.install.getMinecraft() + ".jar to " + profile.install.getTarget() + ".jar");
FileUtils.copyFile(new File(from, profile.install.getMinecraft() + ".jar"),
new File(to, profile.install.getTarget() + ".jar"));
HMCLog.log("Creating new version profile..." + profile.install.getTarget() + ".json");
FileUtils.write(new File(to, profile.install.getTarget() + ".json"), C.GSON.toJson(profile.versionInfo));
HMCLog.log("Extracting universal forge pack..." + profile.install.getFilePath());
entry = zipFile.getEntry(profile.install.getFilePath());
InputStream is = zipFile.getInputStream(entry);
MinecraftLibrary forge = new MinecraftLibrary(profile.install.getPath());
File file = new File(gameDir, "libraries/" + forge.getDownloadInfo().path);
if (file.getParentFile().mkdirs())
HMCLog.warn("Failed to make library directory " + file.getParent());
try (FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos)) {
int c;
while ((c = is.read()) != -1)
bos.write((byte) c);
}
mp.version().refreshVersions();
}
}
@Override
public String getInfo() {
return C.i18n("install.forge.install");
}
}
@@ -1,38 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.forge;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.jackhuang.hellominecraft.launcher.core.install.PackMinecraftInstaller;
/**
*
* @author huangyuhui
*/
public class ForgeOldInstaller {
public static void install(String destMinecraftJar, String srcMinecraftJar, String forgeUniversal) throws IOException {
ArrayList<String> al = new ArrayList<>();
al.add(srcMinecraftJar);
al.add(forgeUniversal);
new PackMinecraftInstaller(al, new File(destMinecraftJar)).install();
}
}
@@ -1,91 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.forge;
/**
*
* @author huangyuhui
*/
public class MinecraftForgeVersion {
public String branch, mcversion, jobver, version;
public int build;
public double modified;
public String[][] files;
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
public String getMCVersion() {
return mcversion;
}
public void setMCVersion(String mcversion) {
this.mcversion = mcversion;
}
public String getJobver() {
return jobver;
}
public void setJobver(String jobver) {
this.jobver = jobver;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public int getBuild() {
return build;
}
public void setBuild(int build) {
this.build = build;
}
public double getModified() {
return modified;
}
public void setModified(double modified) {
this.modified = modified;
}
public MinecraftForgeVersion() {
}
public MinecraftForgeVersion(String branch, String mcversion, String jobver, String version, int build, double modified) {
this.branch = branch;
this.mcversion = mcversion;
this.jobver = jobver;
this.version = version;
this.build = build;
this.modified = modified;
}
}
@@ -1,136 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.forge;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionNewerComparator;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
import org.jackhuang.hellominecraft.util.tasks.download.HTTPGetTask;
/**
*
* @author huangyuhui
*/
public class MinecraftForgeVersionList extends InstallerVersionList {
private static volatile MinecraftForgeVersionList instance;
public static MinecraftForgeVersionList getInstance() {
if (instance == null)
instance = new MinecraftForgeVersionList();
return instance;
}
public MinecraftForgeVersionRoot root;
public Map<String, List<InstallerVersion>> versionMap;
public List<InstallerVersion> versions;
@Override
public Task refresh(String[] needed) {
if (root != null)
return null;
return new TaskInfo(C.i18n("install.forge.get_list")) {
HTTPGetTask task = new HTTPGetTask(DownloadType.getSuggestedDownloadType().getProvider().getParsedDownloadURL(C.URL_FORGE_LIST));
@Override
public Collection<Task> getDependTasks() {
return Arrays.asList(task);
}
@Override
public void executeTask() throws Throwable {
if (!areDependTasksSucceeded)
return;
String s = task.getResult();
root = C.GSON.fromJson(s, MinecraftForgeVersionRoot.class);
versionMap = new HashMap<>();
versions = new ArrayList<>();
for (Map.Entry<String, int[]> arr : root.mcversion.entrySet()) {
String mcver = StrUtils.formatVersion(arr.getKey());
ArrayList<InstallerVersion> al = new ArrayList<>();
for (int num : arr.getValue()) {
MinecraftForgeVersion v = root.number.get(num);
InstallerVersion iv = new InstallerVersion(v.version, StrUtils.formatVersion(v.mcversion));
for (String[] f : v.files) {
String ver = v.mcversion + "-" + v.version;
if (!StrUtils.isBlank(v.branch))
ver = ver + "-" + v.branch;
String filename = root.artifact + "-" + ver + "-" + f[1] + "." + f[0];
String url = DownloadType.getSuggestedDownloadType().getProvider().getParsedDownloadURL(root.webpath + ver + "/" + filename);
switch (f[1]) {
case "installer":
iv.installer = url;
break;
case "universal":
iv.universal = url;
break;
case "changelog":
iv.changelog = url;
break;
default:
break;
}
}
if (StrUtils.isBlank(iv.installer) || StrUtils.isBlank(iv.universal))
continue;
Collections.sort(al, new InstallerVersionNewerComparator());
al.add(iv);
versions.add(iv);
}
versionMap.put(StrUtils.formatVersion(mcver), al);
}
Collections.sort(versions, new InstallerVersionComparator());
}
};
}
@Override
public List<InstallerVersion> getVersionsImpl(String mcVersion) {
if (versions == null || versionMap == null)
return null;
if (StrUtils.isBlank(mcVersion))
return versions;
List c = versionMap.get(mcVersion);
if (c == null)
return versions;
Collections.sort(c, InstallerVersionComparator.INSTANCE);
return c;
}
@Override
public String getName() {
return "Forge - MinecraftForge Offical Site";
}
}
@@ -1,100 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.liteloader;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.communication.PreviousResult;
import org.jackhuang.hellominecraft.util.tasks.communication.PreviousResultRegistrar;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftLibrary;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
/**
*
* @author huangyuhui
*/
public class LiteLoaderInstaller extends Task implements PreviousResultRegistrar<File> {
public LiteLoaderVersionList.LiteLoaderInstallerVersion version;
public File installer;
public String installId;
public IMinecraftService service;
public LiteLoaderInstaller(IMinecraftService service, String installId, LiteLoaderVersionList.LiteLoaderInstallerVersion v) {
this(service, installId, v, null);
}
public LiteLoaderInstaller(IMinecraftService service, String installId, LiteLoaderVersionList.LiteLoaderInstallerVersion v, File installer) {
this.service = service;
this.installId = installId;
this.version = v;
this.installer = installer;
}
@Override
public void executeTask() throws Exception {
if (installId == null)
throw new IllegalStateException(C.i18n("install.no_version"));
if (pre.size() != 1 && installer == null)
throw new IllegalStateException("No registered previous task.");
if (installer == null)
installer = pre.get(pre.size() - 1).getResult();
MinecraftVersion mv = (MinecraftVersion) service.version().getVersionById(installId).clone();
mv.inheritsFrom = mv.id;
mv.jar = mv.jar == null ? mv.id : mv.jar;
mv.libraries = new ArrayList(Arrays.asList(version.libraries));
MinecraftLibrary ml = new MinecraftLibrary("com.mumfrey:liteloader:" + version.selfVersion);
//ml.url = "http://dl.liteloader.com/versions/com/mumfrey/liteloader/" + version.mcVersion + "/liteloader-" + version.selfVersion + ".jar";
mv.libraries.add(0, ml);
FileUtils.copyFile(installer, new File(service.baseDirectory(), "libraries/com/mumfrey/liteloader/" + version.selfVersion + "/liteloader-" + version.selfVersion + ".jar"));
mv.id += "-LiteLoader" + version.selfVersion;
mv.mainClass = "net.minecraft.launchwrapper.Launch";
mv.minecraftArguments += " --tweakClass " + version.tweakClass;
File folder = new File(service.baseDirectory(), "versions/" + mv.id);
if (!folder.exists() && folder.mkdirs())
HMCLog.warn("Failed to create new liteloader version " + folder);
File json = new File(folder, mv.id + ".json");
HMCLog.log("Creating new version profile..." + mv.id + ".json");
FileUtils.write(json, C.GSON.toJson(mv));
service.version().refreshVersions();
}
@Override
public String getInfo() {
return C.i18n("install.liteloader.install");
}
ArrayList<PreviousResult<File>> pre = new ArrayList<>();
@Override
public Task registerPreviousResult(PreviousResult pr) {
pre.add(pr);
return this;
}
}
@@ -1,133 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.liteloader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftLibrary;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList.InstallerVersion;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionNewerComparator;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
import org.jackhuang.hellominecraft.util.tasks.download.HTTPGetTask;
/**
*
* @author huangyuhui
*/
public class LiteLoaderVersionList extends InstallerVersionList {
private static volatile LiteLoaderVersionList instance = null;
public static LiteLoaderVersionList getInstance() {
if (instance == null)
instance = new LiteLoaderVersionList();
return instance;
}
public LiteLoaderVersionsRoot root;
public Map<String, List<InstallerVersion>> versionMap;
public List<InstallerVersion> versions;
@Override
public Task refresh(String[] needed) {
if (root != null)
return null;
return new TaskInfo(C.i18n("install.liteloader.get_list")) {
HTTPGetTask task = new HTTPGetTask(C.URL_LITELOADER_LIST);
@Override
public Collection<Task> getDependTasks() {
return Arrays.asList(task);
}
@Override
public void executeTask() throws Throwable {
if (!areDependTasksSucceeded)
return;
String s = task.getResult();
root = C.GSON.fromJson(s, LiteLoaderVersionsRoot.class);
versionMap = new HashMap<>();
versions = new ArrayList<>();
for (Map.Entry<String, LiteLoaderMCVersions> arr : root.versions.entrySet()) {
ArrayList<InstallerVersion> al = new ArrayList<>();
LiteLoaderMCVersions mcv = arr.getValue();
if (mcv == null || mcv.artefacts == null || mcv.artefacts.get("com.mumfrey:liteloader") == null)
continue;
for (Map.Entry<String, LiteLoaderVersion> entry : mcv.artefacts.get("com.mumfrey:liteloader").entrySet()) {
if ("latest".equals(entry.getKey()))
continue;
LiteLoaderVersion v = entry.getValue();
LiteLoaderInstallerVersion iv = new LiteLoaderInstallerVersion(v.version, StrUtils.formatVersion(arr.getKey()));
iv.universal = "http://dl.liteloader.com/versions/com/mumfrey/liteloader/" + arr.getKey() + "/" + v.file;
iv.tweakClass = v.tweakClass;
iv.libraries = Arrays.copyOf(v.libraries, v.libraries.length);
iv.installer = "http://dl.liteloader.com/redist/" + iv.mcVersion + "/liteloader-installer-" + iv.selfVersion.replace("_", "-") + ".jar";
al.add(iv);
versions.add(iv);
}
Collections.sort(al, new InstallerVersionNewerComparator());
versionMap.put(StrUtils.formatVersion(arr.getKey()), al);
}
Collections.sort(versions, InstallerVersionComparator.INSTANCE);
}
};
}
@Override
public List<InstallerVersion> getVersionsImpl(String mcVersion) {
if (versions == null || versionMap == null)
return null;
if (StrUtils.isBlank(mcVersion))
return versions;
List c = versionMap.get(mcVersion);
if (c == null)
return versions;
Collections.sort(c, InstallerVersionComparator.INSTANCE);
return c;
}
@Override
public String getName() {
return "LiteLoader - LiteLoader Official Site(By: Mumfrey)";
}
public static class LiteLoaderInstallerVersion extends InstallerVersion {
public MinecraftLibrary[] libraries;
public String tweakClass;
public LiteLoaderInstallerVersion(String selfVersion, String mcVersion) {
super(selfVersion, mcVersion);
}
}
}
@@ -1,100 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.optifine;
import java.io.File;
import java.util.ArrayList;
import java.util.zip.ZipFile;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.communication.PreviousResult;
import org.jackhuang.hellominecraft.util.tasks.communication.PreviousResultRegistrar;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftLibrary;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
/**
*
* @author huangyuhui
*/
public class OptiFineInstaller extends Task implements PreviousResultRegistrar<File> {
public File installer;
public IMinecraftService service;
public InstallerVersionList.InstallerVersion version;
public String installId;
public OptiFineInstaller(IMinecraftService service, String installId, InstallerVersionList.InstallerVersion version) {
this(service, installId, version, null);
}
public OptiFineInstaller(IMinecraftService service, String installId, InstallerVersionList.InstallerVersion version, File installer) {
this.service = service;
this.installId = installId;
this.installer = installer;
this.version = version;
}
@Override
public void executeTask() throws Exception {
if (installId == null)
throw new Exception(C.i18n("install.no_version"));
String selfId = version.selfVersion;
MinecraftVersion mv = (MinecraftVersion) service.version().getVersionById(installId).clone();
mv.inheritsFrom = mv.id;
mv.jar = mv.jar == null ? mv.id : mv.jar;
mv.libraries.clear();
mv.libraries.add(0, new MinecraftLibrary("optifine:OptiFine:" + selfId));
FileUtils.copyFile(installer, new File(service.baseDirectory(), "libraries/optifine/OptiFine/" + selfId + "/OptiFine-" + selfId + ".jar"));
mv.id += "-" + selfId;
try (ZipFile zipFile = new ZipFile(installer)) {
if (zipFile.getEntry("optifine/OptiFineTweaker.class") != null) {
if (!mv.mainClass.startsWith("net.minecraft.launchwrapper.")) {
mv.mainClass = "net.minecraft.launchwrapper.Launch";
mv.libraries.add(1, new MinecraftLibrary("net.minecraft:launchwrapper:1.7"));
}
mv.minecraftArguments += " --tweakClass optifine.OptiFineTweaker";
}
}
File loc = new File(service.baseDirectory(), "versions/" + mv.id);
if (!loc.exists() && loc.mkdirs())
HMCLog.warn("Failed to make directories: " + loc);
File json = new File(loc, mv.id + ".json");
FileUtils.writeStringToFile(json, C.GSON.toJson(mv, MinecraftVersion.class));
service.version().refreshVersions();
}
@Override
public String getInfo() {
return "OptiFine Installer";
}
ArrayList<PreviousResult<File>> pre = new ArrayList();
@Override
public Task registerPreviousResult(PreviousResult pr) {
pre.add(pr);
return this;
}
}
@@ -1,67 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.optifine;
/**
*
* @author huangyuhui
*/
public class OptiFineVersion {
private String dl, ver, date, mirror, mcver;
public String getDownloadLink() {
return dl;
}
public void setDownloadLink(String dl) {
this.dl = dl;
}
public String getVersion() {
return ver;
}
public void setVersion(String ver) {
this.ver = ver;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getMirror() {
return mirror;
}
public void setMirror(String mirror) {
this.mirror = mirror;
}
public String getMCVersion() {
return mcver;
}
public void setMCVersion(String mcver) {
this.mcver = mcver;
}
}
@@ -1,122 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.optifine.bmcl;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.ArrayUtils;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
import org.jackhuang.hellominecraft.launcher.core.install.optifine.OptiFineVersion;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
import org.jackhuang.hellominecraft.util.tasks.download.HTTPGetTask;
/**
*
* @author huangyuhui
*/
public class OptiFineBMCLVersionList extends InstallerVersionList {
private static OptiFineBMCLVersionList instance;
public static OptiFineBMCLVersionList getInstance() {
if (null == instance)
instance = new OptiFineBMCLVersionList();
return instance;
}
public ArrayList<OptiFineVersion> root;
public Map<String, List<InstallerVersion>> versionMap;
public List<InstallerVersion> versions;
private static final Type TYPE = new TypeToken<ArrayList<OptiFineVersion>>() {
}.getType();
@Override
public Task refresh(String[] needed) {
return new TaskInfo(C.i18n("install.optifine.get_list")) {
HTTPGetTask task = new HTTPGetTask("http://bmclapi.bangbang93.com/optifine/versionlist");
@Override
public Collection<Task> getDependTasks() {
return Arrays.asList(task);
}
@Override
public void executeTask() throws Throwable {
String s = task.getResult();
versionMap = new HashMap<>();
versions = new ArrayList<>();
if (s == null)
return;
root = C.GSON.fromJson(s, TYPE);
for (OptiFineVersion v : root) {
v.setMirror(v.getMirror().replace("http://optifine.net/http://optifine.net/", "http://optifine.net/"));
if (StrUtils.isBlank(v.getMCVersion())) {
Pattern p = Pattern.compile("OptiFine (.*) HD");
Matcher m = p.matcher(v.getVersion());
while (m.find())
v.setMCVersion(m.group(1));
}
InstallerVersion iv = new InstallerVersion(v.getVersion(), StrUtils.formatVersion(v.getMCVersion()));
List<InstallerVersion> al = ArrayUtils.tryGetMapWithList(versionMap, StrUtils.formatVersion(v.getMCVersion()));
//String url = "http://bmclapi.bangbang93.com/optifine/" + iv.selfVersion.replace(" ", "%20");
iv.installer = iv.universal = v.getMirror();
al.add(iv);
versions.add(iv);
}
Collections.sort(versions, InstallerVersionComparator.INSTANCE);
}
};
}
@Override
public List<InstallerVersion> getVersionsImpl(String mcVersion) {
if (versions == null || versionMap == null)
return null;
if (StrUtils.isBlank(mcVersion))
return versions;
List c = versionMap.get(mcVersion);
if (c == null)
return versions;
Collections.sort(c, InstallerVersionComparator.INSTANCE);
return c;
}
@Override
public String getName() {
return "OptiFine - BMCLAPI(By: bangbang93)";
}
}
@@ -1,58 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.optifine.vanilla;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.communication.PreviousResult;
import org.jackhuang.hellominecraft.util.NetUtils;
/**
*
* @author huangyuhui
*/
public class OptiFineDownloadFormatter extends Task implements PreviousResult<String> {
String url, result;
public OptiFineDownloadFormatter(String url) {
this.url = url;
}
@Override
public void executeTask() throws Exception {
String content = NetUtils.get(url);
Pattern p = Pattern.compile("\"downloadx\\?f=OptiFine(.*)\"");
Matcher m = p.matcher(content);
while (m.find())
result = m.group(1);
result = "http://optifine.net/downloadx?f=OptiFine" + result;
}
@Override
public String getInfo() {
return C.i18n("install.optifine.get_download_link");
}
@Override
public String getResult() {
return result;
}
}
@@ -1,155 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.install.optifine.vanilla;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
import org.jackhuang.hellominecraft.launcher.core.install.optifine.OptiFineVersion;
import org.jackhuang.hellominecraft.util.ArrayUtils;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
import org.jackhuang.hellominecraft.util.tasks.download.HTTPGetTask;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
*
* @author huangyuhui
*/
public class OptiFineVersionList extends InstallerVersionList {
private static OptiFineVersionList instance;
public static OptiFineVersionList getInstance() {
if (null == instance)
instance = new OptiFineVersionList();
return instance;
}
public ArrayList<OptiFineVersion> root = new ArrayList();
public Map<String, List<InstallerVersion>> versionMap;
public List<InstallerVersion> versions;
@Override
public Task refresh(String[] sss) {
if (versions != null)
return null;
return new TaskInfo(C.i18n("install.optifine.get_list")) {
HTTPGetTask task = new HTTPGetTask("http://optifine.net/downloads");
@Override
public Collection<Task> getDependTasks() {
return Arrays.asList(task);
}
@Override
public void executeTask() throws Throwable {
if (!areDependTasksSucceeded)
return;
String content = task.getResult();
versionMap = new HashMap<>();
versions = new ArrayList<>();
content = content.replace("&nbsp;", " ").replace("&gt;", ">").replace("&lt;", "<").replace("<br>", "<br />");
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
Document doc = db.parse(new ByteArrayInputStream(content.getBytes("UTF-8")));
Element r = doc.getDocumentElement();
NodeList tables = r.getElementsByTagName("table");
for (int i = 0; i < tables.getLength(); i++) {
Element e = (Element) tables.item(i);
if ("downloadTable".equals(e.getAttribute("class"))) {
NodeList tr = e.getElementsByTagName("tr");
for (int k = 0; k < tr.getLength(); k++) {
NodeList downloadLine = ((Element) tr.item(k)).getElementsByTagName("td");
OptiFineVersion v = new OptiFineVersion();
for (int j = 0; j < downloadLine.getLength(); j++) {
Element td = (Element) downloadLine.item(j);
if (StrUtils.startsWith(td.getAttribute("class"), "downloadLineMirror"))
v.setMirror(((Element) td.getElementsByTagName("a").item(0)).getAttribute("href"));
if (StrUtils.startsWith(td.getAttribute("class"), "downloadLineDownload"))
v.setDownloadLink(((Element) td.getElementsByTagName("a").item(0)).getAttribute("href"));
if (StrUtils.startsWith(td.getAttribute("class"), "downloadLineDate"))
v.setDate(td.getTextContent());
if (StrUtils.startsWith(td.getAttribute("class"), "downloadLineFile"))
v.setVersion(td.getTextContent());
}
if (StrUtils.isBlank(v.getMCVersion())) {
Pattern p = Pattern.compile("OptiFine (.*?) ");
Matcher m = p.matcher(v.getVersion());
while (m.find())
v.setMCVersion(StrUtils.formatVersion(m.group(1)));
}
InstallerVersion iv = new InstallerVersion(v.getVersion(), StrUtils.formatVersion(v.getMCVersion()));
iv.installer = iv.universal = v.getMirror();
root.add(v);
versions.add(iv);
List<InstallerVersion> ivl = ArrayUtils.tryGetMapWithList(versionMap, StrUtils.formatVersion(v.getMCVersion()));
ivl.add(iv);
}
}
}
} catch (ParserConfigurationException | SAXException | IOException | DOMException ex) {
throw new RuntimeException(ex);
}
Collections.sort(versions, InstallerVersionComparator.INSTANCE);
}
};
}
@Override
public String getName() {
return "OptiFine - OptiFine Official Site";
}
@Override
public List<InstallerVersion> getVersionsImpl(String mcVersion) {
if (versions == null || versionMap == null)
return null;
if (StrUtils.isBlank(mcVersion))
return versions;
List c = versionMap.get(mcVersion);
if (c == null)
return versions;
Collections.sort(c, InstallerVersionComparator.INSTANCE);
return c;
}
}
@@ -1,197 +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.core.launch;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.system.JdkVersion;
import org.jackhuang.hellominecraft.util.MathUtils;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.system.OS;
import org.jackhuang.hellominecraft.util.system.Platform;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.Utils;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.auth.UserProfileProvider;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftLoader;
/**
*
* @author huangyuhui
*/
public abstract class AbstractMinecraftLoader implements IMinecraftLoader {
protected LaunchOptions options;
protected UserProfileProvider lr;
protected File gameDir;
protected IMinecraftService service;
protected final MinecraftVersion version;
public AbstractMinecraftLoader(LaunchOptions options, IMinecraftService service, String versionId, UserProfileProvider lr) throws GameException {
if (service.version().getVersionById(versionId) == null)
throw new GameException("No version: " + versionId);
this.lr = lr;
this.options = options;
this.service = service;
this.gameDir = service.baseDirectory();
this.version = service.version().getVersionById(versionId).resolve(service.version());
}
@Override
public MinecraftVersion getMinecraftVersion() {
return version;
}
public void makeHeadCommand(List<String> res) {
HMCLog.log("On making head command.");
if (StrUtils.isNotBlank(options.getWrapper()))
res.add(options.getWrapper());
JdkVersion jv = options.getJava();
res.add(options.getJavaDir());
if (options.hasJavaArgs())
res.addAll(Arrays.asList(StrUtils.tokenize(options.getJavaArgs())));
if (!options.isNoJVMArgs()) {
appendJVMArgs(res);
if (jv == null || !jv.isEarlyAccess()) {
if (OS.os() == OS.WINDOWS)
res.add("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump");
if (jv != null && jv.getParsedVersion() >= JdkVersion.JAVA_17)
res.add("-XX:+UseG1GC");
else
res.add("-Xincgc");
res.add("-XX:-UseAdaptiveSizePolicy");
res.add("-XX:-OmitStackTraceInFastThrow");
res.add("-Xmn128m");
}
if (!StrUtils.isBlank(options.getPermSize()))
if (jv == null || jv.getParsedVersion() < JdkVersion.JAVA_18)
res.add("-XX:PermSize=" + options.getPermSize() + "m");
else if (jv.getParsedVersion() >= JdkVersion.JAVA_18)
res.add("-XX:MetaspaceSize=" + options.getPermSize() + "m");
}
if (jv != null) {
HMCLog.log("Java Version: " + jv.getVersion());
HMCLog.log("Java Platform: " + jv.getPlatform().getBit());
}
HMCLog.log("System Platform: " + Platform.getPlatform().getBit());
if (jv != null && jv.getPlatform() == Platform.BIT_32 && Platform.getPlatform() == Platform.BIT_64)
MessageBox.Show(C.i18n("advice.os64butjdk32"));
if (!StrUtils.isBlank(options.getMaxMemory())) {
int mem = MathUtils.parseMemory(options.getMaxMemory(), 2147483647);
if (jv != null && jv.getPlatform() == Platform.BIT_32 && mem > 1024)
MessageBox.Show(C.i18n("launch.too_big_memory_alloc_64bit"));
else {
long a = OS.getTotalPhysicalMemory() / 1024 / 1024;
HMCLog.log("System Physical Memory: " + a);
if (a > 0 && a < mem)
MessageBox.Show(C.i18n("launch.too_big_memory_alloc_free_space_too_low", a));
}
String a = "-Xmx" + options.getMaxMemory();
if (MathUtils.canParseInt(options.getMaxMemory()))
a += "m";
res.add(a);
}
res.add("-Djava.library.path=" + service.version().getDecompressNativesToLocation(version).getPath());
res.add("-Dfml.ignoreInvalidMinecraftCertificates=true");
res.add("-Dfml.ignorePatchDiscrepancies=true");
if (OS.os() != OS.WINDOWS)
res.add("-Duser.home=" + gameDir.getParent());
}
@Override
public List<String> makeLaunchingCommand() throws GameException {
HMCLog.log("*** Make shell command ***");
ArrayList<String> res = new ArrayList<>();
makeHeadCommand(res);
makeSelf(res);
HMCLog.log("On making launcher args.");
if (StrUtils.isNotBlank(options.getHeight()) && StrUtils.isNotBlank(options.getWidth())) {
res.add("--height");
res.add(options.getHeight());
res.add("--width");
res.add(options.getWidth());
}
String serverIp = options.getServerIp();
if (StrUtils.isNotBlank(serverIp)) {
String[] args = serverIp.split(":");
res.add("--server");
res.add(args[0]);
res.add("--port");
res.add(args.length > 1 ? args[1] : "25565");
}
if (options.isFullscreen())
res.add("--fullscreen");
if (StrUtils.isNotBlank(options.getProxyHost()) && StrUtils.isNotBlank(options.getProxyPort()) && MathUtils.canParseInt(options.getProxyPort())) {
res.add("--proxyHost");
res.add(options.getProxyHost());
res.add("--proxyPort");
res.add(options.getProxyPort());
if (StrUtils.isNotBlank(options.getProxyUser()) && StrUtils.isNotBlank(options.getProxyPass())) {
res.add("--proxyUser");
res.add(options.getProxyUser());
res.add("-=proxyPass");
res.add(options.getProxyPass());
}
}
if (StrUtils.isNotBlank(options.getMinecraftArgs()))
res.addAll(Arrays.asList(options.getMinecraftArgs().split(" ")));
return res;
}
/**
* You must do these things:
* <ul>
* <li>minecraft class path</li>
* <li>main class</li>
* <li>minecraft arguments</li>
* </ul>
*
* @param list the command list you shoud edit.
*/
protected abstract void makeSelf(List<String> list) throws GameException;
protected void appendJVMArgs(List<String> list) {
}
}
@@ -1,72 +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.core.launch;
import java.io.IOException;
import java.util.HashSet;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.auth.IAuthenticator;
import org.jackhuang.hellominecraft.launcher.core.auth.LoginInfo;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadLibraryJob;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.util.tasks.ParallelTask;
import org.jackhuang.hellominecraft.util.tasks.TaskWindow;
import org.jackhuang.hellominecraft.util.system.Compressor;
import org.jackhuang.hellominecraft.util.MessageBox;
public class DefaultGameLauncher extends GameLauncher {
public DefaultGameLauncher(LaunchOptions options, IMinecraftService service, LoginInfo info, IAuthenticator lg) {
super(options, service, info, lg);
register();
}
private void register() {
downloadLibrariesEvent.register((sender, t) -> {
final TaskWindow.TaskWindowFactory dw = TaskWindow.factory();
ParallelTask parallelTask = new ParallelTask();
HashSet<String> names = new HashSet<>();
for (DownloadLibraryJob s : t) {
if (names.contains(s.lib.name))
continue;
names.add(s.lib.name);
parallelTask.addDependsTask(new LibraryDownloadTask(s));
}
dw.append(parallelTask);
boolean flag = true;
if (t.size() > 0)
flag = dw.create();
if (!flag && MessageBox.Show(C.i18n("launch.not_finished_downloading_libraries"), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
flag = true;
return flag;
});
decompressNativesEvent.register((sender, value) -> {
if (value == null)
return false;
for (int i = 0; i < value.decompressFiles.length; i++)
try {
Compressor.unzip(value.decompressFiles[i], value.getDecompressTo(), value.extractRules[i]::allow, false);
} catch (IOException ex) {
HMCLog.err("Unable to decompress library: " + value.decompressFiles[i] + " to " + value.getDecompressTo(), ex);
}
return true;
});
}
}
@@ -1,194 +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.core.launch;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftLoader;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.api.PluginManager;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.auth.IAuthenticator;
import org.jackhuang.hellominecraft.launcher.core.auth.LoginInfo;
import org.jackhuang.hellominecraft.launcher.core.auth.UserProfileProvider;
import org.jackhuang.hellominecraft.launcher.core.auth.AuthenticationException;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadLibraryJob;
import org.jackhuang.hellominecraft.launcher.core.version.DecompressLibraryJob;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.system.JavaProcess;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.system.OS;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.EventHandler;
import org.jackhuang.hellominecraft.util.system.ProcessManager;
public class GameLauncher {
public static final ProcessManager PROCESS_MANAGER = new ProcessManager();
LaunchOptions options;
IMinecraftService service;
LoginInfo info;
UserProfileProvider result;
IAuthenticator login;
public final EventHandler<List<DownloadLibraryJob>> downloadLibrariesEvent = new EventHandler<>(this);
public final EventHandler<List<String>> successEvent = new EventHandler<>(this);
public final EventHandler<JavaProcess> launchEvent = new EventHandler<>(this);
public final EventHandler<LaunchingState> launchingStateChangedEvent = new EventHandler<>(this);
public final EventHandler<DecompressLibraryJob> decompressNativesEvent = new EventHandler<>(this);
public GameLauncher(LaunchOptions options, IMinecraftService version, LoginInfo info, IAuthenticator lg) {
this.options = options;
this.service = version;
this.info = info;
this.login = lg;
}
private Object tag;
public Object getTag() {
return tag;
}
public void setTag(Object tag) {
this.tag = tag;
}
public IMinecraftLoader makeLaunchCommand() throws AuthenticationException, GameException {
HMCLog.log("Building process");
HMCLog.log("Logging in...");
launchingStateChangedEvent.execute(LaunchingState.LoggingIn);
IMinecraftLoader loader;
if (info != null)
result = login.login(info);
else
result = login.loginBySettings();
if (result == null)
throw new AuthenticationException("Result can not be null.");
PluginManager.plugin().onProcessingLoginResult(result);
launchingStateChangedEvent.execute(LaunchingState.GeneratingLaunchingCodes);
loader = service.launch(options, result);
File file = service.version().getDecompressNativesToLocation(loader.getMinecraftVersion());
if (file != null)
FileUtils.cleanDirectoryQuietly(file);
if (!options.isNotCheckGame()) {
HMCLog.log("Detecting libraries...");
launchingStateChangedEvent.execute(LaunchingState.DownloadingLibraries);
if (!downloadLibrariesEvent.execute(service.download().getDownloadLibraries(loader.getMinecraftVersion())))
throw new GameException("Failed to download libraries");
}
HMCLog.log("Unpacking natives...");
launchingStateChangedEvent.execute(LaunchingState.DecompressingNatives);
DecompressLibraryJob job = service.version().getDecompressLibraries(loader.getMinecraftVersion());
if (!decompressNativesEvent.execute(job))
throw new GameException("Failed to decompress natives");
successEvent.execute(loader.makeLaunchingCommand());
return loader;
}
/**
* Launch the game "as soon as possible".
*
* @param str launch command
*
* @throws IOException failed creating process
*/
public void launch(List str) throws IOException {
if (!service.version().onLaunch())
return;
if (StrUtils.isNotBlank(options.getPrecalledCommand())) {
Process p = Runtime.getRuntime().exec(options.getPrecalledCommand());
try {
if (p.isAlive())
p.waitFor();
} catch (InterruptedException ex) {
HMCLog.warn("Failed to invoke precalled command", ex);
}
}
HMCLog.log("Starting process");
ProcessBuilder builder = new ProcessBuilder(str);
if (options.getLaunchVersion() == null || service.baseDirectory() == null)
throw new Error("Fucking bug!");
builder.redirectErrorStream(true).directory(service.version().getRunDirectory(options.getLaunchVersion()))
.environment().put("APPDATA", service.baseDirectory().getAbsolutePath());
JavaProcess jp = new JavaProcess(str, builder.start(), PROCESS_MANAGER);
HMCLog.log("Have started the process");
launchEvent.execute(jp);
}
/**
* According to the name...
*
* @param launcherName the name of launch bat/sh
* @param str launch command
*
* @return launcher location
*
* @throws java.io.IOException write contents failed.
*/
public File makeLauncher(String launcherName, List str) throws IOException {
HMCLog.log("Making shell launcher...");
service.version().onLaunch();
boolean isWin = OS.os() == OS.WINDOWS;
File f = new File(launcherName + (isWin ? ".bat" : ".sh"));
if (!f.exists() && !f.createNewFile())
HMCLog.warn("Failed to create " + f);
BufferedWriter writer;
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), System.getProperty("sun.jnu.encoding", "UTF-8")));
} catch (UnsupportedEncodingException ex) {
HMCLog.warn("Failed to create writer, will try again.", ex);
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
}
if (isWin) {
writer.write("@echo off");
writer.newLine();
String appdata = IOUtils.tryGetCanonicalFilePath(service.baseDirectory());
if (appdata != null) {
writer.write("set appdata=" + appdata);
writer.newLine();
}
}
if (StrUtils.isNotBlank(options.getPrecalledCommand())) {
writer.write(options.getPrecalledCommand());
writer.newLine();
}
writer.write(StrUtils.makeCommand(str));
writer.close();
if (!f.setExecutable(true)) {
HMCLog.warn("Failed to give launcher permission.");
MessageBox.Show(C.i18n("launch.failed_sh_permission"));
}
HMCLog.log("Command: " + StrUtils.parseParams("", str, " "));
return f;
}
}
@@ -1,233 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.launch;
import java.io.File;
import org.jackhuang.hellominecraft.launcher.core.version.GameDirType;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.system.JdkVersion;
/**
*
* @author huangyuhui
*/
public class LaunchOptions {
private String name, versionName, javaArgs, minecraftArgs, maxMemory, permSize, width, height, serverIp, wrapper;
private String proxyHost, proxyPort, proxyUser, proxyPass, javaDir, launchVersion, type, precalledCommand;
private boolean fullscreen, noJVMArgs, notCheckGame;
private JdkVersion java;
private File gameDir;
private GameDirType gameDirType;
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
public File getGameDir() {
return gameDir;
}
public void setGameDir(File gameDir) {
this.gameDir = gameDir;
}
public void setJavaDir(String javaDir) {
this.javaDir = javaDir;
}
public String getJavaDir() {
return javaDir;
}
public JdkVersion getJava() {
return java;
}
public void setJava(JdkVersion java) {
this.java = java;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJavaArgs() {
return javaArgs;
}
public void setJavaArgs(String javaArgs) {
this.javaArgs = javaArgs;
}
public boolean hasJavaArgs() {
return StrUtils.isNotBlank(getJavaArgs().trim());
}
public String getMaxMemory() {
return maxMemory;
}
public void setMaxMemory(String maxMemory) {
this.maxMemory = maxMemory;
}
public String getWrapper() {
return wrapper;
}
public void setWrapper(String wrapper) {
this.wrapper = wrapper;
}
public String getWidth() {
return width;
}
public void setWidth(String width) {
this.width = width;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public boolean isFullscreen() {
return fullscreen;
}
public void setFullscreen(boolean fullscreen) {
this.fullscreen = fullscreen;
}
public GameDirType getGameDirType() {
return gameDirType;
}
public void setGameDirType(GameDirType gameDirType) {
this.gameDirType = gameDirType;
}
public String getPermSize() {
return permSize;
}
public void setPermSize(String permSize) {
this.permSize = permSize;
}
public boolean isNoJVMArgs() {
return noJVMArgs;
}
public void setNoJVMArgs(boolean noJVMArgs) {
this.noJVMArgs = noJVMArgs;
}
public String getMinecraftArgs() {
return minecraftArgs;
}
public void setMinecraftArgs(String minecraftArgs) {
this.minecraftArgs = minecraftArgs;
}
public String getServerIp() {
return serverIp;
}
public void setServerIp(String serverIp) {
this.serverIp = serverIp;
}
public String getProxyHost() {
return proxyHost;
}
public void setProxyHost(String proxyHost) {
this.proxyHost = proxyHost;
}
public String getProxyPort() {
return proxyPort;
}
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
}
public String getProxyUser() {
return proxyUser;
}
public void setProxyUser(String proxyUser) {
this.proxyUser = proxyUser;
}
public String getProxyPass() {
return proxyPass;
}
public void setProxyPass(String proxyPass) {
this.proxyPass = proxyPass;
}
public String getPrecalledCommand() {
return precalledCommand;
}
public void setPrecalledCommand(String precalledCommand) {
this.precalledCommand = precalledCommand;
}
public String getLaunchVersion() {
return launchVersion;
}
public void setLaunchVersion(String launchVersion) {
this.launchVersion = launchVersion;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isNotCheckGame() {
return notCheckGame;
}
public void setNotCheckGame(boolean notCheckGame) {
this.notCheckGame = notCheckGame;
}
}
@@ -1,66 +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.core.launch;
import java.io.File;
import java.net.URL;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadLibraryJob;
import org.jackhuang.hellominecraft.util.tasks.download.FileDownloadTask;
/**
*
* @author huangyuhui
*/
public class LibraryDownloadTask extends FileDownloadTask {
DownloadLibraryJob job;
public LibraryDownloadTask(DownloadLibraryJob job) {
super();
this.job = job;
}
@Override
public void executeTask() throws Throwable {
String name = job.lib.name;
if (name.startsWith("net.minecraftforge:forge:")) {
String[] s = name.split(":");
if (s.length == 3)
job.url = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/" + s[2] + "/forge-" + s[2] + "-universal.jar";
}
if (name.startsWith("com.mumfrey:liteloader:")) {
String[] s = name.split(":");
if (s.length == 3 && s[2].length() > 3)
job.url = "http://dl.liteloader.com/versions/com/mumfrey/liteloader/" + s[2].substring(0, s[2].length() - 3) + "/liteloader-" + s[2] + ".jar";
}
download(new URL(job.url), job.path);
}
void download(URL url, File filePath) throws Throwable {
this.url = url;
this.filePath = filePath;
super.executeTask();
}
@Override
public String getInfo() {
return C.i18n("download") + ": " + job.lib.name;
}
}
@@ -1,111 +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.core.launch;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.system.OS;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.auth.UserProfileProvider;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftLibrary;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.util.func.BiFunction;
/**
*
* @author huangyuhui
*/
public class MinecraftLoader extends AbstractMinecraftLoader {
public MinecraftLoader(LaunchOptions p, IMinecraftService provider, UserProfileProvider lr) throws GameException {
super(p, provider, p.getLaunchVersion(), lr);
}
@Override
protected void makeSelf(List<String> res) throws GameException {
StringBuilder library = new StringBuilder("");
for (MinecraftLibrary l : version.libraries)
if (l.allow() && !l.isRequiredToUnzip())
library.append(l.getFilePath(gameDir).getAbsolutePath()).append(File.pathSeparator);
File f = version.getJar(service.baseDirectory());
if (!f.exists())
throw new GameException("Minecraft jar does not exists");
library.append(IOUtils.tryGetCanonicalFilePath(f)).append(File.pathSeparator);
res.add("-cp");
res.add(library.toString().substring(0, library.length() - File.pathSeparator.length()));
res.add(version.mainClass);
String[] splitted = StrUtils.tokenize(version.minecraftArguments);
String game_assets = assetProvider.apply(version, !options.isNotCheckGame());
for (String t : splitted) {
t = t.replace("${auth_player_name}", lr.getUserName());
t = t.replace("${auth_session}", lr.getSession());
t = t.replace("${auth_uuid}", lr.getUserId());
t = t.replace("${version_name}", options.getVersionName());
t = t.replace("${profile_name}", options.getName());
t = t.replace("${version_type}", options.getType());
t = t.replace("${game_directory}", service.version().getRunDirectory(version.id).getAbsolutePath());
t = t.replace("${game_assets}", game_assets);
t = t.replace("${assets_root}", service.asset().getAssets().getAbsolutePath());
t = t.replace("${auth_access_token}", lr.getAccessToken());
t = t.replace("${user_type}", lr.getUserType());
t = t.replace("${assets_index_name}", version.getAssetsIndex().getId());
t = t.replace("${user_properties}", lr.getUserProperties());
res.add(t);
}
if (res.indexOf("--gameDir") != -1 && res.indexOf("--workDir") != -1) {
res.add("--workDir");
res.add(gameDir.getAbsolutePath());
}
}
@Override
protected void appendJVMArgs(List<String> list) {
super.appendJVMArgs(list);
try {
if (OS.os() == OS.OSX) {
list.add("-Xdock:icon=" + service.asset().getAssetObject(version.getAssetsIndex().getId(), "icons/minecraft.icns").getAbsolutePath());
list.add("-Xdock:name=Minecraft");
}
} catch (IOException e) {
HMCLog.err("Failed to append jvm arguments when searching for asset objects.", e);
}
}
private final BiFunction<MinecraftVersion, Boolean, String> DEFAULT_ASSET_PROVIDER = (t, allow) -> {
return new File(service.baseDirectory(), "assets").getAbsolutePath();
};
private BiFunction<MinecraftVersion, Boolean, String> assetProvider = DEFAULT_ASSET_PROVIDER;
public void setAssetProvider(BiFunction<MinecraftVersion, Boolean, String> assetProvider) {
if (assetProvider == null)
this.assetProvider = DEFAULT_ASSET_PROVIDER;
else
this.assetProvider = assetProvider;
}
}
@@ -1,117 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.mod;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftModService;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.util.code.DigestUtils;
import org.jackhuang.hellominecraft.util.system.FileUtils;
/**
*
* @author huangyuhui
*/
public class MinecraftModService extends IMinecraftModService {
Map<String, List<ModInfo>> modCache = Collections.synchronizedMap(new HashMap<>());
public MinecraftModService(IMinecraftService service) {
super(service);
}
@Override
public List<ModInfo> getMods(String id) {
if (modCache.containsKey(id))
return modCache.get(id);
else
return recacheMods(id);
}
@Override
public List<ModInfo> recacheMods(String id) {
File modsFolder = service.version().getRunDirectory(id, "mods");
ArrayList<ModInfo> mods = new ArrayList<>();
File[] fs = modsFolder.listFiles();
if (fs != null)
for (File f : fs)
if (ModInfo.isFileMod(f))
mods.add(ModInfo.readModInfo(f));
else if (f.isDirectory()) {
File[] ss = f.listFiles();
if (ss != null)
for (File ff : ss)
if (ModInfo.isFileMod(ff))
mods.add(ModInfo.readModInfo(ff));
}
Collections.sort(mods);
modCache.put(id, mods);
return mods;
}
@Override
public boolean addMod(String id, File f) {
try {
if (!ModInfo.isFileMod(f))
return false;
if (!modCache.containsKey(id))
recacheMods(id);
File modsFolder = service.version().getRunDirectory(id, "mods");
if (!modsFolder.exists() && !modsFolder.mkdirs())
HMCLog.warn("Failed to make directories: " + modsFolder);
File newf = new File(modsFolder, f.getName());
FileUtils.copyFile(f, newf);
ModInfo i = ModInfo.readModInfo(f);
modCache.get(id).add(i);
return true;
} catch (IOException ex) {
HMCLog.warn("Failed to copy mod", ex);
return false;
}
}
@Override
public void removeMod(String id, Object[] rows) {
if (rows.length == 0)
return;
for (Object r : rows)
if (r instanceof ModInfo) {
if (!((ModInfo) r).location.delete())
HMCLog.warn("Failed to delete mod" + r);
} else if (r instanceof Number)
if (!getMods(id).get(((Number) r).intValue()).location.delete())
HMCLog.warn("Failed to delete mod " + r + ", maybe not a file?");
recacheMods(id);
}
public String[] checkMd5s(String id) throws IOException {
String[] res = new String[getMods(id).size()];
for (int i = 0; i < res.length; i++)
res[i] = DigestUtils.md5Hex(new FileInputStream(getMods(id).get(i).location));
return res;
}
}
@@ -1,147 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.mod;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.system.FileUtils;
/**
*
* @author huangyuhui
*/
public class ModInfo implements Comparable<ModInfo> {
public File location;
public String modid, name, description, author, version, mcversion, url, updateUrl, credits;
public String[] authorList;
public boolean isActive() {
return !location.getName().endsWith(".disabled");
}
public void reverseModState() {
File f = location, newf;
if (f.getName().endsWith(".disabled"))
newf = new File(f.getParentFile(), f.getName().substring(0, f.getName().length() - ".disabled".length()));
else
newf = new File(f.getParentFile(), f.getName() + ".disabled");
if (f.renameTo(newf))
location = newf;
}
@Override
public int compareTo(ModInfo o) {
return getFileName().compareToIgnoreCase(o.getFileName());
}
public String getName() {
return name == null ? FileUtils.removeExtension(location.getName()) : name;
}
public String getAuthor() {
if (authorList != null && authorList.length > 0)
return StrUtils.parseParams("", authorList, ", ");
else if (StrUtils.isNotBlank(author))
return author;
else
return "Unknown";
}
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof ModInfo && (((ModInfo) obj).location == location || ((ModInfo) obj).location.equals(location));
}
@Override
public int hashCode() {
return location.hashCode();
}
@Override
public String toString() {
return getFileName();
}
public String getFileName() {
String n = location.getName();
return FileUtils.removeExtension(isActive() ? n : n.substring(0, n.length() - ".disabled".length()));
}
public static boolean isFileMod(File file) {
if (file == null)
return false;
String name = file.getName();
boolean disabled = name.endsWith(".disabled");
if (disabled)
name = name.substring(0, name.length() - ".disabled".length());
return name.endsWith(".zip") || name.endsWith(".jar") || name.endsWith("litemod");
}
private static final Type TYPE = new TypeToken<List<ModInfo>>() {
}.getType();
private static ModInfo getForgeModInfo(File f, ZipFile jar, ZipEntry entry) throws IOException {
ModInfo i = new ModInfo();
i.location = f;
List<ModInfo> m = C.GSON.fromJson(new InputStreamReader(jar.getInputStream(entry), "UTF-8"), TYPE);
if (m != null && m.size() > 0) {
i = m.get(0);
i.location = f;
}
return i;
}
private static ModInfo getLiteLoaderModInfo(File f, ZipFile jar, ZipEntry entry) throws IOException {
ModInfo m = C.GSON.fromJson(new InputStreamReader(jar.getInputStream(entry), "UTF-8"), ModInfo.class);
if (m == null)
m = new ModInfo();
m.location = f;
return m;
}
public static ModInfo readModInfo(File f) {
ModInfo i = new ModInfo();
i.location = f;
try {
try (ZipFile jar = new ZipFile(f)) {
ZipEntry entry = jar.getEntry("mcmod.info");
if (entry != null)
return getForgeModInfo(f, jar, entry);
entry = jar.getEntry("litemod.json");
if (entry != null)
return getLiteLoaderModInfo(f, jar, entry);
return i;
}
} catch (IOException ex) {
HMCLog.warn("File " + f + " is not a jar.", ex);
} catch (JsonSyntaxException ignore) {
}
return i;
}
}
@@ -1,283 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.mod;
import java.awt.Dimension;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.FileSystemException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipFile;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftProvider;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.func.BiFunction;
import org.jackhuang.hellominecraft.util.func.CallbackIO;
import org.jackhuang.hellominecraft.util.system.Compressor;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.system.ZipEngine;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.ui.WebPage;
import org.jackhuang.hellominecraft.util.MinecraftVersionRequest;
import org.jackhuang.hellominecraft.util.tasks.NoShownTaskException;
/**
* A mod pack(*.zip) includes these things:
* <ul>
* <li>sth created by the game automatically, including "mods", "scripts",
* "config", etc..
* <li>pack.json, the same as Minecraft version configuration file:
* "gameDir/versions/{MCVER}/{MCVER}.json", will be renamed to that one.
* <li>all things should be included in "minecraft" folder under the root
* folder.
* </ul>
*
* This class can manage mod packs, for example, importing and exporting, the
* format of game is the offical one.
* Not compatible with MultiMC(no instance.cfg processor) & FTB(not leaving
* mcversion(jar) in pack.json).
*
* @author huangyuhui
*/
public final class ModpackManager {
/**
* Install the compressed modpack.
*
* @param input modpack.zip
* @param service MinecraftService, whose version service only supports
* MinecraftVersionManager.
* @param id new version id, if null, will use suggested name from
* modpack
*
* @return The installing Task, may take long time, please consider
* TaskWindow.
*/
public static Task install(JFrame parFrame, final File input, final IMinecraftService service, final String idFUCK) {
return new Task() {
Collection<Task> c = new ArrayList<>();
@Override
public void executeTask() throws Throwable {
String id = idFUCK;
String description = C.i18n("modpack.task.install.will");
// Read modpack name and description from `modpack.json`
try (ZipFile zip = new ZipFile(input)) {
HashMap map = C.GSON.fromJson(new InputStreamReader(zip.getInputStream(zip.getEntry("modpack.json")), "UTF-8"), HashMap.class);
if (map != null) {
if (id == null)
if (map.containsKey("name") && map.get("name") instanceof String)
id = (String) map.get("name");
if (id != null)
description += id;
if (map.containsKey("description") && map.get("description") instanceof String)
description += "\n" + (String) map.get("description");
}
if (id == null)
throw new IllegalStateException("Illegal modpack id!");
}
// Show a window to let the user know that what and how the modpack is.
Object msgs[] = new Object[2];
msgs[0] = C.i18n("modpack.task.install");
msgs[1] = new WebPage(description);
((WebPage) msgs[1]).setPreferredSize(new Dimension(800, 350));
int result = JOptionPane.showOptionDialog(parFrame, msgs, (String) msgs[0], JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
if (result == JOptionPane.NO_OPTION)
throw new NoShownTaskException("Operation was canceled by user.");
File versions = new File(service.baseDirectory(), "versions");
// `minecraft` folder is the existent root folder of the modpack
// Then we will decompress the modpack and there would be a folder named `minecraft`
// So if `minecraft` folder does exist, backup it and then restore it.
File oldFile = new File(versions, "minecraft"), newFile = null;
if (oldFile.exists()) {
newFile = new File(versions, "minecraft-" + System.currentTimeMillis());
if (newFile.isDirectory())
FileUtils.deleteDirectory(newFile);
else if (newFile.isFile())
if (!newFile.delete())
HMCLog.warn("Failed to delete file " + newFile);
if (!oldFile.renameTo(newFile))
HMCLog.warn("Failed to rename " + oldFile + " to " + newFile);
}
// If the user install the modpack into an existent version, maybe it wants to update the modpack
// So backup the game, copy the saved games.
File preVersion = new File(versions, id), preVersionRenamed = null;
if (preVersion.exists()) {
HMCLog.log("Backing up the game");
String preId = id + "-" + System.currentTimeMillis();
if (!preVersion.renameTo(preVersionRenamed = new File(versions, preId)))
HMCLog.warn("Failed to rename pre-version folder " + preVersion + " to a temp folder " + preVersionRenamed);
if (!new File(preVersionRenamed, id + ".json").renameTo(new File(preVersionRenamed, preId + ".json")))
HMCLog.warn("Failed to rename pre json to new json");
if (!new File(preVersionRenamed, id + ".jar").renameTo(new File(preVersionRenamed, preId + ".jar")))
HMCLog.warn("Failed to rename pre jar to new jar");
}
try {
final AtomicInteger b = new AtomicInteger(0);
HMCLog.log("Decompressing modpack");
Compressor.unzip(input, versions, t -> {
if (t.equals("minecraft/pack.json"))
b.incrementAndGet();
return true;
}, true);
// No pack.json here, illegal modpack.
if (b.get() < 1)
throw new FileNotFoundException(C.i18n("modpack.incorrect_format.no_json"));
File nowFile = new File(versions, id);
if (oldFile.exists() && !oldFile.renameTo(nowFile))
HMCLog.warn("Failed to rename incorrect json " + oldFile + " to " + nowFile);
File json = new File(nowFile, "pack.json");
MinecraftVersion mv = C.GSON.fromJson(FileUtils.readFileToString(json), MinecraftVersion.class);
if (mv.jar == null)
throw new FileNotFoundException(C.i18n("modpack.incorrect_format.no_jar"));
c.add(service.download().downloadMinecraftJar(mv, new File(nowFile, id + ".jar")));
mv.jar = null;
FileUtils.writeStringToFile(json, C.GSON.toJson(mv));
if (!json.renameTo(new File(nowFile, id + ".json")))
HMCLog.warn("Failed to rename pack.json to new id");
// Restore the saved game from the old version.
if (preVersionRenamed != null) {
HMCLog.log("Restoring saves");
File presaves = new File(preVersionRenamed, "saves");
File saves = new File(nowFile, "saves");
if (presaves.exists()) {
FileUtils.deleteDirectory(saves);
FileUtils.copyDirectory(presaves, saves);
}
}
} finally {
FileUtils.deleteDirectoryQuietly(oldFile);
if (newFile != null)
newFile.renameTo(oldFile);
}
}
@Override
public String getInfo() {
return C.i18n("modpack.task.install");
}
@Override
public Collection<Task> getAfterTasks() {
return c;
}
};
}
public static final List<String> MODPACK_BLACK_LIST = Arrays.asList(new String[] { "usernamecache.json", "asm", "logs", "backups", "versions", "assets", "usercache.json", "libraries", "crash-reports", "launcher_profiles.json", "NVIDIA", "AMD", "TCNodeTracker", "screenshots", "natives", "native", "$native", "pack.json", "launcher.jar", "minetweaker.log", "launcher.pack.lzma", "hmclmc.log" });
public static final List<String> MODPACK_SUGGESTED_BLACK_LIST = Arrays.asList(new String[] { "fonts", "saves", "servers.dat", "options.txt", "optionsof.txt", "journeymap", "optionsshaders.txt", "mods/VoxelMods" });
/**
* &lt; String, Boolean, Boolean &gt;: Folder/File name, Is Directory,
* Return 0: non blocked, 1: non shown, 2: suggested, checked.
*/
public static final BiFunction<String, Boolean, Integer> MODPACK_PREDICATE = (String x, Boolean y) -> {
if (ModpackManager.MODPACK_BLACK_LIST_PREDICATE.apply(x, y))
return 1;
if (ModpackManager.MODPACK_SUGGESTED_BLACK_LIST_PREDICATE.apply(x, y))
return 2;
return 0;
};
public static final BiFunction<String, Boolean, Boolean> MODPACK_BLACK_LIST_PREDICATE = modpackPredicateMaker(MODPACK_BLACK_LIST);
public static final BiFunction<String, Boolean, Boolean> MODPACK_SUGGESTED_BLACK_LIST_PREDICATE = modpackPredicateMaker(MODPACK_SUGGESTED_BLACK_LIST);
private static BiFunction<String, Boolean, Boolean> modpackPredicateMaker(final List<String> l) {
return (String x, Boolean y) -> {
for (String s : l)
if (y) {
if (x.startsWith(s + "/"))
return true;
} else if (x.equals(s))
return true;
return false;
};
}
/**
* Export the game to a mod pack file.
*
* @param output mod pack file.
* @param baseFolder if the game dir type is ROOT_FOLDER, use ".minecraft",
* or use ".minecraft/versions/{MCVER}/"
* @param version to locate version.json
*
* @throws IOException if create tmp directory failed
*/
public static void export(File output, IMinecraftProvider provider, String version, List<String> blacklist, Map modpackJson, CallbackIO<ZipEngine> callback) throws IOException, GameException {
final ArrayList<String> b = new ArrayList<>(MODPACK_BLACK_LIST);
if (blacklist != null)
b.addAll(blacklist);
b.add(version + ".jar");
b.add(version + ".json");
HMCLog.log("Compressing game files without some files in blacklist, including files or directories: usernamecache.json, asm, logs, backups, versions, assets, usercache.json, libraries, crash-reports, launcher_profiles.json, NVIDIA, TCNodeTracker");
ZipEngine zip = null;
try {
zip = new ZipEngine(output);
zip.putDirectory(provider.getRunDirectory(version), (String x, Boolean y) -> {
for (String s : b)
if (y) {
if (x.startsWith(s + "/"))
return null;
} else if (x.equals(s))
return null;
return "minecraft/" + x;
});
MinecraftVersion mv = provider.getVersionById(version).resolve(provider);
MinecraftVersionRequest r = MinecraftVersionRequest.minecraftVersion(provider.getMinecraftJar(version));
if (r.type != MinecraftVersionRequest.OK)
throw new FileSystemException(C.i18n("modpack.cannot_read_version") + ": " + MinecraftVersionRequest.getResponse(r));
mv.jar = r.version;
mv.runDir = "version";
zip.putTextFile(C.GSON.toJson(mv), "minecraft/pack.json");
zip.putTextFile(C.GSON.toJson(modpackJson), "modpack.json");
if (callback != null)
callback.call(zip);
} finally {
if (zip != null)
zip.closeFile();
}
}
}
@@ -1,53 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.service;
import java.io.File;
import java.io.IOException;
import org.jackhuang.hellominecraft.launcher.core.version.AssetIndexDownloadInfo;
import org.jackhuang.hellominecraft.util.tasks.Task;
/**
*
* @author huangyuhui
*/
public abstract class IMinecraftAssetService extends IMinecraftBasicService {
public IMinecraftAssetService(IMinecraftService service) {
super(service);
}
public abstract Task downloadAssets(String mcVersion);
public abstract File getAssets();
/**
* Redownload the Asset index json of the given version.
*
* @param a the given version name
*
* @return Is the action successful?
*/
public abstract boolean refreshAssetsIndex(String a);
public abstract boolean downloadMinecraftAssetsIndexAsync(AssetIndexDownloadInfo assetsId);
public abstract Task downloadMinecraftAssetsIndex(AssetIndexDownloadInfo assetsId);
public abstract File getAssetObject(String assetVersion, String name) throws IOException;
}
@@ -1,50 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.service;
import java.io.File;
import java.util.List;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadLibraryJob;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.tasks.Task;
/**
*
* @author huangyuhui
*/
public abstract class IMinecraftDownloadService extends IMinecraftBasicService {
public IMinecraftDownloadService(IMinecraftService service) {
super(service);
}
public abstract Task downloadMinecraft(String id);
public abstract Task downloadMinecraftJar(MinecraftVersion mv, File f);
public abstract Task downloadMinecraftVersionJson(String id);
/**
* Get the libraries that need to download.
*
* @return the library collection
*/
public abstract List<DownloadLibraryJob> getDownloadLibraries(MinecraftVersion mv) throws GameException;
}
@@ -1,42 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.service;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerType;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
import org.jackhuang.hellominecraft.util.tasks.Task;
/**
*
* @author huangyuhui
*/
public abstract class IMinecraftInstallerService extends IMinecraftBasicService {
public IMinecraftInstallerService(IMinecraftService service) {
super(service);
}
public abstract Task download(String installId, InstallerVersionList.InstallerVersion v, InstallerType type);
public abstract Task downloadForge(String installId, InstallerVersionList.InstallerVersion v);
public abstract Task downloadOptiFine(String installId, InstallerVersionList.InstallerVersion v);
public abstract Task downloadLiteLoader(String installId, InstallerVersionList.InstallerVersion v);
}
@@ -1,173 +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.core.service;
import java.io.File;
import java.util.Collection;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.version.DecompressLibraryJob;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.EventHandler;
import org.jackhuang.hellominecraft.util.func.Consumer;
import org.jackhuang.hellominecraft.util.func.Predicate;
/**
* Provide everything of the Minecraft of a Profile.
*
* @see
* org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersionManager
* @author huangyuhui
*/
public abstract class IMinecraftProvider {
protected IMinecraftService service;
public IMinecraftProvider(IMinecraftService service) {
this.service = service;
}
/**
* To download mod packs.
*/
public abstract void initializeMiencraft();
/**
* Get the run directory of given version.
*
* @param id the given version name
*
* @return the run directory
*/
public abstract File getRunDirectory(String id);
public abstract File versionRoot(String id);
public File getRunDirectory(String id, String subFolder) {
return new File(getRunDirectory(id), subFolder);
}
public abstract void open(String version, String folder);
/**
* Install a new version to this profile.
*
* @param version the new version name
*
* @return Is the action successful?
*/
public abstract boolean install(String version, Consumer<MinecraftVersion> callback);
/**
* Returns the thing like ".minecraft/resourcepacks".
*
* @return the thing
*/
public abstract File getResourcePacks();
/**
*
* @param v should be resolved
*
* @return libraries of resolved minecraft version v.
*/
public abstract DecompressLibraryJob getDecompressLibraries(MinecraftVersion v) throws GameException;
public abstract File getDecompressNativesToLocation(MinecraftVersion v);
/**
* @return the Minecraft jar of selected version.
*/
public abstract File getMinecraftJar(String id);
/**
* Rename version
*
* @param from The old name
* @param to The new name
*
* @return Is the action successful?
*/
public abstract boolean renameVersion(String from, String to);
/**
* Remove the given version from disk.
*
* @param a the version name
*
* @return Is the action successful?
*/
public abstract boolean removeVersionFromDisk(String a);
/**
* Choose a version randomly.
*
* @return the version
*/
public abstract MinecraftVersion getOneVersion(Predicate<MinecraftVersion> p);
/**
* All Minecraft version in this profile.
*
* @return the collection of all Minecraft version
*/
public abstract Collection<MinecraftVersion> getVersions();
/**
* Get the Minecraft json instance of given version.
*
* @param id the given version name
*
* @return the Minecraft json instance
*/
public abstract MinecraftVersion getVersionById(String id);
/**
* getVersions().size()
*
* @return getVersions().size()
*/
public abstract int getVersionCount();
/**
* Refind the versions in this profile.
* Must call onRefreshingVersions, onRefreshedVersions, onLoadedVersion
* Events.
*/
public abstract void refreshVersions();
public final EventHandler<IMinecraftService> onRefreshingVersions = new EventHandler<>(this),
onRefreshedVersions = new EventHandler<>(this);
public final EventHandler<String> onLoadedVersion = new EventHandler<>(this);
/**
* Clean redundant files.
*/
public abstract void cleanFolder();
/**
* When GameLauncher launches the game, this function will be called.
*
* @return if false, will break the launch process.
*/
public abstract boolean onLaunch();
public File baseDirectory() {
return service.baseDirectory();
}
}
@@ -1,60 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.service;
import java.io.File;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.auth.UserProfileProvider;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
import org.jackhuang.hellominecraft.launcher.core.launch.LaunchOptions;
/**
*
* @author huangyuhui
*/
public abstract class IMinecraftService {
public abstract File baseDirectory();
public DownloadType getDownloadType() {
return DownloadType.getSuggestedDownloadType();
}
public abstract IMinecraftAssetService asset();
public abstract IMinecraftDownloadService download();
public abstract IMinecraftModService mod();
public abstract IMinecraftProvider version();
public abstract IMinecraftInstallerService install();
/**
* Provide the Minecraft Loader to generate the launching command.
*
* @see org.jackhuang.hellominecraft.launcher.core.service.IMinecraftLoader
* @param p player informations, including username & auth_token
*
* @return what you want
*
* @throws GameException circular denpendency versions
*/
public abstract IMinecraftLoader launch(LaunchOptions options, UserProfileProvider p) throws GameException;
}
@@ -1,46 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.version;
import java.io.File;
/**
*
* @author huangyuhui
*/
public class DecompressLibraryJob {
public File[] decompressFiles;
public Extract[] extractRules;
private File decompressTo;
public DecompressLibraryJob(File[] decompressFiles, Extract[] extractRules, File decompressTo) {
this.decompressFiles = decompressFiles.clone();
this.extractRules = extractRules.clone();
this.decompressTo = decompressTo;
}
public File getDecompressTo() {
return decompressTo;
}
public void setDecompressTo(File decompressTo) {
this.decompressTo = decompressTo;
}
}
@@ -1,75 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.version;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
/**
*
* @author huangyuhui
*/
public class GameDownloadInfo implements Cloneable {
public String sha1;
public int size;
protected String url;
/**
* Ready for AssetIndexDownloadInfo, and GameDownloadInfo also need this.
*/
public String id = null;
/**
* Get the game download url.
*
* @param dt where to download?
*
* @return the download url
*/
public String getUrl(DownloadType dt) {
return getUrl(dt, dt.getProvider().isAllowedToUseSelfURL());
}
/**
* Get the game download url.
*
* @param dt where to download?
* @param allowSelf allow this game to be downloaded from its modified url?
*
* @return the download url
*/
public String getUrl(DownloadType dt, boolean allowSelf) {
if (url != null && allowSelf)
return dt.getProvider().getParsedDownloadURL(url);
else
return getCustomizedURL(dt);
}
protected String getCustomizedURL(DownloadType dt) {
return dt.getProvider().getVersionsDownloadURL() + id + "/" + id + ".jar";
}
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
throw new Error(ex);
}
}
}
@@ -1,67 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.version;
import java.io.File;
/**
*
* @author huangyuhui
*/
public abstract class IMinecraftLibrary implements Cloneable {
public String name;
public IMinecraftLibrary(String name) {
this.name = name;
}
public abstract boolean isRequiredToUnzip();
public abstract Extract getDecompressExtractRules();
public abstract LibraryDownloadInfo getDownloadInfo();
public abstract boolean allow();
public abstract File getFilePath(File gameDir);
@Override
public boolean equals(Object obj) {
if (obj instanceof MinecraftLibrary)
return ((MinecraftLibrary) obj).name.equals(name);
return false;
}
@Override
public int hashCode() {
int hash = 3;
hash = 89 * hash + (this.name != null ? this.name.hashCode() : 0);
return hash;
}
@Override
@SuppressWarnings("CloneDeclaresCloneNotSupported")
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
throw new InternalError(ex);
}
}
}
@@ -1,45 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.version;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
/**
*
* @author huangyuhui
*/
public class LibraryDownloadInfo extends GameDownloadInfo {
public String path;
public String forgeURL;
@Override
public String getUrl(DownloadType dt, boolean allowSelf) {
String myURL = (forgeURL == null ? dt.getProvider().getLibraryDownloadURL() : forgeURL);
if (StrUtils.isNotBlank(url) && allowSelf)
myURL = url;
if (!myURL.endsWith(".jar"))
if (path == null)
return null;
else
myURL = IOUtils.addURLSeparator(myURL) + path.replace('\\', '/');
return myURL;
}
}
@@ -1,74 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.version;
import java.io.File;
import java.util.ArrayList;
import java.util.Set;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftProvider;
/**
*
* @author huangyuhui
*/
public class MinecraftClassicVersion extends MinecraftVersion {
public MinecraftClassicVersion() {
super();
mainClass = "net.minecraft.client.Minecraft";
id = "Classic";
type = "release";
processArguments = assets = releaseTime = time = null;
minecraftArguments = "${auth_player_name} ${auth_session} --workDir ${game_directory}";
libraries = new ArrayList<>();
libraries.add(new MinecraftOldLibrary("lwjgl"));
libraries.add(new MinecraftOldLibrary("jinput"));
libraries.add(new MinecraftOldLibrary("lwjgl_util"));
}
@Override
public Object clone() {
return super.clone();
}
@Override
public MinecraftVersion resolve(IMinecraftProvider manager, Set<String> resolvedSoFar) {
return this;
}
@Override
public File getJar(File gameDir) {
return new File(gameDir, "bin/minecraft.jar");
}
@Override
public File getJar(File gameDir, String suffix) {
return new File(gameDir, "bin/minecraft" + suffix + ".jar");
}
@Override
public File getNatives(File gameDir) {
return new File(gameDir, "bin/natives");
}
@Override
public boolean isAllowedToUnpackNatives() {
return false;
}
}
@@ -1,133 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.version;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import org.jackhuang.hellominecraft.util.system.OS;
import org.jackhuang.hellominecraft.util.system.Platform;
import org.jackhuang.hellominecraft.util.StrUtils;
/**
*
* @author huangyuhui
*/
public class MinecraftLibrary extends IMinecraftLibrary {
public ArrayList<Rules> rules;
public String url;
public Natives natives;
public Extract extract;
public LibrariesDownloadInfo downloads;
public MinecraftLibrary(String name) {
super(name);
}
public MinecraftLibrary(ArrayList<Rules> rules, String url, Natives natives, String name, Extract extract, LibraryDownloadInfo downloads) {
super(name);
this.rules = rules == null ? null : (ArrayList<Rules>) rules.clone();
this.url = url;
this.natives = natives == null ? null : (Natives) natives.clone();
this.extract = extract == null ? null : (Extract) extract.clone();
}
/**
* is the library allowed to load.
*
* @return
*/
@Override
public boolean allow() {
if (rules != null) {
boolean flag = false;
for (Rules r : rules)
if ("disallow".equals(r.action()))
return false;
else if ("allow".equals(r.action()))
flag = true;
return flag;
} else
return true;
}
private String formatArch(String nati) {
return nati == null ? "" : nati.replace("${arch}", Platform.getPlatform().getBit());
}
private String getNative() {
switch (OS.os()) {
case WINDOWS:
return formatArch(natives.windows);
case OSX:
return formatArch(natives.osx);
default:
return formatArch(natives.linux);
}
}
@Override
public boolean isRequiredToUnzip() {
return natives != null && allow();
}
public String formatName() {
String[] s = name.split(":");
if (s.length < 3)
return null;
StringBuilder sb = new StringBuilder(s[0].replace('.', '/')).append('/').append(s[1]).append('/').append(s[2]).append('/').append(s[1]).append('-').append(s[2]);
if (natives != null)
sb.append('-').append(getNative());
return sb.append(".jar").toString();
}
@Override
public File getFilePath(File gameDir) {
return new File(gameDir, "libraries/" + getDownloadInfo().path);
}
@Override
public Extract getDecompressExtractRules() {
return extract == null ? new Extract() : extract;
}
public LibraryDownloadInfo getDownloadInfo() {
if (downloads == null)
downloads = new LibrariesDownloadInfo();
LibraryDownloadInfo info;
if (natives != null) {
if (downloads.classifiers == null)
downloads.classifiers = new HashMap<>();
if (!downloads.classifiers.containsKey(getNative()))
downloads.classifiers.put(getNative(), info = new LibraryDownloadInfo());
else
info = downloads.classifiers.get(getNative());
} else if (downloads.artifact == null)
downloads.artifact = info = new LibraryDownloadInfo();
else
info = downloads.artifact;
if (StrUtils.isBlank(info.path)) {
info.path = formatName();
if (info.path == null)
return null;
}
info.forgeURL = this.url;
return info;
}
}
@@ -1,175 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.version;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftProvider;
import org.jackhuang.hellominecraft.launcher.core.asset.AssetsIndex;
import org.jackhuang.hellominecraft.util.ArrayUtils;
import org.jackhuang.hellominecraft.util.Utils;
/**
*
* @author huangyuhui
*/
public class MinecraftVersion implements Cloneable, Comparable<MinecraftVersion> {
public String minecraftArguments, mainClass, time, id, type, processArguments,
releaseTime, jar, inheritsFrom, runDir;
protected String assets;
public int minimumLauncherVersion;
public boolean hidden;
public AssetIndexDownloadInfo assetIndex;
private Map<String, GameDownloadInfo> downloads;
public ArrayList<MinecraftLibrary> libraries;
public MinecraftVersion() {
}
public MinecraftVersion(String minecraftArguments, String mainClass, String time, String id, String type, String processArguments, String releaseTime, String assets, String jar, String inheritsFrom, String runDir, int minimumLauncherVersion, List<MinecraftLibrary> libraries, boolean hidden, Map<String, GameDownloadInfo> downloads, AssetIndexDownloadInfo assetIndexDownloadInfo) {
this();
this.minecraftArguments = minecraftArguments;
this.mainClass = mainClass;
this.time = time;
this.id = id;
this.type = type;
this.processArguments = processArguments;
this.releaseTime = releaseTime;
this.assets = assets;
this.jar = jar;
this.inheritsFrom = inheritsFrom;
this.minimumLauncherVersion = minimumLauncherVersion;
this.hidden = hidden;
this.runDir = runDir;
if (assetIndexDownloadInfo == null)
this.assetIndex = null;
else
this.assetIndex = (AssetIndexDownloadInfo) assetIndexDownloadInfo.clone();
if (libraries == null)
this.libraries = new ArrayList<>();
else {
this.libraries = new ArrayList<>(libraries.size());
for (MinecraftLibrary library : libraries)
if (library != null)
this.libraries.add((MinecraftLibrary) library.clone());
}
if (downloads == null)
this.downloads = null;
else {
this.downloads = new HashMap<>(downloads.size());
for (Map.Entry<String, GameDownloadInfo> entry : downloads.entrySet())
this.downloads.put(entry.getKey(), (GameDownloadInfo) entry.getValue().clone());
}
}
@Override
public Object clone() {
try {
MinecraftVersion mv = (MinecraftVersion) super.clone();
mv.libraries = (ArrayList<MinecraftLibrary>) mv.libraries.clone();
return mv;
} catch (CloneNotSupportedException ex) {
throw new InternalError();
}
}
public MinecraftVersion resolve(IMinecraftProvider provider) throws GameException {
return resolve(provider, new HashSet<>());
}
protected MinecraftVersion resolve(IMinecraftProvider provider, Set<String> resolvedSoFar) throws GameException {
if (inheritsFrom == null)
return this;
if (!resolvedSoFar.add(id))
throw new GameException(C.i18n("launch.circular_dependency_versions"));
MinecraftVersion parent = provider.getVersionById(inheritsFrom);
if (parent == null) {
if (!provider.install(inheritsFrom, t -> t.hidden = true))
return this;
parent = provider.getVersionById(inheritsFrom);
}
parent = parent.resolve(provider, resolvedSoFar);
MinecraftVersion result = new MinecraftVersion(
this.minecraftArguments != null ? this.minecraftArguments : parent.minecraftArguments,
this.mainClass != null ? this.mainClass : parent.mainClass,
this.time, this.id, this.type, parent.processArguments, this.releaseTime,
this.assets != null ? this.assets : parent.assets,
this.jar != null ? this.jar : parent.jar,
null, this.runDir, parent.minimumLauncherVersion,
this.libraries != null ? ArrayUtils.merge(this.libraries, parent.libraries) : parent.libraries, this.hidden,
this.downloads != null ? this.downloads : parent.downloads,
this.assetIndex != null ? this.assetIndex : parent.assetIndex);
return result;
}
public File getJar(File gameDir) {
String jarId = this.jar == null ? this.id : this.jar;
return new File(gameDir, "versions/" + jarId + "/" + jarId + ".jar");
}
public File getJar(File gameDir, String suffix) {
String jarId = this.jar == null ? this.id : this.jar;
return new File(gameDir, "versions/" + jarId + "/" + jarId + suffix + ".jar");
}
public File getNatives(File gameDir) {
return new File(gameDir, "versions/" + id + "/" + id
+ "-natives");
}
public boolean isAllowedToUnpackNatives() {
return true;
}
@Override
public int compareTo(MinecraftVersion o) {
return id.compareTo(o.id);
}
public AssetIndexDownloadInfo getAssetsIndex() {
if (assetIndex == null)
assetIndex = new AssetIndexDownloadInfo((String) Utils.firstNonNull(assets, AssetsIndex.DEFAULT_ASSET_NAME));
return assetIndex;
}
public GameDownloadInfo getClientDownloadInfo() {
if (downloads == null)
downloads = new HashMap<>();
if (!downloads.containsKey("client"))
downloads.put("client", new GameDownloadInfo());
GameDownloadInfo i = downloads.get("client");
if (i.id == null)
i.id = id;
return i;
}
public Set<IMinecraftLibrary> getLibraries() {
return libraries == null ? new HashSet() : new HashSet(libraries);
}
}
@@ -1,288 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.core.version;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.core.GameException;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftProvider;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.launcher.core.MCUtils;
import org.jackhuang.hellominecraft.util.tasks.TaskWindow;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.func.Consumer;
import org.jackhuang.hellominecraft.util.func.Predicate;
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public class MinecraftVersionManager extends IMinecraftProvider {
final Map<String, MinecraftVersion> versions = new TreeMap();
/**
*
* @param p
*/
public MinecraftVersionManager(IMinecraftService p) {
super(p);
}
@Override
public Collection<MinecraftVersion> getVersions() {
return versions.values();
}
@Override
public int getVersionCount() {
return versions.size();
}
@Override
public synchronized void refreshVersions() {
onRefreshingVersions.execute(service);
try {
MCUtils.tryWriteProfile(service.baseDirectory());
} catch (IOException ex) {
HMCLog.warn("Failed to create launcher_profiles.json, Forge/LiteLoader installer will not work.", ex);
}
versions.clear();
File oldDir = new File(service.baseDirectory(), "bin");
if (oldDir.exists()) {
MinecraftClassicVersion v = new MinecraftClassicVersion();
versions.put(v.id, v);
}
File version = new File(service.baseDirectory(), "versions");
File[] files = version.listFiles();
if (files != null && files.length > 0)
for (File dir : files) {
String id = dir.getName();
File jsonFile = new File(dir, id + ".json");
if (!dir.isDirectory())
continue;
boolean ask = false;
File[] jsons = null;
if (!jsonFile.exists()) {
jsons = FileUtils.searchSuffix(dir, "json");
if (jsons.length == 1)
ask = true;
}
if (ask) {
HMCLog.warn("Found not matched filenames version: " + id + ", json: " + jsons[0].getName());
if (MessageBox.Show(String.format(C.i18n("launcher.versions_json_not_matched"), id, jsons[0].getName()), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
if (!jsons[0].renameTo(new File(jsons[0].getParent(), id + ".json")))
HMCLog.warn("Failed to rename version json " + jsons[0]);
}
if (!jsonFile.exists()) {
if (MessageBox.Show(C.i18n("launcher.versions_json_not_matched_cannot_auto_completion", id), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
FileUtils.deleteDirectoryQuietly(dir);
continue;
}
MinecraftVersion mcVersion;
try {
mcVersion = C.GSON.fromJson(FileUtils.readFileToString(jsonFile), MinecraftVersion.class);
if (mcVersion == null)
throw new GameException("Wrong json format, got null.");
} catch (Exception e) {
HMCLog.warn("Found wrong format json, try to fix it.", e);
if (MessageBox.Show(C.i18n("launcher.versions_json_not_formatted", id), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) {
service.download().downloadMinecraftVersionJson(id);
try {
mcVersion = C.GSON.fromJson(FileUtils.readFileToString(jsonFile), MinecraftVersion.class);
if (mcVersion == null)
throw new GameException("Wrong json format, got null.");
} catch (IOException | GameException | JsonSyntaxException ex) {
HMCLog.warn("Ignoring: " + dir + ", the json of this Minecraft is malformed.", ex);
continue;
}
} else
continue;
}
try {
if (!id.equals(mcVersion.id)) {
HMCLog.warn("Found: " + dir + ", it contains id: " + mcVersion.id + ", expected: " + id + ", this app will fix this problem.");
mcVersion.id = id;
FileUtils.writeQuietly(jsonFile, C.GSON.toJson(mcVersion));
}
versions.put(id, mcVersion);
onLoadedVersion.execute(id);
} catch (Exception e) {
HMCLog.warn("Ignoring: " + dir + ", the json of this Minecraft is malformed.", e);
}
}
onRefreshedVersions.execute(service);
}
@Override
public File versionRoot(String id) {
return new File(service.baseDirectory(), "versions/" + id);
}
@Override
public boolean removeVersionFromDisk(String name) {
File version = versionRoot(name);
if (!version.exists())
return true;
versions.remove(name);
return FileUtils.deleteDirectoryQuietly(version);
}
@Override
public boolean renameVersion(String from, String to) {
try {
File fromJson = new File(versionRoot(from), from + ".json");
MinecraftVersion mcVersion = C.GSON.fromJson(FileUtils.readFileToString(fromJson), MinecraftVersion.class);
mcVersion.id = to;
FileUtils.writeQuietly(fromJson, C.GSON.toJson(mcVersion));
File toDir = versionRoot(to);
if (!versionRoot(from).renameTo(toDir))
HMCLog.warn("MinecraftVersionManager.RenameVersion: Failed to rename version root " + from + " to " + to);
File toJson = new File(toDir, to + ".json");
File toJar = new File(toDir, to + ".jar");
if (new File(toDir, from + ".json").renameTo(toJson))
HMCLog.warn("MinecraftVersionManager.RenameVersion: Failed to rename json");
File newJar = new File(toDir, from + ".jar");
if (newJar.exists() && !newJar.renameTo(toJar))
HMCLog.warn("Failed to rename pre jar " + newJar + " to new jar " + toJar);
return true;
} catch (IOException | JsonSyntaxException e) {
HMCLog.warn("Failed to rename " + from + " to " + to + ", the json of this Minecraft is malformed.", e);
return false;
}
}
@Override
public File getRunDirectory(String id) {
if (getVersionById(id) != null)
if ("version".equals(getVersionById(id).runDir))
return versionRoot(id);
return baseDirectory();
}
@Override
public boolean install(String id, Consumer<MinecraftVersion> callback) {
if (!TaskWindow.factory().append(service.download().downloadMinecraft(id)).create())
return false;
if (callback != null) {
File mvt = new File(versionRoot(id), id + ".json");
MinecraftVersion v = C.GSON.fromJson(FileUtils.readFileToStringQuietly(mvt), MinecraftVersion.class);
if (v == null)
return false;
callback.accept(v);
FileUtils.writeQuietly(mvt, C.GSON.toJson(v));
}
refreshVersions();
return true;
}
@Override
public void open(String mv, String name) {
SwingUtils.openFolder((name == null) ? getRunDirectory(mv) : new File(getRunDirectory(mv), name));
}
@Override
public DecompressLibraryJob getDecompressLibraries(MinecraftVersion v) throws GameException {
if (v.libraries == null)
throw new GameException("Wrong format: minecraft.json");
ArrayList<File> unzippings = new ArrayList<>();
ArrayList<Extract> extractRules = new ArrayList<>();
for (IMinecraftLibrary l : v.libraries)
if (l.isRequiredToUnzip() && v.isAllowedToUnpackNatives()) {
unzippings.add(IOUtils.tryGetCanonicalFile(l.getFilePath(service.baseDirectory())));
extractRules.add(l.getDecompressExtractRules());
}
return new DecompressLibraryJob(unzippings.toArray(new File[unzippings.size()]), extractRules.toArray(new Extract[extractRules.size()]), getDecompressNativesToLocation(v));
}
@Override
public File getDecompressNativesToLocation(MinecraftVersion v) {
return v == null ? null : v.getNatives(service.baseDirectory());
}
@Override
public File getMinecraftJar(String id) {
if (versions.containsKey(id))
return versions.get(id).getJar(service.baseDirectory());
else
return null;
}
@Override
public MinecraftVersion getOneVersion(Predicate<MinecraftVersion> pred) {
for (MinecraftVersion v : versions.values())
if (pred == null || pred.apply(v))
return v;
return null;
}
@Override
public MinecraftVersion getVersionById(String id) {
return StrUtils.isBlank(id) ? null : versions.get(id);
}
@Override
public File getResourcePacks() {
return new File(service.baseDirectory(), "resourcepacks");
}
@Override
public boolean onLaunch() {
File resourcePacks = getResourcePacks();
if (!resourcePacks.exists() && !resourcePacks.mkdirs())
HMCLog.warn("Failed to make resourcePacks: " + resourcePacks);
return true;
}
@Override
public void cleanFolder() {
for (MinecraftVersion s : getVersions()) {
FileUtils.deleteDirectoryQuietly(new File(versionRoot(s.id), s.id + "-natives"));
File f = getRunDirectory(s.id);
String[] dir = { "natives", "native", "$native", "AMD", "crash-reports", "logs", "asm", "NVIDIA", "server-resource-packs", "natives", "native" };
for (String str : dir)
FileUtils.deleteDirectoryQuietly(new File(f, str));
String[] files = { "output-client.log", "usercache.json", "usernamecache.json", "hmclmc.log" };
for (String str : files)
if (!new File(f, str).delete())
HMCLog.warn("Failed to delete " + str);
}
}
@Override
public void initializeMiencraft() {
}
}
@@ -1,259 +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.setting;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import org.jackhuang.hellominecraft.launcher.core.auth.IAuthenticator;
import org.jackhuang.hellominecraft.lookandfeel.Theme;
import org.jackhuang.hellominecraft.util.EventHandler;
import org.jackhuang.hellominecraft.util.system.JdkVersion;
import org.jackhuang.hellominecraft.util.system.OS;
/**
*
* @author huangyuhui
*/
public final class Config implements Cloneable {
@SerializedName("last")
private String last;
@SerializedName("bgpath")
private String bgpath;
@SerializedName("clientToken")
private final String clientToken;
private String proxyHost, proxyPort, proxyUserName, proxyPassword;
@SerializedName("enableShadow")
private boolean enableShadow;
@SerializedName("decorated")
private boolean decorated;
@SerializedName("enableAnimation")
private boolean enableAnimation;
@SerializedName("theme")
private int theme;
@SerializedName("java")
private List<JdkVersion> java;
@SerializedName("localization")
private String localization;
@SerializedName("logintype")
private int logintype;
@SerializedName("downloadtype")
private int downloadtype;
@SerializedName("configurations")
private TreeMap<String, Profile> configurations;
@SerializedName("auth")
@SuppressWarnings("FieldMayBeFinal")
private Map<String, Map> auth;
public List<JdkVersion> getJava() {
return java == null ? java = new ArrayList<>() : java;
}
public transient final EventHandler<Theme> themeChangedEvent = new EventHandler<>(this);
public transient final EventHandler<DownloadType> downloadTypeChangedEvent = new EventHandler<>(this);
public transient final EventHandler<IAuthenticator> authChangedEvent = new EventHandler<>(this);
public Theme getTheme() {
if (theme >= Theme.values().length)
theme = 0;
return Theme.values()[theme];
}
public void setTheme(int theme) {
this.theme = theme;
themeChangedEvent.execute(getTheme());
Settings.save();
}
public boolean isDecorated() {
return decorated;
}
public void setDecorated(boolean decorated) {
this.decorated = decorated;
}
public boolean isEnableShadow() {
return enableShadow;
}
public void setEnableShadow(boolean enableShadow) {
this.enableShadow = enableShadow;
Settings.save();
}
public String getLast() {
if (last == null)
last = Settings.DEFAULT_PROFILE;
return last;
}
public void setLast(String last) {
this.last = last;
Settings.onProfileChanged();
Settings.save();
}
public String getBgpath() {
return bgpath;
}
public void setBgpath(String bgpath) {
this.bgpath = bgpath;
Settings.save();
}
public boolean isEnableAnimation() {
return enableAnimation;
}
public void setEnableAnimation(boolean enableAnimation) {
this.enableAnimation = enableAnimation;
Settings.save();
}
public String getClientToken() {
return clientToken;
}
public IAuthenticator getAuthenticator() {
return IAuthenticator.LOGINS.get(getLoginType());
}
public int getLoginType() {
if (logintype < 0 || logintype >= IAuthenticator.LOGINS.size())
logintype = 0;
return logintype;
}
public void setLoginType(int logintype) {
if (logintype < 0 || logintype >= IAuthenticator.LOGINS.size())
return;
this.logintype = logintype;
authChangedEvent.execute(IAuthenticator.LOGINS.get(logintype));
Settings.save();
}
public int getDownloadType() {
return downloadtype;
}
public void setDownloadType(int downloadtype) {
this.downloadtype = downloadtype;
downloadTypeChangedEvent.execute(getDownloadSource());
Settings.save();
}
public TreeMap<String, Profile> getConfigurations() {
if (configurations == null)
configurations = new TreeMap<>();
if (configurations.isEmpty()) {
Profile profile = new Profile();
configurations.put(profile.getName(), profile);
}
return configurations;
}
public Map getAuthenticatorConfig(String authId) {
return auth.get(authId);
}
public void setAuthenticatorConfig(String authId, Map map) {
auth.put(authId, map);
Settings.save();
}
public Config() {
clientToken = UUID.randomUUID().toString();
logintype = downloadtype = 0;
enableShadow = false;
enableAnimation = true;
theme = 4;
decorated = OS.os() == OS.LINUX;
auth = new HashMap<>();
}
public DownloadType getDownloadSource() {
if (downloadtype >= DownloadType.values().length || downloadtype < 0) {
downloadtype = 0;
Settings.save();
}
return DownloadType.values()[downloadtype];
}
public String getProxyHost() {
return proxyHost == null ? "" : proxyHost;
}
public void setProxyHost(String proxyHost) {
this.proxyHost = proxyHost;
Settings.save();
}
public String getProxyPort() {
return proxyPort == null ? "" : proxyPort;
}
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
Settings.save();
}
public String getProxyUserName() {
return proxyUserName == null ? "" : proxyUserName;
}
public void setProxyUserName(String proxyUserName) {
this.proxyUserName = proxyUserName;
Settings.save();
}
public String getProxyPassword() {
return proxyPassword == null ? "" : proxyPassword;
}
public void setProxyPassword(String proxyPassword) {
this.proxyPassword = proxyPassword;
Settings.save();
}
public String getLocalization() {
return localization;
}
public void setLocalization(String localization) {
this.localization = localization;
Settings.save();
}
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
}
@@ -1,153 +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.setting;
import org.jackhuang.hellominecraft.launcher.util.HMCLGameLauncher;
import org.jackhuang.hellominecraft.launcher.util.HMCLMinecraftService;
import java.io.File;
import org.jackhuang.hellominecraft.launcher.api.PluginManager;
import org.jackhuang.hellominecraft.launcher.core.MCUtils;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.EventHandler;
import org.jackhuang.hellominecraft.util.system.OS;
/**
*
* @author huangyuhui
*/
public final class Profile {
private String name, selectedMinecraftVersion = "", gameDir;
private transient IMinecraftService service;
private transient HMCLGameLauncher launcher = new HMCLGameLauncher(this);
public transient final EventHandler<String> propertyChanged = new EventHandler<>(this);
public Profile() {
this("Default");
}
public Profile(String name) {
this(name, new File(IOUtils.currentDir(), ".minecraft").getPath());
}
public Profile(String name, String gameDir) {
this.name = name;
this.gameDir = gameDir;
}
public Profile(String name, Profile v) {
this();
if (v == null)
return;
this.name = name;
gameDir = v.gameDir;
}
public IMinecraftService service() {
if (service == null)
service = PluginManager.plugin().provideMinecraftService(this);
return service;
}
public HMCLGameLauncher launcher() {
return launcher;
}
private transient final VersionSetting defaultVersionSetting = new VersionSetting();
public VersionSetting getSelectedVersionSetting() {
VersionSetting vs = getVersionSetting(getSelectedVersion());
if (vs == null)
vs = defaultVersionSetting;
return vs;
}
public VersionSetting getVersionSetting(String id) {
return ((HMCLMinecraftService) service()).getVersionSetting(id);
}
public String getSettingsSelectedMinecraftVersion() {
return selectedMinecraftVersion;
}
public String getSelectedVersion() {
String v = selectedMinecraftVersion;
if (StrUtils.isBlank(v) || service().version().getVersionById(v) == null || service().version().getVersionById(v).hidden) {
MinecraftVersion mv = service().version().getOneVersion(t -> !t.hidden);
if (mv != null)
v = mv.id;
if (StrUtils.isNotBlank(v))
setSelectedMinecraftVersion(v);
}
return StrUtils.isBlank(v) ? null : v;
}
public transient final EventHandler<String> selectedVersionChangedEvent = new EventHandler<>(this);
public void setSelectedMinecraftVersion(String selectedMinecraftVersion) {
this.selectedMinecraftVersion = selectedMinecraftVersion;
propertyChanged.execute("selectedMinecraftVersion");
selectedVersionChangedEvent.execute(selectedMinecraftVersion);
}
public String getGameDir() {
if (StrUtils.isBlank(gameDir))
gameDir = MCUtils.getInitGameDir().getPath();
return IOUtils.addSeparator(gameDir);
}
public String getCanonicalGameDir() {
return IOUtils.tryGetCanonicalFolderPath(getGameDirFile());
}
public File getCanonicalGameDirFile() {
return IOUtils.tryGetCanonicalFile(getGameDirFile());
}
public File getGameDirFile() {
return new File(getGameDir());
}
public Profile setGameDir(String gameDir) {
this.gameDir = gameDir;
service().version().refreshVersions();
propertyChanged.execute("gameDir");
return this;
}
public String getName() {
return name;
}
void setName(String name) {
this.name = name;
propertyChanged.execute("name");
}
public void checkFormat() {
gameDir = gameDir.replace('/', OS.os().fileSeparator).replace('\\', OS.os().fileSeparator);
}
public void onSelected() {
service().version().refreshVersions();
}
}
@@ -1,182 +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.setting;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.Main;
import org.jackhuang.hellominecraft.launcher.core.MCUtils;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
import org.jackhuang.hellominecraft.util.CollectionUtils;
import org.jackhuang.hellominecraft.util.EventHandler;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.UpdateChecker;
/**
*
* @author huangyuhui
*/
public final class Settings {
public static final String DEFAULT_PROFILE = "Default";
public static final String HOME_PROFILE = "Home";
public static final File SETTINGS_FILE = new File(IOUtils.currentDir(), "hmcl.json");
private static final Config SETTINGS;
public static final UpdateChecker UPDATE_CHECKER = new UpdateChecker(Main.getVersionNumber(), "hmcl");
public static Config getInstance() {
return SETTINGS;
}
static {
SETTINGS = initSettings();
SETTINGS.downloadTypeChangedEvent.register(DownloadType::setSuggestedDownloadType);
DownloadType.setSuggestedDownloadType(SETTINGS.getDownloadSource());
if (!getProfiles().containsKey(DEFAULT_PROFILE))
getProfiles().put(DEFAULT_PROFILE, new Profile(DEFAULT_PROFILE));
for (Map.Entry<String, Profile> entry : getProfiles().entrySet()) {
Profile e = entry.getValue();
e.setName(entry.getKey());
e.checkFormat();
e.propertyChanged.register(Settings::save);
}
}
private static Config initSettings() {
Config c = new Config();
if (SETTINGS_FILE.exists())
try {
String str = FileUtils.readFileToString(SETTINGS_FILE);
if (str == null || str.trim().equals(""))
HMCLog.log("Settings file is empty, use the default settings.");
else {
Config d = C.GSON.fromJson(str, Config.class);
if (d != null)
c = d;
}
HMCLog.log("Initialized settings.");
} catch (IOException | JsonSyntaxException e) {
HMCLog.warn("Something happened wrongly when load settings.", e);
}
else {
HMCLog.log("No settings file here, may be first loading.");
if (!c.getConfigurations().containsKey(HOME_PROFILE))
c.getConfigurations().put(HOME_PROFILE, new Profile(HOME_PROFILE, MCUtils.getLocation().getPath()));
}
return c;
}
public static void save() {
try {
FileUtils.write(SETTINGS_FILE, C.GSON.toJson(SETTINGS));
} catch (IOException ex) {
HMCLog.err("Failed to save config", ex);
}
}
public static Profile getLastProfile() {
if (!hasProfile(getInstance().getLast()))
getInstance().setLast(DEFAULT_PROFILE);
return getProfile(getInstance().getLast());
}
public static Profile getProfile(String name) {
if (name == null)
name = DEFAULT_PROFILE;
Profile p = getProfiles().get(name);
if (p == null)
if (getProfiles().containsKey(DEFAULT_PROFILE))
p = getProfiles().get(DEFAULT_PROFILE);
else
getProfiles().put(DEFAULT_PROFILE, p = new Profile());
return p;
}
public static boolean hasProfile(String name) {
if (name == null)
name = DEFAULT_PROFILE;
return getProfiles().containsKey(name);
}
public static Map<String, Profile> getProfiles() {
return SETTINGS.getConfigurations();
}
public static void setProfile(Profile ver) {
getProfiles().put(ver.getName(), ver);
}
public static Collection<Profile> getProfilesFiltered() {
return CollectionUtils.map(getProfiles().values(), t -> t != null && t.getName() != null);
}
public static Profile getOneProfile() {
return SETTINGS.getConfigurations().firstEntry().getValue();
}
public static boolean putProfile(Profile ver) {
if (ver == null || ver.getName() == null || getProfiles().containsKey(ver.getName()))
return false;
getProfiles().put(ver.getName(), ver);
return true;
}
public static boolean delProfile(Profile ver) {
return delProfile(ver.getName());
}
public static boolean delProfile(String ver) {
if (DEFAULT_PROFILE.equals(ver)) {
MessageBox.Show(C.i18n("settings.cannot_remove_default_config"));
return false;
}
boolean notify = false;
if (getLastProfile().getName().equals(ver))
notify = true;
boolean flag = getProfiles().remove(ver) != null;
if (notify && flag)
onProfileChanged();
return flag;
}
public static final EventHandler<Profile> profileChangedEvent = new EventHandler(null);
public static final EventHandler<Void> profileLoadingEvent = new EventHandler(null);
static void onProfileChanged() {
Profile p = getLastProfile();
if (p == null)
throw new Error("No profiles here, it should not happen");
profileChangedEvent.execute(p);
p.onSelected();
}
public static void onProfileLoading() {
profileLoadingEvent.execute(null);
onProfileChanged();
}
}
@@ -1,324 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.setting;
import java.io.File;
import java.io.IOException;
import org.jackhuang.hellominecraft.launcher.Main;
import org.jackhuang.hellominecraft.launcher.util.LauncherVisibility;
import org.jackhuang.hellominecraft.launcher.core.launch.LaunchOptions;
import org.jackhuang.hellominecraft.launcher.core.version.GameDirType;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.EventHandler;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.Utils;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.system.Java;
import org.jackhuang.hellominecraft.util.system.JdkVersion;
/**
*
* @author huangyuhui
*/
public class VersionSetting {
public transient String id;
private String javaArgs, minecraftArgs, maxMemory, permSize, width, height;
private String javaDir, precalledCommand, serverIp, java, wrapper;
private boolean fullscreen, noJVMArgs, notCheckGame;
/**
* 0 - Close the launcher when the game starts.<br/>
* 1 - Hide the launcher when the game starts.<br/>
* 2 - Keep the launcher open.<br/>
*/
private int launcherVisibility;
/**
* 0 - .minecraft<br/>
* 1 - .minecraft/versions/&lt;version&gt;/<br/>
*/
private int gameDirType;
public transient final EventHandler<String> propertyChanged = new EventHandler<>(this);
public VersionSetting() {
fullscreen = false;
launcherVisibility = 1;
gameDirType = 0;
javaDir = java = minecraftArgs = serverIp = precalledCommand = wrapper = "";
}
public VersionSetting(VersionSetting v) {
this();
if (v == null)
return;
maxMemory = v.maxMemory;
width = v.width;
height = v.height;
java = v.java;
fullscreen = v.fullscreen;
javaArgs = v.javaArgs;
javaDir = v.javaDir;
minecraftArgs = v.minecraftArgs;
permSize = v.permSize;
gameDirType = v.gameDirType;
noJVMArgs = v.noJVMArgs;
launcherVisibility = v.launcherVisibility;
precalledCommand = v.precalledCommand;
wrapper = v.wrapper;
serverIp = v.serverIp;
}
public String getJavaDir() {
Java j = getJava();
if (j.getHome() == null)
return javaDir;
else
return j.getJava();
}
public String getSettingsJavaDir() {
return javaDir;
}
public File getJavaDirFile() {
return new File(getJavaDir());
}
public void setJavaDir(String javaDir) {
this.javaDir = javaDir;
propertyChanged.execute("javaDir");
}
public Java getJava() {
return Java.JAVA.get(getJavaIndexInAllJavas());
}
public int getJavaIndexInAllJavas() {
if (StrUtils.isBlank(java) && StrUtils.isNotBlank(javaDir))
java = "Custom";
int idx = Java.JAVA.indexOf(new Java(java, null));
if (idx == -1) {
java = Java.suggestedJava().getName();
idx = 0;
}
return idx;
}
public void setJava(Java java) {
if (java == null)
this.java = Java.JAVA.get(0).getName();
else {
int idx = Java.JAVA.indexOf(java);
if (idx == -1)
return;
this.java = java.getName();
}
propertyChanged.execute("java");
}
public String getJavaArgs() {
if (StrUtils.isBlank(javaArgs))
return "";
return javaArgs;
}
public void setJavaArgs(String javaArgs) {
this.javaArgs = javaArgs;
propertyChanged.execute("javaArgs");
}
public boolean hasJavaArgs() {
return StrUtils.isNotBlank(getJavaArgs().trim());
}
public String getMaxMemory() {
if (StrUtils.isBlank(maxMemory))
return String.valueOf(Utils.getSuggestedMemorySize());
return maxMemory;
}
public void setMaxMemory(String maxMemory) {
this.maxMemory = maxMemory;
propertyChanged.execute("maxMemory");
}
public String getWidth() {
if (StrUtils.isBlank(width))
return "854";
return width;
}
public void setWidth(String width) {
this.width = width;
propertyChanged.execute("width");
}
public String getHeight() {
if (StrUtils.isBlank(height))
return "480";
return height;
}
public void setHeight(String height) {
this.height = height;
propertyChanged.execute("height");
}
public boolean isFullscreen() {
return fullscreen;
}
public void setFullscreen(boolean fullscreen) {
this.fullscreen = fullscreen;
propertyChanged.execute("fullscreen");
}
public LauncherVisibility getLauncherVisibility() {
return LauncherVisibility.values()[launcherVisibility];
}
public void setLauncherVisibility(LauncherVisibility launcherVisibility) {
this.launcherVisibility = launcherVisibility.ordinal();
propertyChanged.execute("launcherVisibility");
}
public GameDirType getGameDirType() {
if (gameDirType < 0 || gameDirType > 1)
setGameDirType(GameDirType.ROOT_FOLDER);
return GameDirType.values()[gameDirType];
}
public void setGameDirType(GameDirType gameDirType) {
this.gameDirType = gameDirType.ordinal();
propertyChanged.execute("gameDirType");
}
public String getPermSize() {
return permSize;
}
public void setPermSize(String permSize) {
this.permSize = permSize;
propertyChanged.execute("permSize");
}
public boolean isNoJVMArgs() {
return noJVMArgs;
}
public void setNoJVMArgs(boolean noJVMArgs) {
this.noJVMArgs = noJVMArgs;
propertyChanged.execute("noJVMArgs");
}
public String getMinecraftArgs() {
return minecraftArgs;
}
public void setMinecraftArgs(String minecraftArgs) {
this.minecraftArgs = minecraftArgs;
propertyChanged.execute("minecraftArgs");
}
public String getPrecalledCommand() {
return precalledCommand;
}
public void setPrecalledCommand(String precalledCommand) {
this.precalledCommand = precalledCommand;
propertyChanged.execute("precalledCommand");
}
public String getWrapper() {
return wrapper;
}
public void setWrapper(String wrapper) {
this.wrapper = wrapper;
propertyChanged.execute("wrapper");
}
public String getServerIp() {
return serverIp;
}
public void setServerIp(String serverIp) {
this.serverIp = serverIp;
propertyChanged.execute("serverIp");
}
public boolean isNotCheckGame() {
return notCheckGame;
}
public void setNotCheckGame(boolean notCheckGame) {
this.notCheckGame = notCheckGame;
propertyChanged.execute("notCheckGame");
}
public LaunchOptions createLaunchOptions(File gameDir) {
LaunchOptions x = new LaunchOptions();
x.setFullscreen(isFullscreen());
x.setWrapper(getWrapper());
x.setGameDir(gameDir);
x.setGameDirType(getGameDirType());
x.setHeight(getHeight());
x.setJavaArgs(getJavaArgs());
x.setLaunchVersion(id);
x.setMaxMemory(getMaxMemory());
x.setMinecraftArgs(getMinecraftArgs());
x.setName(Main.shortTitle());
x.setType(Main.shortTitle());
x.setVersionName(Main.shortTitle());
x.setNoJVMArgs(isNoJVMArgs());
x.setNotCheckGame(isNotCheckGame());
x.setPermSize(getPermSize());
x.setPrecalledCommand(getPrecalledCommand());
x.setProxyHost(Settings.getInstance().getProxyHost());
x.setProxyPort(Settings.getInstance().getProxyPort());
x.setProxyUser(Settings.getInstance().getProxyUserName());
x.setProxyPass(Settings.getInstance().getProxyPassword());
x.setServerIp(getServerIp());
x.setWidth(getWidth());
String str = getJavaDir();
if (!getJavaDirFile().exists()) {
HMCLog.err(C.i18n("launch.wrong_javadir"));
setJava(null);
str = getJavaDir();
}
JdkVersion jv = new JdkVersion(str);
if (Settings.getInstance().getJava().contains(jv))
jv = Settings.getInstance().getJava().get(Settings.getInstance().getJava().indexOf(jv));
else
try {
jv = JdkVersion.getJavaVersionFromExecutable(str);
Settings.getInstance().getJava().add(jv);
Settings.save();
} catch (IOException ex) {
HMCLog.warn("Failed to get java version", ex);
jv = null;
}
x.setJava(jv);
x.setJavaDir(str);
return x;
}
}
@@ -1,124 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
/**
*
* @author huangyuhui
*/
public class AnimatedPanel extends JPanel implements Selectable {
private static final int ANIMATION_LENGTH = 10;
public AnimatedPanel() {
timer = new Timer(1, (e) -> {
SwingUtilities.invokeLater(() -> {
AnimatedPanel.this.repaint();
offsetX += 0.15;
if (offsetX >= ANIMATION_LENGTH) {
timer.stop();
AnimatedPanel.this.repaint();
}
});
});
}
double offsetX = ANIMATION_LENGTH;
Timer timer;
boolean animationEnabled = true;
public void animate() {
if (Settings.getInstance().isEnableAnimation() && animationEnabled) {
offsetX = 0;
timer.start();
}
}
@Override
public void paint(Graphics g) {
if (!(g instanceof Graphics2D)) {
super.paint(g);
return;
}
double pgs = 1 - Math.sin(Math.PI / 2 / ANIMATION_LENGTH * offsetX);
if (Math.abs(ANIMATION_LENGTH - offsetX) < 0.1) {
super.paint(g);
return;
}
if (pgs > 1)
pgs = 1;
if (pgs < 0)
pgs = 0;
Graphics2D gg = (Graphics2D) g;
int width = this.getWidth();
int height = this.getHeight();
if (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, width, height);
}
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
g2d.translate((int) (pgs * 50), 0);
super.paint(g2d);
g2d.dispose();
gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, (float) (1 - pgs)));
g.drawImage(image, 0, 0, this);
}
boolean selected = false;
@Override
public boolean isSelected() {
return selected;
}
@Override
public void onSelect() {
if (!selected)
animate();
selected = true;
}
@Override
public void onLeave() {
selected = false;
}
boolean created = false;
@Override
public void onCreate() {
created = true;
}
@Override
public boolean isCreated() {
return created;
}
}
@@ -1,74 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
/**
*
* @author huangyuhui
*/
public class DraggableFrame extends JFrame
implements MouseListener, MouseMotionListener {
private int dragGripX;
private int dragGripY;
@SuppressWarnings("LeakingThisInConstructor")
public DraggableFrame() {
addMouseListener(this);
addMouseMotionListener(this);
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == 1 && isUndecorated()) {
this.dragGripX = e.getX();
this.dragGripY = e.getY();
}
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
if ((e.getModifiersEx() & 0x400) != 0 && isUndecorated())
setLocation(e.getXOnScreen() - this.dragGripX, e.getYOnScreen() - this.dragGripY);
}
@Override
public void mouseMoved(MouseEvent e) {
}
}
@@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jScrollPane2" pref="350" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="btnDownload" max="32767" attributes="0"/>
<Component id="btnRefreshGameDownloads" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="btnRefreshGameDownloads" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="btnDownload" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane2" alignment="0" pref="300" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="btnDownload">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.button.download" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnDownloadActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="lstDownloads">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="SwingUtils.makeDefaultTableModel(new String[]{C.i18n(&quot;install.version&quot;), C.i18n(&quot;install.time&quot;), C.i18n(&quot;install.type&quot;)},new Class[]{String.class, String.class, String.class}, new boolean[]{false, false, false})" type="code"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="true" resizingAllowed="true"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnRefreshGameDownloads">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.button.refresh" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRefreshGameDownloadsActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>
@@ -1,143 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import javax.swing.table.DefaultTableModel;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
import org.jackhuang.hellominecraft.launcher.core.download.MinecraftRemoteVersions;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.tasks.TaskWindow;
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public class GameDownloadPanel extends AnimatedPanel {
GameSettingsPanel gsp;
/**
* Creates new form GameDownloadPanel
*/
public GameDownloadPanel(GameSettingsPanel gsp) {
initComponents();
this.gsp = gsp;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
btnDownload = new javax.swing.JButton();
jScrollPane2 = new javax.swing.JScrollPane();
lstDownloads = new javax.swing.JTable();
btnRefreshGameDownloads = new javax.swing.JButton();
btnDownload.setText(C.i18n("ui.button.download")); // NOI18N
btnDownload.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnDownloadActionPerformed(evt);
}
});
lstDownloads.setModel(SwingUtils.makeDefaultTableModel(new String[]{C.i18n("install.version"), C.i18n("install.time"), C.i18n("install.type")},new Class[]{String.class, String.class, String.class}, new boolean[]{false, false, false}));
lstDownloads.setToolTipText("");
lstDownloads.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jScrollPane2.setViewportView(lstDownloads);
btnRefreshGameDownloads.setText(C.i18n("ui.button.refresh")); // NOI18N
btnRefreshGameDownloads.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRefreshGameDownloadsActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(btnDownload, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnRefreshGameDownloads, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(btnRefreshGameDownloads)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnDownload))
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
private void btnDownloadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDownloadActionPerformed
downloadMinecraft();
gsp.refreshVersions();
}//GEN-LAST:event_btnDownloadActionPerformed
private void btnRefreshGameDownloadsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRefreshGameDownloadsActionPerformed
refreshDownloads();
}//GEN-LAST:event_btnRefreshGameDownloadsActionPerformed
public void refreshDownloads() {
DefaultTableModel model = SwingUtils.clearDefaultTable(lstDownloads);
MinecraftRemoteVersions.refreshRomoteVersions(Settings.getLastProfile().service().getDownloadType())
.reg((ver) -> model.addRow(new Object[] { ver.id, ver.time,
StrUtils.equalsOne(ver.type, "old_beta", "old_alpha", "release", "snapshot") ? C.i18n("versions." + ver.type) : ver.type }))
.regDone(lstDownloads::requestFocus).execute();
}
void downloadMinecraft() {
if (lstDownloads.getSelectedRow() < 0) {
MessageBox.Show(C.i18n("gamedownload.not_refreshed"));
return;
}
String id = (String) lstDownloads.getModel().getValueAt(lstDownloads.getSelectedRow(), 0);
TaskWindow.execute(Settings.getLastProfile().service().download().downloadMinecraft(id));
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnDownload;
private javax.swing.JButton btnRefreshGameDownloads;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JTable lstDownloads;
// End of variables declaration//GEN-END:variables
boolean refreshedDownloads = false;
@Override
public void onSelect() {
super.onSelect();
if (!refreshedDownloads) {
refreshedDownloads = true;
refreshDownloads();
}
}
}
@@ -1,989 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="ff" green="ff" red="ff" type="rgb"/>
</Property>
<Property name="opaque" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnlTop" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="tabVersionEdit" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="btnMakeLaunchScript" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnShowLog" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnTestGame" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="btnIncludeMinecraft" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="577" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="pnlTop" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tabVersionEdit" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnTestGame" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnShowLog" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnMakeLaunchScript" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace pref="447" max="32767" attributes="0"/>
<Component id="btnIncludeMinecraft" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JTabbedPane" name="tabVersionEdit">
<Properties>
<Property name="name" type="java.lang.String" value="tabVersionEdit" noResource="true"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new NewTabPane()"/>
<AuxValue name="JavaCodeGenerator_CreateCodePost" type="java.lang.String" value="((NewTabPane)tabVersionEdit).initializing = true;"/>
<AuxValue name="JavaCodeGenerator_allCodePost" type="java.lang.String" value="((NewTabPane)tabVersionEdit).initializing = false;"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="pnlSettings">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new AnimatedPanel()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="&lt;settings&gt;">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblJavaDir" min="-2" max="-2" attributes="0"/>
<Component id="lblMaxMemory" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblGameDir" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblRunDirectory" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblLauncherVisibility" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblDimension" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cboLauncherVisibility" alignment="1" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="txtWidth" min="-2" pref="100" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblDimensionX" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtHeight" min="-2" pref="100" max="-2" attributes="0"/>
<EmptySpace pref="63" max="32767" attributes="0"/>
<Component id="chkFullscreen" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="txtMaxMemory" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblMaxMemorySize" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="txtGameDir" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnChoosingGameDir" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="cboJava" min="-2" pref="100" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtJavaDir" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnChoosingJavaDir" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="cboRunDirectory" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="btnDownloadAllAssets" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="btnCleanGame" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtGameDir" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblGameDir" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnChoosingGameDir" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtJavaDir" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblJavaDir" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnChoosingJavaDir" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="cboJava" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblMaxMemorySize" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtMaxMemory" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblMaxMemory" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cboLauncherVisibility" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblLauncherVisibility" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cboRunDirectory" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblRunDirectory" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="4" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtHeight" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="chkFullscreen" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblDimensionX" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblDimension" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtWidth" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="99" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnDownloadAllAssets" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnCleanGame" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lblGameDir">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.game_directory" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtGameDir">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtGameDirFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblDimension">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.dimension" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtWidth">
<Properties>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtWidthFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="txtHeight">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtHeightFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblDimensionX">
<Properties>
<Property name="text" type="java.lang.String" value="x"/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="chkFullscreen">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.fullscreen" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkFullscreenItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="txtJavaDir">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtJavaDirFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblJavaDir">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.java_dir" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblMaxMemory">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.max_memory" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtMaxMemory">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtMaxMemoryFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblMaxMemorySize">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="C.i18n(&quot;settings.physical_memory&quot;) + &quot;: &quot; + OS.getTotalPhysicalMemory() / 1024 / 1024 + &quot;MB&quot;" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnDownloadAllAssets">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="assets.download_all" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnDownloadAllAssetsActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JComboBox" name="cboLauncherVisibility">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new javax.swing.DefaultComboBoxModel(new String[] { C.i18n(&quot;advancedsettings.launcher_visibility.close&quot;), C.i18n(&quot;advancedsettings.launcher_visibility.hide&quot;), C.i18n(&quot;advancedsettings.launcher_visibility.keep&quot;) })" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboLauncherVisibilityItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblLauncherVisibility">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="advancedsettings.launcher_visible" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblRunDirectory">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.run_directory" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboRunDirectory">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new javax.swing.DefaultComboBoxModel(new String[] { C.i18n(&quot;advancedsettings.game_dir.default&quot;), C.i18n(&quot;advancedsettings.game_dir.independent&quot;) })" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboRunDirectoryItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnChoosingJavaDir">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="ui.button.explore" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnChoosingJavaDirActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JComboBox" name="cboJava">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboJavaItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnChoosingGameDir">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="ui.button.explore" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnChoosingGameDirActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnCleanGame">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="setupwindow.clean" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCleanGameActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnlAdvancedSettings">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new AnimatedPanel()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="&lt;advancedsettings&gt;">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="advancedsettings" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtPrecalledCommand" alignment="0" max="32767" attributes="0"/>
<Component id="txtServerIP" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblMinecraftArgs" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblPermSize" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblJavaArgs" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtJavaArgs" pref="325" max="32767" attributes="0"/>
<Component id="txtMinecraftArgs" max="32767" attributes="0"/>
<Component id="txtPermSize" alignment="1" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtWrapperLauncher" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="lblPrecalledCommand1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="chkNoJVMArgs" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="chkDontCheckGame" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblPrecalledCommand" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblServerIP" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtJavaArgs" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblJavaArgs" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtMinecraftArgs" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblMinecraftArgs" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtPermSize" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblPermSize" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblPrecalledCommand1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtWrapperLauncher" min="-2" pref="26" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblPrecalledCommand" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtPrecalledCommand" min="-2" pref="26" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblServerIP" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtServerIP" min="-2" pref="26" max="-2" attributes="0"/>
<EmptySpace pref="39" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="chkNoJVMArgs" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="chkDontCheckGame" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lblJavaArgs">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="advancedsettings.jvm_args" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtJavaArgs">
<Properties>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="advancedsettings.java_args_default" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtJavaArgsFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="txtMinecraftArgs">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtMinecraftArgsFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblMinecraftArgs">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="advancedsettings.Minecraft_arguments" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblPermSize">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="advancedsettings.java_permanent_generation_space" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtPermSize">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtPermSizeFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="chkNoJVMArgs">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="advancedsettings.no_jvm_args" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkNoJVMArgsItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblPrecalledCommand">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="advancedsettings.precall_command" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtPrecalledCommand">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtPrecalledCommandFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblServerIP">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="advancedsettings.server_ip" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtServerIP">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtServerIPFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblPrecalledCommand1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="advancedsettings.wrapper_launcher" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtWrapperLauncher">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtWrapperLauncherFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="chkDontCheckGame">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="advancedsettings.dont_check_game_completeness" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkDontCheckGameItemStateChanged"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnlModManagement">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new AnimatedPanel()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="&lt;mods&gt;">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="mods" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnlModManagementContent" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnlModManagementContent" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="pnlModManagementContent">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="jScrollPane1" pref="550" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="btnRemoveMod" max="32767" attributes="0"/>
<Component id="btnAddMod" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="lblModInfo" pref="646" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="btnAddMod" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnRemoveMod" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="jScrollPane1" pref="299" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="lblModInfo" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="lstExternalMods">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="SwingUtils.makeDefaultTableModel(new String[]{&quot;&quot;, &quot;Mod&quot;, C.i18n(&quot;ui.label.version&quot;)}, new Class[]{Boolean.class,String.class,String.class}, new boolean[]{true,false,false})" type="code"/>
</Property>
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
<TableColumnModel selectionModel="1"/>
</Property>
<Property name="columnSelectionAllowed" type="boolean" value="true"/>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
</Properties>
<Events>
<EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="lstExternalModsKeyPressed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnAddMod">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="mods.add" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAddModActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnRemoveMod">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="mods.remove" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRemoveModActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblModInfo">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="mods.default_information" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="&#x9ed8;&#x8ba4;&#x5149;&#x6807;"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="lblModInfoMouseClicked"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnlAutoInstall">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new AnimatedPanel()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="&lt;settings.tabs.installers&gt;">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.tabs.installers" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tabInstallers" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tabInstallers" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JTabbedPane" name="tabInstallers">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new NewTabPane()"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnlTop">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="pnlSelection" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pnlManagement" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="pnlSelection" max="32767" attributes="0"/>
<Component id="pnlManagement" max="32767" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="pnlSelection">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblVersions" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblProfile" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cboProfiles" max="32767" attributes="0"/>
<Component id="cboVersions" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cboProfiles" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblProfile" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cboVersions" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblVersions" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lblProfile">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="ui.label.profile" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboProfiles">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboProfilesItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JComboBox" name="cboVersions">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboVersionsItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblVersions">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="ui.label.version" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnlManagement">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="btnNewProfile" max="32767" attributes="0"/>
<Component id="txtMinecraftVersion" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="btnRemoveProfile" max="32767" attributes="0"/>
<Component id="btnRefreshVersions" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="btnModify" max="32767" attributes="0"/>
<Component id="btnExplore" max="32767" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnNewProfile" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="btnRemoveProfile" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="btnExplore" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtMinecraftVersion" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="btnRefreshVersions" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="btnModify" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="btnModify">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.manage" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="btnModifyMouseClicked"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnRefreshVersions">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="ui.button.refresh" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRefreshVersionsActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="txtMinecraftVersion">
<Properties>
<Property name="editable" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnNewProfile">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="setupwindow.new" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnNewProfileActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnRemoveProfile">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="ui.button.delete" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRemoveProfileActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnExplore">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/launcher/I18N.properties" key="settings.explore" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="btnExploreMouseClicked"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnTestGame">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="settings.test_game" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnTestGameActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnShowLog">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="mainwindow.show_log" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnShowLogActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnMakeLaunchScript">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="mainwindow.make_launch_script" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnMakeLaunchScriptActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnIncludeMinecraft">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="setupwindow.include_minecraft" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnIncludeMinecraftActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>
File diff suppressed because it is too large. Load diff
@@ -1,112 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import java.awt.EventQueue;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.DefaultButtonModel;
import javax.swing.JLabel;
/**
*
* @author huangyuhui
*/
public class HeaderTab extends JLabel
implements MouseListener {
private boolean isActive;
private final DefaultButtonModel model;
public HeaderTab(String text) {
super(text);
this.model = new DefaultButtonModel();
setIsActive(false);
setBorder(BorderFactory.createEmptyBorder(6, 18, 7, 18));
addMouseListener(this);
}
public boolean isActive() {
return this.isActive;
}
public final void setIsActive(boolean isActive) {
this.isActive = isActive;
setOpaque(isActive);
EventQueue.invokeLater(HeaderTab.this::repaint);
}
public void addActionListener(ActionListener listener) {
this.model.addActionListener(listener);
}
public String getActionCommand() {
return this.model.getActionCommand();
}
public ActionListener[] getActionListeners() {
return this.model.getActionListeners();
}
public void removeActionListener(ActionListener listener) {
this.model.removeActionListener(listener);
}
public void setActionCommand(String command) {
this.model.setActionCommand(command);
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
if (!isEnabled())
return;
this.model.setPressed(true);
this.model.setArmed(true);
}
@Override
public void mouseReleased(MouseEvent e) {
if (!isEnabled())
return;
this.model.setPressed(false);
this.model.setArmed(false);
}
@Override
public void mouseEntered(MouseEvent e) {
if (!isEnabled())
return;
this.model.setRollover(true);
}
@Override
public void mouseExited(MouseEvent e) {
if (!isEnabled())
return;
this.model.setRollover(false);
}
}
@@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jScrollPane12" pref="292" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="btnRefresh" max="32767" attributes="0"/>
<Component id="btnInstall" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane12" pref="147" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="btnInstall" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnRefresh" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="btnInstall">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.button.install" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnInstallActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane12">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="lstInstallers">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="SwingUtils.makeDefaultTableModel(new String[]{C.i18n(&quot;install.version&quot;), C.i18n(&quot;install.mcversion&quot;)},&#xa; new Class[]{String.class, String.class}, new boolean[]{false, false})" type="code"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="true" resizingAllowed="true"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnRefresh">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.button.refresh" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRefreshActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>
@@ -1,173 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerType;
import org.jackhuang.hellominecraft.launcher.core.install.InstallerVersionList;
import org.jackhuang.hellominecraft.util.tasks.TaskRunnable;
import org.jackhuang.hellominecraft.util.tasks.TaskWindow;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public class InstallerPanel extends AnimatedPanel {
GameSettingsPanel gsp;
/**
* Creates new form InstallerPanel
*
* @param gsp To get the minecraft version
* @param installerType load which installer
*/
public InstallerPanel(GameSettingsPanel gsp, InstallerType installerType) {
initComponents();
setOpaque(false);
this.gsp = gsp;
id = installerType;
list = Settings.getInstance().getDownloadSource().getProvider().getInstallerByType(id);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
btnInstall = new javax.swing.JButton();
jScrollPane12 = new javax.swing.JScrollPane();
lstInstallers = new javax.swing.JTable();
btnRefresh = new javax.swing.JButton();
btnInstall.setText(C.i18n("ui.button.install")); // NOI18N
btnInstall.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnInstallActionPerformed(evt);
}
});
lstInstallers.setModel(SwingUtils.makeDefaultTableModel(new String[]{C.i18n("install.version"), C.i18n("install.mcversion")},
new Class[]{String.class, String.class}, new boolean[]{false, false}));
lstInstallers.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jScrollPane12.setViewportView(lstInstallers);
btnRefresh.setText(C.i18n("ui.button.refresh")); // NOI18N
btnRefresh.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRefreshActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane12, javax.swing.GroupLayout.DEFAULT_SIZE, 292, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(btnRefresh, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnInstall, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane12, javax.swing.GroupLayout.DEFAULT_SIZE, 147, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(btnInstall)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnRefresh)
.addGap(0, 0, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void btnInstallActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnInstallActionPerformed
downloadSelectedRow();
}//GEN-LAST:event_btnInstallActionPerformed
private void btnRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRefreshActionPerformed
refreshVersions();
}//GEN-LAST:event_btnRefreshActionPerformed
transient List<InstallerVersionList.InstallerVersion> versions;
transient InstallerVersionList list;
InstallerType id;
void refreshVersions() {
if (TaskWindow.execute(list.refresh(new String[] { gsp.getMinecraftVersionFormatted() })))
loadVersions();
}
public synchronized InstallerVersionList.InstallerVersion getVersion(int idx) {
return versions.get(idx);
}
synchronized void downloadSelectedRow() {
int idx = lstInstallers.getSelectedRow();
if (versions == null || idx < 0 || idx >= versions.size()) {
MessageBox.Show(C.i18n("install.not_refreshed"));
return;
}
TaskWindow.execute(Settings.getLastProfile().service().install().download(Settings.getLastProfile().getSelectedVersion(), getVersion(idx), id),
new TaskRunnable(this::refreshVersions));
}
public void loadVersions() {
SwingUtilities.invokeLater(() -> {
synchronized (InstallerPanel.this) {
DefaultTableModel model = (DefaultTableModel) lstInstallers.getModel();
String mcver = StrUtils.formatVersion(gsp.getMinecraftVersionFormatted());
versions = list.getVersions(mcver);
SwingUtils.clearDefaultTable(lstInstallers);
if (versions != null)
for (InstallerVersionList.InstallerVersion v : versions)
if (v != null)
model.addRow(new Object[] { v.selfVersion == null ? "null" : v.selfVersion, v.mcVersion == null ? "null" : v.mcVersion });
}
});
}
boolean refreshed = false;
@Override
public void onSelect() {
if (!refreshed) {
refreshVersions();
refreshed = true;
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnInstall;
private javax.swing.JButton btnRefresh;
private javax.swing.JScrollPane jScrollPane12;
private javax.swing.JTable lstInstallers;
// End of variables declaration//GEN-END:variables
}
@@ -1,349 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="chkEnableShadow" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="chkEnableAnimation" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="btnCheckUpdate" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="chkDecorated" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="lblProxy" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="lblProxyHost" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtProxyHost" min="-2" pref="80" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblProxyPort" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtProxyPort" min="-2" pref="80" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblProxyUserName" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtProxyUsername" min="-2" pref="80" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblProxyPassword" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtProxyPassword" min="-2" pref="80" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblDownloadSource" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblTheme" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblBackground" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblLang" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cboLang" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Component id="txtBackgroundPath" pref="664" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnSelBackgroundPath" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="cboDownloadSource" alignment="1" max="32767" attributes="0"/>
<Component id="cboTheme" alignment="1" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblAbout" min="-2" max="-2" attributes="0"/>
<Component id="lblModpack" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblRestart" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblBackground" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnSelBackgroundPath" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="txtBackgroundPath" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblDownloadSource" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboDownloadSource" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblTheme" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboTheme" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblLang" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboLang" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtProxyHost" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblProxy" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblProxyHost" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtProxyPort" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblProxyPort" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtProxyUsername" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblProxyUserName" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtProxyPassword" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblProxyPassword" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="chkEnableShadow" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="chkEnableAnimation" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnCheckUpdate" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="chkDecorated" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblRestart" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="65" max="32767" attributes="0"/>
<Component id="lblModpack" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblAbout" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JComboBox" name="cboDownloadSource">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboDownloadSourceItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblAbout">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.about" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="&#x624b;&#x578b;&#x5149;&#x6807;"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="lblAboutMouseClicked"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnSelBackgroundPath">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.button.explore" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSelBackgroundPathActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblBackground">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.background_location" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtBackgroundPath">
<Properties>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.background_tooltip" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtBackgroundPathFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblDownloadSource">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.download_source" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnCheckUpdate">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.update_launcher" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCheckUpdateActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="chkEnableShadow">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.enable_shadow" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkEnableShadowItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblTheme">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.theme" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboTheme">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultComboBoxModel(new String[]{C.i18n(&quot;color.blue&quot;),C.i18n(&quot;color.green&quot;),C.i18n(&quot;color.purple&quot;),C.i18n(&quot;color.dark_blue&quot;),C.i18n(&quot;color.orange&quot;),C.i18n(&quot;color.red&quot;)})" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboThemeItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblProxy">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.proxy" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtProxyHost">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtProxyHostFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblProxyHost">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="proxy.host" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtProxyPort">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtProxyPortFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblProxyPort">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="proxy.port" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblProxyUserName">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="proxy.username" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtProxyUsername">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtProxyUsernameFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="txtProxyPassword">
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtProxyPasswordFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblProxyPassword">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="proxy.password" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="chkEnableAnimation">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.enable_animation" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkEnableAnimationItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="chkDecorated">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.decorated" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkDecoratedItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblModpack">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.modpack" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="&#x624b;&#x578b;&#x5149;&#x6807;"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="lblModpackMouseClicked"/>
</Events>
</Component>
<Component class="javax.swing.JComboBox" name="cboLang">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultComboBoxModel(new String[]{C.i18n(&quot;color.blue&quot;),C.i18n(&quot;color.green&quot;),C.i18n(&quot;color.purple&quot;),C.i18n(&quot;color.dark_blue&quot;),C.i18n(&quot;color.orange&quot;),C.i18n(&quot;color.red&quot;)})" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboLangItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblLang">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.lang" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblRestart">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="launcher.restart" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>
@@ -1,455 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import java.awt.Color;
import java.io.IOException;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
import org.jackhuang.hellominecraft.launcher.core.download.DownloadType;
import org.jackhuang.hellominecraft.util.system.IOUtils;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.lang.SupportedLocales;
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public class LauncherSettingsPanel extends AnimatedPanel {
/**
* Creates new form LancherSettingsPanel
*/
public LauncherSettingsPanel() {
}
void initGui() {
initComponents();
DefaultComboBoxModel d = new DefaultComboBoxModel();
for (DownloadType type : DownloadType.values())
d.addElement(type.getName());
cboDownloadSource.setModel(d);
d = new DefaultComboBoxModel();
int id = 0;
for (SupportedLocales type : SupportedLocales.values()) {
d.addElement(type.showString());
if (type.name().equals(Settings.getInstance().getLocalization()))
id = type.ordinal();
}
cboLang.setModel(d);
cboLang.setSelectedIndex(id);
txtBackgroundPath.setText(Settings.getInstance().getBgpath());
txtProxyHost.setText(Settings.getInstance().getProxyHost());
txtProxyPort.setText(Settings.getInstance().getProxyPort());
txtProxyUsername.setText(Settings.getInstance().getProxyUserName());
txtProxyPassword.setText(Settings.getInstance().getProxyPassword());
cboDownloadSource.setSelectedIndex(Settings.getInstance().getDownloadType());
cboTheme.setSelectedIndex(Settings.getInstance().getTheme().ordinal());
chkEnableShadow.setSelected(Settings.getInstance().isEnableShadow());
chkEnableAnimation.setSelected(Settings.getInstance().isEnableAnimation());
chkDecorated.setSelected(Settings.getInstance().isDecorated());
setBackground(Color.white);
setOpaque(true);
}
@Override
public void onCreate() {
initGui();
super.onCreate();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
cboDownloadSource = new javax.swing.JComboBox();
lblAbout = new javax.swing.JLabel();
btnSelBackgroundPath = new javax.swing.JButton();
lblBackground = new javax.swing.JLabel();
txtBackgroundPath = new javax.swing.JTextField();
lblDownloadSource = new javax.swing.JLabel();
btnCheckUpdate = new javax.swing.JButton();
chkEnableShadow = new javax.swing.JCheckBox();
lblTheme = new javax.swing.JLabel();
cboTheme = new javax.swing.JComboBox();
lblProxy = new javax.swing.JLabel();
txtProxyHost = new javax.swing.JTextField();
lblProxyHost = new javax.swing.JLabel();
txtProxyPort = new javax.swing.JTextField();
lblProxyPort = new javax.swing.JLabel();
lblProxyUserName = new javax.swing.JLabel();
txtProxyUsername = new javax.swing.JTextField();
txtProxyPassword = new javax.swing.JTextField();
lblProxyPassword = new javax.swing.JLabel();
chkEnableAnimation = new javax.swing.JCheckBox();
chkDecorated = new javax.swing.JCheckBox();
lblModpack = new javax.swing.JLabel();
cboLang = new javax.swing.JComboBox();
lblLang = new javax.swing.JLabel();
lblRestart = new javax.swing.JLabel();
cboDownloadSource.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboDownloadSourceItemStateChanged(evt);
}
});
lblAbout.setText(C.i18n("launcher.about")); // NOI18N
lblAbout.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
lblAbout.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
lblAboutMouseClicked(evt);
}
});
btnSelBackgroundPath.setText(C.i18n("ui.button.explore")); // NOI18N
btnSelBackgroundPath.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnSelBackgroundPathActionPerformed(evt);
}
});
lblBackground.setText(C.i18n("launcher.background_location")); // NOI18N
lblBackground.setToolTipText("");
txtBackgroundPath.setToolTipText(C.i18n("launcher.background_tooltip")); // NOI18N
txtBackgroundPath.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtBackgroundPathFocusLost(evt);
}
});
lblDownloadSource.setText(C.i18n("launcher.download_source")); // NOI18N
btnCheckUpdate.setText(C.i18n("launcher.update_launcher")); // NOI18N
btnCheckUpdate.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCheckUpdateActionPerformed(evt);
}
});
chkEnableShadow.setText(C.i18n("launcher.enable_shadow")); // NOI18N
chkEnableShadow.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkEnableShadowItemStateChanged(evt);
}
});
lblTheme.setText(C.i18n("launcher.theme")); // NOI18N
cboTheme.setModel(new DefaultComboBoxModel(new String[]{C.i18n("color.blue"),C.i18n("color.green"),C.i18n("color.purple"),C.i18n("color.dark_blue"),C.i18n("color.orange"),C.i18n("color.red")}));
cboTheme.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboThemeItemStateChanged(evt);
}
});
lblProxy.setText(C.i18n("launcher.proxy")); // NOI18N
txtProxyHost.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtProxyHostFocusLost(evt);
}
});
lblProxyHost.setText(C.i18n("proxy.host")); // NOI18N
txtProxyPort.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtProxyPortFocusLost(evt);
}
});
lblProxyPort.setText(C.i18n("proxy.port")); // NOI18N
lblProxyUserName.setText(C.i18n("proxy.username")); // NOI18N
txtProxyUsername.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtProxyUsernameFocusLost(evt);
}
});
txtProxyPassword.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtProxyPasswordFocusLost(evt);
}
});
lblProxyPassword.setText(C.i18n("proxy.password")); // NOI18N
chkEnableAnimation.setText(C.i18n("launcher.enable_animation")); // NOI18N
chkEnableAnimation.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkEnableAnimationItemStateChanged(evt);
}
});
chkDecorated.setText(C.i18n("launcher.decorated")); // NOI18N
chkDecorated.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkDecoratedItemStateChanged(evt);
}
});
lblModpack.setText(C.i18n("launcher.modpack")); // NOI18N
lblModpack.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
lblModpack.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
lblModpackMouseClicked(evt);
}
});
cboLang.setModel(new DefaultComboBoxModel(new String[]{C.i18n("color.blue"),C.i18n("color.green"),C.i18n("color.purple"),C.i18n("color.dark_blue"),C.i18n("color.orange"),C.i18n("color.red")}));
cboLang.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboLangItemStateChanged(evt);
}
});
lblLang.setText(C.i18n("launcher.lang")); // NOI18N
lblRestart.setText(C.i18n("launcher.restart")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(chkEnableShadow)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkEnableAnimation))
.addGroup(layout.createSequentialGroup()
.addComponent(btnCheckUpdate)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkDecorated))
.addGroup(layout.createSequentialGroup()
.addComponent(lblProxy)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lblProxyHost)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtProxyHost, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblProxyPort)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtProxyPort, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblProxyUserName)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtProxyUsername, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblProxyPassword)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtProxyPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblDownloadSource)
.addComponent(lblTheme)
.addComponent(lblBackground)
.addComponent(lblLang))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(cboLang, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(txtBackgroundPath, javax.swing.GroupLayout.DEFAULT_SIZE, 664, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnSelBackgroundPath))
.addComponent(cboDownloadSource, javax.swing.GroupLayout.Alignment.TRAILING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(cboTheme, javax.swing.GroupLayout.Alignment.TRAILING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblAbout, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblModpack, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblRestart))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblBackground)
.addComponent(btnSelBackgroundPath, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtBackgroundPath, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblDownloadSource)
.addComponent(cboDownloadSource, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblTheme)
.addComponent(cboTheme, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblLang)
.addComponent(cboLang, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtProxyHost, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblProxy)
.addComponent(lblProxyHost)
.addComponent(txtProxyPort, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblProxyPort)
.addComponent(txtProxyUsername, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblProxyUserName)
.addComponent(txtProxyPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblProxyPassword))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(chkEnableShadow)
.addComponent(chkEnableAnimation))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnCheckUpdate, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(chkDecorated))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblRestart)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 65, Short.MAX_VALUE)
.addComponent(lblModpack, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblAbout, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void cboDownloadSourceItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboDownloadSourceItemStateChanged
Settings.getInstance().setDownloadType(cboDownloadSource.getSelectedIndex());
}//GEN-LAST:event_cboDownloadSourceItemStateChanged
private void btnSelBackgroundPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSelBackgroundPathActionPerformed
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setDialogTitle(C.i18n("launcher.choose_bgpath"));
fc.setMultiSelectionEnabled(false);
fc.setFileFilter(new FileNameExtensionFilter("*.png", "png"));
fc.addChoosableFileFilter(new FileNameExtensionFilter("*.jpg", "jpg"));
fc.showOpenDialog(this);
if (fc.getSelectedFile() == null)
return;
try {
String path = fc.getSelectedFile().getCanonicalPath();
path = IOUtils.removeLastSeparator(path);
txtBackgroundPath.setText(path);
Settings.getInstance().setBgpath(path);
MainFrame.INSTANCE.loadBackground();
} catch (IOException e) {
HMCLog.warn("Failed to set background path.", e);
MessageBox.Show(C.i18n("ui.label.failed_set") + e.getMessage());
}
}//GEN-LAST:event_btnSelBackgroundPathActionPerformed
private void txtBackgroundPathFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtBackgroundPathFocusLost
Settings.getInstance().setBgpath(txtBackgroundPath.getText());
MainFrame.INSTANCE.loadBackground();
}//GEN-LAST:event_txtBackgroundPathFocusLost
private void btnCheckUpdateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheckUpdateActionPerformed
Settings.UPDATE_CHECKER.process(true);
Settings.UPDATE_CHECKER.checkOutdate();
}//GEN-LAST:event_btnCheckUpdateActionPerformed
private void cboThemeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboThemeItemStateChanged
Settings.getInstance().setTheme(cboTheme.getSelectedIndex());
}//GEN-LAST:event_cboThemeItemStateChanged
private void lblModpackMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lblModpackMouseClicked
SwingUtils.openLink("http://huangyuhui.duapp.com/link.php?type=modpack");
}//GEN-LAST:event_lblModpackMouseClicked
private void cboLangItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboLangItemStateChanged
Settings.getInstance().setLocalization(SupportedLocales.values()[cboLang.getSelectedIndex()].name());
}//GEN-LAST:event_cboLangItemStateChanged
private void chkEnableShadowItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkEnableShadowItemStateChanged
Settings.getInstance().setEnableShadow(chkEnableShadow.isSelected());
}//GEN-LAST:event_chkEnableShadowItemStateChanged
private void chkDecoratedItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkDecoratedItemStateChanged
Settings.getInstance().setDecorated(chkDecorated.isSelected());
}//GEN-LAST:event_chkDecoratedItemStateChanged
private void chkEnableAnimationItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkEnableAnimationItemStateChanged
Settings.getInstance().setEnableAnimation(chkEnableAnimation.isSelected());
}//GEN-LAST:event_chkEnableAnimationItemStateChanged
private void txtProxyHostFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtProxyHostFocusLost
Settings.getInstance().setProxyHost(txtProxyHost.getText());
}//GEN-LAST:event_txtProxyHostFocusLost
private void txtProxyPortFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtProxyPortFocusLost
Settings.getInstance().setProxyPort(txtProxyPort.getText());
}//GEN-LAST:event_txtProxyPortFocusLost
private void txtProxyUsernameFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtProxyUsernameFocusLost
Settings.getInstance().setProxyUserName(txtProxyUsername.getText());
}//GEN-LAST:event_txtProxyUsernameFocusLost
private void txtProxyPasswordFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtProxyPasswordFocusLost
Settings.getInstance().setProxyPassword(txtProxyPassword.getText());
}//GEN-LAST:event_txtProxyPasswordFocusLost
private void lblAboutMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lblAboutMouseClicked
SwingUtils.openLink("http://huangyuhui.duapp.com/link.php?type=sponsor");
}//GEN-LAST:event_lblAboutMouseClicked
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnCheckUpdate;
private javax.swing.JButton btnSelBackgroundPath;
private javax.swing.JComboBox cboDownloadSource;
private javax.swing.JComboBox cboLang;
private javax.swing.JComboBox cboTheme;
private javax.swing.JCheckBox chkDecorated;
private javax.swing.JCheckBox chkEnableAnimation;
private javax.swing.JCheckBox chkEnableShadow;
private javax.swing.JLabel lblAbout;
private javax.swing.JLabel lblBackground;
private javax.swing.JLabel lblDownloadSource;
private javax.swing.JLabel lblLang;
private javax.swing.JLabel lblModpack;
private javax.swing.JLabel lblProxy;
private javax.swing.JLabel lblProxyHost;
private javax.swing.JLabel lblProxyPassword;
private javax.swing.JLabel lblProxyPort;
private javax.swing.JLabel lblProxyUserName;
private javax.swing.JLabel lblRestart;
private javax.swing.JLabel lblTheme;
private javax.swing.JTextField txtBackgroundPath;
private javax.swing.JTextField txtProxyHost;
private javax.swing.JTextField txtProxyPassword;
private javax.swing.JTextField txtProxyPort;
private javax.swing.JTextField txtProxyUsername;
// End of variables declaration//GEN-END:variables
}
@@ -1,166 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.swing.JOptionPane;
import org.jackhuang.hellominecraft.launcher.util.LauncherVisibility;
import org.jackhuang.hellominecraft.launcher.core.launch.GameLauncher;
import org.jackhuang.hellominecraft.launcher.core.launch.LaunchingState;
import org.jackhuang.hellominecraft.launcher.setting.Profile;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
import org.jackhuang.hellominecraft.launcher.util.MinecraftCrashAdvicer;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.Event;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.func.Consumer;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.system.JavaProcessMonitor;
import org.jackhuang.hellominecraft.util.ui.LogWindow;
import org.jackhuang.hellominecraft.util.ui.WebFrame;
/**
*
* @author huangyuhui
*/
public class LaunchingUIDaemon {
Runnable customizedSuccessEvent = null;
void runGame(Profile profile) {
MainFrame.INSTANCE.showMessage(C.i18n("ui.message.launching"));
profile.launcher().genLaunchCode(value -> {
value.launchingStateChangedEvent.register(LAUNCHING_STATE_CHANGED);
value.successEvent.register(LAUNCH_FINISHER);
value.successEvent.register(customizedSuccessEvent);
}, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword());
}
void makeLaunchScript(Profile profile) {
MainFrame.INSTANCE.showMessage(C.i18n("ui.message.launching"));
profile.launcher().genLaunchCode(value -> {
value.launchingStateChangedEvent.register(LAUNCHING_STATE_CHANGED);
value.successEvent.register(LAUNCH_SCRIPT_FINISHER);
value.successEvent.register(customizedSuccessEvent);
}, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword());
}
private static final Consumer<LaunchingState> LAUNCHING_STATE_CHANGED = t -> {
String message = null;
switch (t) {
case LoggingIn:
message = "launch.state.logging_in";
break;
case GeneratingLaunchingCodes:
message = "launch.state.generating_launching_codes";
break;
case DownloadingLibraries:
message = "launch.state.downloading_libraries";
break;
case DecompressingNatives:
message = "launch.state.decompressing_natives";
break;
}
MainFrame.INSTANCE.showMessage(C.i18n(message));
};
private static final Event<List<String>> LAUNCH_FINISHER = (sender, str) -> {
final GameLauncher obj = (GameLauncher) sender;
obj.launchEvent.register(p -> {
if ((LauncherVisibility) obj.getTag() == LauncherVisibility.CLOSE && !LogWindow.INSTANCE.isVisible()) {
HMCLog.log("Without the option of keeping the launcher visible, this application will exit and will NOT catch game logs, but you can turn on \"Debug Mode\".");
System.exit(0);
} else if ((LauncherVisibility) obj.getTag() == LauncherVisibility.KEEP)
MainFrame.INSTANCE.closeMessage();
else {
if (LogWindow.INSTANCE.isVisible())
LogWindow.INSTANCE.setExit(() -> true);
MainFrame.INSTANCE.dispose();
}
JavaProcessMonitor jpm = new JavaProcessMonitor(p);
jpm.applicationExitedAbnormallyEvent.register(t -> {
HMCLog.err("The game exited abnormally, exit code: " + t);
String[] logs = jpm.getJavaProcess().getStdOutLines().toArray(new String[0]);
String errorText = null;
for (String s : logs) {
int pos = s.lastIndexOf("#@!@#");
if (pos >= 0 && pos < s.length() - "#@!@#".length() - 1) {
errorText = s.substring(pos + "#@!@#".length()).trim();
break;
}
}
String msg = C.i18n("launch.exited_abnormally") + " exit code: " + t;
if (errorText != null)
msg += ", advice: " + MinecraftCrashAdvicer.getAdvice(FileUtils.readFileToStringQuietly(new File(errorText)));
MessageBox.Show(msg);
WebFrame f = new WebFrame(logs);
f.setModal(true);
f.setTitle("Game output");
f.setVisible(true);
checkExit((LauncherVisibility) obj.getTag());
});
jpm.jvmLaunchFailedEvent.register(t -> {
HMCLog.err("Cannot create jvm, exit code: " + t);
MessageBox.Show(C.i18n("launch.cannot_create_jvm") + " exit code: " + t);
WebFrame f = new WebFrame(jpm.getJavaProcess().getStdOutLines().toArray(new String[0]));
f.setModal(true);
f.setTitle("Game output");
f.setVisible(true);
checkExit((LauncherVisibility) obj.getTag());
});
jpm.stoppedEvent.register(() -> checkExit((LauncherVisibility) obj.getTag()));
jpm.start();
});
try {
obj.launch(str);
} catch (IOException e) {
MainFrame.INSTANCE.failed(C.i18n("launch.failed_creating_process") + "\n" + e.getMessage());
HMCLog.err("Failed to launch when creating a new process.", e);
}
return true;
};
private static void getCrashReport() {
}
private static void checkExit(LauncherVisibility v) {
if (v != LauncherVisibility.KEEP && !LogWindow.INSTANCE.isVisible()) {
HMCLog.log("Launcher will exit now.");
System.exit(0);
}
}
private static final Event<List<String>> LAUNCH_SCRIPT_FINISHER = (sender, str) -> {
boolean flag = false;
try {
String s = JOptionPane.showInputDialog(C.i18n("mainwindow.enter_script_name"));
if (s != null)
MessageBox.Show(C.i18n("mainwindow.make_launch_succeed") + " " + ((GameLauncher) sender).makeLauncher(s, str).getAbsolutePath());
flag = true;
} catch (IOException ex) {
MessageBox.Show(C.i18n("mainwindow.make_launch_script_failed"));
HMCLog.err("Failed to create script file.", ex);
}
MainFrame.INSTANCE.closeMessage();
return flag;
};
}
@@ -1,469 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Transparency;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.launcher.Main;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
import org.jackhuang.hellominecraft.launcher.core.auth.IAuthenticator;
import org.jackhuang.hellominecraft.util.ui.GraphicsUtils;
import org.jackhuang.hellominecraft.lookandfeel.Theme;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.util.ui.DropShadowBorder;
import org.jackhuang.hellominecraft.util.ui.TintablePanel;
import org.jackhuang.hellominecraft.util.ui.BasicColors;
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public final class MainFrame extends DraggableFrame {
public static final MainFrame INSTANCE = new MainFrame();
TintablePanel centralPanel;
JPanel header, infoSwap, realPanel;
CardLayout infoLayout;
JLabel backgroundLabel, windowTitle;
DropShadowBorder border;
boolean enableShadow;
String defaultTitle;
private int tempW, tempH;
void setContentSize(int w, int h) {
setSize(w, h);
tempW = w;
tempH = h;
}
MainFrame() {
setUndecorated(!Settings.getInstance().isDecorated());
defaultTitle = isUndecorated() ? Main.makeTitle() : "";
enableShadow = Settings.getInstance().isEnableShadow() && isUndecorated();
if (enableShadow)
setContentSize(834, 542);
else
setContentSize(802, 511);
setDefaultCloseOperation(3);
setTitle(Main.makeTitle());
initComponents();
loadBackground();
setLocationRelativeTo(null);
if (MainFrame.this.isUndecorated())
setResizable(false);
this.addWindowListener(new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
closing();
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
if (!MainFrame.this.isUndecorated()) {
int w = tempW + getWidth() - getContentPane().getWidth(), h = tempH + getHeight() - getContentPane().getHeight();
setSize(w, h);
setResizable(false);
setLocationRelativeTo(null);
}
}
@Override
public void windowDeactivated(WindowEvent e) {
}
});
if (enableShadow)
try {
setBackground(new Color(0, 0, 0, 0));
getRootPane().setBorder(border = new DropShadowBorder(borderColor, 4));
} catch (Throwable ex) {
HMCLog.err("Failed to set window transparent.", ex);
Settings.getInstance().setEnableShadow(false);
setSize(802, 511);
}
((JPanel) getContentPane()).setOpaque(true);
Settings.getInstance().themeChangedEvent.register(this::reloadColor);
SwingUtilities.invokeLater(() -> selectTab("main"));
}
private void initComponents() {
initBorderColor(Settings.getInstance().getTheme());
realPanel = new JPanel();
realPanel.setLayout(null);
header = new JPanel();
header.setBounds(0, 0, 800, 30);
realPanel.add(header);
header.setOpaque(true);
header.setLayout(new BoxLayout(header, BoxLayout.LINE_AXIS));
header.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 5));
header.setBackground(borderColor);
header.setForeground(BasicColors.COLOR_WHITE_TEXT);
ImageIcon headerIcon = Main.getIcon("icon.png");
this.setIconImage(headerIcon.getImage());
headerIcon = SwingUtils.scaleImage(headerIcon, 16, 16);
JLabel headerLabel = new JLabel(headerIcon);
headerLabel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 0));
header.add(headerLabel);
header.add(Box.createRigidArea(new Dimension(8, 0)));
initializeTab(new MainPagePanel(), "main");
initializeTab(new GameSettingsPanel(this), "game");
initializeTab(new LauncherSettingsPanel(), "launcher");
header.add(Box.createHorizontalGlue());
JPanel rightHeaderPanel = new JPanel();
rightHeaderPanel.setOpaque(false);
rightHeaderPanel.setLayout(new BoxLayout(rightHeaderPanel, BoxLayout.PAGE_AXIS));
rightHeaderPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0));
JPanel windowGadgetPanel = new JPanel();
windowGadgetPanel.setOpaque(false);
windowGadgetPanel.setLayout(new BoxLayout(windowGadgetPanel, BoxLayout.LINE_AXIS));
windowGadgetPanel.setAlignmentX(1.0F);
if (!Settings.getInstance().isDecorated()) {
ImageIcon minimizeIcon = Main.getIcon("minimize.png");
JButton minimizeButton = new JButton(minimizeIcon);
minimizeButton.setBorder(BorderFactory.createEmptyBorder());
minimizeButton.setContentAreaFilled(false);
minimizeButton.setCursor(new Cursor(12));
minimizeButton.setFocusable(false);
minimizeButton.addActionListener((e) -> MainFrame.this.minimizeWindow());
windowGadgetPanel.add(minimizeButton);
ImageIcon closeIcon = Main.getIcon("close.png");
JButton closeButton = new JButton(closeIcon);
closeButton.setBorder(BorderFactory.createEmptyBorder());
closeButton.setContentAreaFilled(false);
closeButton.addActionListener((e) -> MainFrame.this.closeWindow());
closeButton.setCursor(new Cursor(12));
closeButton.setFocusable(false);
windowGadgetPanel.add(closeButton);
}
rightHeaderPanel.add(windowGadgetPanel);
windowTitle = new JLabel(defaultTitle);
windowTitle.setForeground(BasicColors.COLOR_WHITE_TEXT);
windowTitle.addMouseListener(MouseListenerImpl.INSTANCE);
header.add(windowTitle);
header.add(Box.createHorizontalGlue());
header.add(rightHeaderPanel);
this.centralPanel = new TintablePanel();
this.centralPanel.setTintColor(BasicColors.COLOR_CENTRAL_BACK);
realPanel.add(this.centralPanel);
JPanel truePanel = new JPanel();
truePanel.setLayout(new BorderLayout());
this.infoSwap = new JPanel();
this.infoLayout = new CardLayout();
this.infoSwap.setLayout(infoLayout);
this.infoSwap.setOpaque(false);
tabWrapper = new JPanel[tabHeader.size()];
for (int i = 0; i < tabHeader.size(); i++) {
tabWrapper[i] = new JPanel();
tabWrapper[i].setLayout(new GridLayout());
infoSwap.add(tabWrapper[i], tabHeader.get(i).getActionCommand());
}
truePanel.add(this.infoSwap, "Center");
centralPanel.setLayout(null);
centralPanel.add(truePanel);
truePanel.setBounds(0, 0, 800, 480);
centralPanel.setBounds(0, 30, 800, 480);
setLayout(null);
realPanel.setBounds(1, 0, 800, 511);
add(realPanel);
}
private final ActionListener tabListener = e -> MainFrame.this.selectTab(e.getActionCommand());
private void initializeTab(AnimatedPanel inst, String cmd) {
HeaderTab tab = new HeaderTab(C.i18n("launcher.title." + cmd));
tab.setActionCommand(cmd);
tab.setForeground(BasicColors.COLOR_WHITE_TEXT);
tab.setBackground(borderColorDarker);
tab.setLayout(null);
tab.addActionListener(tabListener);
header.add(tab);
tabHeader.add(tab);
tabContent.add(inst);
}
private final List<HeaderTab> tabHeader = new ArrayList<>();
private JPanel tabWrapper[];
private final List<AnimatedPanel> tabContent = new ArrayList<>();
public void selectTab(String tabName) {
int chosen = -1;
AnimatedPanel onCreate = null, onSelect = null;
for (int i = 0; i < tabHeader.size(); i++)
if (tabName.equalsIgnoreCase(tabHeader.get(i).getActionCommand())) {
if (!tabContent.get(i).isCreated()) {
onCreate = tabContent.get(i);
tabWrapper[i].add(tabContent.get(i));
} else if (tabContent.get(i).isSelected())
continue;
chosen = i;
break;
}
if (chosen != -1) {
for (int i = 0; i < tabHeader.size(); i++)
if (i != chosen && tabContent.get(i) != null && tabContent.get(i).isSelected())
tabContent.get(i).onLeave();
for (int i = 0; i < tabHeader.size(); i++)
if (i == chosen) {
for (int j = 0; j < tabHeader.size(); j++)
if (j != i)
tabHeader.get(j).setIsActive(false);
tabHeader.get(i).setIsActive(true);
onSelect = tabContent.get(i);
}
this.infoLayout.show(this.infoSwap, tabName);
if (onCreate != null)
onCreate.onCreate();
if (onSelect != null)
onSelect.onSelect();
}
}
protected void closing() {
for (int i = 0; i < tabHeader.size(); i++)
if (tabContent.get(i) != null && tabContent.get(i).isSelected())
tabContent.get(i).onLeave();
}
protected void closeWindow() {
closing();
System.exit(0);
}
protected void minimizeWindow() {
setState(1);
}
ImageIcon background;
public void loadBackground() {
background = SwingUtils.searchBackgroundImage(Main.getIcon(Settings.getInstance().getTheme().settings.get("Customized.MainFrame.background_image")), Settings.getInstance().getBgpath(), 800, 480);
if (background != null)
if (backgroundLabel == null) {
backgroundLabel = new JLabel(background);
backgroundLabel.setBounds(0, 0, 800, 480);
centralPanel.add(backgroundLabel, -1);
} else
backgroundLabel.setIcon(background);
else
HMCLog.warn("No background image here! The background will be empty!");
}
public JPanel getTitleBar() {
return header;
}
boolean isShowedMessage = false;
public void closeMessage() {
if (isShowedMessage) {
isShowedMessage = false;
reloadColor(Settings.getInstance().getTheme());
windowTitle.setText(defaultTitle);
windowTitle.setForeground(Settings.UPDATE_CHECKER.OUT_DATED ? Color.red : Color.white);
}
}
public void showMessage(String message) {
isShowedMessage = true;
borderColor = BasicColors.COLOR_RED;
borderColorDarker = BasicColors.COLOR_RED_DARKER;
header.setBackground(borderColor);
for (HeaderTab tab : tabHeader)
tab.setBackground(borderColorDarker);
if (border != null)
border.setColor(borderColor);
repaint();
windowTitle.setText(message);
windowTitle.setForeground(Color.white);
}
public static void showMainFrame() {
IAuthenticator l = Settings.getInstance().getAuthenticator();
if (StrUtils.isBlank(l.getUserName()))
SwingUtilities.invokeLater(() -> MainFrame.INSTANCE.showMessage(C.i18n("ui.message.first_load")));
if (l.hasPassword() && !l.isLoggedIn())
SwingUtilities.invokeLater(() -> MainFrame.INSTANCE.showMessage(C.i18n("ui.message.enter_password")));
INSTANCE.setVisible(true);
}
Color borderColor;
Color borderColorDarker;
private void initBorderColor(Theme t) {
borderColor = GraphicsUtils.getWebColor(t.settings.get("Customized.MainFrame.background"));
borderColorDarker = GraphicsUtils.getWebColor(t.settings.get("Customized.MainFrame.selected_background"));
}
public void reloadColor(Theme t) {
initBorderColor(t);
if (border != null)
border.setColor(borderColor);
header.setBackground(borderColor);
for (HeaderTab tab : tabHeader)
tab.setBackground(borderColorDarker);
repaint();
}
private void paintImpl(Graphics g) {
int off = enableShadow ? 16 : 0, yoff = getInsets().top + off, xoff = getInsets().left + off;
int width = 800;
int height = header.getHeight() + 480 - 1;
super.paint(g);
g.setColor(borderColor);
g.drawLine(xoff, yoff, xoff, height + yoff + 1);
g.drawLine(xoff + width + 1, yoff, xoff + width + 1, height + yoff + 1);
g.drawLine(xoff, height + yoff + 1, xoff + width + 1, height + yoff + 1);
}
@Override
public void paint(Graphics g) {
if (!enableShadow)
paintImpl(g);
else {
int off = enableShadow ? 16 : 0;
int width = this.getWidth();
int height = this.getHeight();
int contentWidth = width - off - off;
int contentHeight = height - off - off;
BufferedImage contentImage = new BufferedImage(contentWidth,
contentHeight, Transparency.OPAQUE);
Graphics2D contentG2d = contentImage.createGraphics();
contentG2d.translate(-off, -off);
paintImpl(g);
paintImpl(contentG2d);
contentG2d.dispose();
g.drawImage(contentImage, off, off, this);
}
}
public void invokeUpdate() {
defaultTitle = Main.makeTitle() + C.i18n("update.found");
if (!isShowedMessage) {
windowTitle.setText(defaultTitle);
windowTitle.setForeground(Color.red);
}
}
private static class MouseListenerImpl implements MouseListener {
public static final MouseListenerImpl INSTANCE = new MouseListenerImpl();
@Override
public void mouseClicked(MouseEvent e) {
Settings.UPDATE_CHECKER.checkOutdate();
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
public void failed(String s) {
if (s != null)
MessageBox.Show(s);
closeMessage();
}
LaunchingUIDaemon daemon = new LaunchingUIDaemon();
final HashMap<String, Runnable> actions = new HashMap<>();
void invokeAction(String name) {
if (actions.containsKey(name))
actions.get(name).run();
}
}
@@ -1,281 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-32,0,0,3,32"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
<Property name="useNullLayout" type="boolean" value="true"/>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="pnlMore">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="cc" green="cc" red="cc" type="rgb"/>
</Property>
<Property name="opaque" type="boolean" value="false"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
<AbsoluteConstraints x="0" y="0" width="190" height="480"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnlPassword" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel10" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblVersion" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cboProfiles" alignment="0" pref="128" max="32767" attributes="0"/>
<Component id="cboVersions" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblUserName" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel7" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cboLoginMode" max="32767" attributes="0"/>
<Component id="txtPlayerName" max="32767" attributes="0"/>
</Group>
</Group>
<Component id="btnExportModpack" alignment="0" max="32767" attributes="0"/>
<Component id="btnImportModpack" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel10" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboProfiles" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cboVersions" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblVersion" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel7" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboLoginMode" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblUserName" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtPlayerName" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="pnlPassword" min="-2" pref="26" max="-2" attributes="0"/>
<EmptySpace pref="248" max="32767" attributes="0"/>
<Component id="btnImportModpack" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnExportModpack" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="txtPlayerName">
<Events>
<EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtPlayerNameFocusGained"/>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtPlayerNameFocusLost"/>
<EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="txtPlayerNameKeyPressed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabel7">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="login.type" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboLoginMode">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboLoginModeItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblUserName">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="login.username" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel10">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.label.profile" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboProfiles">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboProfilesItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblVersion">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.label.version" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.label.version" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboVersions">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboVersionsItemStateChanged"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="pnlPassword">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignCardLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="card2"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel9" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtPassword" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel9" alignment="3" min="-2" pref="22" max="-2" attributes="0"/>
<Component id="txtPassword" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel9">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.label.password" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JPasswordField" name="txtPassword">
<Events>
<EventHandler event="caretUpdate" listener="javax.swing.event.CaretListener" parameters="javax.swing.event.CaretEvent" handler="txtPasswordCaretUpdate"/>
<EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtPasswordFocusGained"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtPasswordActionPerformed"/>
<EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="txtPasswordKeyPressed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jPanel3">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="card3"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="btnLogout" alignment="0" pref="170" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="btnLogout" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="btnLogout">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.button.logout" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnLogoutActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnImportModpack">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="modpack.task.install" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnImportModpackActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnExportModpack">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="modpack.task.save" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnExportModpackActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -1,543 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.core.auth.IAuthenticator;
import org.jackhuang.hellominecraft.launcher.setting.Profile;
import org.jackhuang.hellominecraft.util.MessageBox;
import org.jackhuang.hellominecraft.util.StrUtils;
import org.jackhuang.hellominecraft.launcher.core.version.MinecraftVersion;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
import org.jackhuang.hellominecraft.launcher.core.mod.ModpackManager;
import org.jackhuang.hellominecraft.launcher.core.service.IMinecraftService;
import org.jackhuang.hellominecraft.launcher.ui.modpack.ModpackWizard;
import org.jackhuang.hellominecraft.launcher.util.HMCLMinecraftService;
import org.jackhuang.hellominecraft.util.ui.GraphicsUtils;
import org.jackhuang.hellominecraft.util.Event;
import org.jackhuang.hellominecraft.lookandfeel.comp.ConstomButton;
import org.jackhuang.hellominecraft.util.func.Consumer;
import org.jackhuang.hellominecraft.util.system.FileUtils;
import org.jackhuang.hellominecraft.util.tasks.TaskWindow;
import org.jackhuang.hellominecraft.util.ui.SwingUtils;
import org.jackhuang.hellominecraft.util.ui.wizard.api.WizardDisplayer;
/**
*
* @author huangyuhui
*/
public class MainPagePanel extends AnimatedPanel {
/**
* Creates new form MainPagePanel
*/
public MainPagePanel() {
}
void initGui() {
initComponents();
pnlButtons = new javax.swing.JPanel();
pnlButtons.setLayout(null);
int w = 150, h = 50;
btnRun = new ConstomButton();
btnRun.setBounds(0, 0, w, h);
Font font = btnRun.getFont();
Font newFont = new Font(font.getName(), font.getStyle(), 15);
pnlButtons.add(btnRun);
btnRun.setText(C.i18n("ui.button.run"));
btnRun.setFont(newFont);
btnRun.addActionListener(e -> MainFrame.INSTANCE.daemon.runGame(Settings.getLastProfile()));
this.add(pnlButtons);
pnlButtons.setBounds(0, 0, w, h);
this.setSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
this.pnlButtons.setLocation(DEFAULT_WIDTH - pnlButtons.getWidth() - 25, DEFAULT_HEIGHT - pnlButtons.getHeight() - 25);
pnlMore.setBounds(0, 0, pnlMore.getWidth(), DEFAULT_HEIGHT);
pnlMore.setBackground(GraphicsUtils.getWebColorWithAlpha("FFFFFF7F"));
pnlMore.setOpaque(true);
Settings.getInstance().authChangedEvent.register(onAuthChanged);
Settings.profileLoadingEvent.register(onLoadingProfiles);
Settings.profileChangedEvent.register(onSelectedProfilesChanged);
MainFrame.INSTANCE.daemon.customizedSuccessEvent = this::prepareAuths;
prepareAuths();
animationEnabled = false;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
pnlMore = new javax.swing.JPanel();
txtPlayerName = new javax.swing.JTextField();
jLabel7 = new javax.swing.JLabel();
cboLoginMode = new javax.swing.JComboBox();
lblUserName = new javax.swing.JLabel();
jLabel10 = new javax.swing.JLabel();
cboProfiles = new javax.swing.JComboBox();
lblVersion = new javax.swing.JLabel();
cboVersions = new javax.swing.JComboBox();
pnlPassword = new javax.swing.JPanel();
jPanel1 = new javax.swing.JPanel();
jLabel9 = new javax.swing.JLabel();
txtPassword = new javax.swing.JPasswordField();
jPanel3 = new javax.swing.JPanel();
btnLogout = new javax.swing.JButton();
btnImportModpack = new javax.swing.JButton();
btnExportModpack = new javax.swing.JButton();
setLayout(null);
pnlMore.setBackground(new java.awt.Color(204, 204, 204));
pnlMore.setOpaque(false);
txtPlayerName.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
txtPlayerNameFocusGained(evt);
}
public void focusLost(java.awt.event.FocusEvent evt) {
txtPlayerNameFocusLost(evt);
}
});
txtPlayerName.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
txtPlayerNameKeyPressed(evt);
}
});
jLabel7.setText(C.i18n("login.type")); // NOI18N
cboLoginMode.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboLoginModeItemStateChanged(evt);
}
});
lblUserName.setText(C.i18n("login.username")); // NOI18N
jLabel10.setText(C.i18n("ui.label.profile")); // NOI18N
cboProfiles.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboProfilesItemStateChanged(evt);
}
});
lblVersion.setText(C.i18n("ui.label.version")); // NOI18N
lblVersion.setToolTipText(C.i18n("ui.label.version")); // NOI18N
cboVersions.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboVersionsItemStateChanged(evt);
}
});
pnlPassword.setLayout(new java.awt.CardLayout());
jLabel9.setText(C.i18n("ui.label.password")); // NOI18N
txtPassword.addCaretListener(new javax.swing.event.CaretListener() {
public void caretUpdate(javax.swing.event.CaretEvent evt) {
txtPasswordCaretUpdate(evt);
}
});
txtPassword.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
txtPasswordFocusGained(evt);
}
});
txtPassword.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtPasswordActionPerformed(evt);
}
});
txtPassword.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
txtPasswordKeyPressed(evt);
}
});
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(jLabel9)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtPassword))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel9, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)))
);
pnlPassword.add(jPanel1, "card2");
btnLogout.setText(C.i18n("ui.button.logout")); // NOI18N
btnLogout.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnLogoutActionPerformed(evt);
}
});
javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
jPanel3.setLayout(jPanel3Layout);
jPanel3Layout.setHorizontalGroup(
jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnLogout, javax.swing.GroupLayout.DEFAULT_SIZE, 170, Short.MAX_VALUE)
);
jPanel3Layout.setVerticalGroup(
jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnLogout, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
pnlPassword.add(jPanel3, "card3");
btnImportModpack.setText(C.i18n("modpack.task.install")); // NOI18N
btnImportModpack.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnImportModpackActionPerformed(evt);
}
});
btnExportModpack.setText(C.i18n("modpack.task.save")); // NOI18N
btnExportModpack.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnExportModpackActionPerformed(evt);
}
});
javax.swing.GroupLayout pnlMoreLayout = new javax.swing.GroupLayout(pnlMore);
pnlMore.setLayout(pnlMoreLayout);
pnlMoreLayout.setHorizontalGroup(
pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlMoreLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnlPassword, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(pnlMoreLayout.createSequentialGroup()
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel10, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblVersion, javax.swing.GroupLayout.Alignment.TRAILING))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(cboProfiles, 0, 128, Short.MAX_VALUE)
.addComponent(cboVersions, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(pnlMoreLayout.createSequentialGroup()
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblUserName)
.addComponent(jLabel7))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(cboLoginMode, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(txtPlayerName)))
.addComponent(btnExportModpack, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnImportModpack, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
pnlMoreLayout.setVerticalGroup(
pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnlMoreLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel10)
.addComponent(cboProfiles, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cboVersions, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblVersion))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel7)
.addComponent(cboLoginMode, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlMoreLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblUserName)
.addComponent(txtPlayerName, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pnlPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 248, Short.MAX_VALUE)
.addComponent(btnImportModpack)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnExportModpack)
.addContainerGap())
);
add(pnlMore);
pnlMore.setBounds(0, 0, 190, 480);
}// </editor-fold>//GEN-END:initComponents
private void txtPlayerNameFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtPlayerNameFocusGained
MainFrame.INSTANCE.closeMessage();
}//GEN-LAST:event_txtPlayerNameFocusGained
private void txtPlayerNameFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtPlayerNameFocusLost
IAuthenticator l = Settings.getInstance().getAuthenticator();
l.setUserName(txtPlayerName.getText());
}//GEN-LAST:event_txtPlayerNameFocusLost
private void cboLoginModeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboLoginModeItemStateChanged
if (evt.getStateChange() != ItemEvent.SELECTED)
return;
if (preparingAuth)
return;
Settings.getInstance().setLoginType(cboLoginMode.getSelectedIndex());
}//GEN-LAST:event_cboLoginModeItemStateChanged
private void cboProfilesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboProfilesItemStateChanged
if (!isLoading && cboProfiles.getSelectedIndex() != -1 && !StrUtils.isBlank((String) cboProfiles.getSelectedItem()))
Settings.getInstance().setLast((String) cboProfiles.getSelectedItem());
}//GEN-LAST:event_cboProfilesItemStateChanged
private void cboVersionsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboVersionsItemStateChanged
if (isLoading || evt.getStateChange() != ItemEvent.SELECTED || cboVersions.getSelectedIndex() < 0 || StrUtils.isBlank((String) cboVersions.getSelectedItem()))
return;
String mcv = (String) cboVersions.getSelectedItem();
Settings.getLastProfile().setSelectedMinecraftVersion(mcv);
}//GEN-LAST:event_cboVersionsItemStateChanged
private void txtPasswordFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtPasswordFocusGained
MainFrame.INSTANCE.closeMessage();
}//GEN-LAST:event_txtPasswordFocusGained
private void txtPasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtPasswordActionPerformed
MainFrame.INSTANCE.daemon.runGame(Settings.getLastProfile());
}//GEN-LAST:event_txtPasswordActionPerformed
private void btnLogoutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLogoutActionPerformed
if (preparingAuth)
return;
IAuthenticator l = Settings.getInstance().getAuthenticator();
CardLayout cl = (CardLayout) pnlPassword.getLayout();
if (l.isLoggedIn())
l.logOut();
cl.first(pnlPassword);
SwingUtilities.invokeLater(this::repaint);
}//GEN-LAST:event_btnLogoutActionPerformed
private void txtPlayerNameKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtPlayerNameKeyPressed
if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
IAuthenticator l = Settings.getInstance().getAuthenticator();
l.setUserName(txtPlayerName.getText());
if (!l.hasPassword())
MainFrame.INSTANCE.daemon.runGame(Settings.getLastProfile());
else if (!l.isLoggedIn())
txtPassword.requestFocus();
}
}//GEN-LAST:event_txtPlayerNameKeyPressed
private void txtPasswordKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtPasswordKeyPressed
if (evt.getKeyCode() == KeyEvent.VK_ENTER)
MainFrame.INSTANCE.daemon.runGame(Settings.getLastProfile());
}//GEN-LAST:event_txtPasswordKeyPressed
private void btnImportModpackActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnImportModpackActionPerformed
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setDialogTitle(C.i18n("modpack.choose"));
fc.setMultiSelectionEnabled(false);
fc.setFileFilter(new FileNameExtensionFilter(C.i18n("modpack"), "zip"));
fc.showOpenDialog(this);
if (fc.getSelectedFile() == null)
return;
String suggestedModpackId = JOptionPane.showInputDialog("Please enter your favourite game name", FileUtils.getBaseName(fc.getSelectedFile().getName()));
TaskWindow.factory().append(ModpackManager.install(MainFrame.INSTANCE, fc.getSelectedFile(), Settings.getLastProfile().service(), suggestedModpackId)).create();
Settings.getLastProfile().service().version().refreshVersions();
}//GEN-LAST:event_btnImportModpackActionPerformed
private void btnExportModpackActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExportModpackActionPerformed
if (Settings.getLastProfile().service().version().getVersionCount() <= 0)
return;
WizardDisplayer.showWizard(new ModpackWizard(Settings.getLastProfile()).createWizard());
}//GEN-LAST:event_btnExportModpackActionPerformed
private void txtPasswordCaretUpdate(javax.swing.event.CaretEvent evt) {//GEN-FIRST:event_txtPasswordCaretUpdate
Settings.getInstance().getAuthenticator().setPassword(txtPassword.getText());
}//GEN-LAST:event_txtPasswordCaretUpdate
// <editor-fold defaultstate="collapsed" desc="Loads">
private void prepareAuths() {
preparingAuth = true;
cboLoginMode.removeAllItems();
for (IAuthenticator str : IAuthenticator.LOGINS)
cboLoginMode.addItem(str.getName());
preparingAuth = false;
int loginType = Settings.getInstance().getLoginType();
if (0 <= loginType && loginType < cboLoginMode.getItemCount()) {
cboLoginMode.setSelectedIndex(loginType);
Settings.getInstance().setLoginType(loginType);
}
}
//</editor-fold>
// <editor-fold defaultstate="collapsed" desc="Private Variables">
boolean preparingAuth = true;
private boolean isLoading = false;
private javax.swing.JPanel pnlButtons;
private ConstomButton btnRun;
private static final int DEFAULT_WIDTH = 800, DEFAULT_HEIGHT = 480;
//</editor-fold>
@Override
public void onCreate() {
initGui();
super.onCreate();
Settings.onProfileLoading();
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnExportModpack;
private javax.swing.JButton btnImportModpack;
private javax.swing.JButton btnLogout;
private javax.swing.JComboBox cboLoginMode;
private javax.swing.JComboBox cboProfiles;
private javax.swing.JComboBox cboVersions;
private javax.swing.JLabel jLabel10;
private javax.swing.JLabel jLabel7;
private javax.swing.JLabel jLabel9;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel3;
private javax.swing.JLabel lblUserName;
private javax.swing.JLabel lblVersion;
private javax.swing.JPanel pnlMore;
private javax.swing.JPanel pnlPassword;
private javax.swing.JPasswordField txtPassword;
private javax.swing.JTextField txtPlayerName;
// End of variables declaration//GEN-END:variables
final Event<IAuthenticator> onAuthChanged = (sender, l) -> {
if (l.hasPassword()) {
pnlPassword.setVisible(true);
lblUserName.setText(C.i18n("login.account"));
} else {
pnlPassword.setVisible(false);
lblUserName.setText(C.i18n("login.username"));
}
CardLayout cl = (CardLayout) pnlPassword.getLayout();
if (l.isLoggedIn())
cl.last(pnlPassword);
else
cl.first(pnlPassword);
String username = l.getUserName();
if (username == null)
username = "";
txtPlayerName.setText(username);
return true;
};
final Runnable onLoadingProfiles = this::loadProfiles;
private void loadProfiles() {
isLoading = true;
DefaultComboBoxModel model = new DefaultComboBoxModel();
for (Profile s : Settings.getProfilesFiltered())
model.addElement(s.getName());
cboProfiles.setModel(model);
isLoading = false;
}
final Consumer<IMinecraftService> onRefreshedVersions = t -> {
if (Settings.getLastProfile().service() == t)
loadVersions();
};
boolean showedNoVersion = false;
void loadVersions() {
isLoading = true;
cboVersions.removeAllItems();
String selVersion = Settings.getLastProfile().getSelectedVersion();
if (Settings.getLastProfile().service().version().getVersions().isEmpty()) {
if (!showedNoVersion && ((HMCLMinecraftService) Settings.getLastProfile().service()).checkedModpack) {
showedNoVersion = true;
SwingUtilities.invokeLater(() -> {
if (MessageBox.Show(C.i18n("mainwindow.no_version"), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
MainFrame.INSTANCE.invokeAction("showGameDownloads");
});
}
} else {
for (MinecraftVersion mcVersion : Settings.getLastProfile().service().version().getVersions()) {
if (mcVersion.hidden)
continue;
cboVersions.addItem(mcVersion.id);
}
versionChanged.accept(selVersion);
}
isLoading = false;
}
final Consumer<Boolean> launchingStateChanged = t -> SwingUtils.setEnabled(MainFrame.INSTANCE.getRootPane(), !t);
final Consumer<String> versionChanged = this::versionChanged;
void versionChanged(String selectedVersion) {
isLoading = true;
DefaultComboBoxModel model = (DefaultComboBoxModel) cboVersions.getModel();
for (int i = 0; i < model.getSize(); ++i)
if (model.getElementAt(i).equals(selectedVersion)) {
model.setSelectedItem(selectedVersion);
break;
}
cboVersions.setToolTipText(selectedVersion);
isLoading = false;
}
final Consumer<Profile> onSelectedProfilesChanged = t -> {
t.service().version().onRefreshedVersions.register(onRefreshedVersions);
t.selectedVersionChangedEvent.register(versionChanged);
t.launcher().launchingStateChanged.register(launchingStateChanged);
isLoading = true;
DefaultComboBoxModel model = (DefaultComboBoxModel) cboProfiles.getModel();
for (int i = 0; i < model.getSize(); ++i)
if (model.getElementAt(i).equals(t.getName())) {
model.setSelectedItem(t.getName());
break;
}
isLoading = false;
};
}
@@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.newProfileWindow.title" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtNewProfileName" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cboProfiles" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="262" max="32767" attributes="0"/>
<Component id="btnOK" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtNewProfileName" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboProfiles" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnOK" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.label.newProfileWindow.new_profile_name" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtNewProfileName">
<Events>
<EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="txtNewProfileNameKeyTyped"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabel2">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.label.newProfileWindow.copy_from" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboProfiles">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnCancel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="button.cancel" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCancelActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnOK">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hellominecraft/lang/I18N.properties" key="ui.button.ok" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnOKActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>
@@ -1,164 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.launcher.setting.Profile;
import org.jackhuang.hellominecraft.launcher.setting.Settings;
import org.jackhuang.hellominecraft.util.StrUtils;
/**
*
* @author huangyuhui
*/
public final class NewProfileWindow extends javax.swing.JDialog {
public NewProfileWindow(java.awt.Frame parent) {
super(parent, true);
initComponents();
setLocationRelativeTo(null);
for (Profile s : Settings.getProfilesFiltered())
cboProfiles.addItem(s.getName());
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
txtNewProfileName = new javax.swing.JTextField();
jLabel2 = new javax.swing.JLabel();
cboProfiles = new javax.swing.JComboBox();
btnCancel = new javax.swing.JButton();
btnOK = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(C.i18n("ui.newProfileWindow.title")); // NOI18N
jLabel1.setText(C.i18n("ui.label.newProfileWindow.new_profile_name")); // NOI18N
txtNewProfileName.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
txtNewProfileNameKeyTyped(evt);
}
});
jLabel2.setText(C.i18n("ui.label.newProfileWindow.copy_from")); // NOI18N
btnCancel.setText(C.i18n("button.cancel")); // NOI18N
btnCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCancelActionPerformed(evt);
}
});
btnOK.setText(C.i18n("ui.button.ok")); // NOI18N
btnOK.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnOKActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtNewProfileName))
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cboProfiles, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 262, Short.MAX_VALUE)
.addComponent(btnOK)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(txtNewProfileName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel2)
.addComponent(cboProfiles, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnCancel)
.addComponent(btnOK))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void txtNewProfileNameKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtNewProfileNameKeyTyped
switch (evt.getKeyCode()) {
case 13:
act();
break;
case 27:
this.dispose();
break;
default:
break;
}
}//GEN-LAST:event_txtNewProfileNameKeyTyped
private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed
act();
}//GEN-LAST:event_btnOKActionPerformed
void act() {
if (!StrUtils.isBlank(txtNewProfileName.getText())) {
Profile newProfile = new Profile(txtNewProfileName.getText(), Settings.getProfile(cboProfiles.getSelectedItem().toString()));
Settings.putProfile(newProfile);
}
this.dispose();
}
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.dispose();
}//GEN-LAST:event_btnCancelActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnCancel;
private javax.swing.JButton btnOK;
private javax.swing.JComboBox cboProfiles;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JTextField txtNewProfileName;
// End of variables declaration//GEN-END:variables
}
@@ -1,48 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.launcher.ui;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
*
* @author huangyuhui
*/
public class NewTabPane extends JTabbedPane implements ChangeListener {
public NewTabPane() {
super();
addChangeListener(this);
}
public boolean initializing;
@Override
public void stateChanged(ChangeEvent e) {
if (initializing)
return;
for (int i = 0; i < getComponentCount(); ++i)
if (getSelectedIndex() != i && getComponent(i) instanceof Selectable)
((Selectable) getComponent(i)).onLeave();
if (getSelectedComponent() instanceof Selectable)
((Selectable) getSelectedComponent()).onSelect();
}
}
Loaded 100 of 849 files, more files were not shown because too many files have changed in this diff. Show more