Compare commits

..
Author SHA1 Message Date
huangyuhui 3721842c8b Removed funtionalities of Log4jHandler 2017-11-04 22:30:38 +08:00
huangyuhui 47d8b59b93 Update Gradle 2017-11-04 10:22:37 +08:00
huangyuhui b5fbc69ee6 Default game arguments 2017-11-03 13:38:20 +08:00
huangyuhui 9d95d3ea66 JVM arguments in minecraft.json supported 2017-11-02 20:21:32 +08:00
huangyuhui 06b3ec8337 Launching 1.13 2017-11-02 19:34:21 +08:00
huangyuhui fabb6b50b4 Prevent launching in path that contains ! 2017-10-31 19:31:22 +08:00
huangyuhui ca627b8a2d Update Gradle 2017-10-18 19:27:35 +08:00
huanghongxun a0c619a747 Ignore RejectedExecutionException 2017-10-11 20:03:17 +08:00
huanghongxun 5386ae3736 Removed log4j support 2017-10-11 19:54:08 +08:00
huangyuhui 32fd125b97 Added proxy type selection. Closes #192 2017-08-27 13:34:12 +08:00
huangyuhui 7a86881926 Fixed downloading libraries that are forbidden in specific OS. Closes #163 2017-08-26 17:45:40 +08:00
huangyuhui b255fd4601 CDATA 2017-08-26 09:04:10 +08:00
huangyuhui 562dd8d916 Fixed #190 2017-08-26 08:35:27 +08:00
huangyuhui 97d820446a Fixed Read end dead. Closes #186 2017-08-24 10:03:19 +08:00
huangyuhui 826d382ad5 Changed log colors. Closes #187 2017-08-24 09:37:33 +08:00
huangyuhui 59d7ac3c82 ProcessThread.interrupt 2017-08-20 12:07:13 +08:00
huanghongxun 566aed4ed6 Merge pull request #185 from ron-gh/master
Fix "java.io.IOException: Read end dead"
2017-08-18 21:32:53 +08:00
ron 1b90e94615 Fix "java.io.IOException: Read end dead" when different Threads are writing to a single PipedOutputStream 2017-08-18 14:54:55 +02:00
huanghongxun 22ede84c3d Merge pull request #183 from jp8900308/master
Set a custom User-Agent, fixes optifine.net downloads
2017-08-15 23:43:05 +08:00
Jean-Paul Bergeron 0c4da069b7 Set a custom User-Agent, fixes optifine.net downloads 2017-08-15 07:23:03 -07:00
huangyuhui 90733c6a7e Merge branch 'master' of https://github.com/huanghongxun/HMCL 2017-08-13 19:57:08 +08:00
huangyuhui 44daf656b5 Fixed downloading text2speech 2017-08-13 19:56:02 +08:00
huangyuhui 90f416095e Fixed multi-character account: no player when log in the next time 2017-08-13 19:39:41 +08:00
huanghongxun 076d4d5dce Merge pull request #180 from jp8900308/master
partial rv 7fe3e28a, fixes Forge on 1.12
2017-08-12 09:39:23 +08:00
Jean-Paul Bergeron 3c77f249e5 partial rv 7fe3e28a, fixes Forge on 1.12 2017-08-09 12:24:39 -07:00
huangyuhui 11e5dc3782 Update Russian lang 2017-08-07 21:55:03 +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
huangyuhui 8d5088d2e4 Removed findbugs 2016-04-25 23:28:29 +08:00
huangyuhui 47f5bf1ea5 Added an options to disable online game complete check 2016-04-25 23:09:56 +08:00
huangyuhui deebadef3a Fixed #61 2016-04-11 13:40:06 +08:00
huangyuhui ce24ae4fae Fixed #60 2016-04-06 19:41:33 +08:00
huangyuhui 16152de39d Fixed ClassCastException 2016-04-05 22:16:29 +08:00
huangyuhui 4a2ac63d25 Added removal of installers for Issue #55 2016-03-28 20:57:01 +08:00
huangyuhui 5437968c83 Fixed #56 2016-03-28 20:45:06 +08:00
huangyuhui 8022252452 Fixed task system 2016-03-27 14:13:59 +08:00
huangyuhui ea6571fdb6 Fix #53 2016-03-26 13:02:47 +08:00
huanghongxun 2f7f692b84 Merge pull request #51 from tsl0922/master
Fix cpu ratio for mac
2016-03-25 19:19:46 +08:00
Shuanglei Tao 721df1d17c Fix cpu ratio for mac 2016-03-24 21:29:48 +08:00
huangyuhui 7a2e43f949 Fixed #50 2016-03-19 19:55:42 +08:00
huangyuhui 4e5cc3dadb sponsor 2016-03-17 18:38:17 +08:00
huangyuhui f6d5dd5a82 Fixed NullPointerException when a version not exists. 2016-03-15 18:49:31 +08:00
huangyuhui cafcf458b8 Fixed auto-loading when deleting a profile 2016-03-12 11:57:30 +08:00
huangyuhui e7d0624b96 Added default profile: Home whose default game directory is $USER/.minecraft 2016-03-11 23:05:31 +08:00
huangyuhui 156de2457d Fixed wrong path in modpack zip on Linux/Mac 2016-03-11 20:13:10 +08:00
huangyuhui c839d045cc Might fix some problems 2016-03-09 13:14:53 +08:00
huangyuhui 2eaf32b23d Fixed BMCLAPI 2016-03-06 14:45:42 +08:00
huangyuhui 5899c73ab8 Should fixed #46 2016-03-05 21:43:54 +08:00
huangyuhui 6c0a446692 Fixed: Cannot cancel modpack installing 2016-03-05 14:31:32 +08:00
huangyuhui 7c2cfc171e Switch to CountDownLatch 2016-03-05 13:23:16 +08:00
huangyuhui 5d4a3c1df6 Fixed null when invoking some server commands 2016-03-04 20:18:25 +08:00
huangyuhui 587df1f5bb Fixed #45 2016-03-04 19:30:58 +08:00
huangyuhui 019fcf314b Added wrapper launcher 2016-03-04 14:06:11 +08:00
huangyuhui 1818b3575c Fixed infinite-recursion 2016-03-04 12:59:37 +08:00
huangyuhui afde41135a Fixed #42 2016-03-03 20:26:04 +08:00
huangyuhui 5dc812072f Fixed NullPointerException when only hidden version here 2016-03-01 12:40:25 +08:00
huangyuhui 3ba75d2de3 Fixed #39 2016-03-01 12:37:12 +08:00
huangyuhui dfc6e91321 Adds some suggested files to remove 2016-02-28 14:47:31 +08:00
huangyuhui a5504a4b74 Added font anti-aliasing 2016-02-28 13:49:22 +08:00
huangyuhui d10a7fad20 Fixed #38 2016-02-28 13:43:03 +08:00
huangyuhui f811d4c89f Adds some localization items 2016-02-27 17:08:29 +08:00
huangyuhui dcaa6241ec Testtest 2016-02-27 14:14:23 +08:00
huangyuhui 9527783cdb Fixed #31 2016-02-26 23:59:36 +08:00
huangyuhui db2b0cb159 Fixed #36 2016-02-26 23:42:45 +08:00
huangyuhui 09dbade477 Update README.md 2016-02-26 13:40:41 +08:00
huangyuhui 0817b9aebb Update README.md 2016-02-26 13:22:26 +08:00
huangyuhui e3c923e268 Update README.md 2016-02-25 23:16:28 +08:00
huangyuhui 761e671ecf Update .travis.yml 2016-02-25 23:02:23 +08:00
huangyuhui fe019b8f0f Supported new version json 2016-02-25 22:44:32 +08:00
huangyuhui 55af958792 ci test 2016-02-25 13:43:18 +08:00
huangyuhui da1bdb1322 Oops, invalid yml? 2016-02-25 13:27:07 +08:00
huangyuhui 892d8fe09c Try to fix RejectedExecutionException on OSX 2016-02-25 13:24:23 +08:00
huangyuhui 89fcf4526c Test travis ci again 2016-02-25 13:14:42 +08:00
huangyuhui 5d037b5f0e Test travis ci 2016-02-25 12:46:29 +08:00
huangyuhui 1bb7f8ac60 Might fix #34 2016-02-24 14:10:15 +08:00
huangyuhui 52f761095a Fixed button animation & performance problem 2016-02-23 22:09:17 +08:00
huangyuhui 770ec3ab97 Fixed #33 2016-02-23 20:32:24 +08:00
huangyuhui 7c3159fc23 Dont know update what? 2016-02-22 18:30:58 +08:00
huangyuhui d5924fa6ab May fix missing hmclversion.cfg 2016-02-19 11:14:41 +08:00
huangyuhui 295f44b947 forgot to copy assetIndex, downloads in MinecraftVersion 2016-02-19 11:08:25 +08:00
huangyuhui 115bc85c58 Fix switching download source problem 2016-02-19 10:24:58 +08:00
huangyuhui 6aaad71126 Thanks to gonglinyuan again 2016-02-19 10:16:11 +08:00
huangyuhui 24b4004fd9 Add gradle files 2016-02-18 20:52:16 +08:00
huangyuhui dd0cdb5c83 Fixed #26 2016-02-18 20:00:03 +08:00
huanghongxun 48f14e193a Merge pull request #28 from gonglinyuan/master
Fixed the name rule of a mod pack.
2016-02-18 17:50:20 +08:00
gonglinyuan 7076272768 Fixed the name rule of a mod pack. 2016-02-18 15:11:25 +08:00
huangyuhui bef6a2d61b Fix 2016-02-18 14:32:27 +08:00
huangyuhui 84c6723adc Switch to use oschina instead of minecraftforge maven 2016-02-18 14:28:02 +08:00
huangyuhui 61a179ba67 Thanks to gonglinyuan 2016-02-18 14:24:00 +08:00
huangyuhui afecb87c6d Might fix game log watcher? 2016-02-16 18:57:26 +08:00
huangyuhui cb125b83cb Fixed wrong path in modpack selection ui 2016-02-15 20:37:45 +08:00
huangyuhui cb337fc22f Added markdown support 2016-02-15 19:39:13 +08:00
huangyuhui 781c7369fb Fixed hidden version selection 2016-02-15 13:26:30 +08:00
huangyuhui 5281fc6a69 Fixed stackoverflow 2016-02-14 19:38:05 +08:00
huangyuhui 814d137084 Added game files descriptions in modpack file selection ui 2016-02-14 13:03:22 +08:00
huangyuhui a567ab1984 Fixed #25 2016-02-13 18:04:44 +08:00
huangyuhui 69eaa04ff6 Fixed lots of bugs 2016-02-13 18:02:25 +08:00
huangyuhui d0c8a95f57 Fixed #24 2016-02-12 15:19:06 +08:00
huangyuhui d09607766b Fixed username missing 2016-02-12 13:03:19 +08:00
huangyuhui 8f90d56e0f change version 2016-02-12 11:35:05 +08:00
huangyuhui d20d06ace7 Fixed a lot of bugs 2016-02-12 11:30:02 +08:00
huangyuhui 98282fd319 Fixed #23 2016-02-10 23:08:58 +08:00
huangyuhui 8e8584656e Fix issue #22 2016-02-10 18:15:28 +08:00
huangyuhui 2f97cd8104 try to fix mis-loading library problem 2016-02-10 17:28:33 +08:00
huangyuhui 8b1ff94c5f Added 'remove library files' 2016-02-10 16:36:02 +08:00
huangyuhui c67e7c0d3a fixed issue #20 2016-02-10 14:58:03 +08:00
huangyuhui 21dcb477dc for darkyoooooo's advice 2016-02-09 22:28:36 +08:00
huangyuhui cb5391ed28 Fix mis-encoding in Windows 2016-02-08 12:06:39 +08:00
huangyuhui fdc2570945 Now supports modpack description! 2016-02-07 14:39:47 +08:00
huangyuhui c60b04caf6 accident 2016-02-06 23:48:07 +08:00
huangyuhui fc0c99b436 The version will automatically use the BUILD_NUMBER now! 2016-02-06 23:44:49 +08:00
huangyuhui 0e4c38d99e Supported 16w05a version json 2016-02-06 12:56:16 +08:00
huangyuhui b0845c700f Fix problems with launching 2016-02-06 00:02:35 +08:00
huangyuhui 27a013450e Might fix some bugs? 2016-02-05 17:03:25 +08:00
huangyuhui d4dccd1391 used findbugs 2016-02-05 13:10:22 +08:00
huangyuhui cd972f5945 moved some buttons! 2016-02-05 11:30:42 +08:00
huangyuhui ed876fa607 Fix Issue #18 2016-02-04 10:04:43 +08:00
huangyuhui 06d15b045e Auto-refresh versions after installing 2016-02-02 19:39:20 +08:00
huangyuhui 0821b67019 Fix snapshot version wrong gathering 2016-02-02 19:12:05 +08:00
huangyuhui 0f18e7c1a1 supported lang files 2016-02-01 15:21:38 +08:00
huangyuhui ac7f025952 Added options for localization 2016-02-01 15:11:03 +08:00
huangyuhui 05382a0354 fix crash 2016-01-30 17:54:01 +08:00
huangyuhui 55b200dec4 modify license header 2016-01-30 14:43:13 +08:00
huangyuhui 587abda389 rename packages 2 2016-01-30 10:48:22 +08:00
huangyuhui da0cc62f16 rename packages 2016-01-30 10:41:41 +08:00
huangyuhui 80e60d2753 change version to 2.3.5.9 2016-01-29 22:25:14 +08:00
huangyuhui ff0750f1f7 To make death, I removed xz processor 2016-01-29 22:23:50 +08:00
huangyuhui f8eec1b7d5 Each version has its own settings 2016-01-29 22:21:13 +08:00
huangyuhui d2162f31e4 Clean tukaani.xz 2016-01-26 20:54:52 +08:00
huangyuhui fee3e5251d Try to fix warnings by NetBeans 2016-01-26 20:17:05 +08:00
huangyuhui 409fc83819 To make death I removed RxJava 2016-01-26 19:50:26 +08:00
huangyuhui 54e14a25da choosing files for modpack 2016-01-24 19:54:02 +08:00
huangyuhui 005589955c modpack update 2016-01-23 19:49:12 +08:00
huangyuhui 3bdaaddcd8 add some localization items 2016-01-23 18:04:30 +08:00
huangyuhui 08301bed8d test ModpackManager 2016-01-23 16:52:40 +08:00
huangyuhui 102205de40 initializing modpack coding process 2016-01-23 12:23:56 +08:00
huangyuhui 0da589374a reconstruct code 2016-01-20 19:24:35 +08:00
huangyuhui ab08a8d3f5 getting core 4 2016-01-19 23:16:13 +08:00
huangyuhui ec5bb40758 getting core 3 2016-01-19 22:44:09 +08:00
huangyuhui bbf7f2f3f0 getting core 2 2016-01-19 22:42:06 +08:00
huangyuhui d488df81a6 getting core 2016-01-19 22:40:23 +08:00
huangyuhui d207fa3dfb reconstruct codes 2016-01-19 22:28:50 +08:00
huangyuhui f32ce42af3 Added a console log to warn the user when "always close the launcher" option turned on 2016-01-12 21:54:20 +08:00
huangyuhui 9835aa4110 Fix 'refreshVersions' calling too many times 2016-01-10 10:04:50 +08:00
huangyuhui 6c8c189b72 fix IllegalStateException crashes the application 2016-01-09 13:24:40 +08:00
huangyuhui 296df23e15 Added uuid storage in order to prevent uuid problem 2016-01-08 19:55:52 +08:00
huangyuhui 38027fc5af Fix stackoverflow 2016-01-03 22:50:58 +08:00
huangyuhui 90ab9c088e Merge branch 'master' of https://github.com/huanghongxun/HMCL 2016-01-03 19:22:40 +08:00
huangyuhui 93d747f080 add a link about mod pack 2016-01-03 19:21:52 +08:00
unknown 66c502d424 fix lookandfeel crash in windows 2016-01-02 22:56:46 +08:00
huangyuhui 3e5823b647 commit 2016-01-02 21:06:39 +08:00
huangyuhui c33383733f Changed --version 2016-01-02 12:54:24 +08:00
huangyuhui a62848d4fa each authenticator has its own username now 2016-01-02 10:26:48 +08:00
huangyuhui b82243a9c0 update code style 2016-01-01 11:03:09 +08:00
huangyuhui 1f7eb04215 Fix NullPointerException in SwingUtils.invokeAndWait 2016-01-01 10:51:44 +08:00
huangyuhui 6968809499 supported linux memory reading 2015-12-31 21:30:39 +08:00
huangyuhui 5f78f2725a fix some bugs 2015-12-30 18:51:38 +08:00
huangyuhui 3471b4fec7 fixed crashing when removing mods 2015-12-29 20:35:40 +08:00
huangyuhui e3f0254736 fix some ui problems 2015-12-29 13:57:15 +08:00
huangyuhui 07357db42d why does the ui crash 2015-12-27 10:59:03 +08:00
huanghongxun b1c6c3549f fix hmcsm 2015-12-17 22:25:03 +08:00
huanghongxun 7174e117e3 clean up 2015-12-17 22:12:01 +08:00
huanghongxun eff087d9f0 change to C.i18n 2015-12-17 20:35:23 +08:00
huanghongxun 38460678db change to C.i18n 2015-12-17 19:37:48 +08:00
huanghongxun d3372e6a60 Merge branch 'master' of https://github.com/huanghongxun/HMCL
修改:     HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/auth/SkinmeAuthenticator.java
	修改:     HMCLAPI/src/main/resources/org/jackhuang/hellominecraft/launcher/I18N.properties
	修改:     HMCLAPI/src/main/resources/org/jackhuang/hellominecraft/launcher/I18N_zh_CN.properties
	修改:     README.md
2015-12-17 18:13:30 +08:00
huanghongxun 2b17095c88 add i18n 2015-12-17 18:06:19 +08:00
huanghongxun 4e5fd99a3c Merge pull request #12 from LasmGratel/master
Change the format of lang files.
2015-12-17 12:47:10 +08:00
LasmGratel 02e94da4b8 remove useless files 2015-12-16 21:15:54 +08:00
LasmGratel c6fc2cc685 convert I18N from latin2 format to utf-8 format
edit README.md
2015-12-16 21:14:29 +08:00
huanghongxun 81443b8252 Add an option to disable animations 2015-12-16 12:35:04 +08:00
huanghongxun 713a0171cc Reconstruct codes 2015-12-15 21:39:53 +08:00
huanghongxun b3fb372e3b New animationsublime_text launch4jlinux.cpp 2015-12-12 21:00:32 +08:00
huanghongxun 68a734adb0 Removed redundant codes 2015-12-12 13:01:18 +08:00
huanghongxun 8186482a11 Extracted the codes about installing 2.0 2015-12-11 21:18:51 +08:00
huanghongxun d052442aea Extracted the codes about installing 2015-12-11 21:15:56 +08:00
huanghongxun 78c46aeb64 Add --proxy 2015-12-10 20:34:02 +08:00
huanghongxun e91d4c5477 Try to fix some problems 2015-12-10 14:06:56 +08:00
huanghongxun 52c43bde06 Fixed swing syncing bugs 2015-12-09 23:24:24 +08:00
huanghongxun a436e10d93 Reconstructed too many codes 2015-12-09 21:03:56 +08:00
huanghongxun 8e2fa57868 Removed AssetsMojangOldLoader.java 2015-12-07 13:41:13 +08:00
huanghongxun d3ad805ad3 Change the license to GPL v3 to be compatible with Apache License 2.0. 2015-12-05 21:41:50 +08:00
huanghongxun f0212ea4eb Reconstruct codes. 2015-12-03 20:11:52 +08:00
huanghongxun b6cb5f0bee add lite mod description in mod panel. 2015-12-01 18:20:03 +08:00
huanghongxun 73a9fbb1c4 localized some items in English. 2015-11-30 20:27:24 +08:00
huanghongxun 626cc2f6ed why is a non-null variable null? 2015-11-29 18:19:50 +08:00
huanghongxun 151b865dc5 fix performance problem about downloading file. 2015-11-23 18:28:16 +08:00
huanghongxun c76b0e0ffb add debug information. 2015-11-22 17:50:00 +08:00
huanghongxun 2dede7dea1 clean 2015-11-22 16:07:39 +08:00
huanghongxun 159a992081 format 2015-11-17 12:51:04 +08:00
huanghongxun 39b6d68006 Fixed logging conflicting with Log4j and Minecraft. 2015-11-16 23:26:23 +08:00
huanghongxun b7aa99550d Added logging highlight. 2015-11-16 18:41:28 +08:00
huanghongxun 990f830300 Fixed many bugs 2015-11-15 16:19:10 +08:00
huanghongxun f508645496 cleaning codes. 2015-11-11 22:07:01 +08:00
huanghongxun b65be375e7 Clean redundancy codes. 2015-10-26 13:02:06 +08:00
huanghongxun b9c03d6ec3 clean code. 2015-10-05 21:55:30 +08:00
huanghongxun 1d252ea71c clean 2015-10-05 16:41:36 +08:00
huanghongxun c561faf1f7 fix git. 2015-10-04 23:40:42 +08:00
huanghongxun a58aeee40c test 2015-10-04 09:31:07 +08:00
huanghongxun 9b95f9d2d7 rapiddata 2015-09-29 13:48:12 +08:00
huanghongxun 7916715efa fix CI. 2015-09-07 13:28:56 +08:00
huanghongxun 01526546b1 Fix: TaskWindow causes NullPointerException. 2015-09-07 13:00:54 +08:00
huanghongxun 6e003a7364 Fixed wrong action in mod management. 2015-09-04 19:24:26 +08:00
huanghongxun e727ca331f Fix syncing TaskWindow. 2015-09-02 18:57:24 +08:00
huanghongxun f9968580af Redesign the UI. 2015-08-31 21:06:35 +08:00
huanghongxun 981a11d98b Fix Minecraft crashing when in offline & multiplayer mode. 2015-08-27 13:02:55 +08:00
huanghongxun fef88c0144 Add #5 (1) 2015-08-26 20:23:41 +08:00
huanghongxun db24280400 Update native launcher for HMCL. 2015-08-25 18:34:26 +08:00
huanghongxun 10bb60f998 Reset the java directory when javadir is wrong. 2015-08-25 09:11:29 +08:00
huanghongxun 9fc1470a63 add precalled command 2015-08-17 13:40:24 +08:00
huanghongxun 9ae9b5b912 fix bugs 2015-08-16 17:29:09 +08:00
huanghongxun a77275cfc0 fix bugs 2015-08-14 21:23:50 +08:00
huanghongxun a5388e790f fix bugs with Swing. 2015-08-13 20:54:42 +08:00
huanghongxun f63f888daf crash report uploading system & fix crashing when no version here. 2015-08-11 19:38:28 +08:00
huanghongxun 70f0383b1d Add mod modification. 2015-08-11 13:02:02 +08:00
huanghongxun 798d933079 Fixed finding Java problem with Windows XP. 2015-08-07 21:49:18 +08:00
huanghongxun 1d915194c2 The launching button will disable while launching game. 2015-08-07 10:41:15 +08:00
huanghongxun 92ca0075df Fix StringOutOfBoundException 2015-08-04 20:01:49 +08:00
huanghongxun 95598df273 Now can choose Java Installation in Windows 2015-08-04 15:13:04 +08:00
huanghongxun 4a167253db Update for CI. 2015-07-31 18:06:31 +08:00
huanghongxun 022c1ade39 reconstruct the codes. 2015-07-30 08:53:52 +08:00
huanghongxun bfcad25dee fix ArrayOutOfBoundsException & shows "task aborted". 2015-07-29 23:28:13 +08:00
huanghongxun 7e781dd24c fix wrong recognized java platform. 2015-07-29 23:18:05 +08:00
huanghongxun e4335cf1f0 Now installer will set the url of base jar of Forge and LiteLoader. 2015-07-28 22:56:31 +08:00
huanghongxun c3008ec294 Now have a choosing pane for java directory. 2015-07-28 20:50:31 +08:00
huanghongxun e31b5e3a28 Now can download .pack.xz file for Forge library. 2015-07-28 20:36:41 +08:00
huanghongxun bc8cc93bd9 update gitignore 2015-07-28 14:08:35 +08:00
huanghongxun 482c8e50bb fix installing liteloader without tweakclass 2015-07-28 14:08:08 +08:00
huanghongxun 369fe5e164 TaskWindow now shows progress of each task. 2015-07-28 13:50:14 +08:00
huanghongxun 538688c8f1 fix prompting no jar file when renaming version like Forge or LiteLoader version. 2015-07-24 07:52:20 +08:00
huanghongxun abb17dd05d test for new launcher for java && forgot to add license... 2015-07-14 17:36:04 +08:00
huanghongxun c321cb5f91 fix null field of asset index of 1.7.2 2015-07-13 13:11:01 +08:00
huanghongxun 2434e069f5 Fix the wrong AppData path 2015-07-11 22:29:49 +08:00
huanghongxun 2b63d46ffd Reconstruct the codes. 2015-07-11 17:34:25 +08:00
huanghongxun 0be056ac04 Reconstruct the codes && fix wrong file separator when switch to anther os from Windows. 2015-07-10 22:53:18 +08:00
huanghongxun 244b646225 reconstruct code && add advice for out of memory error. 2015-07-06 12:50:02 +08:00
huanghongxun d398de5d4e Fix no cancel when closing task window. 2015-07-05 11:53:34 +08:00
huanghongxun 01aaa38f81 reconstruct code, update crash suggestions & fix crash when minecraft.json -> libraries is lost 2015-07-04 17:17:41 +08:00
huanghongxun cdb78a31e9 update crash suggestions. 2015-07-03 12:50:11 +08:00
huanghongxun 07b8c5777a Asynchronized UI loading. 2015-07-02 13:17:59 +08:00
huanghongxun 67056f4849 Reconstruct the codes. 2015-07-01 21:27:08 +08:00
huanghongxun dace6ab223 Change the default authenticated token to 0 2015-07-01 20:42:55 +08:00
huanghongxun 25b6d7297c fix platform's bug 2015-06-30 20:43:05 +08:00
huanghongxun bba82f5e24 Mojang Download Source: https -> http 2015-06-29 18:17:27 +08:00
huanghongxun e6c954ae0d Fix JSON Exception. 2015-06-29 12:57:02 +08:00
huanghongxun 5f29c7e711 2.3.3 2015-06-28 23:28:56 +08:00
huanghongxun b069753d07 Test 2.3.3 2015-06-28 23:13:01 +08:00
huanghongxun 5bc76299af optimize the code. 2015-06-28 18:55:36 +08:00
huanghongxun 42ef2fe128 Fix a unlocalized string. 2015-06-27 14:00:15 +08:00
huanghongxun 2f0d80cb26 Merge branch 'master' of https://github.com/huanghongxun/HMCL 2015-06-27 13:43:41 +08:00
huanghongxun 57f69d0cbe Merge pull request #3 from Meow-J/master
Change alignment of profile and version to LEADING
2015-06-27 13:41:59 +08:00
Meow J 782627dd12 Change alignment of profile and version to LEADING 2015-06-27 11:45:43 +08:00
huanghongxun e5acf99b09 check the format of asset for 1.7.2~1.6.0. 2015-06-26 23:22:42 +08:00
huanghongxun 9220a818b3 optimize code. 2015-06-26 23:00:55 +08:00
huanghongxun db8e425b2b Additional: license-header.txt 2015-06-26 18:56:35 +08:00
huanghongxun 0df7479e64 Fix FileNotFoundException *.hmc when launching. 2015-06-26 18:55:36 +08:00
huanghongxun bee81fd6d9 Settings.s() -> Settings.getInstance() 2015-06-25 23:08:05 +08:00
huanghongxun fb7bbbcaaf Merge branch 'master' of https://github.com/huanghongxun/HMCL 2015-06-24 13:46:08 +08:00
huanghongxun e5621d1a58 Fixed Issue #1 & Added proxy support 2015-06-24 13:45:00 +08:00
huanghongxun 7344b1ae05 Update README.md 2015-06-22 17:43:38 +08:00
huanghongxun 7bfe7c3432 it seems that i forgot something i should do. 2015-06-22 17:35:23 +08:00
huanghongxun c760461f91 modify the license. 2015-06-22 17:25:47 +08:00
huanghongxun 0656227183 HMCL 2.3.2 2015-06-22 16:47:05 +08:00
huanghongxun 0693d12f6b Initial commit 2015-06-22 16:06:03 +08:00
872 changed files with 59460 additions and 48601 deletions

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
*.class
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
.gradle
.nb-gradle
*.log
.mine*
*.json
*.hmd
/HMCL/build/
/HMCLaF/build/
/HMCLAPI/build/
/HMCLCore/build/
+36
View File
@@ -0,0 +1,36 @@
<?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>
<task>
<display-name>createApp</display-name>
<non-blocking>no</non-blocking>
<task-names>
<name must-exist="yes">createApp</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>
+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.
BIN
View File
Binary file not shown.
+197
View File
@@ -0,0 +1,197 @@
/*
* 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/}.
*/
import java.util.jar.JarFile
import java.util.jar.Pack200
import java.util.zip.GZIPOutputStream
import java.security.MessageDigest
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
plugins {
id "edu.sc.seis.macAppBundle" version "2.1.8"
id "me.tatarka.retrolambda" version "3.7.0"
id 'edu.sc.seis.launch4j' version '2.4.2'
//id "org.jetbrains.kotlin.jvm" version "1.1.2-2"
}
if (!hasProperty('mainClass')) {
ext.mainClass = 'org.jackhuang.hmcl.Main'
}
def buildnumber = System.getenv("TRAVIS_BUILD_NUMBER")
if (buildnumber == null)
buildnumber = System.getenv("BUILD_NUMBER")
if (buildnumber == null)
buildnumber = "51"
def versionroot = System.getenv("VERSION_ROOT")
if (versionroot == null)
versionroot = "2.7.9"
String mavenGroupId = 'HMCL'
String mavenVersion = versionroot + '.' + buildnumber
String bundleName = "Hello Minecraft! Launcher"
group = mavenGroupId
version = mavenVersion
String mavenArtifactId = name
task generateSources(type: Sync) {
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
configurations {
coreCompile.extendsFrom compile
coreRuntime.extendsFrom runtime
}
configure(install.repositories.mavenInstaller) {
pom.project {
groupId = mavenGroupId
artifactId = mavenArtifactId
version = mavenVersion
}
}
dependencies {
compile project(":HMCLaF")
compile project(":HMCLAPI")
compile project(":HMCLCore")
}
retrolambda {
javaVersion = JavaVersion.VERSION_1_7
}
jar {
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
manifest {
attributes 'Created-By' : 'Copyright(c) 2013-2017 huangyuhui.',
'Main-Class' : mainClass
}
doLast {
new File("build/signed").mkdirs()
ant.signjar(signedjar: archivePath, jar: archivePath,
keystore: "HMCL.keystore", storepass: "123456",
alias: "HMCL")
def messageDigest = MessageDigest.getInstance("SHA1")
archivePath.eachByte 1024 * 1024, { byte[] buf, int bytesRead ->
messageDigest.update(buf, 0, bytesRead);
}
def sha1Hex = new BigInteger(1, messageDigest.digest()).toString(16).padLeft(40, '0')
def fileEx = new File(project.buildDir, "libs/" + archivePath.getName() + ".sha1")
if (!fileEx.exists()) fileEx.createNewFile()
fileEx.append sha1Hex
}
}
launch4j {
supportUrl = 'http://www.mcbbs.net/thread-142335-1-1.html'
jreMinVersion = '1.7.0'
mainClassName = mainClass
icon = new File(project.buildDir, '../icon.ico').absolutePath
version = mavenVersion
downloadUrl = 'http://java.com/download'
copyright = "Copyright(c) 2013-2017 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'
}
processResources {
from(sourceSets.main.resources.srcDirs) {
exclude 'icon.icns'
}
}
task makeExecutable(dependsOn: jar) doLast {
ext {
jar.classifier = ''
makeExecutableinjar = jar.archivePath
jar.classifier = ''
makeExecutableoutjar = jar.archivePath
jar.classifier = ''
}
def loc = new File(project.buildDir, "libs/" + makeExecutableoutjar.getName().substring(0, makeExecutableoutjar.getName().length()-4)+".exe")
def fos = new FileOutputStream(loc)
def is = new FileInputStream(new File(project.buildDir, '../HMCLauncher.exe'))
int read
def bytes = new byte[8192]
while((read = is.read(bytes)) != -1)
fos.write(bytes, 0, read);
is.close()
is = new FileInputStream(makeExecutableinjar)
while((read = is.read(bytes)) != -1)
fos.write(bytes, 0, read);
is.close()
fos.close()
}
task makePackGZ(dependsOn: jar) doLast {
ext {
jar.classifier = ''
makeExecutableinjar = jar.archivePath
jar.classifier = ''
makeExecutableoutjar = jar.archivePath
jar.classifier = ''
}
def loc = new File(project.buildDir, "libs/" + makeExecutableoutjar.getName().substring(0, makeExecutableoutjar.getName().length()-4)+".pack.gz")
def os = new GZIPOutputStream(new FileOutputStream(loc))
Pack200.newPacker().pack new JarFile(makeExecutableinjar), os
os.close()
def messageDigest = MessageDigest.getInstance("SHA1")
loc.eachByte 1024 * 1024, { byte[] buf, int bytesRead ->
messageDigest.update(buf, 0, bytesRead);
}
def sha1Hex = new BigInteger(1, messageDigest.digest()).toString(16).padLeft(40, '0')
def fileEx = new File(project.buildDir, "libs/" + makeExecutableoutjar.getName().substring(0, makeExecutableoutjar.getName().length()-4)+".pack.gz.sha1")
if (!fileEx.exists()) fileEx.createNewFile()
fileEx.append sha1Hex
}
task macAppCompressed(type: Zip, dependsOn: createApp) doLast {
archiveName "HMCL-$mavenVersion-MacOSApp.zip"
include '**'
destinationDir file("$buildDir/libs/")
from "$buildDir/macApp"
}
macAppBundle {
mainClassName = mainClass
icon = "src/main/icon.icns"
javaProperties.put("apple.laf.useScreenMenuBar", "true")
}
build.dependsOn makeExecutable
build.dependsOn makePackGZ
build.dependsOn macAppCompressed
Executable
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

BIN
View File
Binary file not shown.
@@ -0,0 +1,270 @@
/*
* 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.hmcl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
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.JOptionPane;
import javax.swing.RepaintManager;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.api.ILogger;
import org.jackhuang.hmcl.api.PluginManager;
import org.jackhuang.hmcl.api.VersionNumber;
import org.jackhuang.hmcl.core.MCUtils;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.ui.LogWindow;
import org.jackhuang.hmcl.ui.MainFrame;
import org.jackhuang.hmcl.util.CrashReporter;
import org.jackhuang.hmcl.util.DefaultPlugin;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.util.lang.SupportedLocales;
import org.jackhuang.hmcl.util.log.Configuration;
import org.jackhuang.hmcl.util.log.appender.ConsoleAppender;
import org.jackhuang.hmcl.util.log.layout.DefaultLayout;
import org.jackhuang.hmcl.util.ui.MyRepaintManager;
import org.jackhuang.hmcl.util.upgrade.IUpgrader;
import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper;
/**
*
* @author huangyuhui
*/
public final class Main {
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;
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;
/**
* 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 Logger LOGGER = Logger.getLogger(Main.class.getName());
public static void main(String[] args) throws IOException {
{
if (new File("").getAbsolutePath().contains("!")) {
MessageBox.show("HMCL cannot run at such path that contains '!'");
return;
}
try {
File file = new File("hmcl.log").getAbsoluteFile();
if (!file.exists() && !file.createNewFile())
LOGGER.log(Level.WARNING, "Failed to create log file {0}", 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);
}
org.jackhuang.hmcl.util.log.logger.Logger logger = new org.jackhuang.hmcl.util.log.logger.Logger("HMCL");
HMCLog.LOGGER = new ILogger() {
@Override
public void log(String msg) {
logger.info(msg);
}
@Override
public void warn(String msg) {
logger.warn(msg);
}
@Override
public void warn(String msg, Throwable t) {
logger.warn(msg, t);
}
@Override
public void err(String msg) {
logger.error(msg);
}
@Override
public void err(String msg, Throwable t) {
logger.error(msg, t);
}
};
HMCLApi.HMCL_VERSION = VersionNumber.check(LAUNCHER_VERSION);
PluginManager.getPlugin(DefaultPlugin.class);
for (String s : args)
if (s.startsWith("--plugin=")) {
String c = s.substring("--plugin=".length());
try {
PluginManager.getPlugin(Class.forName(c));
} catch (ClassNotFoundException ex) {
HMCLog.warn("Class: " + c + " not found, please add your plugin jar to class path.", ex);
}
} else if (s.startsWith("--help")) {
System.out.println("HMCL command line help");
System.out.println("--noupdate: this arg will prevent HMCL from initializing the newest app version in %appdata%/.hmcl");
System.out.println("--plugin=<your plugin class>: this arg will allow a new plugin to be loaded, please keep your jar in system class path and this class extends IPlugin.");
return;
}
PluginManager.loadPlugins();
IUpgrader.NOW_UPGRADER.parseArguments(HMCLApi.HMCL_VERSION, args);
System.setProperty("awt.useSystemAAFontSettings", "on");
System.setProperty("swing.aatext", "true");
System.setProperty("sun.java2d.noddraw", "true");
System.setProperty("sun.java2d.dpiaware", "false");
System.setProperty("https.protocols", "SSLv3,TLSv1");
try {
SSLContext c = SSLContext.getInstance("SSL");
c.init(null, new X509TrustManager[] { XTM }, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(c.getSocketFactory());
} catch (GeneralSecurityException ignore) {
}
HttpsURLConnection.setDefaultHostnameVerifier(HNV);
Thread.setDefaultUncaughtExceptionHandler(new CrashReporter(true));
HMCLog.log("*** " + Main.makeTitle() + " ***");
String s = Settings.getInstance().getLocalization();
for (SupportedLocales sl : SupportedLocales.values())
if (sl.name().equals(s)) {
SupportedLocales.setNowLocale(sl);
Locale.setDefault(sl.self);
JOptionPane.setDefaultLocale(sl.self);
}
if (System.getProperty("java.vm.name").contains("Open")) // OpenJDK
MessageBox.showLocalized("ui.message.open_jdk");
try {
BeautyEyeLNFHelper.launchBeautyEyeLNF();
RepaintManager.setCurrentManager(new MyRepaintManager());
} catch (Exception ex) {
HMCLog.warn("Failed to set look and feel...", ex);
}
LogWindow.INSTANCE.clean();
Settings.UPDATE_CHECKER.upgrade.register(IUpgrader.NOW_UPGRADER);
Settings.UPDATE_CHECKER.process(false).reg(t -> Main.invokeUpdate()).execute();
if (Settings.getInstance().getProxyType() != Proxy.Type.DIRECT && StrUtils.isNotBlank(Settings.getInstance().getProxyHost())) {
switch (Settings.getInstance().getProxyType()) {
case DIRECT:
break;
case HTTP:
System.setProperty("http.proxyHost", Settings.getInstance().getProxyHost());
if (StrUtils.isNotBlank(Settings.getInstance().getProxyPort()))
System.setProperty("http.proxyPort", Settings.getInstance().getProxyPort());
HMCLog.log("Initialized HTTP proxy.");
break;
case SOCKS:
System.setProperty("socksProxyHost", Settings.getInstance().getProxyHost());
if (StrUtils.isNotBlank(Settings.getInstance().getProxyPort()))
System.setProperty("socksProxyPort", Settings.getInstance().getProxyPort());
HMCLog.log("Initialized Socks v4/v5 proxy.");
break;
}
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 {
unpackDefaultLog4jConfiguration();
} catch(IOException e) {
HMCLog.err("Failed to unpack log4j.xml, log window will not work well.", e);
}
MainFrame.showMainFrame();
}
}
public static void invokeUpdate() {
MainFrame.INSTANCE.invokeUpdate();
}
public static final File LOG4J_FILE = new File(MCUtils.getWorkingDirectory("hmcl"), "log4j.xml");
public static void unpackDefaultLog4jConfiguration() throws IOException {
LOG4J_FILE.getParentFile().mkdirs();
if (LOG4J_FILE.exists()) return;
LOG4J_FILE.createNewFile();
try (InputStream is = Main.class.getResourceAsStream("/org/jackhuang/hmcl/log4j.xml");
FileOutputStream fos = new FileOutputStream(LOG4J_FILE)) {
int b;
while ((b = is.read()) != -1)
fos.write(b);
}
}
public static ImageIcon getIcon(String path) {
try {
return new ImageIcon(Main.class.getResource("/org/jackhuang/hmcl/" + path));
} catch (Exception e) {
HMCLog.err("Failed to load icon", e);
return null;
}
}
}
@@ -0,0 +1,37 @@
/*
* 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.hmcl.api.event.config;
import org.jackhuang.hmcl.api.event.SimpleEvent;
import org.jackhuang.hmcl.setting.Profile;
/**
* This event gets fired when the selected profile changed.
* <br>
* This event is fired on the {@link org.jackhuang.hmcl.api.HMCLApi#EVENT_BUS}
* @param source {@link org.jackhuang.hmcl.setting.Settings}
* @param Profile the new profile.
* @author huangyuhui
*/
public class ProfileChangedEvent extends SimpleEvent<Profile> {
public ProfileChangedEvent(Object source, Profile value) {
super(source, value);
}
}
@@ -0,0 +1,35 @@
/*
* 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.hmcl.api.event.config;
import java.util.EventObject;
/**
* This event gets fired when loading profiles.
* <br>
* This event is fired on the {@link org.jackhuang.hmcl.api.HMCLApi#EVENT_BUS}
* @param source {@link org.jackhuang.hmcl.setting.Settings}
* @author huangyuhui
*/
public class ProfileLoadingEvent extends EventObject {
public ProfileLoadingEvent(Object source) {
super(source);
}
}
+358
View File
@@ -0,0 +1,358 @@
/*
* 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.hmcl.setting;
import org.jackhuang.hmcl.core.download.DownloadType;
import com.google.gson.annotations.SerializedName;
import java.awt.Font;
import java.net.Proxy;
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.hmcl.core.auth.AbstractAuthenticator;
import org.jackhuang.hmcl.laf.LAFTheme;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.config.AuthenticatorChangedEvent;
import org.jackhuang.hmcl.api.event.config.DownloadTypeChangedEvent;
import org.jackhuang.hmcl.api.event.config.ThemeChangedEvent;
import org.jackhuang.hmcl.core.MCUtils;
import org.jackhuang.hmcl.util.sys.JdkVersion;
import org.jackhuang.hmcl.util.sys.OS;
import org.jackhuang.hmcl.api.auth.IAuthenticator;
import org.jackhuang.hmcl.api.ui.Theme;
/**
*
* @author huangyuhui
*/
public final class Config implements Cloneable {
@SerializedName("last")
private String last;
@SerializedName("bgpath")
private String bgpath;
@SerializedName("commonpath")
private String commonpath;
@SerializedName("clientToken")
private final String clientToken;
@SerializedName("proxyHost")
private String proxyHost;
@SerializedName("proxyPort")
private String proxyPort;
@SerializedName("proxyUserName")
private String proxyUserName;
@SerializedName("proxyPassword")
private String proxyPassword;
@SerializedName("proxyType")
private int proxyType;
@SerializedName("enableShadow")
private boolean enableShadow;
@SerializedName("enableBlur")
private boolean enableBlur;
@SerializedName("enableAnimation")
private boolean enableAnimation;
@SerializedName("decorated")
private boolean decorated;
@SerializedName("theme")
private String 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")
private Map<String, Map> auth;
@SerializedName("fontFamily")
private String fontFamily;
@SerializedName("fontSize")
private int fontSize;
@SerializedName("logLines")
private int logLines;
public Config() {
clientToken = UUID.randomUUID().toString();
proxyType = logintype = downloadtype = 0;
logLines = 100;
enableAnimation = enableBlur = true;
if (OS.os() == OS.WINDOWS)
enableShadow = true;
theme = LAFTheme.BLUE.id;
decorated = OS.os() == OS.LINUX;
auth = new HashMap<>();
Font font = Font.decode("Consolas");
if (font == null)
font = Font.decode("Monospace");
if (font != null)
fontFamily = font.getFamily();
fontSize = 12;
commonpath = MCUtils.getLocation().getPath();
}
public List<JdkVersion> getJava() {
return java == null ? java = new ArrayList<>() : java;
}
public Theme getTheme() {
if (!Theme.THEMES.containsKey(theme))
theme = LAFTheme.BLUE.id;
return Theme.THEMES.get(theme);
}
public void setTheme(String theme) {
this.theme = theme;
HMCLApi.EVENT_BUS.fireChannel(new ThemeChangedEvent(this, getTheme()));
Settings.save();
}
public boolean isDecorated() {
return decorated;
}
public void setDecorated(boolean decorated) {
this.decorated = decorated;
}
public boolean isEnableShadow() {
return enableShadow && OS.os() == OS.WINDOWS;
}
public void setEnableShadow(boolean enableShadow) {
this.enableShadow = enableShadow;
Settings.save();
}
public boolean isEnableAnimation() {
return enableAnimation;
}
public void setEnableAnimation(boolean enableAnimation) {
this.enableAnimation = enableAnimation;
Settings.save();
}
public boolean isEnableBlur() {
return enableBlur;
}
public void setEnableBlur(boolean enableBlur) {
this.enableBlur = enableBlur;
Settings.save();
}
/**
* Last selected profile name.
*/
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 String getCommonpath() {
return commonpath;
}
public void setCommonpath(String commonpath) {
this.commonpath = commonpath;
Settings.save();
}
public String getClientToken() {
return clientToken;
}
public IAuthenticator getAuthenticator() {
return AbstractAuthenticator.LOGINS.get(getLoginType());
}
public int getLoginType() {
if (logintype < 0 || logintype >= AbstractAuthenticator.LOGINS.size())
logintype = 0;
return logintype;
}
public void setLoginType(int logintype) {
if (logintype < 0 || logintype >= AbstractAuthenticator.LOGINS.size())
return;
this.logintype = logintype;
HMCLApi.EVENT_BUS.fireChannel(new AuthenticatorChangedEvent(this, AbstractAuthenticator.LOGINS.get(logintype)));
Settings.save();
}
public int getDownloadType() {
return downloadtype;
}
public void setDownloadType(int downloadtype) {
this.downloadtype = downloadtype;
HMCLApi.EVENT_BUS.fireChannel(new DownloadTypeChangedEvent(this, getDownloadSource().name()));
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 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 Proxy.Type getProxyType() {
if (proxyType < 0 || proxyType >= 3) {
proxyType = 0;
Settings.save();
}
return Proxy.Type.values()[proxyType];
}
public void setProxyType(Proxy.Type proxyType) {
this.proxyType = proxyType.ordinal();
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 int getFontSize() {
return fontSize;
}
public void setFontSize(int fontSize) {
this.fontSize = fontSize;
Settings.save();
}
public Font getConsoleFont() {
return Font.decode(fontFamily + "-" + fontSize);
}
public String getFontFamily() {
return Font.decode(fontFamily).getFamily();
}
public void setFontFamily(String fontFamily) {
this.fontFamily = Font.decode(fontFamily).getFamily(); // avoid invalid font family
Settings.save();
}
public String getLocalization() {
return localization;
}
public void setLocalization(String localization) {
this.localization = localization;
Settings.save();
}
public int getLogLines() {
if (logLines == 100 || logLines == 1000 || logLines == 5000)
return logLines;
else
return logLines = 100;
}
public void setLogLines(int logLines) {
this.logLines = logLines;
Settings.save();
}
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
}
+182
View File
@@ -0,0 +1,182 @@
/*
* 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.hmcl.setting;
import org.jackhuang.hmcl.core.service.IProfile;
import com.google.gson.annotations.SerializedName;
import org.jackhuang.hmcl.util.HMCLGameLauncher;
import org.jackhuang.hmcl.util.HMCLMinecraftService;
import java.io.File;
import org.jackhuang.hmcl.core.MCUtils;
import org.jackhuang.hmcl.core.version.MinecraftVersion;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.api.event.EventHandler;
import org.jackhuang.hmcl.api.event.PropertyChangedEvent;
/**
*
* @author huangyuhui
*/
public final class Profile implements IProfile {
@SerializedName("selectedMinecraftVersion")
private String selectedVersion = "";
@SerializedName("gameDir")
private String gameDir;
@SerializedName("noCommon")
private boolean noCommon;
@SerializedName("global")
private VersionSetting global;
private transient String name;
private transient HMCLMinecraftService service = new HMCLMinecraftService(this);
private transient HMCLGameLauncher launcher = new HMCLGameLauncher(this);
public transient final EventHandler<PropertyChangedEvent<String>> propertyChanged = new EventHandler<>();
public Profile() {
this("Default");
}
public Profile(String name) {
this(name, ".minecraft");
}
public Profile(String name, String gameDir) {
this.name = name;
this.gameDir = gameDir;
this.global = new VersionSetting();
}
public Profile(String name, Profile v) {
this();
if (v == null)
return;
this.name = name;
gameDir = v.gameDir;
}
@Override
public HMCLMinecraftService service() {
return service;
}
public HMCLGameLauncher launcher() {
return launcher;
}
public VersionSetting getSelectedVersionSetting() {
return getVersionSetting(getSelectedVersion());
}
public VersionSetting getVersionSetting(String id) {
VersionSetting vs = service().getVersionSetting(id);
if (vs == null || vs.isUsesGlobal()) {
global.isGlobal = true;
global.id = id;
return global;
} else
return vs;
}
public boolean isVersionSettingGlobe(String id) {
VersionSetting vs = service().getVersionSetting(id);
return vs == null || vs.isUsesGlobal();
}
public void makeVersionSettingSpecial(String id) {
VersionSetting vs = service().getVersionSetting(id);
if (vs == null) {
service().createVersionSetting(id);
vs = service().getVersionSetting(id);
if (vs == null)
return;
vs.setUsesGlobal(false);
} else
vs.setUsesGlobal(false);
propertyChanged.fire(new PropertyChangedEvent<>(this, "selectedVersion", selectedVersion, selectedVersion));
}
public void makeVersionSettingGlobal(String id) {
VersionSetting vs = service().getVersionSetting(id);
if (vs == null)
return;
vs.setUsesGlobal(true);
propertyChanged.fire(new PropertyChangedEvent<>(this, "selectedVersion", selectedVersion, selectedVersion));
}
@Override
public String getSelectedVersion() {
String v = selectedVersion;
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))
setSelectedVersion(v);
}
return StrUtils.isBlank(v) ? null : v;
}
@Override
public void setSelectedVersion(String newVersion) {
PropertyChangedEvent event = new PropertyChangedEvent<>(this, "selectedVersion", this.selectedVersion, newVersion);
this.selectedVersion = newVersion;
propertyChanged.fire(event);
}
@Override
public File getGameDir() {
if (StrUtils.isBlank(gameDir))
gameDir = MCUtils.getInitGameDir().getPath();
return new File(gameDir.replace('\\', '/'));
}
@Override
public void setGameDir(File gameDir) {
PropertyChangedEvent event = new PropertyChangedEvent<>(this, "gameDir", this.gameDir, gameDir);
this.gameDir = gameDir.getPath();
service().version().refreshVersions();
propertyChanged.fire(event);
}
public boolean isNoCommon() {
return noCommon;
}
public void setNoCommon(boolean noCommon) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "noCommon", this.noCommon, noCommon);
this.noCommon = noCommon;
propertyChanged.fire(event);
}
@Override
public String getName() {
return name;
}
void setName(String name) {
PropertyChangedEvent event = new PropertyChangedEvent<>(this, "name", this.name, name);
this.name = name;
propertyChanged.fire(event);
}
@Override
public void onSelected() {
service().version().refreshVersions();
}
}
+172
View File
@@ -0,0 +1,172 @@
/*
* 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.hmcl.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.hmcl.util.C;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.core.MCUtils;
import org.jackhuang.hmcl.core.download.DownloadType;
import org.jackhuang.hmcl.util.CollectionUtils;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.config.ProfileChangedEvent;
import org.jackhuang.hmcl.api.event.config.ProfileLoadingEvent;
import org.jackhuang.hmcl.laf.utils.AnimationController;
import org.jackhuang.hmcl.util.sys.FileUtils;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.upgrade.UpdateChecker;
import org.jackhuang.hmcl.util.sys.IOUtils;
/**
*
* @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("hmcl.json").getAbsoluteFile();
private static final Config SETTINGS;
public static final UpdateChecker UPDATE_CHECKER = new UpdateChecker(HMCLApi.HMCL_VERSION, "hmcl");
public static Config getInstance() {
return SETTINGS;
}
static {
SETTINGS = initSettings();
DownloadType.setSuggestedDownloadType(SETTINGS.getDownloadSource().name());
AnimationController.ENABLE_ANIMATION = SETTINGS.isEnableAnimation();
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.propertyChanged.register(Settings::save);
}
}
private static Config initSettings() {
Config c = new Config();
if (SETTINGS_FILE.exists())
try {
String str = FileUtils.read(SETTINGS_FILE, IOUtils.DEFAULT_CHARSET);
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), IOUtils.DEFAULT_CHARSET);
} 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 Collection<Profile> getProfilesFiltered() {
return CollectionUtils.filter(getProfiles().values(), t -> t != null && t.getName() != null);
}
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;
}
static void onProfileChanged() {
Profile p = getLastProfile();
if (p == null)
throw new Error("No profiles here, it should not happen");
HMCLApi.EVENT_BUS.fireChannel(new ProfileChangedEvent(SETTINGS, p));
p.onSelected();
}
public static void onProfileLoading() {
HMCLApi.EVENT_BUS.fireChannel(new ProfileLoadingEvent(SETTINGS));
onProfileChanged();
}
}
@@ -0,0 +1,341 @@
/*
* 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.hmcl.setting;
import com.google.gson.annotations.SerializedName;
import java.io.File;
import org.jackhuang.hmcl.Main;
import org.jackhuang.hmcl.util.LauncherVisibility;
import org.jackhuang.hmcl.api.game.LaunchOptions;
import org.jackhuang.hmcl.api.game.GameDirType;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.api.event.EventHandler;
import org.jackhuang.hmcl.api.event.PropertyChangedEvent;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.util.sys.Java;
import org.jackhuang.hmcl.util.sys.OS;
/**
*
* @author huangyuhui
*/
public class VersionSetting {
public transient String id;
public transient boolean isGlobal = false;
@SerializedName("usesGlobal")
private boolean usesGlobal;
@SerializedName("javaArgs")
private String javaArgs;
@SerializedName("minecraftArgs")
private String minecraftArgs;
@SerializedName("maxMemory")
private String maxMemory;
@SerializedName("permSize")
private String permSize;
@SerializedName("width")
private String width;
@SerializedName("height")
private String height;
@SerializedName("javaDir")
private String javaDir;
@SerializedName("precalledCommand")
private String precalledCommand;
@SerializedName("serverIp")
private String serverIp;
@SerializedName("java")
private String java;
@SerializedName("wrapper")
private String wrapper;
@SerializedName("fullscreen")
private boolean fullscreen;
@SerializedName("noJVMArgs")
private boolean noJVMArgs;
@SerializedName("notCheckGame")
private boolean 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/>
*/
@SerializedName("launcherVisibility")
private int launcherVisibility;
/**
* 0 - .minecraft<br/>
* 1 - .minecraft/versions/&lt;version&gt;/<br/>
*/
@SerializedName("gameDirType")
private int gameDirType;
public transient final EventHandler<PropertyChangedEvent> propertyChanged = new EventHandler<>();
public VersionSetting() {
fullscreen = usesGlobal = false;
launcherVisibility = 1;
gameDirType = 0;
javaDir = java = minecraftArgs = serverIp = precalledCommand = wrapper = "";
}
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) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "javaDir", this.javaDir, javaDir);
this.javaDir = javaDir;
propertyChanged.fire(event);
}
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) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "java", this.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.fire(event);
}
public String getJavaArgs() {
if (StrUtils.isBlank(javaArgs))
return "";
return javaArgs;
}
public void setJavaArgs(String javaArgs) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "javaArgs", this.javaArgs, javaArgs);
this.javaArgs = javaArgs;
propertyChanged.fire(event);
}
public String getMaxMemory() {
if (StrUtils.isBlank(maxMemory))
return String.valueOf(OS.getSuggestedMemorySize());
return maxMemory;
}
public void setMaxMemory(String maxMemory) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "maxMemory", this.maxMemory, maxMemory);
this.maxMemory = maxMemory;
propertyChanged.fire(event);
}
public String getWidth() {
if (StrUtils.isBlank(width))
return "854";
return width;
}
public void setWidth(String width) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "width", this.width, width);
this.width = width;
propertyChanged.fire(event);
}
public String getHeight() {
if (StrUtils.isBlank(height))
return "480";
return height;
}
public void setHeight(String height) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "height", this.height, height);
this.height = height;
propertyChanged.fire(event);
}
public boolean isFullscreen() {
return fullscreen;
}
public void setFullscreen(boolean fullscreen) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "fullscreen", this.fullscreen, fullscreen);
this.fullscreen = fullscreen;
propertyChanged.fire(event);
}
public LauncherVisibility getLauncherVisibility() {
return LauncherVisibility.values()[launcherVisibility];
}
public void setLauncherVisibility(LauncherVisibility launcherVisibility) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "launcherVisibility", this.launcherVisibility, launcherVisibility);
this.launcherVisibility = launcherVisibility.ordinal();
propertyChanged.fire(event);
}
public GameDirType getGameDirType() {
if (gameDirType < 0 || gameDirType > 1)
setGameDirType(GameDirType.ROOT_FOLDER);
return GameDirType.values()[gameDirType];
}
public void setGameDirType(GameDirType gameDirType) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "gameDirType", this.gameDirType, gameDirType);
this.gameDirType = gameDirType.ordinal();
propertyChanged.fire(event);
}
public String getPermSize() {
return permSize;
}
public void setPermSize(String permSize) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "permSize", this.permSize, permSize);
this.permSize = permSize;
propertyChanged.fire(event);
}
public boolean isNoJVMArgs() {
return noJVMArgs;
}
public void setNoJVMArgs(boolean noJVMArgs) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "noJVMArgs", this.noJVMArgs, noJVMArgs);
this.noJVMArgs = noJVMArgs;
propertyChanged.fire(event);
}
public String getMinecraftArgs() {
return minecraftArgs;
}
public void setMinecraftArgs(String minecraftArgs) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "minecraftArgs", this.minecraftArgs, minecraftArgs);
this.minecraftArgs = minecraftArgs;
propertyChanged.fire(event);
}
public String getPrecalledCommand() {
return precalledCommand;
}
public void setPrecalledCommand(String precalledCommand) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "precalledCommand", this.precalledCommand, precalledCommand);
this.precalledCommand = precalledCommand;
propertyChanged.fire(event);
}
public String getWrapper() {
return wrapper;
}
public void setWrapper(String wrapper) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "wrapper", this.wrapper, wrapper);
this.wrapper = wrapper;
propertyChanged.fire(event);
}
public String getServerIp() {
return serverIp;
}
public void setServerIp(String serverIp) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "serverIp", this.serverIp, serverIp);
this.serverIp = serverIp;
propertyChanged.fire(event);
}
public boolean isNotCheckGame() {
return notCheckGame;
}
public void setNotCheckGame(boolean notCheckGame) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "notCheckGame", this.notCheckGame, notCheckGame);
this.notCheckGame = notCheckGame;
propertyChanged.fire(event);
}
public boolean isUsesGlobal() {
return usesGlobal;
}
public void setUsesGlobal(boolean usesGlobal) {
PropertyChangedEvent event = new PropertyChangedEvent(this, "usesGlobal", this.usesGlobal, usesGlobal);
this.usesGlobal = usesGlobal;
propertyChanged.fire(event);
}
public LaunchOptions createLaunchOptions(File gameDir) {
LaunchOptions x = new LaunchOptions();
x.setFullscreen(isFullscreen());
x.setWrapper(getWrapper());
x.setGameDir(gameDir);
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();
}
x.setJavaDir(str);
return x;
}
}
@@ -0,0 +1,73 @@
/*
* 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.hmcl.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;
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,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<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"/>
@@ -17,35 +17,37 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane2" pref="252" max="32767" 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" alignment="1" pref="122" max="32767" attributes="0"/>
<Component id="btnRefresh" alignment="1" max="32767" attributes="0"/>
<Component id="btnDownload" max="32767" attributes="0"/>
<Component id="btnRefreshGameDownloads" 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="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="btnRefresh" 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="280" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" 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/hmcl/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"/>
@@ -55,13 +57,8 @@
<SubComponents>
<Component class="javax.swing.JTable" name="lstDownloads">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
<Table columnCount="4" rowCount="0">
<Column editable="false" title="&#x6574;&#x5408;&#x5305;&#x540d;&#x79f0;" type="java.lang.String"/>
<Column editable="false" title="&#x6574;&#x5408;&#x5305;&#x7248;&#x672c;" type="java.lang.String"/>
<Column editable="false" title="MC&#x7248;&#x672c;" type="java.lang.String"/>
<Column editable="false" title="&#x4f5c;&#x8005;" type="java.lang.String"/>
</Table>
<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.release_time&quot;), C.i18n(&quot;install.time&quot;), C.i18n(&quot;install.type&quot;)},new Class[]{String.class, String.class, String.class, String.class}, new boolean[]{false, 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">
@@ -74,24 +71,14 @@
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnRefresh">
<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/hellominecraftlauncher/I18N.properties" key="&#x5237;&#x65b0;" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
<ResourceString bundle="org/jackhuang/hmcl/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>
<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/hellominecraftlauncher/I18N.properties" key="&#x4e0b;&#x8f7d;" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnDownloadActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRefreshGameDownloadsActionPerformed"/>
</Events>
</Component>
</SubComponents>
@@ -0,0 +1,172 @@
/*
* 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.hmcl.ui;
import org.jackhuang.hmcl.util.ui.Page;
import javax.swing.table.DefaultTableModel;
import org.jackhuang.hmcl.api.ui.TopTabPage;
import org.jackhuang.hmcl.core.download.MinecraftRemoteVersions;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.util.task.ProgressProviderListener;
import org.jackhuang.hmcl.util.task.Task;
import org.jackhuang.hmcl.util.task.TaskWindow;
import org.jackhuang.hmcl.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public class GameDownloadPanel extends Page implements ProgressProviderListener {
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.release_time"), C.i18n("install.time"), C.i18n("install.type")},new Class[]{String.class, String.class, String.class, String.class}, new boolean[]{false, 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() {
if (loading)
return;
loading = true;
DefaultTableModel model = SwingUtils.clearDefaultTable(lstDownloads);
model.addRow(new Object[] { C.i18n("message.loading"), "", "" });
MinecraftRemoteVersions.refreshRomoteVersions(Settings.getLastProfile().service().getDownloadType())
.reg((ver) -> model.addRow(new Object[] { ver.id, ver.releaseTime, ver.time,
StrUtils.equalsOne(ver.type, "old_beta", "old_alpha", "release", "snapshot") ? C.i18n("versions." + ver.type) : ver.type }))
.regDone(SwingUtils.invokeLater(() -> {
loading = false;
lstDownloads.requestFocus();
if (model.getRowCount() > 0)
model.removeRow(0);
})).setProgressProviderListener(this).runAsync();
}
boolean loading = false;
@Override
public void setProgress(Task task, int prog, int max) {
DefaultTableModel model = (DefaultTableModel) lstDownloads.getModel();
if (model.getRowCount() > 0)
model.setValueAt(C.i18n("message.loading") + " " + (prog < 0 ? "???" : Integer.toString(prog * 100 / max) + "%"), 0, 0);
}
@Override
public void setStatus(Task task, String sta) {
}
@Override
public void onProgressProviderDone(Task task) {
}
void downloadMinecraft() {
if (lstDownloads.getSelectedRow() < 0) {
MessageBox.show(C.i18n("gamedownload.not_refreshed"));
return;
}
String id = (String) lstDownloads.getModel().getValueAt(lstDownloads.getSelectedRow(), 0);
TaskWindow.factory().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(TopTabPage page) {
super.onSelect(page);
if (!refreshedDownloads) {
refreshedDownloads = true;
refreshDownloads();
}
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+108
View File
@@ -0,0 +1,108 @@
/*
* 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.hmcl.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 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);
}
}
@@ -0,0 +1,85 @@
<?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/hmcl/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/hmcl/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>
@@ -0,0 +1,210 @@
/*
* 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.hmcl.ui;
import org.jackhuang.hmcl.util.ui.Page;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import org.jackhuang.hmcl.api.ui.TopTabPage;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.core.install.InstallerType;
import org.jackhuang.hmcl.core.install.InstallerVersionList;
import org.jackhuang.hmcl.util.task.TaskRunnable;
import org.jackhuang.hmcl.util.task.TaskWindow;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.util.task.ProgressProviderListener;
import org.jackhuang.hmcl.util.task.Task;
import org.jackhuang.hmcl.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public class InstallerPanel extends Page implements ProgressProviderListener {
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();
animationEnabled = Settings.getInstance().isEnableAnimation();
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;
InstallerVersionList list;
InstallerType id;
void refreshVersions() {
if (loading)
return;
Task t = list.refresh(new String[] { gsp.getMinecraftVersionFormatted() });
if (t != null) {
loading = true;
DefaultTableModel model = SwingUtils.clearDefaultTable(lstInstallers);
model.addRow(new Object[] { C.i18n("message.loading"), "", "" });
t.with(new TaskRunnable(this::loadVersions)).setProgressProviderListener(this).runAsync();
}
}
boolean loading = false;
@Override
public void setProgress(Task task, int prog, int max) {
DefaultTableModel model = (DefaultTableModel) lstInstallers.getModel();
if (model.getRowCount() > 0)
model.setValueAt(C.i18n("message.loading") + " " + (prog < 0 ? "???" : Integer.toString(prog * 100 / max) + "%"), 0, 0);
}
@Override
public void setStatus(Task task, String sta) {
}
@Override
public void onProgressProviderDone(Task task) {
loading = false;
DefaultTableModel model = (DefaultTableModel) lstInstallers.getModel();
if (model.getRowCount() > 0)
model.removeRow(0);
}
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.factory()
.append(Settings.getLastProfile().service().install().download(Settings.getLastProfile().getSelectedVersion(), getVersion(idx), id))
.append(new TaskRunnable(() -> gsp.refreshVersions()))
.execute();
}
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(TopTabPage page) {
super.onSelect(page);
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
}
@@ -0,0 +1,101 @@
/*
* 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.hmcl.ui;
import javax.swing.JTextPane;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BoxView;
import javax.swing.text.ComponentView;
import javax.swing.text.Element;
import javax.swing.text.IconView;
import javax.swing.text.LabelView;
import javax.swing.text.ParagraphView;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
/**
*
* @author huang
*/
public class JLineWrapTextPane extends JTextPane {
// 内部类
// 以下内部类全都用于实现自动强制折行
private class WarpEditorKit extends StyledEditorKit {
private ViewFactory defaultFactory = new WarpColumnFactory();
@Override
public ViewFactory getViewFactory() {
return defaultFactory;
}
}
private class WarpColumnFactory implements ViewFactory {
public View create(Element elem) {
String kind = elem.getName();
if (kind != null) {
if (kind.equals(AbstractDocument.ContentElementName)) {
return new WarpLabelView(elem);
} else if (kind.equals(AbstractDocument.ParagraphElementName)) {
return new ParagraphView(elem);
} else if (kind.equals(AbstractDocument.SectionElementName)) {
return new BoxView(elem, View.Y_AXIS);
} else if (kind.equals(StyleConstants.ComponentElementName)) {
return new ComponentView(elem);
} else if (kind.equals(StyleConstants.IconElementName)) {
return new IconView(elem);
}
}
// default to text display
return new LabelView(elem);
}
}
private class WarpLabelView extends LabelView {
public WarpLabelView(Element elem) {
super(elem);
}
@Override
public float getMinimumSpan(int axis) {
switch (axis) {
case View.X_AXIS:
return 0;
case View.Y_AXIS:
return super.getMinimumSpan(axis);
default:
throw new IllegalArgumentException("Invalid axis: " + axis);
}
}
}
// 本类
// 构造函数
public JLineWrapTextPane() {
super();
this.setEditorKit(new WarpEditorKit());
}
}
@@ -0,0 +1,601 @@
<?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 min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" 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 max="32767" attributes="0"/>
</Group>
<Component id="tabLauncherSettings" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="tabLauncherSettings" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblModpack" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblRestart" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<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/hmcl/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.JLabel" name="lblRestart">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.restart" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JTabbedPane" name="tabLauncherSettings">
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value=""/>
</AccessibilityProperties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new NewTabPane()"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="pnlGeneral">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new Page().setAnimationEnabled(Settings.getInstance().isEnableAnimation())"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="General">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.tab.general" 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 max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="btnCheckUpdate" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnMCBBS" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" 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="lblCommonPath" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblLang" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblProxy" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="cboProxyType" pref="156" max="32767" attributes="0"/>
<EmptySpace max="-2" 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>
<Component id="cboLang" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="txtCommonPath" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnSetCommonPath" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="cboDownloadSource" alignment="1" max="32767" attributes="0"/>
</Group>
</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="lblCommonPath" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtCommonPath" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="btnSetCommonPath" 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="cboLang" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblLang" alignment="3" min="-2" 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"/>
<Component id="cboProxyType" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="69" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnCheckUpdate" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="btnMCBBS" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<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/hmcl/lang/I18N.properties" key="launcher.proxy" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</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/hmcl/lang/I18N.properties" key="proxy.host" 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="lblProxyPort">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="proxy.port" 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="lblProxyUserName">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/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.JLabel" name="lblProxyPassword">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="proxy.password" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</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.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="lblDownloadSource">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.download_source" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblCommonPath">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.common_location" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtCommonPath">
<Properties>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.commpath_tooltip" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="txtCommonPathFocusLost"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnSetCommonPath">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/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="btnSetCommonPathActionPerformed"/>
</Events>
</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/hmcl/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.JButton" name="btnMCBBS">
<Properties>
<Property name="text" type="java.lang.String" value="MCBBS"/>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnMCBBSActionPerformed"/>
</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/hmcl/lang/I18N.properties" key="launcher.lang" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboProxyType">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="3">
<StringItem index="0" value="Direct"/>
<StringItem index="1" value="HTTP"/>
<StringItem index="2" value="Socks"/>
</StringArray>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboProxyTypeItemStateChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnlUI">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new Page().setAnimationEnabled(Settings.getInstance().isEnableAnimation())"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="UI">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.tab.ui" 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 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="chkDecorated" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="chkEnableShadow" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="chkEnableBlur" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="chkEnableAnimation" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="163" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblBackground" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblFont" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblTheme" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cboTheme" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtBackgroundPath" max="32767" attributes="0"/>
<Component id="cboFontFamily" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="btnSelBackgroundPath" max="32767" attributes="0"/>
<Component id="spinnerFontSize" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="lblExample" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</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="txtBackgroundPath" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="btnSelBackgroundPath" 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="cboFontFamily" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblFont" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="spinnerFontSize" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblExample" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cboTheme" alignment="3" min="-2" pref="26" max="-2" attributes="0"/>
<Component id="lblTheme" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="63" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="chkEnableShadow" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="chkEnableBlur" 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"/>
<Component id="chkDecorated" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<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/hmcl/lang/I18N.properties" key="launcher.theme" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboTheme">
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboThemeItemStateChanged"/>
</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/hmcl/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/hmcl/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.JCheckBox" name="chkEnableShadow">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/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.JCheckBox" name="chkEnableBlur">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.enable_blur" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkEnableBlurItemStateChanged"/>
</Events>
</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/hmcl/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/hmcl/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.JButton" name="btnSelBackgroundPath">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/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.JComboBox" name="cboFontFamily">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<SerializedValue value="-84,-19,0,5,115,114,0,32,106,97,118,97,120,46,115,119,105,110,103,46,68,101,102,97,117,108,116,67,111,109,98,111,66,111,120,77,111,100,101,108,92,-10,105,-80,-61,-104,-56,48,2,0,2,76,0,7,111,98,106,101,99,116,115,116,0,18,76,106,97,118,97,47,117,116,105,108,47,86,101,99,116,111,114,59,76,0,14,115,101,108,101,99,116,101,100,79,98,106,101,99,116,116,0,18,76,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,59,120,114,0,29,106,97,118,97,120,46,115,119,105,110,103,46,65,98,115,116,114,97,99,116,76,105,115,116,77,111,100,101,108,87,-79,61,-30,108,45,-87,-39,2,0,1,76,0,12,108,105,115,116,101,110,101,114,76,105,115,116,116,0,37,76,106,97,118,97,120,47,115,119,105,110,103,47,101,118,101,110,116,47,69,118,101,110,116,76,105,115,116,101,110,101,114,76,105,115,116,59,120,112,115,114,0,35,106,97,118,97,120,46,115,119,105,110,103,46,101,118,101,110,116,46,69,118,101,110,116,76,105,115,116,101,110,101,114,76,105,115,116,-79,54,-58,125,-124,-22,-42,68,3,0,0,120,112,116,0,34,106,97,118,97,120,46,115,119,105,110,103,46,101,118,101,110,116,46,76,105,115,116,68,97,116,97,76,105,115,116,101,110,101,114,115,114,0,21,106,97,118,97,120,46,115,119,105,110,103,46,74,67,111,109,98,111,66,111,120,115,-25,-16,-68,-83,109,105,-54,3,0,14,90,0,17,102,105,114,105,110,103,65,99,116,105,111,110,69,118,101,110,116,90,0,10,105,115,69,100,105,116,97,98,108,101,90,0,23,108,105,103,104,116,87,101,105,103,104,116,80,111,112,117,112,69,110,97,98,108,101,100,73,0,15,109,97,120,105,109,117,109,82,111,119,67,111,117,110,116,90,0,13,115,101,108,101,99,116,105,110,103,73,116,101,109,76,0,6,97,99,116,105,111,110,116,0,20,76,106,97,118,97,120,47,115,119,105,110,103,47,65,99,116,105,111,110,59,76,0,13,97,99,116,105,111,110,67,111,109,109,97,110,100,116,0,18,76,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,59,76,0,28,97,99,116,105,111,110,80,114,111,112,101,114,116,121,67,104,97,110,103,101,76,105,115,116,101,110,101,114,116,0,35,76,106,97,118,97,47,98,101,97,110,115,47,80,114,111,112,101,114,116,121,67,104,97,110,103,101,76,105,115,116,101,110,101,114,59,76,0,9,100,97,116,97,77,111,100,101,108,116,0,27,76,106,97,118,97,120,47,115,119,105,110,103,47,67,111,109,98,111,66,111,120,77,111,100,101,108,59,76,0,6,101,100,105,116,111,114,116,0,28,76,106,97,118,97,120,47,115,119,105,110,103,47,67,111,109,98,111,66,111,120,69,100,105,116,111,114,59,76,0,19,107,101,121,83,101,108,101,99,116,105,111,110,77,97,110,97,103,101,114,116,0,43,76,106,97,118,97,120,47,115,119,105,110,103,47,74,67,111,109,98,111,66,111,120,36,75,101,121,83,101,108,101,99,116,105,111,110,77,97,110,97,103,101,114,59,76,0,21,112,114,111,116,111,116,121,112,101,68,105,115,112,108,97,121,86,97,108,117,101,113,0,126,0,2,76,0,8,114,101,110,100,101,114,101,114,116,0,30,76,106,97,118,97,120,47,115,119,105,110,103,47,76,105,115,116,67,101,108,108,82,101,110,100,101,114,101,114,59,76,0,20,115,101,108,101,99,116,101,100,73,116,101,109,82,101,109,105,110,100,101,114,113,0,126,0,2,120,114,0,22,106,97,118,97,120,46,115,119,105,110,103,46,74,67,111,109,112,111,110,101,110,116,51,-17,99,38,30,108,-90,-113,3,0,16,70,0,10,97,108,105,103,110,109,101,110,116,88,70,0,10,97,108,105,103,110,109,101,110,116,89,90,0,11,97,117,116,111,115,99,114,111,108,108,115,73,0,5,102,108,97,103,115,90,0,15,105,115,65,108,105,103,110,109,101,110,116,88,83,101,116,90,0,15,105,115,65,108,105,103,110,109,101,110,116,89,83,101,116,90,0,26,118,101,114,105,102,121,73,110,112,117,116,87,104,101,110,70,111,99,117,115,84,97,114,103,101,116,76,0,9,97,99,116,105,111,110,77,97,112,116,0,23,76,106,97,118,97,120,47,115,119,105,110,103,47,65,99,116,105,111,110,77,97,112,59,76,0,16,97,110,99,101,115,116,111,114,73,110,112,117,116,77,97,112,116,0,22,76,106,97,118,97,120,47,115,119,105,110,103,47,73,110,112,117,116,77,97,112,59,76,0,6,98,111,114,100,101,114,116,0,27,76,106,97,118,97,120,47,115,119,105,110,103,47,98,111,114,100,101,114,47,66,111,114,100,101,114,59,76,0,13,102,111,99,117,115,73,110,112,117,116,77,97,112,113,0,126,0,19,76,0,13,105,110,112,117,116,86,101,114,105,102,105,101,114,116,0,27,76,106,97,118,97,120,47,115,119,105,110,103,47,73,110,112,117,116,86,101,114,105,102,105,101,114,59,76,0,12,108,105,115,116,101,110,101,114,76,105,115,116,113,0,126,0,4,76,0,9,112,111,112,117,112,77,101,110,117,116,0,24,76,106,97,118,97,120,47,115,119,105,110,103,47,74,80,111,112,117,112,77,101,110,117,59,76,0,21,118,101,116,111,97,98,108,101,67,104,97,110,103,101,83,117,112,112,111,114,116,116,0,34,76,106,97,118,97,47,98,101,97,110,115,47,86,101,116,111,97,98,108,101,67,104,97,110,103,101,83,117,112,112,111,114,116,59,76,0,14,119,105,110,100,111,119,73,110,112,117,116,77,97,112,116,0,31,76,106,97,118,97,120,47,115,119,105,110,103,47,67,111,109,112,111,110,101,110,116,73,110,112,117,116,77,97,112,59,120,114,0,18,106,97,118,97,46,97,119,116,46,67,111,110,116,97,105,110,101,114,64,7,-128,115,-3,20,12,39,3,0,8,73,0,30,99,111,110,116,97,105,110,101,114,83,101,114,105,97,108,105,122,101,100,68,97,116Line truncated
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboFontFamilyItemStateChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JFontComboBox()"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="lblFont">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.log_font" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JSpinner" name="spinnerFontSize">
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spinnerFontSizeStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblExample">
<Properties>
<Property name="text" type="java.lang.String" value="19:10:10 [Client Thread/INFO]: Example"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnlAbout">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new Page().setAnimationEnabled(Settings.getInstance().isEnableAnimation())"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="About">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="launcher.tab.about" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="lblAbout" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="252" 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"/>
<Component id="lblAbout" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<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/hmcl/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="&#x9ed8;&#x8ba4;&#x5149;&#x6807;"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,672 @@
/*
* 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.hmcl.ui;
import java.io.IOException;
import java.net.Proxy;
import javax.swing.DefaultComboBoxModel;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.api.ui.Theme;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.core.download.DownloadType;
import org.jackhuang.hmcl.util.MathUtils;
import org.jackhuang.hmcl.util.sys.IOUtils;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.lang.SupportedLocales;
import org.jackhuang.hmcl.util.ui.JFontComboBox;
import org.jackhuang.hmcl.util.ui.JSystemFileChooser;
import org.jackhuang.hmcl.util.ui.Page;
import org.jackhuang.hmcl.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public class LauncherSettingsPanel extends RepaintPage {
public LauncherSettingsPanel() {
setRepainter(this);
}
void initGui() {
initComponents();
animationEnabled = Settings.getInstance().isEnableAnimation();
DefaultComboBoxModel<String> 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);
DefaultComboBoxModel<Theme> g = new DefaultComboBoxModel<>();
for (Theme t : Theme.THEMES.values())
g.addElement(t);
cboTheme.setModel(g);
txtBackgroundPath.setText(Settings.getInstance().getBgpath());
txtCommonPath.setText(Settings.getInstance().getCommonpath());
txtProxyHost.setText(Settings.getInstance().getProxyHost());
txtProxyPort.setText(Settings.getInstance().getProxyPort());
txtProxyUsername.setText(Settings.getInstance().getProxyUserName());
txtProxyPassword.setText(Settings.getInstance().getProxyPassword());
spinnerFontSize.setValue(Settings.getInstance().getFontSize());
cboFontFamily.setSelectedItem(Settings.getInstance().getFontFamily());
cboDownloadSource.setSelectedIndex(Settings.getInstance().getDownloadType());
cboProxyType.setSelectedIndex(Settings.getInstance().getProxyType().ordinal());
cboTheme.setSelectedItem(Settings.getInstance().getTheme());
chkEnableShadow.setSelected(Settings.getInstance().isEnableShadow());
chkEnableBlur.setSelected(Settings.getInstance().isEnableBlur());
chkEnableAnimation.setSelected(Settings.getInstance().isEnableAnimation());
chkDecorated.setSelected(Settings.getInstance().isDecorated());
}
@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() {
lblModpack = new javax.swing.JLabel();
lblRestart = new javax.swing.JLabel();
tabLauncherSettings = new NewTabPane();
pnlGeneral = new Page().setAnimationEnabled(Settings.getInstance().isEnableAnimation());
lblProxy = new javax.swing.JLabel();
lblProxyHost = new javax.swing.JLabel();
txtProxyHost = new javax.swing.JTextField();
lblProxyPort = new javax.swing.JLabel();
txtProxyPort = new javax.swing.JTextField();
lblProxyUserName = new javax.swing.JLabel();
txtProxyUsername = new javax.swing.JTextField();
lblProxyPassword = new javax.swing.JLabel();
txtProxyPassword = new javax.swing.JTextField();
cboDownloadSource = new javax.swing.JComboBox();
lblDownloadSource = new javax.swing.JLabel();
lblCommonPath = new javax.swing.JLabel();
txtCommonPath = new javax.swing.JTextField();
btnSetCommonPath = new javax.swing.JButton();
btnCheckUpdate = new javax.swing.JButton();
btnMCBBS = new javax.swing.JButton();
cboLang = new javax.swing.JComboBox();
lblLang = new javax.swing.JLabel();
cboProxyType = new javax.swing.JComboBox<>();
pnlUI = new Page().setAnimationEnabled(Settings.getInstance().isEnableAnimation());
lblTheme = new javax.swing.JLabel();
cboTheme = new javax.swing.JComboBox();
lblBackground = new javax.swing.JLabel();
txtBackgroundPath = new javax.swing.JTextField();
chkEnableShadow = new javax.swing.JCheckBox();
chkEnableBlur = new javax.swing.JCheckBox();
chkEnableAnimation = new javax.swing.JCheckBox();
chkDecorated = new javax.swing.JCheckBox();
btnSelBackgroundPath = new javax.swing.JButton();
cboFontFamily = new JFontComboBox();
lblFont = new javax.swing.JLabel();
spinnerFontSize = new javax.swing.JSpinner();
lblExample = new javax.swing.JLabel();
pnlAbout = new Page().setAnimationEnabled(Settings.getInstance().isEnableAnimation());
lblAbout = new javax.swing.JLabel();
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);
}
});
lblRestart.setText(C.i18n("launcher.restart")); // NOI18N
lblProxy.setText(C.i18n("launcher.proxy")); // NOI18N
lblProxyHost.setText(C.i18n("proxy.host")); // NOI18N
txtProxyHost.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtProxyHostFocusLost(evt);
}
});
lblProxyPort.setText(C.i18n("proxy.port")); // NOI18N
txtProxyPort.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtProxyPortFocusLost(evt);
}
});
lblProxyUserName.setText(C.i18n("proxy.username")); // NOI18N
txtProxyUsername.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtProxyUsernameFocusLost(evt);
}
});
lblProxyPassword.setText(C.i18n("proxy.password")); // NOI18N
txtProxyPassword.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtProxyPasswordFocusLost(evt);
}
});
cboDownloadSource.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboDownloadSourceItemStateChanged(evt);
}
});
lblDownloadSource.setText(C.i18n("launcher.download_source")); // NOI18N
lblCommonPath.setText(C.i18n("launcher.common_location")); // NOI18N
txtCommonPath.setToolTipText(C.i18n("launcher.commpath_tooltip")); // NOI18N
txtCommonPath.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
txtCommonPathFocusLost(evt);
}
});
btnSetCommonPath.setText(C.i18n("ui.button.explore")); // NOI18N
btnSetCommonPath.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnSetCommonPathActionPerformed(evt);
}
});
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);
}
});
btnMCBBS.setText("MCBBS");
btnMCBBS.setToolTipText("");
btnMCBBS.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnMCBBSActionPerformed(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
cboProxyType.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Direct", "HTTP", "Socks" }));
cboProxyType.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboProxyTypeItemStateChanged(evt);
}
});
javax.swing.GroupLayout pnlGeneralLayout = new javax.swing.GroupLayout(pnlGeneral);
pnlGeneral.setLayout(pnlGeneralLayout);
pnlGeneralLayout.setHorizontalGroup(
pnlGeneralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlGeneralLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnlGeneralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlGeneralLayout.createSequentialGroup()
.addComponent(btnCheckUpdate)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnMCBBS)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(pnlGeneralLayout.createSequentialGroup()
.addGroup(pnlGeneralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblDownloadSource)
.addComponent(lblCommonPath)
.addComponent(lblLang)
.addComponent(lblProxy))
.addGap(28, 28, 28)
.addGroup(pnlGeneralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlGeneralLayout.createSequentialGroup()
.addComponent(cboProxyType, 0, 156, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.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))
.addComponent(cboLang, javax.swing.GroupLayout.Alignment.TRAILING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(pnlGeneralLayout.createSequentialGroup()
.addComponent(txtCommonPath)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnSetCommonPath))
.addComponent(cboDownloadSource, javax.swing.GroupLayout.Alignment.TRAILING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addContainerGap())
);
pnlGeneralLayout.setVerticalGroup(
pnlGeneralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlGeneralLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnlGeneralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblCommonPath)
.addComponent(txtCommonPath, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnSetCommonPath, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlGeneralLayout.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(pnlGeneralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cboLang, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblLang))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlGeneralLayout.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)
.addComponent(cboProxyType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 69, Short.MAX_VALUE)
.addGroup(pnlGeneralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnCheckUpdate, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnMCBBS, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
);
tabLauncherSettings.addTab(C.i18n("launcher.tab.general"), pnlGeneral); // NOI18N
lblTheme.setText(C.i18n("launcher.theme")); // NOI18N
cboTheme.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboThemeItemStateChanged(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);
}
});
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);
}
});
chkEnableBlur.setText(C.i18n("launcher.enable_blur")); // NOI18N
chkEnableBlur.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkEnableBlurItemStateChanged(evt);
}
});
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);
}
});
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);
}
});
cboFontFamily.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboFontFamilyItemStateChanged(evt);
}
});
lblFont.setText(C.i18n("launcher.log_font")); // NOI18N
spinnerFontSize.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
spinnerFontSizeStateChanged(evt);
}
});
lblExample.setText("19:10:10 [Client Thread/INFO]: Example");
javax.swing.GroupLayout pnlUILayout = new javax.swing.GroupLayout(pnlUI);
pnlUI.setLayout(pnlUILayout);
pnlUILayout.setHorizontalGroup(
pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlUILayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlUILayout.createSequentialGroup()
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(chkDecorated)
.addGroup(pnlUILayout.createSequentialGroup()
.addComponent(chkEnableShadow)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkEnableBlur)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkEnableAnimation)))
.addGap(0, 163, Short.MAX_VALUE))
.addGroup(pnlUILayout.createSequentialGroup()
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblBackground)
.addComponent(lblFont)
.addComponent(lblTheme))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(cboTheme, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(pnlUILayout.createSequentialGroup()
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtBackgroundPath)
.addComponent(cboFontFamily, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(btnSelBackgroundPath, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(spinnerFontSize)))
.addGroup(pnlUILayout.createSequentialGroup()
.addComponent(lblExample)
.addGap(0, 0, Short.MAX_VALUE)))))
.addContainerGap())
);
pnlUILayout.setVerticalGroup(
pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlUILayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblBackground)
.addComponent(txtBackgroundPath, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnSelBackgroundPath, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cboFontFamily, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblFont)
.addComponent(spinnerFontSize, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblExample)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cboTheme, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblTheme))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 63, Short.MAX_VALUE)
.addGroup(pnlUILayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(chkEnableShadow)
.addComponent(chkEnableBlur)
.addComponent(chkEnableAnimation))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkDecorated)
.addContainerGap())
);
tabLauncherSettings.addTab(C.i18n("launcher.tab.ui"), pnlUI); // NOI18N
lblAbout.setText(C.i18n("launcher.about")); // NOI18N
lblAbout.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
javax.swing.GroupLayout pnlAboutLayout = new javax.swing.GroupLayout(pnlAbout);
pnlAbout.setLayout(pnlAboutLayout);
pnlAboutLayout.setHorizontalGroup(
pnlAboutLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlAboutLayout.createSequentialGroup()
.addContainerGap()
.addComponent(lblAbout, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(252, Short.MAX_VALUE))
);
pnlAboutLayout.setVerticalGroup(
pnlAboutLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlAboutLayout.createSequentialGroup()
.addContainerGap()
.addComponent(lblAbout, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
tabLauncherSettings.addTab(C.i18n("launcher.tab.about"), pnlAbout); // 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()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblModpack, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblRestart))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(tabLauncherSettings)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(tabLauncherSettings)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblModpack, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblRestart)
.addContainerGap())
);
tabLauncherSettings.getAccessibleContext().setAccessibleName("");
}// </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
JSystemFileChooser fc = new JSystemFileChooser();
fc.setFileSelectionMode(JSystemFileChooser.FILES_ONLY);
fc.setDialogTitle(C.i18n("launcher.choose_bgpath"));
fc.setMultiSelectionEnabled(false);
fc.setFileFilter(new FileNameExtensionFilter("*.png", "png"));
fc.addChoosableFileFilter(new FileNameExtensionFilter("*.jpg", "jpg"));
if (fc.showOpenDialog(this) != JSystemFileChooser.APPROVE_OPTION || 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(((Theme) cboTheme.getSelectedItem()).id);
}//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 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 btnMCBBSActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnMCBBSActionPerformed
SwingUtils.openLink(C.URL_PUBLISH);
}//GEN-LAST:event_btnMCBBSActionPerformed
private void chkEnableBlurItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkEnableBlurItemStateChanged
Settings.getInstance().setEnableBlur(chkEnableBlur.isSelected());
}//GEN-LAST:event_chkEnableBlurItemStateChanged
private void chkEnableAnimationItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkEnableAnimationItemStateChanged
Settings.getInstance().setEnableAnimation(chkEnableAnimation.isSelected());
}//GEN-LAST:event_chkEnableAnimationItemStateChanged
private void btnSetCommonPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSetCommonPathActionPerformed
JSystemFileChooser fc = new JSystemFileChooser();
fc.setFileSelectionMode(JSystemFileChooser.DIRECTORIES_ONLY);
fc.setDialogTitle(C.i18n("launcher.choose_commonpath"));
fc.setMultiSelectionEnabled(false);
if (fc.showOpenDialog(this) != JSystemFileChooser.APPROVE_OPTION || fc.getSelectedFile() == null)
return;
try {
String path = fc.getSelectedFile().getCanonicalPath();
txtCommonPath.setText(path);
Settings.getInstance().setCommonpath(path);
} catch (IOException e) {
HMCLog.warn("Failed to set common path.", e);
MessageBox.show(C.i18n("ui.label.failed_set") + e.getMessage());
}
}//GEN-LAST:event_btnSetCommonPathActionPerformed
private void txtCommonPathFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtCommonPathFocusLost
Settings.getInstance().setCommonpath(txtCommonPath.getText());
}//GEN-LAST:event_txtCommonPathFocusLost
private void cboFontFamilyItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboFontFamilyItemStateChanged
Settings.getInstance().setFontFamily(evt.getItem().toString());
lblExample.setFont(Settings.getInstance().getConsoleFont());
}//GEN-LAST:event_cboFontFamilyItemStateChanged
private void spinnerFontSizeStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerFontSizeStateChanged
Settings.getInstance().setFontSize(MathUtils.parseInt(spinnerFontSize.getValue().toString(), 12));
lblExample.setFont(Settings.getInstance().getConsoleFont());
}//GEN-LAST:event_spinnerFontSizeStateChanged
private void cboProxyTypeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboProxyTypeItemStateChanged
Settings.getInstance().setProxyType(Proxy.Type.values()[cboProxyType.getSelectedIndex()]);
}//GEN-LAST:event_cboProxyTypeItemStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnCheckUpdate;
private javax.swing.JButton btnMCBBS;
private javax.swing.JButton btnSelBackgroundPath;
private javax.swing.JButton btnSetCommonPath;
private javax.swing.JComboBox cboDownloadSource;
private javax.swing.JComboBox cboFontFamily;
private javax.swing.JComboBox cboLang;
private javax.swing.JComboBox<String> cboProxyType;
private javax.swing.JComboBox cboTheme;
private javax.swing.JCheckBox chkDecorated;
private javax.swing.JCheckBox chkEnableAnimation;
private javax.swing.JCheckBox chkEnableBlur;
private javax.swing.JCheckBox chkEnableShadow;
private javax.swing.JLabel lblAbout;
private javax.swing.JLabel lblBackground;
private javax.swing.JLabel lblCommonPath;
private javax.swing.JLabel lblDownloadSource;
private javax.swing.JLabel lblExample;
private javax.swing.JLabel lblFont;
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.JPanel pnlAbout;
private javax.swing.JPanel pnlGeneral;
private javax.swing.JPanel pnlUI;
private javax.swing.JSpinner spinnerFontSize;
private javax.swing.JTabbedPane tabLauncherSettings;
private javax.swing.JTextField txtBackgroundPath;
private javax.swing.JTextField txtCommonPath;
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
}
@@ -0,0 +1,254 @@
/*
* 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.hmcl.ui;
import java.io.File;
import java.io.IOException;
import java.io.PipedOutputStream;
import javax.swing.SwingUtilities;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.process.JVMLaunchFailedEvent;
import org.jackhuang.hmcl.api.event.process.JavaProcessExitedAbnormallyEvent;
import org.jackhuang.hmcl.api.event.process.JavaProcessStoppedEvent;
import org.jackhuang.hmcl.api.event.launch.LaunchEvent;
import org.jackhuang.hmcl.api.event.launch.LaunchSucceededEvent;
import org.jackhuang.hmcl.api.event.launch.LaunchingStateChangedEvent;
import org.jackhuang.hmcl.util.LauncherVisibility;
import org.jackhuang.hmcl.core.launch.GameLauncher;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.util.HMCLGameLauncher;
import org.jackhuang.hmcl.util.MinecraftCrashAdvicer;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.api.func.Consumer;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.api.event.launch.LaunchingState;
import org.jackhuang.hmcl.util.DefaultPlugin;
import org.jackhuang.hmcl.util.Log4jHandler;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.util.sys.FileUtils;
import org.jackhuang.hmcl.util.sys.PrintlnEvent;
import org.jackhuang.hmcl.util.sys.ProcessMonitor;
import org.xml.sax.XMLReader;
/**
*
* @author huangyuhui
*/
public class LaunchingUIDaemon {
XMLReader reader;
Log4jHandler logHandler;
public LaunchingUIDaemon() {
HMCLApi.EVENT_BUS.channel(LaunchingStateChangedEvent.class).register(LAUNCHING_STATE_CHANGED);
HMCLApi.EVENT_BUS.channel(LaunchEvent.class).register(p -> {
GameLauncher obj = (GameLauncher) p.getSource();
HMCLGameLauncher.GameLauncherTag tag = (HMCLGameLauncher.GameLauncherTag) obj.getTag();
if (tag.launcherVisibility == 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 (tag.launcherVisibility == LauncherVisibility.KEEP)
MainFrame.INSTANCE.closeMessage();
else {
if (LogWindow.INSTANCE.isVisible())
LogWindow.INSTANCE.setExit(() -> true);
HMCLApi.EVENT_BUS.fireChannel(new LaunchingStateChangedEvent(obj, LaunchingState.WaitingForGameLaunching));
}
// We promise that JavaProcessMonitor.tag is LauncherVisibility
// See events below.
ProcessMonitor monitor = new ProcessMonitor(p.getValue());
PipedOutputStream os = new PipedOutputStream();
monitor.setTag(obj);
try {
logHandler = new Log4jHandler(monitor, os, false);
logHandler.addForbiddenToken(obj.getLoginResult().getAccessToken(), "<access token>");
logHandler.addForbiddenToken(obj.getLoginResult().getSession(), "<session>");
logHandler.addForbiddenToken(obj.getLoginResult().getUserId(), "<uuid>");
logHandler.addForbiddenToken("Setting user: " + obj.getLoginResult().getUserName(), "<player>");
logHandler.start();
} catch(Exception e) {
HMCLog.err("", e);
}
monitor.registerPrintlnEvent(new PrintlnProcessor(obj, os));
monitor.start();
});
HMCLApi.EVENT_BUS.channel(LaunchSucceededEvent.class).register(p -> {
int state = ((HMCLGameLauncher.GameLauncherTag) ((GameLauncher) p.getSource()).getTag()).state;
if (state == 1)
LAUNCH_FINISHER.accept(p);
else if (state == 2)
LAUNCH_SCRIPT_FINISHER.accept(p);
});
HMCLApi.EVENT_BUS.channel(JavaProcessStoppedEvent.class).register(event -> {
GameLauncher launcher = ((GameLauncher) ((ProcessMonitor) event.getSource()).getTag());
HMCLApi.EVENT_BUS.fireChannel(new LaunchingStateChangedEvent(launcher, LaunchingState.Done));
checkExit(unpackProcessMonitor(event.getSource()));
});
HMCLApi.EVENT_BUS.channel(JavaProcessExitedAbnormallyEvent.class).register(event -> {
ProcessMonitor monitor = (ProcessMonitor) event.getSource();
int exitCode = event.getValue().getExitCode();
HMCLog.err("The game exited abnormally, exit code: " + exitCode);
monitor.waitForCommandLineCompletion();
String[] logs = event.getValue().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: " + exitCode;
if (errorText != null)
msg += ", advice: " + MinecraftCrashAdvicer.getAdvice(FileUtils.readQuietly(new File(errorText)));
HMCLog.err(msg);
SwingUtilities.invokeLater(() -> LogWindow.INSTANCE.setVisible(true));
noExitThisTime = true;
});
HMCLApi.EVENT_BUS.channel(JVMLaunchFailedEvent.class).register(event -> {
int exitCode = event.getValue().getExitCode();
HMCLog.err("Cannot create jvm, exit code: " + exitCode);
SwingUtilities.invokeLater(() -> LogWindow.INSTANCE.setVisible(true));
noExitThisTime = true;
});
}
static LauncherVisibility unpackProcessMonitor(Object obj) {
GameLauncher launcher = ((GameLauncher) ((ProcessMonitor) obj).getTag());
HMCLGameLauncher.GameLauncherTag tag = (HMCLGameLauncher.GameLauncherTag) launcher.getTag();
return tag.launcherVisibility;
}
boolean noExitThisTime = false;
void runGame(Profile profile) {
MainFrame.INSTANCE.showMessage(C.i18n("ui.message.launching"));
profile.launcher().genLaunchCode(value -> {
DefaultPlugin.INSTANCE.saveAuthenticatorConfig();
((HMCLGameLauncher.GameLauncherTag) value.getTag()).state = 1;
}, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword());
}
void testGame(Profile profile) {
MainFrame.INSTANCE.showMessage(C.i18n("ui.message.launching"));
profile.launcher().genLaunchCode(value -> {
DefaultPlugin.INSTANCE.saveAuthenticatorConfig();
((HMCLGameLauncher.GameLauncherTag) value.getTag()).state = 1;
((HMCLGameLauncher.GameLauncherTag) value.getTag()).launcherVisibility = LauncherVisibility.KEEP;
}, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword());
}
void makeLaunchScript(Profile profile) {
MainFrame.INSTANCE.showMessage(C.i18n("ui.message.launching"));
profile.launcher().genLaunchCode(value -> {
DefaultPlugin.INSTANCE.saveAuthenticatorConfig();
((HMCLGameLauncher.GameLauncherTag) value.getTag()).state = 2;
}, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword());
}
class PrintlnProcessor implements Consumer<PrintlnEvent> {
GameLauncher launcher;
PipedOutputStream os;
public PrintlnProcessor(GameLauncher launcher, PipedOutputStream os) {
this.launcher = launcher;
this.os = os;
}
@Override
public void accept(PrintlnEvent t) {
String log = t.getLine();
if (!t.isError() && logHandler != null) {
logHandler.newLogLine(log + C.LINE_SEPARATOR);
}
else System.err.println(t.getLine());
HMCLGameLauncher.GameLauncherTag tag = (HMCLGameLauncher.GameLauncherTag) launcher.getTag();
LauncherVisibility l = tag.launcherVisibility;
if (t.getLine().contains("LWJGL Version: ") && l != LauncherVisibility.KEEP)
SwingUtilities.invokeLater(() -> {
if (l != LauncherVisibility.HIDE_AND_REOPEN)
MainFrame.INSTANCE.dispose();
else { // If current state is 'hide and reopen', closes the main window and reset the state to normal.
MainFrame.INSTANCE.setVisible(false);
HMCLApi.EVENT_BUS.fireChannel(new LaunchingStateChangedEvent(launcher, LaunchingState.Done));
}
});
}
}
private static final Consumer<LaunchingStateChangedEvent> LAUNCHING_STATE_CHANGED = t -> {
String message = null;
switch (t.getValue()) {
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;
case WaitingForGameLaunching:
message = "launch.state.waiting_launching";
break;
case Done:
MainFrame.INSTANCE.closeMessage();
return;
}
MainFrame.INSTANCE.showMessage(C.i18n(message));
};
private static final Consumer<LaunchSucceededEvent> LAUNCH_FINISHER = event -> {
try {
((GameLauncher) event.getSource()).launch(event.getValue());
} 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);
}
};
private void checkExit(LauncherVisibility v) {
if (v == LauncherVisibility.HIDE_AND_REOPEN) {
MainFrame.INSTANCE.setVisible(true);
} else if (v != LauncherVisibility.KEEP && !LogWindow.INSTANCE.isVisible() && !noExitThisTime) {
System.exit(0);
} else {
noExitThisTime = false;
}
}
private static final Consumer<LaunchSucceededEvent> LAUNCH_SCRIPT_FINISHER = event -> {
try {
String s = MessageBox.showInputDialog(C.i18n("mainwindow.enter_script_name"));
if (StrUtils.isNotBlank(s))
MessageBox.show(C.i18n("mainwindow.make_launch_succeed") + " " + ((GameLauncher) event.getSource()).makeLauncher(s, event.getValue()).getAbsolutePath());
} catch (IOException ex) {
MessageBox.show(C.i18n("mainwindow.make_launch_script_failed"));
HMCLog.err("Failed to create script file.", ex);
}
MainFrame.INSTANCE.closeMessage();
};
}
@@ -0,0 +1,245 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
<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/hmcl/I18N.properties" key="logwindow.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>
<Events>
<EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
</Events>
<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="1" attributes="0">
<Component id="btnContact" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="144" max="32767" attributes="0"/>
<Component id="btnTerminateGame" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCopy" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnClear" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnClose" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="lblCrash" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="lblShowLines" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cboShowLines" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblSearch" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtSearch" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnFatal" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnError" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnWarn" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnInfo" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnDebug" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="pnlLog" 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="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblShowLines" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboShowLines" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnDebug" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnInfo" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnWarn" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnError" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnFatal" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtSearch" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblSearch" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblCrash" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pnlLog" pref="281" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnClear" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnClose" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnCopy" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnContact" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnTerminateGame" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="btnClear">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/I18N.properties" key="ui.button.clear" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnClearActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnClose">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/I18N.properties" key="ui.button.close" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCloseActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnCopy">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/I18N.properties" key="ui.button.copy" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCopyActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblCrash">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/I18N.properties" key="ui.label.crashing" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnContact">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="logwindow.contact" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnContactActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnTerminateGame">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/I18N.properties" key="logwindow.terminate_game" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnTerminateGameActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="pnlLog">
<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.JTextPane" name="txtLog">
<Properties>
<Property name="editable" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JLineWrapTextPane()"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="lblShowLines">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="logwindow.show_lines" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboShowLines">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="3">
<StringItem index="0" value="100"/>
<StringItem index="1" value="1000"/>
<StringItem index="2" value="5000"/>
</StringArray>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cboShowLinesItemStateChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JToggleButton" name="btnDebug">
<Properties>
<Property name="text" type="java.lang.String" value="0 debug"/>
</Properties>
</Component>
<Component class="javax.swing.JToggleButton" name="btnInfo">
<Properties>
<Property name="text" type="java.lang.String" value="0 info"/>
</Properties>
</Component>
<Component class="javax.swing.JToggleButton" name="btnWarn">
<Properties>
<Property name="text" type="java.lang.String" value="0 warn"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnError">
<Properties>
<Property name="text" type="java.lang.String" value="0 error"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnFatal">
<Properties>
<Property name="text" type="java.lang.String" value="0 fatal"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtSearch">
<Properties>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtSearchActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblSearch">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="logwindow.search" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>
@@ -0,0 +1,425 @@
/*
* 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.hmcl.ui;
import java.io.PrintStream;
import java.util.Deque;
import java.util.LinkedList;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.util.log.Level;
import org.jackhuang.hmcl.api.func.NonFunction;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.util.DoubleOutputStream;
import org.jackhuang.hmcl.util.Utils;
import org.jackhuang.hmcl.util.sys.ProcessMonitor;
import org.jackhuang.hmcl.util.ui.SwingUtils;
/**
*
* @author huangyuhui
*/
public class LogWindow extends javax.swing.JFrame {
public static LogWindowOutputStream outputStream;
NonFunction<Boolean> listener;
/**
* Creates new form LogWindow
*/
public LogWindow() {
initComponents();
DoubleOutputStream out = new DoubleOutputStream(outputStream = new LogWindowOutputStream(this, Level.INFO), System.out);
System.setOut(new PrintStream(out));
DoubleOutputStream err = new DoubleOutputStream(new LogWindowOutputStream(this, Level.ERROR), System.err);
System.setErr(new PrintStream(err));
SwingUtilities.invokeLater(() -> {
setLocationRelativeTo(null);
//txtLog.setEditable(false);
txtLog.setFont(Settings.getInstance().getConsoleFont());
cboShowLines.setSelectedItem(String.valueOf(Settings.getInstance().getLogLines()));
});
}
public static final LogWindow INSTANCE = new LogWindow();
/**
* 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() {
btnClear = new javax.swing.JButton();
btnClose = new javax.swing.JButton();
btnCopy = new javax.swing.JButton();
lblCrash = new javax.swing.JLabel();
btnContact = new javax.swing.JButton();
btnTerminateGame = new javax.swing.JButton();
pnlLog = new javax.swing.JScrollPane();
txtLog = new JLineWrapTextPane();
lblShowLines = new javax.swing.JLabel();
cboShowLines = new javax.swing.JComboBox<>();
btnDebug = new javax.swing.JToggleButton();
btnInfo = new javax.swing.JToggleButton();
btnWarn = new javax.swing.JToggleButton();
btnError = new javax.swing.JButton();
btnFatal = new javax.swing.JButton();
txtSearch = new javax.swing.JTextField();
lblSearch = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(C.i18n("logwindow.title")); // NOI18N
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
});
btnClear.setText(C.i18n("ui.button.clear")); // NOI18N
btnClear.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnClearActionPerformed(evt);
}
});
btnClose.setText(C.i18n("ui.button.close")); // NOI18N
btnClose.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCloseActionPerformed(evt);
}
});
btnCopy.setText(C.i18n("ui.button.copy")); // NOI18N
btnCopy.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCopyActionPerformed(evt);
}
});
lblCrash.setText(C.i18n("ui.label.crashing")); // NOI18N
btnContact.setText(C.i18n("logwindow.contact")); // NOI18N
btnContact.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnContactActionPerformed(evt);
}
});
btnTerminateGame.setText(C.i18n("logwindow.terminate_game")); // NOI18N
btnTerminateGame.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnTerminateGameActionPerformed(evt);
}
});
txtLog.setEditable(false);
pnlLog.setViewportView(txtLog);
lblShowLines.setText(C.i18n("logwindow.show_lines")); // NOI18N
lblShowLines.setToolTipText("");
cboShowLines.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "100", "1000", "5000" }));
cboShowLines.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboShowLinesItemStateChanged(evt);
}
});
btnDebug.setText("0 debug");
btnInfo.setText("0 info");
btnWarn.setText("0 warn");
btnError.setText("0 error");
btnFatal.setText("0 fatal");
txtSearch.setToolTipText("");
txtSearch.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtSearchActionPerformed(evt);
}
});
lblSearch.setText(C.i18n("logwindow.search")); // NOI18N
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(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(btnContact)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 144, Short.MAX_VALUE)
.addComponent(btnTerminateGame)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCopy)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnClear)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnClose))
.addComponent(lblCrash, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(lblShowLines)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cboShowLines, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblSearch)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtSearch)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnFatal)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnError)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnWarn)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnInfo)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnDebug))
.addComponent(pnlLog))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblShowLines)
.addComponent(cboShowLines, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnDebug)
.addComponent(btnInfo)
.addComponent(btnWarn)
.addComponent(btnError)
.addComponent(btnFatal)
.addComponent(txtSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblSearch))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblCrash)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pnlLog, javax.swing.GroupLayout.DEFAULT_SIZE, 281, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnClear)
.addComponent(btnClose)
.addComponent(btnCopy)
.addComponent(btnContact)
.addComponent(btnTerminateGame))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCloseActionPerformed
if (listener != null && listener.apply())
terminateGames();
SwingUtils.exitIfNoWindow(this, true);
}//GEN-LAST:event_btnCloseActionPerformed
private void btnClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnClearActionPerformed
clean();
}//GEN-LAST:event_btnClearActionPerformed
private void btnCopyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCopyActionPerformed
Utils.setClipboard(this.txtLog.getText());
}//GEN-LAST:event_btnCopyActionPerformed
private void btnContactActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnContactActionPerformed
SwingUtils.openLink(C.URL_CONTACT);
}//GEN-LAST:event_btnContactActionPerformed
private void btnTerminateGameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnTerminateGameActionPerformed
terminateGames();
}//GEN-LAST:event_btnTerminateGameActionPerformed
private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
if (listener != null && listener.apply())
terminateGames();
SwingUtils.exitIfNoWindow(this);
}//GEN-LAST:event_formWindowClosing
private void cboShowLinesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboShowLinesItemStateChanged
Settings.getInstance().setLogLines(Integer.parseInt(cboShowLines.getSelectedItem().toString()));
}//GEN-LAST:event_cboShowLinesItemStateChanged
private void txtSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtSearchActionPerformed
if (evt.getSource() != txtSearch || txtSearch.getText().isEmpty())
return;
try {
if (!s.equals(txtSearch.getText()))
pos = 0;
StyledDocument d = txtLog.getStyledDocument();
s = txtSearch.getText();
String content = d.getText(0, d.getLength());
int x = content.indexOf(s, pos);
if (x == -1) {
pos = 0;
x = content.indexOf(s, pos);
}
if (x == -1)
return;
int len = s.length();
pos = x + len;
SimpleAttributeSet set = new SimpleAttributeSet(d.getLogicalStyle(x).copyAttributes());
StyleConstants.setBackground(set, txtLog.getSelectionColor());
StyleConstants.setForeground(set, txtLog.getSelectedTextColor());
d.setCharacterAttributes(x, len, set, true);
set = new SimpleAttributeSet(d.getLogicalStyle(lastX).copyAttributes());
StyleConstants.setBackground(set, txtLog.getBackground());
StyleConstants.setForeground(set, txtLog.getForeground());
d.setCharacterAttributes(lastX, lastLen, set, true);
txtLog.select(x, pos);
lastX = x;
lastLen = len;
} catch (BadLocationException e) {
}
}//GEN-LAST:event_txtSearchActionPerformed
String s = "";
int pos = 0, lastX = 0, lastLen = 0;
void terminateGames() {
ProcessMonitor.stopAll();
}
int removedLength = 0;
Deque<Integer> offsets = new LinkedList<>();
int fatals = 0, errors = 0, warns = 0, infos = 0, debugs = 0;
public void log(final String status, final Level c) {
if (!isVisible())
return;
SwingUtilities.invokeLater(() -> {
Document d = txtLog.getStyledDocument();
try { // prevent too much memory used.
if (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory() > 1l * 1024 * 1024 * 256) {
d.remove(0, d.getLength());
offsets.clear();
removedLength = 0;
}
} catch (Exception ex) {
HMCLog.err("Failed to clear the text component", ex);
}
String newStatus = status.replace("\t", " ");
SimpleAttributeSet sas = new SimpleAttributeSet();
StyleConstants.setForeground(sas, c.COLOR);
try {
offsets.add(d.getLength() + removedLength);
d.insertString(d.getLength(), newStatus, sas);
} catch (Exception ex) {
HMCLog.err("Failed to insert \"" + newStatus + "\" to " + d.getLength(), ex);
}
switch (c) {
case FATAL:
btnFatal.setText(++fatals + " fatals");
break;
case ERROR:
btnError.setText(++errors + " errors");
break;
case WARN:
btnWarn.setText(++warns + " warns");
break;
case INFO:
btnInfo.setText(++infos + " infos");
break;
case DEBUG:
btnDebug.setText(++debugs + " debugs");
break;
}
int maxLines = Integer.parseInt(cboShowLines.getSelectedItem().toString());
while (offsets.size() > maxLines) {
int start = offsets.pollFirst();
int end = offsets.peekFirst();
try {
d.remove(start - removedLength, end - start); // start - removedLength must become 0
removedLength = end;
} catch (Exception ignore) {
}
}
});
}
public void setExit(NonFunction<Boolean> exit) {
this.listener = exit;
}
public void clean() {
txtLog.setText("");
}
@Override
public void setVisible(boolean b) {
txtLog.setFont(Settings.getInstance().getConsoleFont());
lblCrash.setVisible(false);
btnContact.setVisible(false);
super.setVisible(b);
}
public void showAsCrashWindow(boolean out_date) {
txtLog.setFont(Settings.getInstance().getConsoleFont());
if (out_date) {
lblCrash.setVisible(false);
btnContact.setVisible(false);
lblCrash.setText(C.i18n("ui.label.crashing_out_dated"));
} else {
lblCrash.setVisible(true);
btnContact.setVisible(true);
lblCrash.setText(C.i18n("ui.label.crashing"));
}
super.setVisible(true);
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnClear;
private javax.swing.JButton btnClose;
private javax.swing.JButton btnContact;
private javax.swing.JButton btnCopy;
private javax.swing.JToggleButton btnDebug;
private javax.swing.JButton btnError;
private javax.swing.JButton btnFatal;
private javax.swing.JToggleButton btnInfo;
private javax.swing.JButton btnTerminateGame;
private javax.swing.JToggleButton btnWarn;
private javax.swing.JComboBox<String> cboShowLines;
private javax.swing.JLabel lblCrash;
private javax.swing.JLabel lblSearch;
private javax.swing.JLabel lblShowLines;
private javax.swing.JScrollPane pnlLog;
private javax.swing.JTextPane txtLog;
private javax.swing.JTextField txtSearch;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,83 @@
/*
* 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.hmcl.ui;
import java.io.OutputStream;
import java.util.Objects;
import javax.swing.SwingUtilities;
import org.jackhuang.hmcl.util.log.Level;
/**
*
* @author huangyuhui
*/
public class LogWindowOutputStream extends OutputStream {
private final LogWindow txt;
private final Level sas;
public LogWindowOutputStream(LogWindow logWindow, Level l) {
txt = Objects.requireNonNull(logWindow);
sas = Objects.requireNonNull(l);
}
@Override
public final void write(byte[] arr) {
write(arr, 0, arr.length);
}
@Override
public final void write(byte[] arr, int off, int len) {
append(new String(arr, off, len));
}
final Object obj = new Object();
Level lastLevel = null;
private void append(final String str) {
synchronized(this) {
if (manual) return;
}
SwingUtilities.invokeLater(() -> {
Level level = Level.guessLevel(str);
if (level == null) level = lastLevel;
else lastLevel = level;
txt.log(str, Level.mergeLevel(sas, level));
});
}
@Override
public final void write(int i) {
append(new String(new byte[] { (byte) i }));
}
boolean manual = false;
public void log(String s, Level l) {
synchronized(this) {
manual = true;
System.out.print(s);
manual = false;
}
if (l == null) append(s);
else
SwingUtilities.invokeLater(() -> {
txt.log(s, l);
});
}
}
+504
View File
@@ -0,0 +1,504 @@
/*
* 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.hmcl.ui;
import org.jackhuang.hmcl.util.ui.GaussionPanel;
import org.jackhuang.hmcl.util.ui.IRepaint;
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.Rectangle;
import java.awt.Transparency;
import java.awt.Window;
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.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.Main;
import org.jackhuang.hmcl.api.PluginManager;
import org.jackhuang.hmcl.api.event.config.ThemeChangedEvent;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.util.ui.BasicColors;
import org.jackhuang.hmcl.util.ui.DropShadowBorder;
import org.jackhuang.hmcl.util.ui.GraphicsUtils;
import org.jackhuang.hmcl.util.ui.SwingUtils;
import org.jackhuang.hmcl.util.ui.TintablePanel;
import org.jackhuang.hmcl.api.auth.IAuthenticator;
import org.jackhuang.hmcl.api.ui.Theme;
import org.jackhuang.hmcl.api.ui.TopTabPage;
/**
*
* @author huangyuhui
*/
public final class MainFrame extends DraggableFrame implements IRepaint {
public static final MainFrame INSTANCE = new MainFrame();
TintablePanel centralPanel;
JPanel header, infoSwap, realPanel;
CardLayout infoLayout;
JLabel windowTitle;
GaussionPanel backgroundLabel;
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(EXIT_ON_CLOSE);
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);
HMCLApi.EVENT_BUS.channel(ThemeChangedEvent.class).register(x -> reloadColor(x.getValue()));
SwingUtilities.invokeLater(() -> selectTab("main"));
}
private void initComponents() {
setLayout(null);
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)));
PluginManager.fireAddTab(this, this::initializeTab);
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);
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);
realPanel.setBounds(1, 0, 800, 511);
add(realPanel);
reloadColor(Settings.getInstance().getTheme());
}
private transient final ActionListener tabListener = e -> MainFrame.this.selectTab(e.getActionCommand());
private void initializeTab(TopTabPage inst, String cmd, String title) {
HeaderTab tab = new HeaderTab(title);
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<TopTabPage> tabContent = new ArrayList<>();
public void selectTab(String tabName) {
int chosen = -1;
TopTabPage onCreate = null, onSelect = null, lastPage = 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);
onCreate.setId(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()) {
lastPage = tabContent.get(i);
lastPage.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(lastPage);
}
}
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 GaussionPanel();
backgroundLabel.setDrawBackgroundLayer(true);
backgroundLabel.addAeroObject(backgroundLabel);
backgroundLabel.setBounds(0, 0, 800, 480);
centralPanel.add(backgroundLabel, -1);
}
backgroundLabel.setBackgroundImage(background.getImage());
} 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.isOutOfDate() ? 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() {
borderColor = UIManager.getColor("Customized.MainFrame.background");
borderColorDarker = UIManager.getColor("Customized.MainFrame.selected_background");
}
public void reloadColor(Theme t) {
if (isShowedMessage)
return;
for (Map.Entry<String, String> entry : t.settings.entrySet())
if (entry.getValue().startsWith("#"))
UIManager.put(entry.getKey(), GraphicsUtils.getWebColor(entry.getValue()));
initBorderColor();
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) {
int off = enableShadow ? 16 : 0;
int width = this.getWidth();
int height = this.getHeight();
int contentWidth = width - off - off;
int contentHeight = height - off - off;
if (!enableShadow || contentWidth <= 0 || contentHeight <= 0)
paintImpl(g);
else {
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");
windowTitle.addMouseListener(MouseListenerImpl.INSTANCE);
if (!isShowedMessage) {
windowTitle.setText(defaultTitle);
windowTitle.setForeground(Color.red);
}
}
@Override
public JComponent getRepaintComponent() {
return null;
}
@Override
public Window getRepaintWindow() {
return this;
}
@Override
public Collection<Rectangle> getRepaintRects() {
int off = MainFrame.INSTANCE.enableShadow ? 16 : 0, yoff = MainFrame.INSTANCE.getInsets().top + off, xoff = MainFrame.INSTANCE.getInsets().left + off;
int width = 800, height = MainFrame.INSTANCE.header.getHeight() + 480 - 1;
return Arrays.asList(new Rectangle(xoff, yoff, xoff, height + yoff + 1),
new Rectangle(xoff + width + 1, yoff, xoff + width + 1, height + yoff + 1),
new Rectangle(xoff, height + yoff + 1, xoff + width + 1, height + yoff + 1));
}
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();
}
transient LaunchingUIDaemon daemon = new LaunchingUIDaemon();
}
+304
View File
@@ -0,0 +1,304 @@
<?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="pnlRoot">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.jackhuang.hmcl.launcher.ui.GaussionPanel()"/>
</AuxValues>
<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="800" height="480"/>
</Constraint>
</Constraints>
<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>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.jackhuang.hmcl.launcher.ui.RepaintPage()"/>
<AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="MainPagePanel_pnlMore"/>
</AuxValues>
<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="lblProfile" 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" 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="lblLogin" 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="lblProfile" 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="lblLogin" 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="254" 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="lblLogin">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/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/hmcl/lang/I18N.properties" key="login.username" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<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/hmcl/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/hmcl/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/hmcl/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>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new WideComboBox()"/>
</AuxValues>
</Component>
<Container class="javax.swing.JPanel" name="pnlPassword">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignCardLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="pnlLogIn">
<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="lblPassword" 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="lblPassword" 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="lblPassword">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/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="pnlLogOut">
<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/hmcl/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/hmcl/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/hmcl/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>
</Container>
</SubComponents>
</Form>
+553
View File
@@ -0,0 +1,553 @@
/*
* 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.hmcl.ui;
import org.jackhuang.hmcl.util.ui.Page;
import org.jackhuang.hmcl.util.ui.WideComboBox;
import org.jackhuang.hmcl.util.ui.GaussionPanel;
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.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.config.AuthenticatorChangedEvent;
import org.jackhuang.hmcl.api.event.config.ProfileChangedEvent;
import org.jackhuang.hmcl.api.event.config.ProfileLoadingEvent;
import org.jackhuang.hmcl.api.event.launch.LaunchSucceededEvent;
import org.jackhuang.hmcl.api.event.launch.LaunchingState;
import org.jackhuang.hmcl.api.event.launch.LaunchingStateChangedEvent;
import org.jackhuang.hmcl.api.event.version.RefreshedVersionsEvent;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.core.auth.AbstractAuthenticator;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.core.version.MinecraftVersion;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.core.mod.ModpackManager;
import org.jackhuang.hmcl.ui.modpack.ModpackWizard;
import org.jackhuang.hmcl.laf.button.CustomButton;
import org.jackhuang.hmcl.api.func.Consumer;
import org.jackhuang.hmcl.util.sys.FileUtils;
import org.jackhuang.hmcl.util.task.TaskWindow;
import org.jackhuang.hmcl.util.ui.GraphicsUtils;
import org.jackhuang.hmcl.util.ui.JSystemFileChooser;
import org.jackhuang.hmcl.util.ui.SwingUtils;
import org.jackhuang.hmcl.util.ui.wizard.api.WizardDisplayer;
import org.jackhuang.hmcl.api.auth.IAuthenticator;
import org.jackhuang.hmcl.laf.button.CustomButtonUI;
import org.jackhuang.hmcl.util.ui.MessageBox;
/**
*
* @author huangyuhui
*/
public class MainPagePanel extends Page {
public MainPagePanel() {
}
void initGui() {
initComponents();
animationEnabled = Settings.getInstance().isEnableAnimation();
pnlButtons = new javax.swing.JPanel();
pnlButtons.setLayout(null);
int w = 150, h = 50;
btnRun = new CustomButton();
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()));
btnRun.setUI(new CustomButtonUI());
pnlRoot.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);
if (Settings.getInstance().isEnableBlur())
((GaussionPanel) pnlRoot).addAeroObject(pnlMore);
((GaussionPanel) pnlRoot).setBackgroundImage(MainFrame.INSTANCE.background.getImage());
((RepaintPage) pnlMore).setRepainter(pnlRoot);
HMCLApi.EVENT_BUS.channel(AuthenticatorChangedEvent.class).register(onAuthChanged);
HMCLApi.EVENT_BUS.channel(ProfileLoadingEvent.class).register(onLoadingProfiles);
HMCLApi.EVENT_BUS.channel(ProfileChangedEvent.class).register(onSelectedProfilesChanged);
HMCLApi.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(onRefreshedVersions);
HMCLApi.EVENT_BUS.channel(LaunchingStateChangedEvent.class).register(launchingStateChanged);
HMCLApi.EVENT_BUS.channel(LaunchSucceededEvent.class).register(this::prepareAuths);
prepareAuths();
}
/**
* 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() {
pnlRoot = new GaussionPanel();
pnlMore = new org.jackhuang.hmcl.ui.RepaintPage();
txtPlayerName = new javax.swing.JTextField();
lblLogin = new javax.swing.JLabel();
cboLoginMode = new javax.swing.JComboBox();
lblUserName = new javax.swing.JLabel();
lblProfile = new javax.swing.JLabel();
cboProfiles = new javax.swing.JComboBox();
lblVersion = new javax.swing.JLabel();
cboVersions = new WideComboBox();
pnlPassword = new javax.swing.JPanel();
pnlLogIn = new javax.swing.JPanel();
lblPassword = new javax.swing.JLabel();
txtPassword = new javax.swing.JPasswordField();
pnlLogOut = new javax.swing.JPanel();
btnLogout = new javax.swing.JButton();
btnImportModpack = new javax.swing.JButton();
btnExportModpack = new javax.swing.JButton();
setLayout(null);
pnlRoot.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);
}
});
lblLogin.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
lblProfile.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());
lblPassword.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 pnlLogInLayout = new javax.swing.GroupLayout(pnlLogIn);
pnlLogIn.setLayout(pnlLogInLayout);
pnlLogInLayout.setHorizontalGroup(
pnlLogInLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnlLogInLayout.createSequentialGroup()
.addComponent(lblPassword)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtPassword))
);
pnlLogInLayout.setVerticalGroup(
pnlLogInLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnlLogInLayout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addGroup(pnlLogInLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblPassword, 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(pnlLogIn, "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 pnlLogOutLayout = new javax.swing.GroupLayout(pnlLogOut);
pnlLogOut.setLayout(pnlLogOutLayout);
pnlLogOutLayout.setHorizontalGroup(
pnlLogOutLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnLogout, javax.swing.GroupLayout.DEFAULT_SIZE, 170, Short.MAX_VALUE)
);
pnlLogOutLayout.setVerticalGroup(
pnlLogOutLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnLogout, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
pnlPassword.add(pnlLogOut, "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(lblProfile, 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, javax.swing.GroupLayout.DEFAULT_SIZE, 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(lblLogin))
.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(lblProfile)
.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(lblLogin)
.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, 254, Short.MAX_VALUE)
.addComponent(btnImportModpack)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnExportModpack)
.addContainerGap())
);
pnlRoot.add(pnlMore);
pnlMore.setBounds(0, 0, 190, 480);
add(pnlRoot);
pnlRoot.setBounds(0, 0, 800, 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().setSelectedVersion(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
JSystemFileChooser fc = new JSystemFileChooser();
fc.setFileSelectionMode(JSystemFileChooser.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 = MessageBox.showInputDialog(C.i18n("modpack.enter_name"), FileUtils.getBaseName(fc.getSelectedFile().getName()));
if (StrUtils.isBlank(suggestedModpackId))
return;
TaskWindow.factory().append(ModpackManager.install(MainFrame.INSTANCE, fc.getSelectedFile(), Settings.getLastProfile().service(), suggestedModpackId)).execute();
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 : AbstractAuthenticator.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 CustomButton 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 lblLogin;
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblProfile;
private javax.swing.JLabel lblUserName;
private javax.swing.JLabel lblVersion;
private javax.swing.JPanel pnlLogIn;
private javax.swing.JPanel pnlLogOut;
private javax.swing.JPanel pnlMore;
private javax.swing.JPanel pnlPassword;
private javax.swing.JPanel pnlRoot;
private javax.swing.JPasswordField txtPassword;
private javax.swing.JTextField txtPlayerName;
// End of variables declaration//GEN-END:variables
final Consumer<AuthenticatorChangedEvent> onAuthChanged = (x) -> {
if (x.getValue().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 (x.getValue().isLoggedIn())
cl.last(pnlPassword);
else
cl.first(pnlPassword);
String username = x.getValue().getUserName();
if (username == null)
username = "";
txtPlayerName.setText(username);
};
final Runnable onLoadingProfiles = () -> {
isLoading = true;
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
for (Profile s : Settings.getProfilesFiltered())
model.addElement(s.getName());
cboProfiles.setModel(model);
isLoading = false;
};
final Consumer<RefreshedVersionsEvent> onRefreshedVersions = t -> {
if (Settings.getLastProfile().service().version() == t.getSource())
loadVersions();
};
boolean showedNoVersion = false;
void loadVersions() {
isLoading = true;
cboVersions.removeAllItems();
String selVersion = Settings.getLastProfile().getSelectedVersion();
if (!Settings.getLastProfile().service().version().getVersions().isEmpty()) {
for (MinecraftVersion mcVersion : Settings.getLastProfile().service().version().getVersions()) {
if (mcVersion.hidden)
continue;
cboVersions.addItem(mcVersion.id);
}
versionChanged(selVersion);
}
isLoading = false;
}
final Consumer<LaunchingStateChangedEvent> launchingStateChanged = t -> SwingUtilities.invokeLater(() -> SwingUtils.setEnabled(MainFrame.INSTANCE.getRootPane(), t.getValue() == LaunchingState.Done));
void versionChanged(String selectedVersion) {
isLoading = true;
DefaultComboBoxModel<String> model = (DefaultComboBoxModel<String>) cboVersions.getModel();
for (int i = 0; i < model.getSize(); ++i)
if (model.getElementAt(i).equals(selectedVersion)) {
model.setSelectedItem(selectedVersion);
break;
}
isLoading = false;
}
final Consumer<ProfileChangedEvent> onSelectedProfilesChanged = event -> {
Profile t = event.getValue();
t.propertyChanged.register(e -> {
if ("selectedVersion".equals(e.getPropertyName()))
versionChanged(e.getNewValue());
});
isLoading = true;
DefaultComboBoxModel<String> model = (DefaultComboBoxModel<String>) 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,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<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/hmcl/lang/I18N.properties" key="ui.newProfileWindow.title" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
@@ -26,23 +29,18 @@
<Group type="102" attributes="0">
<EmptySpace 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="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtServerName" max="32767" attributes="0"/>
<Component id="txtAddress" max="32767" attributes="0"/>
</Group>
<Component id="txtNewProfileName" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="chkIsHide" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<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="62" max="32767" 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"/>
@@ -58,19 +56,17 @@
<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="txtServerName" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtNewProfileName" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<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="txtAddress" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboProfiles" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="chkIsHide" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnOK" alignment="3" min="-2" max="-2" 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>
@@ -80,44 +76,49 @@
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" value="&#x670d;&#x52a1;&#x5668;&#x540d;"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/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="txtServerName">
<Component class="javax.swing.JTextField" name="txtNewProfileName">
<Events>
<EventHandler event="propertyChange" listener="java.beans.PropertyChangeListener" parameters="java.beans.PropertyChangeEvent" handler="txtServerNamePropertyChange"/>
<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" value="&#x5730;&#x5740;"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/lang/I18N.properties" key="ui.label.newProfileWindow.copy_from" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtAddress">
<Events>
<EventHandler event="propertyChange" listener="java.beans.PropertyChangeListener" parameters="java.beans.PropertyChangeEvent" handler="txtAddressPropertyChange"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="chkIsHide">
<Component class="javax.swing.JComboBox" name="cboProfiles">
<Properties>
<Property name="text" type="java.lang.String" value="&#x9690;&#x85cf;&#x5730;&#x5740;"/>
<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/hmcl/lang/I18N.properties" key="button.cancel" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="propertyChange" listener="java.beans.PropertyChangeListener" parameters="java.beans.PropertyChangeEvent" handler="chkIsHidePropertyChange"/>
<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" value="&#x786e;&#x5b9a;"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/jackhuang/hmcl/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>
<Component class="javax.swing.JButton" name="btnCancel">
<Properties>
<Property name="text" type="java.lang.String" value="&#x53d6;&#x6d88;"/>
</Properties>
</Component>
</SubComponents>
</Form>
@@ -0,0 +1,164 @@
/*
* 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.hmcl.ui;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.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
}
+59
View File
@@ -0,0 +1,59 @@
/*
* 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.hmcl.ui;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jackhuang.hmcl.api.ui.TopTabPage;
/**
*
* @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 (getComponent(i) instanceof TopTabPage) {
TopTabPage comp = (TopTabPage) getComponent(i);
comp.setId(i);
if (getSelectedIndex() != i)
((TopTabPage) getComponent(i)).onLeave();
}
if (getSelectedComponent() instanceof TopTabPage) {
if (page == null && getComponentCount() > 0 && getComponent(0) instanceof TopTabPage)
page = (TopTabPage) getComponent(0);
((TopTabPage) getSelectedComponent()).onSelect(page);
page = (TopTabPage) getSelectedComponent();
}
}
TopTabPage page = null;
}
@@ -0,0 +1,58 @@
/*
* 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.hmcl.ui;
import org.jackhuang.hmcl.util.ui.Page;
import org.jackhuang.hmcl.util.ui.IRepaint;
import java.awt.Rectangle;
import java.awt.Window;
import java.util.Arrays;
import java.util.Collection;
import javax.swing.JComponent;
/**
*
* @author huang
*/
public class RepaintPage extends Page implements IRepaint {
public RepaintPage() {
super();
}
JComponent repainter;
@Override
public JComponent getRepaintComponent() {
return repainter;
}
public void setRepainter(JComponent repainter) {
this.repainter = repainter;
}
@Override
public Collection<Rectangle> getRepaintRects() {
return Arrays.asList(this.getBounds());
}
@Override
public Window getRepaintWindow() {
return null;
}
}
@@ -0,0 +1,75 @@
<?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">
<Component id="jScrollPane1" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="jButton1" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="lblTitle" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="lblTitle" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="250" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jButton1" 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.JTextPane" name="txtDescription">
<Events>
<EventHandler event="caretUpdate" listener="javax.swing.event.CaretListener" parameters="javax.swing.event.CaretEvent" handler="txtDescriptionCaretUpdate"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="jButton1">
<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.preview" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblTitle">
<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.desc" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>
@@ -0,0 +1,129 @@
/*
* 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.hmcl.ui.modpack;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.io.IOException;
import java.util.Map;
import javax.swing.JOptionPane;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.util.net.WebPage;
import org.jackhuang.hmcl.util.ui.wizard.spi.WizardController;
import org.markdown4j.Markdown4jProcessor;
/**
*
* @author huangyuhui
*/
public class ModpackDescriptionPanel extends javax.swing.JPanel {
public static final String KEY_MODPACK_DESCRITION = "modpackDescription";
private final transient WizardController controller;
private final Map wizardData;
/**
* Creates new form ModpackDescriptionPanel
*/
public ModpackDescriptionPanel(WizardController controller, Map wizardData) {
initComponents();
this.controller = controller;
this.wizardData = wizardData;
}
/**
* 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() {
jScrollPane1 = new javax.swing.JScrollPane();
txtDescription = new javax.swing.JTextPane();
jButton1 = new javax.swing.JButton();
lblTitle = new javax.swing.JLabel();
txtDescription.addCaretListener(new javax.swing.event.CaretListener() {
public void caretUpdate(javax.swing.event.CaretEvent evt) {
txtDescriptionCaretUpdate(evt);
}
});
jScrollPane1.setViewportView(txtDescription);
jButton1.setText(C.i18n("ui.button.preview")); // NOI18N
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
lblTitle.setText(C.i18n("modpack.desc")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(jButton1))
.addGroup(layout.createSequentialGroup()
.addComponent(lblTitle)
.addGap(0, 0, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(lblTitle)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jButton1))
);
}// </editor-fold>//GEN-END:initComponents
private void txtDescriptionCaretUpdate(javax.swing.event.CaretEvent evt) {//GEN-FIRST:event_txtDescriptionCaretUpdate
wizardData.put(KEY_MODPACK_DESCRITION, txtDescription.getText());
}//GEN-LAST:event_txtDescriptionCaretUpdate
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
try {
Object msgs[] = new Object[2];
msgs[0] = C.i18n("ui.button.preview");
msgs[1] = new WebPage(new Markdown4jProcessor().process(txtDescription.getText()));
((WebPage) msgs[1]).setPreferredSize(new Dimension(800, 350));
JOptionPane.showOptionDialog(null, msgs, (String) msgs[0], JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
} catch (HeadlessException | IOException e) {
MessageBox.show(StrUtils.getStackTrace(e), C.i18n("message.error"), MessageBox.WARNING_MESSAGE);
}
}//GEN-LAST:event_jButton1ActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton jButton1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel lblTitle;
private javax.swing.JTextPane txtDescription;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,41 @@
<?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">
<Component id="jScrollPane1" alignment="0" pref="400" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="1" pref="300" max="32767" attributes="0"/>
</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.JTree" name="jTree1">
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,141 @@
/*
* 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.hmcl.ui.modpack;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.tree.DefaultTreeModel;
import org.jackhuang.hmcl.core.mod.ModAdviser;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.sys.FileUtils;
import org.jackhuang.hmcl.util.ui.checktree.CheckBoxTreeCellRenderer;
import org.jackhuang.hmcl.util.ui.checktree.CheckBoxTreeNode;
import org.jackhuang.hmcl.util.ui.checktree.CheckBoxTreeNodeSelectionListener;
import org.jackhuang.hmcl.util.ui.wizard.spi.WizardController;
/**
*
* @author huangyuhui
*/
public class ModpackFileSelectionPanel extends javax.swing.JPanel {
private transient final WizardController controller;
private final Map wizardData;
private transient final ModAdviser blackList;
private final Set<String> bannedFiles = new HashSet<>();
/**
* Creates new form ModpackFileSelectionPanel
*
* @param blackList Return 0: non blocked, 1: non shown, 2: suggested,
* checked
*/
public ModpackFileSelectionPanel(WizardController controller, Map wizardData, File gameDir, ModAdviser blackList) {
initComponents();
this.controller = controller;
this.wizardData = wizardData;
this.blackList = blackList;
CheckBoxTreeNode root = create(gameDir, "minecraft");
jTree1.setModel(new DefaultTreeModel(root));
jTree1.setCellRenderer(new CheckBoxTreeCellRenderer());
jTree1.addMouseListener(new CheckBoxTreeNodeSelectionListener());
wizardData.put("blackList", root);
}
private static final HashMap<String, String> TRANSLATION = new HashMap<String, String>() {
{
put("minecraft/servers.dat", C.i18n("modpack.files.servers_dat"));
put("minecraft/saves", C.i18n("modpack.files.saves"));
put("minecraft/mods", C.i18n("modpack.files.mods"));
put("minecraft/config", C.i18n("modpack.files.config"));
put("minecraft/liteconfig", C.i18n("modpack.files.liteconfig"));
put("minecraft/resourcepacks", C.i18n("modpack.files.resourcepacks"));
put("minecraft/options.txt", C.i18n("modpack.files.options_txt"));
put("minecraft/optionsshaders.txt", C.i18n("modpack.files.optionsshaders_txt"));
put("minecraft/mods/VoxelMods", C.i18n("modpack.files.mods.voxelmods"));
put("minecraft/dumps", C.i18n("modpack.files.dumps"));
put("minecraft/blueprints", C.i18n("modpack.files.blueprints"));
put("minecraft/scripts", C.i18n("modpack.files.scripts"));
}
};
CheckBoxTreeNode create(File file, String basePath) {
ModAdviser.ModSuggestion state = ModAdviser.ModSuggestion.NORMAL;
if (basePath.length() > "minecraft/".length())
if ((state = blackList.advise(basePath.substring("minecraft/".length()) + (file.isDirectory() ? "/" : ""), file.isDirectory())) == ModAdviser.ModSuggestion.HIDDEN)
return null;
CheckBoxTreeNode node = new CheckBoxTreeNode(TRANSLATION.containsKey(basePath) ? new Pair<>(FileUtils.getName(basePath), TRANSLATION.get(basePath)) : FileUtils.getName(basePath));
if (state == ModAdviser.ModSuggestion.SUGGESTED)
node.setSelected(true);
if (file.isDirectory()) {
File[] f = file.listFiles();
for (File subFile : f) {
CheckBoxTreeNode subNode = create(subFile, basePath + "/" + subFile.getName());
if (subNode != null) {
subNode.setSelected(subNode.isSelected() | node.isSelected());
node.add(subNode);
}
}
if (!node.children().hasMoreElements())
return null;
}
return node;
}
/**
* 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() {
jScrollPane1 = new javax.swing.JScrollPane();
jTree1 = new javax.swing.JTree();
jScrollPane1.setViewportView(jTree1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTree jTree1;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,145 @@
<?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">
<Component id="txtModpackName" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="lblModpackLocation" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="353" max="32767" attributes="0"/>
<Component id="cboModpackLocation" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="txtModpackLocation" max="32767" attributes="0"/>
<Component id="cboGameVersion" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblGameVersion" min="-2" max="-2" attributes="0"/>
<Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="chkIncludeLauncher" 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"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="19" max="32767" attributes="0"/>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtModpackName" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblModpackLocation" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cboModpackLocation" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtModpackLocation" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="lblGameVersion" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cboGameVersion" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="chkIncludeLauncher" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lblModpackLocation">
<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.wizard.step.initialization.save" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtModpackLocation">
<Events>
<EventHandler event="caretUpdate" listener="javax.swing.event.CaretListener" parameters="javax.swing.event.CaretEvent" handler="txtModpackLocationCaretUpdate"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="cboModpackLocation">
<Properties>
<Property name="text" type="java.lang.String" value="..."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cboModpackLocationActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblGameVersion">
<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.wizard.step.initialization.exported_version" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cboGameVersion">
<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="cboGameVersionItemStateChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<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="modpack.wizard.step.initialization.warning" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</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="modpack.name" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtModpackName">
<Properties>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="caretUpdate" listener="javax.swing.event.CaretListener" parameters="javax.swing.event.CaretEvent" handler="txtModpackNameCaretUpdate"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="chkIncludeLauncher">
<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.wizard.step.initialization.include_launcher" replaceFormat="C.i18n(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkIncludeLauncherItemStateChanged"/>
</Events>
</Component>
</SubComponents>
</Form>
@@ -0,0 +1,230 @@
/*
* 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.hmcl.ui.modpack;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Pattern;
import javax.swing.DefaultComboBoxModel;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.ui.JSystemFileChooser;
import org.jackhuang.hmcl.util.ui.wizard.spi.WizardController;
/**
*
* @author huangyuhui
*/
public class ModpackInitializationPanel extends javax.swing.JPanel {
public static final String KEY_GAME_VERSION = "gameVersion";
public static final String KEY_MODPACK_LOCATION = "modpackLocation";
public static final String KEY_MODPACK_NAME = "modpackName";
public static final String KEY_INCLUDING_LAUNCHER = "launcher";
private final transient WizardController controller;
private final Map<String, Object> wizardData;
/**
* Creates new form ModpackInitializationPanel
*/
public ModpackInitializationPanel(WizardController controller, Map<String, Object> wizardData, Vector<String> versions, String selVersion) {
initComponents();
this.controller = controller;
this.wizardData = wizardData;
wizardData.put(KEY_GAME_VERSION, versions);
wizardData.put("selVersion", selVersion);
wizardData.put(KEY_INCLUDING_LAUNCHER, false);
configureComboContents();
checkProblem();
}
private void configureComboContents() {
Vector<String> versions = (Vector<String>) wizardData.get(KEY_GAME_VERSION);
cboGameVersion.setModel(new DefaultComboBoxModel<>(versions));
wizardData.put(KEY_GAME_VERSION, wizardData.get("selVersion"));
}
/**
* 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() {
lblModpackLocation = new javax.swing.JLabel();
txtModpackLocation = new javax.swing.JTextField();
cboModpackLocation = new javax.swing.JButton();
lblGameVersion = new javax.swing.JLabel();
cboGameVersion = new javax.swing.JComboBox<>();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
txtModpackName = new javax.swing.JTextField();
chkIncludeLauncher = new javax.swing.JCheckBox();
lblModpackLocation.setText(C.i18n("modpack.wizard.step.initialization.save")); // NOI18N
txtModpackLocation.addCaretListener(new javax.swing.event.CaretListener() {
public void caretUpdate(javax.swing.event.CaretEvent evt) {
txtModpackLocationCaretUpdate(evt);
}
});
cboModpackLocation.setText("...");
cboModpackLocation.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cboModpackLocationActionPerformed(evt);
}
});
lblGameVersion.setText(C.i18n("modpack.wizard.step.initialization.exported_version")); // NOI18N
cboGameVersion.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboGameVersionItemStateChanged(evt);
}
});
jLabel1.setText(C.i18n("modpack.wizard.step.initialization.warning")); // NOI18N
jLabel2.setText(C.i18n("modpack.name")); // NOI18N
txtModpackName.setToolTipText("");
txtModpackName.addCaretListener(new javax.swing.event.CaretListener() {
public void caretUpdate(javax.swing.event.CaretEvent evt) {
txtModpackNameCaretUpdate(evt);
}
});
chkIncludeLauncher.setText(C.i18n("modpack.wizard.step.initialization.include_launcher")); // NOI18N
chkIncludeLauncher.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkIncludeLauncherItemStateChanged(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()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtModpackName)
.addGroup(layout.createSequentialGroup()
.addComponent(lblModpackLocation)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 353, Short.MAX_VALUE)
.addComponent(cboModpackLocation))
.addComponent(txtModpackLocation)
.addComponent(cboGameVersion, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblGameVersion)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel2)
.addComponent(chkIncludeLauncher))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 19, Short.MAX_VALUE)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtModpackName, 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(lblModpackLocation)
.addComponent(cboModpackLocation))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtModpackLocation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblGameVersion)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cboGameVersion, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkIncludeLauncher)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void cboModpackLocationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cboModpackLocationActionPerformed
JSystemFileChooser fc = new JSystemFileChooser();
fc.setFileSelectionMode(JSystemFileChooser.FILES_ONLY);
fc.setDialogTitle(C.i18n("modpack.wizard.step.initialization.save"));
fc.setMultiSelectionEnabled(false);
fc.setFileFilter(new FileNameExtensionFilter(C.i18n("modpack") + "(*.zip)", "zip"));
fc.showSaveDialog(this);
if (fc.getSelectedFile() != null) {
String path = fc.getSelectedFile().getAbsolutePath();
if (!path.endsWith(".zip"))
path += ".zip";
txtModpackLocation.setText(path);
}
}//GEN-LAST:event_cboModpackLocationActionPerformed
private void txtModpackLocationCaretUpdate(javax.swing.event.CaretEvent evt) {//GEN-FIRST:event_txtModpackLocationCaretUpdate
wizardData.put(KEY_MODPACK_LOCATION, txtModpackLocation.getText());
checkProblem();
}//GEN-LAST:event_txtModpackLocationCaretUpdate
private void cboGameVersionItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cboGameVersionItemStateChanged
wizardData.put(KEY_GAME_VERSION, cboGameVersion.getSelectedItem());
}//GEN-LAST:event_cboGameVersionItemStateChanged
private void txtModpackNameCaretUpdate(javax.swing.event.CaretEvent evt) {//GEN-FIRST:event_txtModpackNameCaretUpdate
wizardData.put(KEY_MODPACK_NAME, txtModpackName.getText());
checkProblem();
}//GEN-LAST:event_txtModpackNameCaretUpdate
private void chkIncludeLauncherItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkIncludeLauncherItemStateChanged
wizardData.put(KEY_INCLUDING_LAUNCHER, chkIncludeLauncher.isSelected());
}//GEN-LAST:event_chkIncludeLauncherItemStateChanged
static final Pattern PATTERN = Pattern.compile("[-a-zA-Z0-9_\\.\\(\\)\\[\\]\\{\\}\\<\\>\"\'\u4E00-\u9FA5]+$");
void checkProblem() {
controller.setProblem(null);
if (txtModpackLocation.getText().trim().isEmpty())
controller.setProblem(C.i18n("modpack.not_a_valid_location"));
if (!PATTERN.matcher(txtModpackName.getText()).matches())
controller.setProblem(C.i18n("modpack.not_a_valid_name"));
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox<String> cboGameVersion;
private javax.swing.JButton cboModpackLocation;
private javax.swing.JCheckBox chkIncludeLauncher;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel lblGameVersion;
private javax.swing.JLabel lblModpackLocation;
private javax.swing.JTextField txtModpackLocation;
private javax.swing.JTextField txtModpackName;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,193 @@
/*
* 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.hmcl.ui.modpack;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.swing.JComponent;
import org.jackhuang.hmcl.core.GameException;
import org.jackhuang.hmcl.core.mod.ModpackManager;
import org.jackhuang.hmcl.core.version.MinecraftVersion;
import org.jackhuang.hmcl.setting.Config;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.util.HMCLMinecraftService;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.util.Utils;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.util.sys.IOUtils;
import org.jackhuang.hmcl.util.sys.ZipEngine;
import org.jackhuang.hmcl.util.net.WebPage;
import org.jackhuang.hmcl.util.ui.checktree.CheckBoxTreeNode;
import org.jackhuang.hmcl.util.ui.wizard.spi.DeferredWizardResult;
import org.jackhuang.hmcl.util.ui.wizard.spi.ResultProgressHandle;
import org.jackhuang.hmcl.util.ui.wizard.spi.Summary;
import org.jackhuang.hmcl.util.ui.wizard.spi.WizardBranchController;
import org.jackhuang.hmcl.util.ui.wizard.spi.WizardController;
import org.jackhuang.hmcl.util.ui.wizard.spi.WizardException;
import org.jackhuang.hmcl.util.ui.wizard.spi.WizardPanelProvider;
/**
*
* @author huangyuhui
*/
public class ModpackWizard extends WizardBranchController {
static void process(CheckBoxTreeNode node, String basePath, List<String> list) {
if (node == null)
return;
if (node.isSelected()) {
if (basePath.length() > "minecraft/".length())
list.add(basePath.substring("minecraft/".length()));
return;
}
Enumeration<CheckBoxTreeNode> e = node.children();
for (; e.hasMoreElements();) {
CheckBoxTreeNode n = e.nextElement();
String s;
if (n.getUserObject() instanceof Pair)
s = ((Pair<String, String>) n.getUserObject()).key;
else
s = n.getUserObject().toString();
process(n, basePath + "/" + s, list);
}
}
public ModpackWizard(Profile profile) {
super(new WizardPanelProvider(C.i18n("modpack.wizard"), new String[] { C.i18n("modpack.wizard.step.1"), C.i18n("modpack.wizard.step.2"), C.i18n("modpack.wizard.step.3") }, new String[] { C.i18n("modpack.wizard.step.1.title"), C.i18n("modpack.wizard.step.2.title"), C.i18n("modpack.wizard.step.3.title") }) {
@Override
protected Object finish(Map settings) throws WizardException {
return new DeferredWizardResult(false) {
@Override
public void start(Map settings, ResultProgressHandle progress) {
progress.setBusy("Processing modpack");
ArrayList<String> blackList = new ArrayList<>(ModpackManager.MODPACK_BLACK_LIST);
CheckBoxTreeNode root = (CheckBoxTreeNode) settings.get("blackList");
process(root, "minecraft", blackList);
HashMap map = new HashMap();
map.put("name", (String) settings.get(ModpackInitializationPanel.KEY_MODPACK_NAME));
if (settings.containsKey(ModpackDescriptionPanel.KEY_MODPACK_DESCRITION))
try {
map.put("description", new org.markdown4j.Markdown4jProcessor().process((String) settings.get(ModpackDescriptionPanel.KEY_MODPACK_DESCRITION)));
} catch (IOException ex) {
progress.failed(C.i18n("modpack.export_error") + ": " + StrUtils.getStackTrace(ex), true);
}
try {
String gameVersion = (String) settings.get(ModpackInitializationPanel.KEY_GAME_VERSION);
String strLocation = (String) settings.get(ModpackInitializationPanel.KEY_MODPACK_LOCATION);
if (!strLocation.endsWith(".zip"))
strLocation += ".zip";
File loc = new File(strLocation);
File modpack = loc;
if ((Boolean) settings.get(ModpackInitializationPanel.KEY_INCLUDING_LAUNCHER))
modpack = new File(loc.getAbsolutePath() + ".temp");
ModpackManager.export(modpack, profile.service().version(), gameVersion, blackList, map,
t -> t.putTextFile(C.GSON.toJson(((HMCLMinecraftService) profile.service()).getVersionSetting(gameVersion)), "minecraft/hmclversion.cfg"));
String summary = "<html>" + C.i18n("modpack.export_finished") + ": " + loc.getAbsolutePath();
boolean including = false;
if ((Boolean) settings.get(ModpackInitializationPanel.KEY_INCLUDING_LAUNCHER)) {
boolean flag = true;
try (ZipEngine engine = new ZipEngine(loc)) {
Config s = new Config();
if (!IOUtils.isAbsolutePath(Settings.getInstance().getBgpath()))
s.setBgpath(Settings.getInstance().getBgpath());
s.setDownloadType(Settings.getInstance().getDownloadType());
engine.putTextFile(C.GSON.toJson(s), "hmcl.json");
engine.putFile(modpack, "modpack.zip");
File bg = new File("bg").getAbsoluteFile();
if (bg.isDirectory())
engine.putDirectory(bg);
bg = new File("background.png").getAbsoluteFile();
if (bg.isFile())
engine.putFile(bg, "background.png");
bg = new File("background.jpg").getAbsoluteFile();
if (bg.isFile())
engine.putFile(bg, "background.jpg");
for (URL u : Utils.getURL())
try {
File f = new File(u.toURI());
if (f.getName().endsWith(".exe") || f.getName().endsWith(".jar"))
engine.putFile(f, f.getName());
} catch (IOException | URISyntaxException e) {
HMCLog.err("Failed to add launcher files.", e);
flag = false;
break;
}
}
if (flag) {
including = true;
if (!modpack.delete())
HMCLog.warn("Failed to delete modpack.zip.temp, maybe the file is in using.");
}
}
summary += "<br/>" + C.i18n(including ? "modpack.included_launcher" : "modpack.not_included_launcher") + "</html>";
progress.finished(new Summary(new WebPage(summary), null));
} catch (IOException | GameException ex) {
HMCLog.err("Failed to export modpack", ex);
progress.failed(C.i18n("modpack.export_error") + ": " + StrUtils.getStackTrace(ex), true);
}
}
};
}
@Override
protected JComponent createPanel(WizardController controller, String id, Map settings) {
switch (indexOfStep(id)) {
case 0:
Vector<String> s = new Vector<>(profile.service().version().getVersionCount());
for (MinecraftVersion v : profile.service().version().getVersions())
if (!v.hidden)
s.add(v.id);
controller.setForwardNavigationMode(WizardController.MODE_CAN_CONTINUE);
return new ModpackInitializationPanel(controller, settings, s, profile.getSelectedVersion());
case 1:
controller.setForwardNavigationMode(WizardController.MODE_CAN_CONTINUE_OR_FINISH);
return new ModpackFileSelectionPanel(controller, settings, profile.service().baseDirectory(), ModpackManager.MODPACK_PREDICATE);
case 2:
controller.setForwardNavigationMode(WizardController.MODE_CAN_FINISH);
return new ModpackDescriptionPanel(controller, settings);
default:
throw new IllegalArgumentException(id);
}
}
});
}
@Override
protected WizardPanelProvider getPanelProviderForStep(String step, Map settings) {
return null;
}
}
@@ -0,0 +1,151 @@
/*
* 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.hmcl.util;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.util.ui.MessageBox;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import org.jackhuang.hmcl.api.HMCLog;
import static org.jackhuang.hmcl.Main.LAUNCHER_VERSION;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.util.net.NetUtils;
import org.jackhuang.hmcl.util.sys.OS;
import org.jackhuang.hmcl.ui.LogWindow;
/**
*
* @author huangyuhui
*/
public class CrashReporter implements Thread.UncaughtExceptionHandler {
private static final Logger LOGGER = Logger.getLogger(CrashReporter.class.getName());
private static final HashMap<String, String> SOURCE = new HashMap<String, String>() {
{
put("MessageBox", "");
put("AWTError", "");
put("JFileChooser", "Has your operating system been installed completely or is a ghost system?");
put("JSystemFileChooser", "Has your operating system been installed completely or is a ghost system?");
put("Jce", "Has your operating system been installed completely or is a ghost system?");
put("couldn't create component peer", "Fucking computer!");
put("sun.awt.shell.Win32ShellFolder2", "crash.user_fault");
put("UnsatisfiedLinkError", "crash.user_fault");
put("java.awt.HeadlessException", "crash.headless");
put("java.lang.NoClassDefFoundError", "crash.NoClassDefFound");
put("java.lang.VerifyError", "crash.NoClassDefFound");
put("java.lang.NoSuchMethodError", "crash.NoClassDefFound");
put("java.lang.IncompatibleClassChangeError", "crash.NoClassDefFound");
put("java.lang.ClassFormatError", "crash.NoClassDefFound");
put("java.lang.OutOfMemoryError", "FUCKING MEMORY LIMIT!");
put("Trampoline", "ui.message.update_java");
put("NoSuchAlgorithmException", "Has your operating system been installed completely or is a ghost system?");
}
};
boolean enableLogger = false;
public CrashReporter(boolean enableLogger) {
this.enableLogger = enableLogger;
}
public boolean checkThrowable(Throwable e) {
String s = StrUtils.getStackTrace(e);
for (HashMap.Entry<String, String> entry : SOURCE.entrySet())
if (s.contains(entry.getKey())) {
if (StrUtils.isNotBlank(entry.getValue())) {
String info = C.i18n(entry.getKey());
LOGGER.severe(info);
try {
showMessage(info);
} catch (Throwable t) {
LOGGER.log(Level.SEVERE, "Failed to show message", t);
}
}
return false;
}
return true;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
String s = StrUtils.getStackTrace(e);
if (!s.contains("org.jackhuang"))
return;
try {
String text = "\n---- Hello Minecraft! Crash Report ----\n";
text += " Version: " + LAUNCHER_VERSION + "\n";
text += " Time: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\n";
text += " Thread: " + t.toString() + "\n";
text += "\n Content: \n ";
text += s + "\n\n";
text += "-- System Details --\n";
text += " Operating System: " + OS.getSystemVersion() + "\n";
text += " Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n";
text += " Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n";
if (enableLogger)
HMCLog.err(text);
else
System.out.println(text);
if (checkThrowable(e) && !System.getProperty("java.vm.name").contains("OpenJDK")) {
SwingUtilities.invokeLater(() -> LogWindow.INSTANCE.showAsCrashWindow(Settings.UPDATE_CHECKER.isOutOfDate()));
if (!Settings.UPDATE_CHECKER.isOutOfDate())
reportToServer(text, s);
}
} catch (Throwable ex) {
LOGGER.log(Level.SEVERE, "Failed to caught exception", ex);
LOGGER.log(Level.SEVERE, "There is the original exception", e);
}
}
void showMessage(String s) {
try {
MessageBox.show(s, "ERROR", MessageBox.ERROR_MESSAGE);
} catch (Throwable e) {
LOGGER.log(Level.SEVERE, "ERROR", e);
}
}
private static final HashSet<String> THROWABLE_SET = new HashSet<>();
void reportToServer(final String text, String stacktrace) {
if (THROWABLE_SET.contains(stacktrace) || stacktrace.contains("Font") || stacktrace.contains("InternalError"))
return;
THROWABLE_SET.add(stacktrace);
Thread t = new Thread(() -> {
HashMap<String, String> map = new HashMap<>();
map.put("CrashReport", text);
try {
NetUtils.post(NetUtils.constantURL("http://huangyuhui.duapp.com/crash.php"), map);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Failed to post HMCL server.", ex);
}
});
t.setDaemon(true);
t.start();
}
}
@@ -0,0 +1,78 @@
/*
* 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.hmcl.util;
import java.util.ArrayList;
import javax.swing.JFrame;
import org.jackhuang.hmcl.api.ui.AddTabCallback;
import org.jackhuang.hmcl.api.IPlugin;
import org.jackhuang.hmcl.core.auth.OfflineAuthenticator;
import org.jackhuang.hmcl.core.auth.YggdrasilAuthenticator;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.ui.GameSettingsPanel;
import org.jackhuang.hmcl.ui.LauncherSettingsPanel;
import org.jackhuang.hmcl.ui.MainPagePanel;
import org.jackhuang.hmcl.api.auth.IAuthenticator;
import org.jackhuang.hmcl.api.func.Consumer;
import org.jackhuang.hmcl.api.ui.Theme;
import org.jackhuang.hmcl.laf.LAFTheme;
/**
*
* @author huangyuhui
*/
public class DefaultPlugin implements IPlugin {
public static DefaultPlugin INSTANCE;
public DefaultPlugin() {
INSTANCE = this;
for (Theme t : LAFTheme.THEMES)
Theme.THEMES.put(t.getId(), t);
}
ArrayList<IAuthenticator> auths = new ArrayList<>();
@Override
public void onRegisterAuthenticators(Consumer<IAuthenticator> apply) {
String clientToken = Settings.getInstance().getClientToken();
auths.add(new OfflineAuthenticator(clientToken));
auths.add(new YggdrasilAuthenticator(clientToken));
try {
Runtime.getRuntime().addShutdownHook(new Thread(this::saveAuthenticatorConfig));
} catch (IllegalStateException ignore) { // Shutdown in progress
}
for (IAuthenticator i : auths) {
i.onLoadSettings(Settings.getInstance().getAuthenticatorConfig(i.id()));
apply.accept(i);
}
}
public void saveAuthenticatorConfig() {
for (IAuthenticator i : auths)
Settings.getInstance().setAuthenticatorConfig(i.id(), i.onSaveSettings());
}
@Override
public void onAddTab(JFrame frame, AddTabCallback callback) {
callback.addTab(new MainPagePanel(), "main", C.i18n("launcher.title.main"));
callback.addTab(new GameSettingsPanel(), "game", C.i18n("launcher.title.game"));
callback.addTab(new LauncherSettingsPanel(), "launcher", C.i18n("launcher.title.launcher"));
}
}
@@ -0,0 +1,45 @@
/*
* 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.hmcl.util;
import java.io.File;
import javax.swing.filechooser.FileFilter;
import org.jackhuang.hmcl.util.sys.FileUtils;
/**
*
* @author huangyuhui
*/
public class FileNameFilter extends FileFilter {
String acceptedName;
public FileNameFilter(String acceptedName) {
this.acceptedName = acceptedName;
}
@Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().equals(acceptedName) && !FileUtils.getExtension(f.getName()).equals("lnk");
}
@Override
public String getDescription() {
return acceptedName;
}
}
@@ -0,0 +1,47 @@
/*
* 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.hmcl.util;
import java.io.File;
import org.jackhuang.hmcl.core.asset.MinecraftAssetService;
import org.jackhuang.hmcl.core.service.IMinecraftService;
import org.jackhuang.hmcl.setting.Settings;
/**
*
* @author huang
*/
public class HMCLAssetService extends MinecraftAssetService {
public HMCLAssetService(IMinecraftService service) {
super(service);
}
private boolean useSelf(String assetId) {
return new File(service.baseDirectory(), "assets/indexes/" + assetId + ".json").exists() || ((HMCLMinecraftService) service).getProfile().isNoCommon();
}
@Override
public File getAssets(String assetId) {
if (useSelf(assetId))
return new File(service.baseDirectory(), "assets");
else
return new File(Settings.getInstance().getCommonpath(), "assets");
}
}
@@ -0,0 +1,112 @@
/*
* 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.hmcl.util;
import org.jackhuang.hmcl.core.GameException;
import org.jackhuang.hmcl.api.auth.AuthenticationException;
import org.jackhuang.hmcl.core.auth.AbstractAuthenticator;
import org.jackhuang.hmcl.api.auth.LoginInfo;
import org.jackhuang.hmcl.core.launch.DefaultGameLauncher;
import org.jackhuang.hmcl.core.launch.GameLauncher;
import org.jackhuang.hmcl.api.game.LaunchOptions;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.launch.LaunchSucceededEvent;
import org.jackhuang.hmcl.api.event.launch.LaunchingState;
import org.jackhuang.hmcl.api.event.launch.LaunchingStateChangedEvent;
import org.jackhuang.hmcl.api.event.launch.ProcessingLaunchOptionsEvent;
import org.jackhuang.hmcl.core.RuntimeGameException;
import org.jackhuang.hmcl.api.func.Consumer;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.api.Wrapper;
import org.jackhuang.hmcl.util.sys.JavaProcess;
import org.jackhuang.hmcl.api.auth.IAuthenticator;
/**
*
* @author huangyuhui
*/
public class HMCLGameLauncher {
Profile profile;
boolean isLaunching = false;
public HMCLGameLauncher(Profile p) {
this.profile = p;
HMCLApi.EVENT_BUS.channel(LaunchSucceededEvent.class).register(() -> setLaunching(false));
}
void setLaunching(boolean isLaunching) {
if (isLaunching != this.isLaunching)
HMCLApi.EVENT_BUS.fireChannel(new LaunchingStateChangedEvent(this, isLaunching ? LaunchingState.Starting : LaunchingState.Done));
this.isLaunching = isLaunching;
}
public void genLaunchCode(final Consumer<GameLauncher> listener, final Consumer<String> failed, String passwordIfNeeded) {
if (isLaunching || profile == null)
return;
setLaunching(true);
HMCLog.log("Start generating launching command...");
if (!profile.getGameDir().exists()) {
failed.accept(C.i18n("minecraft.wrong_path"));
setLaunching(false);
return;
}
if (profile.getSelectedVersion() == null) {
failed.accept(C.i18n("minecraft.no_selected_version"));
setLaunching(false);
return;
}
final IAuthenticator l = AbstractAuthenticator.LOGINS.get(Settings.getInstance().getLoginType());
final LoginInfo li = new LoginInfo(l.getUserName(), l.isLoggedIn() || !l.hasPassword() ? null : passwordIfNeeded);
Thread t = new Thread() {
@Override
public void run() {
Thread.currentThread().setName("Game Launcher");
try {
Wrapper<LaunchOptions> options = new Wrapper<>(profile.getSelectedVersionSetting().createLaunchOptions(profile.getGameDir()));
HMCLApi.EVENT_BUS.fireChannel(new ProcessingLaunchOptionsEvent(this, options));
DefaultGameLauncher gl = new DefaultGameLauncher(options.getValue(), profile.service(), li, l);
GameLauncherTag tag = new GameLauncherTag();
tag.launcherVisibility = profile.getSelectedVersionSetting().getLauncherVisibility();
gl.setTag(tag);
listener.accept(gl);
gl.makeLaunchCommand();
} catch (GameException | RuntimeGameException e) {
failed.accept(C.i18n("launch.failed") + ", " + e.getMessage());
setLaunching(false);
} catch (AuthenticationException e) {
failed.accept(C.i18n("login.failed") + ", " + e.getMessage());
setLaunching(false);
}
}
};
t.setDaemon(true);
t.start();
}
public static class GameLauncherTag {
public LauncherVisibility launcherVisibility;
public JavaProcess process;
public int state; // 0 - unknown; 1 - launch; 2 - make launch script.
}
}
@@ -0,0 +1,58 @@
/*
* 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.hmcl.util;
import java.io.File;
import org.jackhuang.hmcl.api.game.GameDirType;
import org.jackhuang.hmcl.api.game.IMinecraftLibrary;
import org.jackhuang.hmcl.core.version.MinecraftVersion;
import org.jackhuang.hmcl.core.version.MinecraftVersionManager;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.setting.VersionSetting;
/**
*
* @author huangyuhui
*/
public class HMCLGameProvider extends MinecraftVersionManager<HMCLMinecraftService> {
public HMCLGameProvider(HMCLMinecraftService p) {
super(p);
}
@Override
public File getLibraryFile(MinecraftVersion version, IMinecraftLibrary lib) {
VersionSetting vs = service.getProfile().getVersionSetting(version.id);
File self = super.getLibraryFile(version, lib);
if (self == null || self.exists() || (vs != null && service.getProfile().isNoCommon()))
return self;
else
return lib.getFilePath(new File(Settings.getInstance().getCommonpath()));
}
@Override
public File getRunDirectory(String id) {
VersionSetting vs = service.getProfile().getVersionSetting(id);
if (vs == null)
return super.getRunDirectory(id);
else
return vs.getGameDirType() == GameDirType.VERSION_FOLDER
? service.version().versionRoot(id)
: super.getRunDirectory(id);
}
}
@@ -0,0 +1,46 @@
/*
* 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.hmcl.util;
import java.util.List;
import java.util.Map;
import org.jackhuang.hmcl.Main;
import org.jackhuang.hmcl.api.auth.UserProfileProvider;
import org.jackhuang.hmcl.api.game.LaunchOptions;
import org.jackhuang.hmcl.core.GameException;
import org.jackhuang.hmcl.core.launch.MinecraftLoader;
import org.jackhuang.hmcl.core.service.IMinecraftService;
/**
*
* @author huang
*/
public class HMCLMinecraftLoader extends MinecraftLoader {
public HMCLMinecraftLoader(LaunchOptions p, IMinecraftService provider, UserProfileProvider lr) throws GameException {
super(p, provider, lr);
}
@Override
protected Map<String, String> getConfigurations() {
Map<String, String> map = super.getConfigurations();
map.put("${launcher_version}", Main.LAUNCHER_VERSION);
map.put("${launcher_name}", Main.LAUNCHER_NAME);
return map;
}
}
@@ -0,0 +1,187 @@
/*
* 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.hmcl.util;
import org.jackhuang.hmcl.core.service.IMinecraftService;
import org.jackhuang.hmcl.core.service.IMinecraftLoader;
import org.jackhuang.hmcl.core.service.IMinecraftModService;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.swing.SwingUtilities;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.version.LoadedOneVersionEvent;
import org.jackhuang.hmcl.api.event.version.RefreshedVersionsEvent;
import org.jackhuang.hmcl.api.event.version.RefreshingVersionsEvent;
import org.jackhuang.hmcl.core.GameException;
import org.jackhuang.hmcl.core.install.MinecraftInstallerService;
import org.jackhuang.hmcl.api.auth.UserProfileProvider;
import org.jackhuang.hmcl.core.download.MinecraftDownloadService;
import org.jackhuang.hmcl.api.game.LaunchOptions;
import org.jackhuang.hmcl.core.launch.MinecraftLoader;
import org.jackhuang.hmcl.core.mod.MinecraftModService;
import org.jackhuang.hmcl.core.mod.ModpackManager;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.VersionSetting;
import org.jackhuang.hmcl.ui.MainFrame;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.util.sys.FileUtils;
import org.jackhuang.hmcl.util.task.TaskWindow;
/**
*
* @author huangyuhui
*/
public class HMCLMinecraftService extends IMinecraftService {
private Profile p;
final Map<String, VersionSetting> versionSettings = new HashMap<>();
public HMCLMinecraftService(Profile p) {
this.p = p;
this.provider = new HMCLGameProvider(this);
provider.initializeMinecraft();
HMCLApi.EVENT_BUS.channel(RefreshingVersionsEvent.class).register(versionSettings::clear);
HMCLApi.EVENT_BUS.channel(RefreshedVersionsEvent.class).registerFirst(() -> {
if (!checkingModpack) {
checkingModpack = true;
if (version().getVersionCount() == 0) {
File modpack = new File("modpack.zip").getAbsoluteFile();
if (modpack.exists())
SwingUtilities.invokeLater(() -> {
if (TaskWindow.factory().execute(ModpackManager.install(MainFrame.INSTANCE, modpack, this, null)))
version().refreshVersions();
checkedModpack = true;
});
}
}
});
HMCLApi.EVENT_BUS.channel(LoadedOneVersionEvent.class).register(e -> loadVersionSetting(e.getValue()));
this.mms = new MinecraftModService(this);
this.mds = new MinecraftDownloadService(this);
this.mas = new HMCLAssetService(this);
this.mis = new MinecraftInstallerService(this);
}
public boolean checkedModpack = false, checkingModpack = false;
private void loadVersionSetting(String id) {
if (provider.getVersionById(id) == null)
return;
VersionSetting vs = null;
File f = new File(provider.versionRoot(id), "hmclversion.cfg");
if (f.exists()) {
String s = FileUtils.readQuietly(f);
if (s != null)
try {
vs = C.GSON.fromJson(s, VersionSetting.class);
} catch (JsonSyntaxException ex) {
HMCLog.warn("Failed to load version setting: " + id, ex);
vs = null;
}
}
if (vs == null)
return;
initVersionSetting(id, vs);
}
public void createVersionSetting(String id) {
if (provider.getVersionById(id) == null || versionSettings.containsKey(id))
return;
initVersionSetting(id, new VersionSetting());
}
private void initVersionSetting(String id, VersionSetting vs) {
vs.id = id;
vs.propertyChanged.register(event -> saveVersionSetting(((VersionSetting) event.getSource()).id));
versionSettings.put(id, vs);
}
/**
* Get the version setting for version id.
*
* @param id version id
*
* @return may return null if the id not exists
*/
public VersionSetting getVersionSetting(String id) {
if (!versionSettings.containsKey(id))
loadVersionSetting(id);
return versionSettings.get(id);
}
public void saveVersionSetting(String id) {
if (!versionSettings.containsKey(id))
return;
File f = new File(provider.versionRoot(id), "hmclversion.cfg");
FileUtils.writeQuietly(f, C.GSON.toJson(versionSettings.get(id)));
}
@Override
public File baseDirectory() {
return p.getGameDir();
}
protected HMCLGameProvider provider;
@Override
public HMCLGameProvider version() {
return provider;
}
protected MinecraftModService mms;
@Override
public IMinecraftModService mod() {
return mms;
}
protected MinecraftDownloadService mds;
@Override
public MinecraftDownloadService download() {
return mds;
}
final HMCLAssetService mas;
@Override
public HMCLAssetService asset() {
return mas;
}
protected MinecraftInstallerService mis;
@Override
public MinecraftInstallerService install() {
return mis;
}
@Override
public IMinecraftLoader launch(LaunchOptions options, UserProfileProvider p) throws GameException {
MinecraftLoader l = new HMCLMinecraftLoader(options, this, p);
l.setAssetProvider(mas.ASSET_PROVIDER_IMPL);
return l;
}
public Profile getProfile() {
return p;
}
}
@@ -0,0 +1,44 @@
/*
* 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.hmcl.util;
/**
*
* @author huangyuhui
*/
public enum LauncherVisibility {
/**
* Close the launcher anyway when the game process created even if failed to
* launch game.
*/
CLOSE,
/**
* Hide the launcher when the game process created, if failed to launch
* game, will show the log window.
*/
HIDE,
/**
* Keep the launcher visible even if the game launched successfully.
*/
KEEP,
/**
* Hide the launcher and reopen it when game closes.
*/
HIDE_AND_REOPEN
}
@@ -0,0 +1,149 @@
/*
* 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.hmcl.util;
import java.io.PipedOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.process.JavaProcessStoppedEvent;
import org.jackhuang.hmcl.api.func.Consumer;
import org.jackhuang.hmcl.ui.LogWindow;
import org.jackhuang.hmcl.util.log.Level;
import org.jackhuang.hmcl.util.sys.ProcessMonitor;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
*
* @author huang
*/
public class Log4jHandler extends Thread implements Consumer<JavaProcessStoppedEvent> {
ProcessMonitor monitor;
List<Pair<String, String>> forbiddenTokens = new LinkedList<>();
AtomicBoolean interrupted = new AtomicBoolean(false);
boolean enabled = true;
public Log4jHandler(ProcessMonitor monitor, PipedOutputStream outputStream, boolean enabled) {
this.monitor = monitor;
this.enabled = enabled;
HMCLApi.EVENT_BUS.channel(JavaProcessStoppedEvent.class).register((Consumer<JavaProcessStoppedEvent>) this);
}
public void addForbiddenToken(String token, String replacement) {
forbiddenTokens.add(new Pair<>(token, replacement));
}
@Override
public void run() {
}
@Override
public void accept(JavaProcessStoppedEvent t) {
}
/**
* Always use this instance method to write to the log,
* to make sure only this Thread writes to the PipedOutputStream.
*
* It will also flush the buffer, directly after write.
*
* This prevents java.io.IOException: Read end dead
* See also https://techtavern.wordpress.com/2008/07/16/whats-this-ioexception-write-end-dead/
*
* @param content The content to be written to the log
*/
public Future newLogLine(String content) {
printlnImpl(content, Level.guessLevel(content));
return null;
}
class Log4jHandlerImpl extends DefaultHandler {
private final SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
String date = "", thread = "", logger = "";
StringBuilder message = null;
Level l = null;
boolean readingMessage = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
switch (localName) {
case "log4j_Event":
message = new StringBuilder();
Date d = new Date(Long.valueOf(attributes.getValue("timestamp")));
date = df.format(d);
try {
l = Level.valueOf(attributes.getValue("level"));
} catch (IllegalArgumentException e) {
l = Level.INFO;
}
thread = attributes.getValue("thread");
logger = attributes.getValue("logger");
if ("STDERR".equals(logger))
l = Level.ERROR;
break;
case "log4j_Message":
readingMessage = true;
break;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
switch (localName) {
case "log4j_Event":
println("[" + date + "] [" + thread + "/" + l.name() + "] [" + logger + "] " + message.toString(), l);
break;
case "log4j_Message":
readingMessage = false;
break;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String line = new String(ch, start, length);
if (line.trim().isEmpty())
return;
if (readingMessage)
message.append(line).append(C.LINE_SEPARATOR);
else
println(line, Level.guessLevel(line));
}
public void println(String message, Level l) {
printlnImpl(message, l);
}
}
private void printlnImpl(String message, Level l) {
for (Pair<String, String> entry : forbiddenTokens)
message = message.replace(entry.key, entry.value);
if (LogWindow.outputStream != null)
LogWindow.outputStream.log(message, l);
}
}
@@ -0,0 +1,58 @@
/*
* 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.hmcl.util;
import org.jackhuang.hmcl.util.lang.SupportedLocales;
/**
* Give the advice to solve the Minecraft crashing.
*
* @author huangyuhui
*/
public final class MinecraftCrashAdvicer {
public static String getAdvice(String trace) {
return getAdvice(trace, false);
}
public static String getAdvice(String trace, boolean selfCrash) {
if (trace == null)
return C.i18n("crash.advice.no");
trace = trace.toLowerCase(SupportedLocales.getNowLocale().self);
if (trace.contains("pixel format not accelerated"))
return C.i18n("crash.advice.LWJGLException");
else if (trace.contains("unsupportedclassversionrrror"))
return C.i18n("crash.advice.UnsupportedClassVersionError");
else if (trace.contains("concurrentmodificationexception"))
return C.i18n("crash.advice.ConcurrentModificationException");
else if (trace.contains("securityexception"))
return C.i18n("crash.advice.SecurityException");
else if (trace.contains("nosuchfieldexception") || trace.contains("nosuchmethodexception") || trace.contains("nosuchfielderror") || trace.contains("nosuchmethoderror"))
return C.i18n("crash.advice.NoSuchFieldError");
else if (trace.contains("outofmemory") || trace.contains("out of memory"))
return C.i18n("crash.advice.OutOfMemoryError");
else if (trace.contains("noclassdeffounderror") || trace.contains("classnotfoundexception"))
return C.i18n("crash.advice.ClassNotFoundException");
else if (trace.contains("no lwjgl in java.library.path"))
return C.i18n("crash.advice.no_lwjgl");
else if (trace.contains("opengl") || trace.contains("openal"))
return C.i18n("crash.advice.OpenGL");
return C.i18n(selfCrash ? "crash.advice.no" : "crash.advice.otherwise");
}
}
@@ -0,0 +1,257 @@
/*
* 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.hmcl.util.upgrade;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Pack200;
import java.util.logging.Level;
import java.util.zip.GZIPInputStream;
import org.jackhuang.hmcl.Main;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.api.event.SimpleEvent;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.core.MCUtils;
import org.jackhuang.hmcl.util.task.Task;
import org.jackhuang.hmcl.util.task.TaskWindow;
import org.jackhuang.hmcl.util.net.FileDownloadTask;
import org.jackhuang.hmcl.util.ArrayUtils;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.Utils;
import org.jackhuang.hmcl.api.VersionNumber;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.util.sys.FileUtils;
import org.jackhuang.hmcl.util.sys.IOUtils;
import org.jackhuang.hmcl.util.sys.OS;
/**
*
* @author huangyuhui
*/
public class AppDataUpgrader extends IUpgrader {
private boolean launchNewerVersion(String[] args, File jar) throws IOException, PrivilegedActionException {
try (JarFile jarFile = new JarFile(jar)) {
String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class");
if (mainClass != null) {
ArrayList<String> al = new ArrayList<>(Arrays.asList(args));
al.add("--noupdate");
AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
new URLClassLoader(new URL[] { jar.toURI().toURL() },
URLClassLoader.getSystemClassLoader().getParent()).loadClass(mainClass)
.getMethod("main", String[].class).invoke(null, new Object[] { al.toArray(new String[0]) });
return null;
});
return true;
}
}
return false;
}
@Override
public void parseArguments(VersionNumber nowVersion, String[] args) {
File f = AppDataUpgraderPackGzTask.HMCL_VER_FILE;
if (!ArrayUtils.contains(args, "--noupdate"))
try {
if (f.exists()) {
Map<String, String> m = C.GSON.fromJson(FileUtils.read(f), Map.class);
String s = m.get("ver");
if (s != null && VersionNumber.check(s).compareTo(nowVersion) > 0) {
String j = m.get("loc");
if (j != null) {
File jar = new File(j);
if (jar.exists() && launchNewerVersion(args, jar))
System.exit(0);
}
}
}
} catch (JsonSyntaxException ex) {
f.delete();
} catch (IOException | PrivilegedActionException t) {
HMCLog.err("Failed to execute newer version application", t);
}
}
@Override
public void accept(SimpleEvent<VersionNumber> event) {
final VersionNumber version = event.getValue();
((UpdateChecker) event.getSource()).requestDownloadLink().reg(map -> {
if (MessageBox.show(C.i18n("update.newest_version") + version.firstVer + "." + version.secondVer + "." + version.thirdVer + "\n"
+ C.i18n("update.should_open_link"),
MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
if (map != null && map.containsKey("jar") && !StrUtils.isBlank(map.get("jar")))
try {
String hash = null;
if (map.containsKey("jarsha1"))
hash = map.get("jarsha1");
if (TaskWindow.factory().append(new AppDataUpgraderJarTask(map.get("jar"), version.version, hash)).execute()) {
new ProcessBuilder(new String[] { IOUtils.getJavaDir(), "-jar", AppDataUpgraderJarTask.getSelf(version.version).getAbsolutePath() }).directory(new File("").getAbsoluteFile()).start();
System.exit(0);
}
} catch (IOException ex) {
Main.LOGGER.log(Level.SEVERE, "Failed to create upgrader", ex);
}
else if (map != null && map.containsKey("pack") && !StrUtils.isBlank(map.get("pack")))
try {
String hash = null;
if (map.containsKey("packsha1"))
hash = map.get("packsha1");
if (TaskWindow.factory().append(new AppDataUpgraderPackGzTask(map.get("pack"), version.version, hash)).execute()) {
new ProcessBuilder(new String[] { IOUtils.getJavaDir(), "-jar", AppDataUpgraderPackGzTask.getSelf(version.version).getAbsolutePath() }).directory(new File("").getAbsoluteFile()).start();
System.exit(0);
}
} catch (IOException ex) {
HMCLog.err("Failed to create upgrader", ex);
}
else {
String url = C.URL_PUBLISH;
if (map != null)
if (map.containsKey(OS.os().checkedName))
url = map.get(OS.os().checkedName);
else if (map.containsKey(OS.UNKNOWN.checkedName))
url = map.get(OS.UNKNOWN.checkedName);
if (url == null)
url = C.URL_PUBLISH;
try {
java.awt.Desktop.getDesktop().browse(new URI(url));
} catch (URISyntaxException | IOException e) {
HMCLog.err("Failed to browse uri: " + url, e);
Utils.setClipboard(url);
MessageBox.show(C.i18n("update.no_browser"));
}
}
}).execute();
}
public static class AppDataUpgraderPackGzTask extends Task {
public static final File BASE_FOLDER = MCUtils.getWorkingDirectory("hmcl");
public static final File HMCL_VER_FILE = new File(BASE_FOLDER, "hmclver.json");
public static File getSelf(String ver) {
return new File(BASE_FOLDER, "HMCL-" + ver + ".jar");
}
private final String downloadLink, newestVersion, expectedHash;
File tempFile;
public AppDataUpgraderPackGzTask(String downloadLink, String newestVersion, String hash) throws IOException {
this.downloadLink = downloadLink;
this.newestVersion = newestVersion;
this.expectedHash = hash;
tempFile = File.createTempFile("hmcl", ".pack.gz");
}
@Override
public Collection<Task> getDependTasks() {
return Arrays.asList(new FileDownloadTask(downloadLink, tempFile, expectedHash));
}
@Override
public void executeTask(boolean areDependTasksSucceeded) throws Exception {
if (!areDependTasksSucceeded) {
tempFile.delete();
return;
}
HashMap<String, String> json = new HashMap<>();
File f = getSelf(newestVersion);
if (!FileUtils.makeDirectory(f.getParentFile()))
throw new IOException("Failed to make directories: " + f.getParent());
for (int i = 0; f.exists(); i++)
f = new File(BASE_FOLDER, "HMCL-" + newestVersion + (i > 0 ? "-" + i : "") + ".jar");
if (!f.createNewFile())
throw new IOException("Failed to create new file: " + f);
try (JarOutputStream jos = new JarOutputStream(FileUtils.openOutputStream(f))) {
Pack200.newUnpacker().unpack(new GZIPInputStream(FileUtils.openInputStream(tempFile)), jos);
}
json.put("ver", newestVersion);
json.put("loc", f.getAbsolutePath());
String result = C.GSON.toJson(json);
FileUtils.write(HMCL_VER_FILE, result);
}
@Override
public String getInfo() {
return "Upgrade";
}
}
public static class AppDataUpgraderJarTask extends Task {
public static final File BASE_FOLDER = MCUtils.getWorkingDirectory("hmcl");
public static final File HMCL_VER_FILE = new File(BASE_FOLDER, "hmclver.json");
public static File getSelf(String ver) {
return new File(BASE_FOLDER, "HMCL-" + ver + ".jar");
}
private final String downloadLink, newestVersion, expectedHash;
File tempFile;
public AppDataUpgraderJarTask(String downloadLink, String newestVersion, String hash) throws IOException {
this.downloadLink = downloadLink;
this.newestVersion = newestVersion;
this.expectedHash = hash;
tempFile = File.createTempFile("hmcl", ".jar");
}
@Override
public Collection<Task> getDependTasks() {
return Arrays.asList(new FileDownloadTask(downloadLink, tempFile, expectedHash));
}
@Override
public void executeTask(boolean areDependTasksSucceeded) throws Exception {
if (!areDependTasksSucceeded) {
tempFile.delete();
return;
}
HashMap<String, String> json = new HashMap<>();
File f = getSelf(newestVersion);
FileUtils.copyFile(tempFile, f);
json.put("ver", newestVersion);
json.put("loc", f.getAbsolutePath());
String result = C.GSON.toJson(json);
FileUtils.write(HMCL_VER_FILE, result);
}
@Override
public String getInfo() {
return "Upgrade";
}
}
}
@@ -0,0 +1,50 @@
/*
* 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.hmcl.util.upgrade;
import org.jackhuang.hmcl.api.event.SimpleEvent;
import org.jackhuang.hmcl.api.VersionNumber;
import org.jackhuang.hmcl.api.func.Consumer;
/**
*
* @author huangyuhui
*/
public abstract class IUpgrader implements Consumer<SimpleEvent<VersionNumber>> {
public static final IUpgrader NOW_UPGRADER = new AppDataUpgrader();
/**
* Paring arguments to decide on whether the upgrade is needed.
*
* @param nowVersion now launcher version
* @param args Application CommandLine Arguments
*/
public abstract void parseArguments(VersionNumber nowVersion, String[] args);
/**
* Just download the new app.
*
* @param sender Should be VersionChecker
* @param number the newest version
*
* @return should return true
*/
@Override
public abstract void accept(SimpleEvent<VersionNumber> event);
}
@@ -0,0 +1,65 @@
/*
* 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.hmcl.util.upgrade;
import java.io.File;
import java.io.IOException;
import org.jackhuang.hmcl.api.event.SimpleEvent;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.util.task.TaskWindow;
import org.jackhuang.hmcl.util.net.FileDownloadTask;
import org.jackhuang.hmcl.util.ArrayUtils;
import org.jackhuang.hmcl.api.VersionNumber;
import org.jackhuang.hmcl.util.sys.FileUtils;
import org.jackhuang.hmcl.util.sys.IOUtils;
/**
*
* @author huangyuhui
*/
public class NewFileUpgrader extends IUpgrader {
@Override
public void parseArguments(VersionNumber nowVersion, String[] args) {
int i = ArrayUtils.indexOf(args, "--removeOldLauncher");
if (i != -1 && i < args.length - 1) {
File f = new File(args[i + 1]);
if (f.exists())
f.deleteOnExit();
}
}
@Override
public void accept(SimpleEvent<VersionNumber> event) {
String str = requestDownloadLink();
File newf = new File(FileUtils.getName(str));
if (TaskWindow.factory().append(new FileDownloadTask(str, newf)).execute()) {
try {
new ProcessBuilder(new String[] { newf.getCanonicalPath(), "--removeOldLauncher", IOUtils.getRealPath() }).directory(new File("").getAbsoluteFile()).start();
} catch (IOException ex) {
HMCLog.err("Failed to start new app", ex);
}
System.exit(0);
}
}
private String requestDownloadLink() {
return null;
}
}
@@ -0,0 +1,109 @@
/*
* 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.hmcl.util.upgrade;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.api.VersionNumber;
import org.jackhuang.hmcl.api.event.EventHandler;
import org.jackhuang.hmcl.util.net.NetUtils;
import com.google.gson.JsonSyntaxException;
import java.io.IOException;
import org.jackhuang.hmcl.api.HMCLog;
import java.util.Map;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.SimpleEvent;
import org.jackhuang.hmcl.api.event.OutOfDateEvent;
import org.jackhuang.hmcl.util.AbstractSwingWorker;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.util.IUpdateChecker;
/**
*
* @author huangyuhui
*/
public final class UpdateChecker implements IUpdateChecker {
private volatile boolean outOfDate = false;
public VersionNumber base;
public String versionString;
public String type;
private Map<String, String> download_link = null;
public UpdateChecker(VersionNumber base, String type) {
this.base = base;
this.type = type;
}
VersionNumber value;
public boolean isOutOfDate() {
return outOfDate;
}
@Override
public AbstractSwingWorker<VersionNumber> process(final boolean showMessage) {
return new AbstractSwingWorker<VersionNumber>() {
@Override
protected void work() throws Exception {
if (value == null) {
versionString = NetUtils.get("http://huangyuhui.duapp.com/info.php?type=" + type);
value = VersionNumber.check(versionString);
}
if (value == null) {
HMCLog.warn("Failed to check update...");
if (showMessage)
MessageBox.show(C.i18n("update.failed"));
} else if (VersionNumber.isOlder(base, value))
outOfDate = true;
if (outOfDate)
publish(value);
}
};
}
@Override
public VersionNumber getNewVersion() {
return value;
}
@Override
public synchronized AbstractSwingWorker<Map<String, String>> requestDownloadLink() {
return new AbstractSwingWorker<Map<String, String>>() {
@Override
protected void work() throws Exception {
if (download_link == null)
try {
download_link = C.GSON.<Map<String, String>>fromJson(NetUtils.get("http://huangyuhui.duapp.com/update_link.php?type=" + type), Map.class);
} catch (JsonSyntaxException | IOException e) {
HMCLog.warn("Failed to get update link.", e);
}
publish(download_link);
}
};
}
public final EventHandler<SimpleEvent<VersionNumber>> upgrade = new EventHandler<>();
@Override
public void checkOutdate() {
if (outOfDate)
if (HMCLApi.EVENT_BUS.fireChannelResulted(new OutOfDateEvent(this, getNewVersion())))
upgrade.fire(new SimpleEvent<>(this, getNewVersion()));
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="SysOut" target="SYSTEM_OUT">
<LegacyXMLLayout />
<XMLLayout />
</Console>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<OnStartupTriggeringPolicy />
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="info">
<filters>
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL" />
</filters>
<AppenderRef ref="SysOut"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

@@ -1,305 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import org.jackhuang.hellominecraftlauncher.apis.LogUtils;
import org.jackhuang.hellominecraftlauncher.apis.DoneListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jackhuang.hellominecraftlauncher.apis.handlers.Login;
import org.jackhuang.hellominecraftlauncher.apis.handlers.LoginInfo;
import org.jackhuang.hellominecraftlauncher.apis.handlers.LoginResult;
import org.jackhuang.hellominecraftlauncher.apis.PluginHandlerType;
import org.jackhuang.hellominecraftlauncher.apis.version.MinecraftLibrary;
import org.jackhuang.hellominecraftlauncher.loaders.MinecraftLoader;
import org.jackhuang.hellominecraftlauncher.loaders.MinecraftOldLoader;
import org.jackhuang.hellominecraftlauncher.plugin.PluginHandler;
import org.jackhuang.hellominecraftlauncher.utilities.SettingsManager;
import org.jackhuang.hellominecraftlauncher.settings.Version;
import org.jackhuang.hellominecraftlauncher.utilities.C;
import org.jackhuang.hellominecraftlauncher.apis.utils.MessageBox;
import org.jackhuang.hellominecraftlauncher.apis.utils.OperatingSystems;
import org.jackhuang.hellominecraftlauncher.apis.utils.Utils;
import org.jackhuang.hellominecraftlauncher.apis.utils.Compressor;
import org.jackhuang.hellominecraftlauncher.apis.version.MinecraftVersion;
/**
*
* @author hyh
*/
public class GameLauncher {
private static String makeCommand(List<String> cmd) {
StringBuilder cmdbuf = new StringBuilder(120);
for (int i = 0; i < cmd.size(); i++) {
if (i > 0) {
cmdbuf.append(' ');
}
String s = cmd.get(i);
if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0) {
if (s.charAt(0) != '"') {
cmdbuf.append('"');
cmdbuf.append(s);
if (s.endsWith("\\")) {
cmdbuf.append("\\");
}
cmdbuf.append('"');
} else if (s.endsWith("\"")) {
/* The argument has already been quoted. */
cmdbuf.append(s);
} else {
/* Unmatched quote for the argument. */
throw new IllegalArgumentException();
}
} else {
cmdbuf.append(s);
}
}
String str = cmdbuf.toString();
return str;
}
Version get;
LoginInfo info;
Login login;
ArrayList<ArrayList<DoneListener<List, GameLauncher>>> listeners;
public GameLauncher(Version version, LoginInfo info, int loginType) {
this.get = version;
this.info = info;
listeners = new ArrayList<ArrayList<DoneListener<List, GameLauncher>>>(101);
for (int i = 0; i < 101; i++) {
listeners.add(new ArrayList<DoneListener<List, GameLauncher>>());
}
this.login = (Login)PluginHandler.getPluginHandlers(PluginHandlerType.getType("LOGIN")).get(loginType);
}
private void executeEvent(int eventType, List p) {
for (DoneListener<List, GameLauncher> dl : listeners.get(eventType)) {
dl.onDone(p, this);
}
}
public void addListener(int eventType, DoneListener<List, GameLauncher> dl) {
listeners.get(eventType).add(dl);
}
public void makeLaunchCommand() {
ArrayList al = new ArrayList();
LoginResult result;
if(info != null)
result = login.login(info);
else
result = login.loginBySettings();
if (result == null || result.success == false) {
String error;
if (result == null || result.error == null) {
error = C.I18N.getString("登录失败:") + C.I18N.getString("插件错误");
} else {
error = C.I18N.getString("登录失败:") + result.error;
}
al.add(error);
executeEvent(0, al);
return;
}
String name = get.name;
final String realpa = Utils.addSeparator(Utils.getGameDir(get, SettingsManager.settings.publicSettings.gameDir));
if (get.isVer16) {
String minecraftJar = realpa
+ "versions" + File.separator + name + File.separator + name
+ ".jar";
String minecraftJarTo = realpa
+ "versions" + File.separator + name + File.separator + name
+ "-HMCL-MERGE-TEMP.jar";
if (get.minecraftJar != null && !get.minecraftJar.isEmpty()) {
String unzipDir = Utils.addSeparator(Utils.currentDir())
+ "HMCL-MERGE-TEMP" + File.separator;
Compressor.unzip(minecraftJar, unzipDir);
for (int i = 0; i < get.minecraftJar.size(); i++) {
if (get.minecraftJarIsActive == null || get.minecraftJarIsActive.get(i)) {
Compressor.unzip(get.minecraftJar.get(i), unzipDir);
}
}
Compressor.zip(unzipDir, minecraftJarTo);
Utils.deleteAll(new File(unzipDir));
minecraftJar = minecraftJarTo;
}
MinecraftVersion mv = Utils.getMinecraftVersion(get, SettingsManager.settings.publicSettings.gameDir);
if (mv.minimumLauncherVersion > Main.minimumLauncherVersion) {
MessageBox.Show("对不起,本启动器现在可能不能启动这个版本的Minecraft,但启动器还是会尝试启动");
}
final MinecraftLoader ml = new MinecraftLoader(mv,
SettingsManager.settings.publicSettings, get, result,
minecraftJar);
//Find assets
//Find, download & unzip libraries
MinecraftVersion v = (ml).getVersion();
File file = new File(realpa + "versions" + File.separator + name + File.separator + name + "-natives");
Utils.deleteAll(file);
file.mkdirs();
ArrayList<String[]> unzippings = new ArrayList<String[]>();
ArrayList<String[]> downloadLibraries = new ArrayList<String[]>();
for (int i = 0; i < v.libraries.size(); i++) {
MinecraftLibrary l = v.libraries.get(i);
if (l.allow()) {
File ff = new File(realpa + "libraries" + File.separator
+ l.formatted);
if (!ff.exists()) {
new File(ff.getParent()).mkdirs();
final String location = l.formatted.replace('\\', '/');
String[] lib = new String[3];
lib[0] = location;
lib[1] = C.URL_LIBRARIES[SettingsManager.settings.downloadtype] + location;
lib[2] = ff.getPath();
downloadLibraries.add(lib);
}
}
if (l.natives != null && l.allow()) {
String[] unzip = new String[2];
unzip[0] = realpa + "libraries" + File.separator + l.formatted;
unzip[1] = realpa + "versions" + File.separator
+ name + File.separator + name + "-natives";
unzippings.add(unzip);
}
}
executeEvent(2, downloadLibraries);
executeEvent(3, unzippings);
executeEvent(100, ml.makeLaunchingCommand());
} else {
String minecraftJar = realpa + "bin" + File.separator + "minecraft.jar";
String minecraftJarTo = realpa + "bin" + File.separator + "minecraft-HMCL-MERGE-TEMP.jar";
if (get.minecraftJar != null && !get.minecraftJar.isEmpty()) {
String unzipDir = Utils.addSeparator(Utils.currentDir())
+ "HMCL-MERGE-TEMP" + File.separator;
Compressor.unzip(minecraftJar, unzipDir);
for (int i = 0; i < get.minecraftJar.size(); i++) {
if (get.minecraftJarIsActive == null || get.minecraftJarIsActive.get(i)) {
Compressor.unzip(get.minecraftJar.get(i), unzipDir);
}
}
Compressor.zip(unzipDir, minecraftJarTo);
Utils.deleteAll(new File(unzipDir));
minecraftJar = minecraftJarTo;
}
String command;
MinecraftOldLoader loader = new MinecraftOldLoader(
SettingsManager.settings.publicSettings, get, result,
minecraftJar);
command = makeCommand(loader.makeLaunchingCommand());
al.add(command);
executeEvent(100, al);
}
}
/**
* Launch the game "as soon as possible".
* @param str launch command
*/
public void launch(List str) {
try {
Process p;
File dir = new File(Utils.getGameDir(get, SettingsManager.settings.publicSettings.gameDir));
String appdata = dir.getParent();
LogUtils.info("APPDATA: " + appdata);
ProcessBuilder builder = new ProcessBuilder(str);
builder.environment().put("APPDATA", appdata);
builder.directory(dir);
p = builder.start();
ArrayList<JavaProcess> al = new ArrayList<JavaProcess>();
al.add(new JavaProcess(str, p));
executeEvent(4, al);
} catch (IOException e) {
e.printStackTrace();
MessageBox.Show(C.I18N.getString("启动失败"));
}
}
/**
* According to the name...
*
* @param launcherName the name of launch bat/sh
* @param str launch command
*/
public void makeLauncher(String launcherName, List str) {
OperatingSystems os = Utils.os();
String gameDir = Utils.getGameDir(get, SettingsManager.settings.publicSettings.gameDir);
File f;
boolean isWin = os == OperatingSystems.WINDOWS;
if (isWin) {
f = new File(launcherName + ".bat");
} else {
f = new File(launcherName + ".sh");
}
if (!f.exists()) {
try {
f.createNewFile();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), System.getProperty("sun.jnu.encoding", "gbk")));
} catch (FileNotFoundException ex) {
throw new RuntimeException(ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(GameLauncher.class.getName()).log(Level.SEVERE, null, ex);
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
} catch (FileNotFoundException ex1) {
throw new RuntimeException(ex1);
}
}
if (isWin) {
File dir = new File(gameDir);
String appdata = dir.getParent();
if (appdata != null) {
try {
writer.write("set appdata=" + appdata);
writer.newLine();
} catch (IOException ex) {
System.err.println("Failed to write.");
ex.printStackTrace();
}
}
}
try {
writer.write(makeCommand(str));
writer.close();
} catch (IOException ex) {
Logger.getLogger(GameLauncher.class.getName()).log(Level.SEVERE, null, ex);
}
if (!isWin) {
try {
Runtime.getRuntime().exec("chmod +x launch.sh");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@@ -1,19 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
/**
*
* @author hyh
*/
public enum GameLauncherRequest {
ERROR,
DOWNLOAD_ASSETS,
DOWNLOAD_LIBRARIES,
UNZIP_LIBRARIES,
PROCESS_STARTED,
SUCCEED
}
@@ -1,238 +0,0 @@
# To change this template, choose Tools | Templates
# and open the template in the editor.
\u6e38\u620f\u7248\u672c=\u6e38\u620f\u7248\u672c
\u8fd9\u4e2aMINECRAFT\u6587\u4ef6\u5939\u65e2\u4e0d\u662f1.6\u7248\u4e5f\u4e0d\u662f\u65e7\u7248\u7684\u600e\u4e48\u5bfc\u5165\u561b0V0\u3002=\u8fd9\u4e2aminecraft\u6587\u4ef6\u5939\u65e2\u4e0d\u662f1.6\u7248\u4e5f\u4e0d\u662f\u65e7\u7248\u7684\u600e\u4e48\u5bfc\u5165\u561b0v0\u3002
\u672a\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u7248\u672c=\u672a\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u7248\u672c
\u5bfc\u5165\u5931\u8d25\:\ {0}=\u5bfc\u5165\u5931\u8d25: {0}
\u627e\u5230\u540c\u540d\u7684MINECRAFT\u7248\u672c\uff0c\u8bf7\u6362\u7528\u53e6\u4e00\u4e2a\u540d\u79f0=\u627e\u5230\u540c\u540d\u7684Minecraft\u7248\u672c\uff0c\u8bf7\u6362\u7528\u53e6\u4e00\u4e2a\u540d\u79f0
\u8bf7\u8f93\u5165\u8be5\u65e7\u7248\u672c\u7684\u540d\u79f0=\u8bf7\u8f93\u5165\u8be5\u65e7\u7248\u672c\u7684\u540d\u79f0
\u627e\u4e0d\u5230MINECRAFT.JAR=\u627e\u4e0d\u5230minecraft.jar
\u9009\u62e9MINECRAFT\u8def\u5f84=\u9009\u62e9Minecraft\u8def\u5f84
\u542f\u52a8\u5931\u8d25=\u542f\u52a8\u5931\u8d25
\u590d\u5236\u914d\u7f6e\u6587\u4ef6\u5931\u8d25\:\ =\u590d\u5236\u914d\u7f6e\u6587\u4ef6\u5931\u8d25:
\u590d\u5236\u6838\u5fc3\u6a21\u7ec4\u5931\u8d25\:\ =\u590d\u5236\u6838\u5fc3\u6a21\u7ec4\u5931\u8d25:
\u590d\u5236\u666e\u901a\u6a21\u7ec4\u5931\u8d25\:\ =\u590d\u5236\u666e\u901a\u6a21\u7ec4\u5931\u8d25:
\u4e0b\u8f7d\u7f3a\u5931\u5e93\uff1a{0}=\u4e0b\u8f7d\u7f3a\u5931\u5e93\uff1a{0}
\u6ca1\u6709\u9009\u62e9\u4efb\u4f55\u4e00\u4e2aMINECRAFT\u7248\u672c=\u6ca1\u6709\u9009\u62e9\u4efb\u4f55\u4e00\u4e2aMinecraft\u7248\u672c
\u9519\u8bef\u7684MINECRAFT\u8def\u5f84=\u9519\u8bef\u7684Minecraft\u8def\u5f84
\u5173\u4e8e=\u5173\u4e8e
\u4e0b\u8f7d=\u4e0b\u8f7d
\u5bc6\u7801=\u5bc6\u7801
\u624b\u52a8\u8bbe\u7f6e=\u624b\u52a8\u8bbe\u7f6e
\u4e0d\u9650\u5236=\u4e0d\u9650\u5236
32\u4f4d=32\u4f4d
64\u4f4d=64\u4f4d
\u542f\u52a8\u6a21\u5f0f=\u542f\u52a8\u6a21\u5f0f
\u6700\u5927\u5185\u5b58=\u6700\u5927\u5185\u5b58
\u6e38\u620f\u540d\u79f0=\u540d\u5b57
\u6e38\u620f\u8def\u5f84=\u6e38\u620f\u8def\u5f84
\u5bfc\u5165\u6587\u4ef6\u5939=\u5bfc\u5165\u6587\u4ef6\u5939
\u65b0\u5efa=\u65b0\u5efa
\u5220\u9664=\u5220\u9664
\u7f16\u8f91=\u7f16\u8f91
\u590d\u5236=\u590d\u5236
\u5bfc\u5165\u65e7\u7248\u672c=\u5bfc\u5165\u65e7\u7248\u672c
\u5236\u4f5c\u4e00\u952e\u542f\u52a8=\u5236\u4f5c\u4e00\u952e\u542f\u52a8
\u51c6\u5907\u4e2d=\u51c6\u5907\u4e2d
\u5f00\u59cbMINECRAFT\u4e4b\u65c5!=\u542f\u52a8\u6e38\u620f
\u5237\u65b0=\u5237\u65b0
public_settings=\u5168\u5c40\u8bbe\u7f6e
game_download=\u6e38\u620f\u4e0b\u8f7d
\u66f4\u65b0\u4fe1\u606f=\u66f4\u65b0\u4fe1\u606f
\u8bbe\u7f6e\u5931\u8d25\uff1a=\u8bbe\u7f6e\u5931\u8d25\uff1a
\u7f3a\u5931\u5e93\u4e0b\u8f7d=\u7f3a\u5931\u5e93\u4e0b\u8f7d
\u9009\u62e9\u80cc\u666f\u8def\u5f84=\u9009\u62e9\u80cc\u666f\u8def\u5f84
MineLogin0=\u7f51\u7edc\u9519\u8bef
MineLogin1=\u7528\u6237\u540d\u6216\u5bc6\u7801\u4e0d\u5408\u6cd5
MineLogin2=\u5185\u90e8\u9519\u8bef
MineLogin3=\u7528\u6237\u4e0d\u5b58\u5728
MineLogin4=\u9700\u8981\u9a8c\u8bc1
MineLogin5=\u5bc6\u7801\u9519\u8bef
ForgeMod=Forge mod
ModLoaderMod=ModLoader mod
Forge=Forge
ModLoader=ModLoader
Unknown=\u672a\u77e5
Mods\u6587\u4ef6\u5939=Mods\u6587\u4ef6\u5939
Coremods\u6587\u4ef6\u5939=Coremods\u6587\u4ef6\u5939
Mod\u72ec\u7acb\u6587\u4ef6\u5939=Mod\u72ec\u7acb\u6587\u4ef6\u5939
\u914d\u7f6e\u6587\u4ef6\u5939=\u914d\u7f6e\u6587\u4ef6\u5939
\u767b\u5f55\u5931\u8d25\uff1a=\u767b\u5f55\u5931\u8d25\uff1a
\u9009\u62e9\u5931\u8d25=\u9009\u62e9\u5931\u8d25
\u63d2\u4ef6\u9519\u8bef\uff1a=\u63d2\u4ef6\u9519\u8bef\uff1a
\u767b\u5f55\u5931\u8d25\uff1a=\u767b\u5f55\u5931\u8d25\uff1a
\u6ca1\u6709\u767b\u5165\u65b9\u5f0f...=\u6ca1\u6709\u767b\u5165\u65b9\u5f0f...
\u4fdd\u5b58=\u4fdd\u5b58
\u767b\u5f55\u6a21\u5f0f=\u767b\u5f55\u6a21\u5f0f
\u7248\u672c\u7f16\u8f91=\u7248\u672c\u7f16\u8f91
\u7248\u672c\u53f7=\u7248\u672c\u53f7
\u5bfc\u5165=\u5bfc\u5165
\u64cd\u4f5c=\u64cd\u4f5c
\u4e0b\u8f7d\u4fe1\u606f=\u4e0b\u8f7d\u4fe1\u606f
\u5b89\u88c5=\u5b89\u88c5
\u6dfb\u52a0=\u6dfb\u52a0
\u5168\u90e8\u4e0b\u8f7d=\u5168\u90e8\u4e0b\u8f7d
\u52a0\u5165MINECRAFT.JAR=\u52a0\u5165minecraft.jar
\u7ba1\u7406=\u7ba1\u7406
\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4=\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4
\u5e93=\u5e93
AdvancedSettings=\u9ad8\u7ea7\u8bbe\u7f6e
\u6700\u5927\u5316=\u6700\u5927\u5316
\u68c0\u67e5\u66f4\u65b0=\u68c0\u67e5\u66f4\u65b0
\u67e5\u770b\u65e5\u5fd7=\u67e5\u770b\u65e5\u5fd7
\u80cc\u666f\u5730\u5740=\u80cc\u666f\u5730\u5740
UNEXPECTED\ EXCEPTION\ LOADING\ =Unexpected exception loading
\u5f53\u524d\u662f\u6700\u65b0\u7248\u672c=\u5f53\u524d\u662f\u6700\u65b0\u7248\u672c
\u65e0\u6cd5\u6253\u5f00\u6d4f\u89c8\u5668\uff0c\u7f51\u5740\u5df2\u7ecf\u590d\u5236\u5230\u526a\u8d34\u677f\u4e86\uff0c\u60a8\u53ef\u4ee5\u624b\u52a8\u7c98\u8d34\u7f51\u5740\u6253\u5f00\u9875\u9762=\u65e0\u6cd5\u6253\u5f00\u6d4f\u89c8\u5668\uff0c\u7f51\u5740\u5df2\u7ecf\u590d\u5236\u5230\u526a\u8d34\u677f\u4e86\uff0c\u60a8\u53ef\u4ee5\u624b\u52a8\u7c98\u8d34\u7f51\u5740\u6253\u5f00\u9875\u9762
\u662f\u5426\u524d\u5f80\u53d1\u5e03\u9875\u9762\u66f4\u65b0\uff1f=\u662f\u5426\u524d\u5f80\u53d1\u5e03\u9875\u9762\u66f4\u65b0\uff1f
\u66f4\u65b0\u4fe1\u606f\u4e3a\:\ =\u66f4\u65b0\u4fe1\u606f\u4e3a:
\u6700\u65b0\u7248\u672c\u4e3a\uff1a=\u6700\u65b0\u7248\u672c\u4e3a\uff1a
\u68c0\u67e5\u66f4\u65b0\u5931\u8d25=\u68c0\u67e5\u66f4\u65b0\u5931\u8d25
\u8fde\u63a5\u4e2d=\u8fde\u63a5\u4e2d
\u83b7\u53d6\u5217\u8868\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u91cd\u8bd5=\u83b7\u53d6\u5217\u8868\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u91cd\u8bd5
INVALID\ PLUGIN=Invalid plugin
\u65e0\u6cd5\u8fde\u63a5=\u65e0\u6cd5\u8fde\u63a5
\ \u5dee\ ORANGERED=\ \u5dee orangered
\ \u8f83\u5dee\ ORANGE=\ \u8f83\u5dee orange
\ \u4e2d\ YELLOGREEN=\ \u4e2d yellogreen
\ \u8f83\u597d\ BLUE=\ \u8f83\u597d blue
\ \u597d\ GREEN=\ \u597d green
\u670d\u52a1\u5668{0}\u7684\u56de\u590d\u65e0\u6548=\u670d\u52a1\u5668{0}\u7684\u56de\u590d\u65e0\u6548
ForgeInstall=\u63a5\u4e0b\u6765\u5f39\u51fa\u6765\u7684\u7a97\u53e3\u91cc\u8bf7\u9009\u62e9\u8def\u5f84\u4e3a\u6e38\u620f\u8def\u5f84\u3002\u7a0b\u5e8f\u5df2\u7ecf\u5c06\u76ee\u5f55\u590d\u5236\u5230\u4e86\u526a\u8d34\u677f\uff0c\u76f4\u63a5\u5728\u7a97\u53e3\u91cc\u9009\u62e9"..."\u6309\u94ae\uff0c\u7c98\u8d34\u8def\u5f84\uff0c\u786e\u5b9a\u5373\u53ef
\u65e0\u6cd5\u6253\u5f00\u8d44\u6e90\u7ba1\u7406\u5668\:\ =\u65e0\u6cd5\u6253\u5f00\u8d44\u6e90\u7ba1\u7406\u5668:
\u63d0\u793a=\u63d0\u793a
\u8f93\u5165\u65b0\u7248\u672c\u540d\u79f0=\u8f93\u5165\u65b0\u7248\u672c\u540d\u79f0
\u540d\u79f0=\u540d\u79f0
\u4fdd\u5b58\u5931\u8d25=\u4fdd\u5b58\u5931\u8d25
\u4fdd\u5b58\u538b\u7f29\u5305\u5230=\u4fdd\u5b58\u538b\u7f29\u5305\u5230
\u9009\u62e9\u6750\u8d28\u5305=\u9009\u62e9\u6750\u8d28\u5305
\u9009\u62e9\u8d44\u6e90\u5305=\u9009\u62e9\u8d44\u6e90\u5305
\u9009\u62e9\u5e93/\u6a21\u7ec4=\u9009\u62e9\u5e93/\u6a21\u7ec4
\u6ca1\u6709\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u5e93/\u6a21\u7ec4\u3002=\u6ca1\u6709\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u5e93/\u6a21\u7ec4\u3002
\u5220\u9664\u5931\u8d25=\u5220\u9664\u5931\u8d25
\u6dfb\u52a0\u5931\u8d25=\u6dfb\u52a0\u5931\u8d25
\u9009\u62e9\u6a21\u7ec4=\u9009\u62e9\u6a21\u7ec4
\u7248\u672c\u540d\u79f0\u4e0d\u80fd\u4e3a\u7a7a=\u7248\u672c\u540d\u79f0\u4e0d\u80fd\u4e3a\u7a7a
\u5907\u4efd\u5230=\u5907\u4efd\u5230
\u662fCOREODS\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6838\u5fc3\u6a21\u7ec4=\u662fCoremods\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6838\u5fc3\u6a21\u7ec4
\u662fMODS\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6a21\u7ec4=\u662fMods\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6a21\u7ec4
\u901a\u5e38\u662f\u6a21\u7ec4=\u901a\u5e38\u662f\u6a21\u7ec4
\u4e0b\u79fb=\u4e0b\u79fb
\u4e0a\u79fb=\u4e0a\u79fb
\u5220\u9664=\u5220\u9664
\u589e\u52a0=\u589e\u52a0
\u901a\u5e38\u662fFORGE,MODLOADER\u4ee5\u53caMINECRAFT\u6240\u4f9d\u8d56\u7684\u5e93=\u901a\u5e38\u662fForge,Modloader\u4ee5\u53caMinecraft\u6240\u4f9d\u8d56\u7684\u5e93
\u9644\u52a0\u542f\u52a8\u53c2\u6570=\u9644\u52a0\u542f\u52a8\u53c2\u6570
\u81ea\u5b9a\u4e49\u5e93\u6587\u4ef6\u5939(LIBRARIES\u6587\u4ef6\u5939)=\u81ea\u5b9a\u4e49\u5e93\u6587\u4ef6\u5939(libraries\u6587\u4ef6\u5939)
\u4e3b\u7c7b=\u4e3b\u7c7b
\u81ea\u5b9a\u4e49\u8d44\u6e90\u6587\u4ef6\u5939(ASSETS\u6587\u4ef6\u5939)=\u81ea\u5b9a\u4e49\u8d44\u6e90\u6587\u4ef6\u5939(assets\u6587\u4ef6\u5939)
\u624b\u52a8\u8bbe\u7f6e=\u624b\u52a8\u8bbe\u7f6e
\u4e0d\u5f3a\u5236=\u4e0d\u5f3a\u5236
32\u4f4d=32\u4f4d
64\u4f4d=64\u4f4d
\u542f\u52a8\u6a21\u5f0f=\u542f\u52a8\u6a21\u5f0f
\u73a9\u5bb6\u540d=\u73a9\u5bb6\u540d
1.6\u53ca\u4ee5\u4e0a\u7248\u672c\u4ee5\u53ca\u5bfc\u5165\u7684\u65e7\u7248\u672c=1.6\u53ca\u4ee5\u4e0a\u7248\u672c\u4ee5\u53ca\u5bfc\u5165\u7684\u65e7\u7248\u672c
\u6700\u5927\u5185\u5b58=\u6700\u5927\u5185\u5b58\uff08MB\uff09
JAVA\u865a\u62df\u673a\u53c2\u6570=Java\u865a\u62df\u673a\u53c2\u6570
JAVA\u8def\u5f84=Java\u8def\u5f84
\u5168\u5c4f=\u5168\u5c4f
\u5206\u8fa8\u7387=\u5206\u8fa8\u7387
\u6e38\u620f\u8def\u5f84=\u6e38\u620f\u8def\u5f84
\u4ee5\u4e0b\u8bbe\u7f6e\u5b57\u6bb5\u4e3a\u7a7a\u4ee3\u8868\u7740\u4f7f\u7528\u9ed8\u8ba4\u8bbe\u7f6e=\u9664\u540d\u79f0\u4ee5\u4e0b\u5b57\u6bb5\u53ef\u4ee5\u4e0d\u586b
\u53d6\u6d88=\u53d6\u6d88
\u786e\u5b9a=\u786e\u5b9a
game_download=\u6e38\u620f\u4e0b\u8f7d
public_settings=\u5168\u5c40\u8bbe\u7f6e
invalid=\u65e0\u6548\u7684
invalid_jar=\u65e0\u6548\u7684jar\u5305
not_a_file=\u4e0d\u662f\u6587\u4ef6
not_found=\u627e\u4e0d\u5230minecraft.jar
not_readable=minecraft.jar\u4e0d\u53ef\u8bfb
modified=(\u4fee\u6539\u7684!)
\u83b7\u53d6\u4e2d=\u83b7\u53d6\u4e2d
\u63d2\u4ef6\u9519\u8bef=\u63d2\u4ef6\u9519\u8bef
CannotLoadPluginsBecauseOfAnError=\u65e0\u6cd5\u52a0\u8f7d\u63d2\u4ef6\uff0c\u56e0\u4e3a\u53d1\u751f\u4e86\u4e00\u4e2a\u9519\u8bef\u3002
CRASH\ REPORT\ DETECTED,\ BUT\ UNKNOWN\ FORMAT\:=Crash report detected, but unknown format:
COULDN'T\ OPEN\ CRASH\ REPORT=Couldn't open crash report
CRASH\ REPORT\ DETECTED,\ OPENING\:=Crash report detected, opening:
MinecraftCrashed=Minecraft\u5d29\u6e83\u4e86\uff01(\u9519\u8bef\u4ee3\u7801:{0})
RememberMe=\u8bb0\u4f4f\u6211
Logout=\u767b\u51fa
ShowIfIsLoaded=\u663e\u793a\u63d2\u4ef6\u662f\u5426\u52a0\u8f7d\uff0c\u70b9\u51fb\u67e5\u770b\u9519\u8bef
IsLoaded=\u662f\u5426\u52a0\u8f7d
PluginSettings=\u63d2\u4ef6\u8bbe\u7f6e
Details=\u4fe1\u606f
Authors=\u4f5c\u8005
Version=\u7248\u672c
Name=\u540d\u79f0
CheckUpdate=\u68c0\u67e5\u672c\u542f\u52a8\u5668\u7684\u66f4\u65b0
DownloadSource=\u4e0b\u8f7d\u6e90
DisableMoveMods=\u7981\u6b62\u7248\u672c\u81ea\u6709\u6a21\u7ec4\uff08\u79fb\u52a8\u6a21\u7ec4\uff09\u529f\u80fd
ShowConsoleOutput=\u5c31\u662fMinecraft\u7684\u63a7\u5236\u53f0\u8f93\u51fa
MinecraftLocation=Minecraft\u8def\u5f84\uff08\u5373.minecraft\u6587\u4ef6\u5939\uff09
MaxMemoryTooltip=\u5141\u8bb8Minecraft\u6700\u591a\u5141\u8bb8\u4f7f\u7528\u7684\u5185\u5b58\uff08\u770b\u4e0d\u61c2\u5c31\u4f7f\u7528\u9ed8\u8ba4\u76841024\u5427\uff09
FailedToLoad=\u52a0\u8f7d\u5931\u8d25
Loaded=\u5df2\u52a0\u8f7d
NoCharacter=\u8be5\u5e10\u53f7\u6ca1\u6709\u89d2\u8272
LegacyLogin=\u65e7\u7248\u6b63\u7248\u767b\u5f55
YggdrasilLogin=\u65b0\u7248\u6b63\u7248\u767b\u5f55
PleaseChooseCharacter=\u8bf7\u9009\u62e9\u60a8\u8981\u4f7f\u7528\u7684\u89d2\u8272
WrongPassword=\u53ef\u80fd\u662f\u60a8\u7684\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef
OfflineLogin=\u79bb\u7ebf\u6a21\u5f0f
GameDownload=\u6e38\u620f\u4e0b\u8f7d
IntegrateDownload=\u6574\u5408\u5305\u4e0b\u8f7d
AssetsDownload=\u8d44\u6e90\u4e0b\u8f7d
Installers=\u81ea\u52a8\u5b89\u88c5
WorldSaving=\u5907\u4efd\u5730\u56fe
ServerEditor=\u670d\u52a1\u5668\u7f16\u8f91
TexturepackEditor=\u6750\u8d28\u5305\u7ba1\u7406
Refresh=\u5237\u65b0\u5217\u8868
Install=\u5b89\u88c5
AssetsType=\u8d44\u6e90\u7c7b\u578b
InstallOptifine=\u5b89\u88c5\u9009\u4e2d\u7684Optifine
Changelog=\u66f4\u65b0\u4fe1\u606f
InstallForge=\u5b89\u88c5\u9009\u4e2d\u7684Forge
ModManaging=\u6a21\u7ec4\u7ba1\u7406
PluginCenter=\u63d2\u4ef6\u4e2d\u5fc3
ExtMods=\u5916\u90e8\u6a21\u7ec4
CoreMods=\u6838\u5fc3\u6a21\u7ec4
NormalSettings=\u666e\u901a\u8bbe\u7f6e
1.6AndAbove=1.6\u53ca\u4ee5\u4e0a
1.5AndBelow=1.5\u53ca\u4ee5\u4e0b
IsActive=\u6d3b\u52a8
Location=\u8def\u5f84
Type=\u7c7b\u578b
ReleaseTime=\u91ca\u653e\u65f6\u95f4
Time=\u53d1\u5e03\u65f6\u95f4
Version=\u7248\u672c
MCVersion=MC\u7248\u672c
IntegrateName=\u6574\u5408\u5305\u540d\u79f0
IntegrateVersion=\u6574\u5408\u5305\u7248\u672c
ServerName=\u670d\u52a1\u5668\u540d\u79f0
HideAddress=\u9690\u85cf\u5730\u5740
Address=\u5730\u5740
Introduction=\u4ecb\u7ecd
Online=\u5728\u7ebf
Delay=\u5ef6\u8fdf
Clear=\u6e05\u9664
Close=\u5173\u95ed
Save=\u4fdd\u5b58
JoinMinecraftJar=\u52a0\u5165minecraft.jar
ExternalMods=\u5916\u90e8\u6a21\u7ec4
DynamicLoadingMods=\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4
Libraries=\u5e93
TagArguments=\u9644\u52a0\u7ed9\u4e88Minecraft\u7684\u53c2\u6570
MainClass=Minecraft\u7684\u4e3b\u7c7b\uff08\u4e0d\u77e5\u9053\u4ec0\u4e48\u610f\u601d\u7684\u8bdd\u4e5f\u5c31\u7528\u4e0d\u4e0a\u4e86\uff09
DefaultLibrariesFolder=\u9ed8\u8ba4\u4e3a.minecraft/libraries\u6587\u4ef6\u5939
DefaultAssetsFolder=\u9ed8\u8ba4\u4e3a.minecraft/assets\u6587\u4ef6\u5939
MakeMCMaximum=\u4f7fMinecraft\u7a97\u53e3\u6700\u5927\u5316
MCFolderFormat=\u5c31\u662fMinecraft\u6587\u4ef6\u5939\u683c\u5f0f
MakeMCFullscreen=\u4f7fMinecraft\u7a97\u53e3\u5168\u5c4f
MCHeight=Minecraft\u7a97\u53e3\u9ad8
MCWidth=Minecraft\u7a97\u53e3\u5bbd
Personalization=\u4e2a\u6027\u5316
MaxPermGen=\u6700\u5927\u6c38\u4e45\u4fdd\u5b58\u533a\u57df\uff08MB\uff09
Options=\u8bbe\u7f6e
Setup=\u8bbe\u7f6e
@@ -1,230 +0,0 @@
\u6e38\u620f\u7248\u672c=Game versions
\u8fd9\u4e2aMINECRAFT\u6587\u4ef6\u5939\u65e2\u4e0d\u662f1.6\u7248\u4e5f\u4e0d\u662f\u65e7\u7248\u7684\u600e\u4e48\u5bfc\u5165\u561b0V0\u3002=This chosen minecraft folder is not a format of version 1.6 above or 1.5 below, so the launcher cannot import it.
\u672a\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u7248\u672c=Not version selected.
\u5bfc\u5165\u5931\u8d25\:\ {0}=Failed to include: {0}
\u627e\u5230\u540c\u540d\u7684MINECRAFT\u7248\u672c\uff0c\u8bf7\u6362\u7528\u53e6\u4e00\u4e2a\u540d\u79f0=Already existed a Minecraft version which has same name, please use another name.
\u8bf7\u8f93\u5165\u8be5\u65e7\u7248\u672c\u7684\u540d\u79f0=Please enter the name of this old version
\u627e\u4e0d\u5230MINECRAFT.JAR=Cannot find minecraft.jar
\u9009\u62e9MINECRAFT\u8def\u5f84=Choose Minecraft path
\u542f\u52a8\u5931\u8d25=Failed to launch
\u590d\u5236\u914d\u7f6e\u6587\u4ef6\u5931\u8d25\:\ =Failed to copy config folder:
\u590d\u5236\u6838\u5fc3\u6a21\u7ec4\u5931\u8d25\:\ =Failed to copy coremods folder:
\u590d\u5236\u666e\u901a\u6a21\u7ec4\u5931\u8d25\:\ =Failed to copy mods foler:
\u4e0b\u8f7d\u7f3a\u5931\u5e93\uff1a{0}=Download missing libraries\uff1a{0}
\u6ca1\u6709\u9009\u62e9\u4efb\u4f55\u4e00\u4e2aMINECRAFT\u7248\u672c=Not version selected.
\u9519\u8bef\u7684MINECRAFT\u8def\u5f84=An erroneous Minecraft path.
\u5173\u4e8e=About
\u4e0b\u8f7d=Download
\u5bc6\u7801=Password
\u624b\u52a8\u8bbe\u7f6e=Select
\u4e0d\u9650\u5236=Default
32\u4f4d=32 bit
64\u4f4d=64 bit
\u542f\u52a8\u6a21\u5f0f=Launch mode
\u6700\u5927\u5185\u5b58=Max memory(MB)
\u6e38\u620f\u540d\u79f0=User name
\u6e38\u620f\u8def\u5f84=Game location
\u5bfc\u5165\u6587\u4ef6\u5939=Import folder
\u65b0\u5efa=New
\u5220\u9664=Delete
\u7f16\u8f91=Edit
\u590d\u5236=Copy
\u5bfc\u5165\u65e7\u7248\u672c=Import old version
\u5236\u4f5c\u4e00\u952e\u542f\u52a8=Make bat/sh launcher
\u51c6\u5907\u4e2d=Preparing
\u5f00\u59cbMINECRAFT\u4e4b\u65c5!=Enjoy Minecraft now!
\u5237\u65b0=Refresh
game_download=Game downloads
public_settings=Public settings
\u8bbe\u7f6e\u5931\u8d25\uff1a=Failed to set\uff1a
\u7f3a\u5931\u5e93\u4e0b\u8f7d=Download missing libraries
\u9009\u62e9\u80cc\u666f\u8def\u5f84=Choose background image path
MineLogin0=Network error
MineLogin1=User name or password is incorrect
MineLogin2=Internal error
MineLogin3=User does not exist
MineLogin4=Need to verify
MineLogin5=Wrong password
ForgeMod=Forge mod
ModLoaderMod=ModLoader mod
Forge=Forge
ModLoader=ModLoader
Unknown=Unknown
Mods\u6587\u4ef6\u5939=Mods folder
Coremods\u6587\u4ef6\u5939=Coremods folder
Mod\u72ec\u7acb\u6587\u4ef6\u5939=Moddir folder
\u914d\u7f6e\u6587\u4ef6\u5939=Config folder
\u767b\u5f55\u5931\u8d25\uff1a=Failed to login
\u9009\u62e9\u5931\u8d25=Failed to select
\u63d2\u4ef6\u9519\u8bef\uff1a=Plugin error\uff1a
\u767b\u5f55\u5931\u8d25\uff1a=Failed to login\uff1a
\u6ca1\u6709\u767b\u5165\u65b9\u5f0f...=No sign...
\u4fdd\u5b58=Save
\u767b\u5f55\u6a21\u5f0f=Log-In mode
\u7248\u672c\u7f16\u8f91=Preferences
\u7248\u672c\u53f7=Version
\u5bfc\u5165=Import
\u64cd\u4f5c=Operations
\u4e0b\u8f7d\u4fe1\u606f=Download Info
\u5b89\u88c5=Install
\u6dfb\u52a0=Add
\u5168\u90e8\u4e0b\u8f7d=Download all
\u52a0\u5165MINECRAFT.JAR=Join minecraft.jar
\u7ba1\u7406=Managings
\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4=Dynamic Loading Mods
\u5e93=Libraries
AdvancedSettings=Advanced
\u6700\u5927\u5316=Maximized
\u68c0\u67e5\u66f4\u65b0=Check for updates
\u67e5\u770b\u65e5\u5fd7=View Log
\u80cc\u666f\u5730\u5740=Background Location
UNEXPECTED\ EXCEPTION\ LOADING\ =Unexpected exception loading
\u5f53\u524d\u662f\u6700\u65b0\u7248\u672c=This is the latest version
\u65e0\u6cd5\u6253\u5f00\u6d4f\u89c8\u5668\uff0c\u7f51\u5740\u5df2\u7ecf\u590d\u5236\u5230\u526a\u8d34\u677f\u4e86\uff0c\u60a8\u53ef\u4ee5\u624b\u52a8\u7c98\u8d34\u7f51\u5740\u6253\u5f00\u9875\u9762=Unable to open the browser, the URL has been copied to the clipboard, you can paste the URL manually open the page
\u662f\u5426\u524d\u5f80\u53d1\u5e03\u9875\u9762\u66f4\u65b0\uff1f=Do you wish to go to the publishing page to update?
\u66f4\u65b0\u4fe1\u606f\u4e3a\:\ =Update notes:
\u6700\u65b0\u7248\u672c\u4e3a\uff1a=Latest version\uff1a
\u68c0\u67e5\u66f4\u65b0\u5931\u8d25=Failed to check update
\u8fde\u63a5\u4e2d=Connecting
\u83b7\u53d6\u5217\u8868\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u91cd\u8bd5=Failed to get the list, please retry to refresh
INVALID\ PLUGIN=Invalid plugin
\u65e0\u6cd5\u8fde\u63a5=Unable to connect
\ \u5dee\ ORANGERED=\ Bad orangered
\ \u8f83\u5dee\ ORANGE=\ Not good orange
\ \u4e2d\ YELLOGREEN=\ So-so yellogreen
\ \u8f83\u597d\ BLUE=\ OK blue
\ \u597d\ GREEN=\ Good green
\u670d\u52a1\u5668{0}\u7684\u56de\u590d\u65e0\u6548=The reply of the server {0} is invalid
\u63a5\u4e0b\u6765\u5f39\u51fa\u6765\u7684\u7a97\u53e3\u91cc\u8bf7\u9009\u62e9\u8def\u5f84\u4e3a\u6e38\u620f\u8def\u5f84\u3002\u7a0b\u5e8f\u5df2\u7ecf\u5c06\u76ee\u5f55\u590d\u5236\u5230\u4e86\u526a\u8d34\u677f\uff0c\u76f4\u63a5\u5728\u7a97\u53e3\u91cc\u9009\u62e9\\"...\\"\u6309\u94ae\uff0c\u7c98\u8d34\u8def\u5f84\uff0c\u786e\u5b9a\u5373\u53ef=In the next pop-up window, select the path as the game paths. Launcher has been copied the directory to the clipboard. In the window, choose \\"...\\" button, paste the path, and click OK. It can be determined.
\u65e0\u6cd5\u6253\u5f00\u8d44\u6e90\u7ba1\u7406\u5668\:\ =Can not open Explorer:
\u63d0\u793a=Notice
\u8f93\u5165\u65b0\u7248\u672c\u540d\u79f0=Enter the name of the new version
\u540d\u79f0=Name
\u4fdd\u5b58\u5931\u8d25=Failed to save
\u4fdd\u5b58\u538b\u7f29\u5305\u5230=Save zip file to
\u9009\u62e9\u6750\u8d28\u5305=Choose texture pack
\u9009\u62e9\u8d44\u6e90\u5305=Choose resource pack
\u9009\u62e9\u5e93/\u6a21\u7ec4=Choose library/mod
\u6ca1\u6709\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u5e93/\u6a21\u7ec4\u3002=Not selected any library/mod.
\u5220\u9664\u5931\u8d25=Failed to delete
\u6dfb\u52a0\u5931\u8d25=Failed to add
\u9009\u62e9\u6a21\u7ec4=Choose mod
\u7248\u672c\u540d\u79f0\u4e0d\u80fd\u4e3a\u7a7a=Version name cannot be empty.
\u5907\u4efd\u5230=Backup to
\u662fCOREODS\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6838\u5fc3\u6a21\u7ec4=They're all the core mods in coremods folder.
\u662fMODS\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6a21\u7ec4=They're all the mods in mods folder.
\u901a\u5e38\u662f\u6a21\u7ec4=Usually mods.
\u4e0b\u79fb=Down
\u4e0a\u79fb=Up
\u5220\u9664=Delete
\u589e\u52a0=Add
\u901a\u5e38\u662fFORGE,MODLOADER\u4ee5\u53caMINECRAFT\u6240\u4f9d\u8d56\u7684\u5e93=They're usually Forge, Modloader and libraries.
\u9644\u52a0\u542f\u52a8\u53c2\u6570=Addition arguments
\u81ea\u5b9a\u4e49\u5e93\u6587\u4ef6\u5939(LIBRARIES\u6587\u4ef6\u5939)=Customize libraries folder
\u4e3b\u7c7b=Main class
\u81ea\u5b9a\u4e49\u8d44\u6e90\u6587\u4ef6\u5939(ASSETS\u6587\u4ef6\u5939)=Customize assets folder
\u624b\u52a8\u8bbe\u7f6e=Manually set
\u4e0d\u5f3a\u5236=Default
32\u4f4d=32 bit
64\u4f4d=64 bit
\u542f\u52a8\u6a21\u5f0f=Launch mode
\u73a9\u5bb6\u540d=Player name
1.6\u53ca\u4ee5\u4e0a\u7248\u672c\u4ee5\u53ca\u5bfc\u5165\u7684\u65e7\u7248\u672c=Version 1.6 and above, and imported the old version
\u6700\u5927\u5185\u5b58=Max memory
JAVA\u865a\u62df\u673a\u53c2\u6570=JVM arguments
JAVA\u8def\u5f84=Java path
\u5168\u5c4f=Fullscreen
\u5206\u8fa8\u7387=Resolution
\u6e38\u620f\u8def\u5f84=Game dir
\u4ee5\u4e0b\u8bbe\u7f6e\u5b57\u6bb5\u4e3a\u7a7a\u4ee3\u8868\u7740\u4f7f\u7528\u9ed8\u8ba4\u8bbe\u7f6e=These field could not fill except the name field.
\u53d6\u6d88=Cancel
\u786e\u5b9a=Ok
invalid=invalid
invalid_jar=invalid jar
not_a_file=not a file
not_found=not found
not_readable=not readable
modified=(modified!)
\u83b7\u53d6\u4e2d=Loading
\u63d2\u4ef6\u9519\u8bef=Plugin error
CannotLoadPluginsBecauseOfAnError=Cannot load plugins because an error occurred.
CRASH\ REPORT\ DETECTED,\ BUT\ UNKNOWN\ FORMAT\:=Crash report detected, but unknown format:
COULDN'T\ OPEN\ CRASH\ REPORT=Couldn't open crash report
CRASH\ REPORT\ DETECTED,\ OPENING\:=Crash report detected, opening:
MinecraftCrashed=Minecraft crashed! (Error code: {0})
RememberMe=Remember me
Logout=Log out
ShowIfIsLoaded=To show if plugins are loaded.
IsLoaded=Is loaded
PluginSettings=Plugin settings
Details=Details
Authors=Authors
Version=Version
Name=Name
CheckUpdate=Check for update
DownloadSource=Download source
DisableMoveMods=Disable moving mods.
ShowConsoleOutput=To show Minecraft console output.
MinecraftLocation=Minecraft location
MaxMemoryTooltip=Maximum memory(default 1024)
FailedToLoad=Failed to load
Loaded=Loaded
NoCharacter=No characters
LegacyLogin=Legacy
YggdrasilLogin=Yggdrasil
PleaseChooseCharacter=Please choose the character you want to use.
WrongPassword=Maybe your user name or password is wrong.
OfflineLogin=Offline
GameDownload=Downloads
IntegrateDownload=Integrate Packs
AssetsDownload=Assets
Installers=Installers
WorldSaving=World Backups
ServerEditor=Server List
TexturepackEditor=Texturepacks
Refresh=Refresh
AssetsType=Type
Install=Install
InstallOptifine=Install selected Optifine
Changelog=Changelog
InstallForge=Install selected Forge
ModManaging=Mods
PluginCenter=Plugins
ExtMods=External Mods
CoreMods=Core Mods
NormalSettings=Normal
1.6AndAbove=1.6 And Above
1.5AndBelow=1.5 And Below
IsActive=Active
Location=Location
Type=Type
ReleaseTime=Release Time
Time=Time
Version=Version
MCVersion=MC Version
IntegrateName=Pack Name
IntegrateVersion=Pack Version
ServerName=Server Name
HideAddress=Hide Address
Address=Address
Introduction=Introduction
Online=Online
Delay=Delay
Clear=Clear
Close=Close
Save=Save
JoinMinecraftJar=Join minecraft.jar
ExternalMods=External Mods
DynamicLoadingMods=Dynamic Loading Mods
Libraries=Libraries
TagArguments=Tag Args
MainClass=Minecraft Main Class
DefaultLibrariesFolder=Default: .minecraft/libraries
DefaultAssetsFolder=Default: .minecraft/assets
MakeMCMaximum=Make Minecraft Maximum
MCFolderFormat=Minecraft Folder format
MakeMCFullscreen=Make Minecraft fullscreen
MCHeight=Minecraft window height
MCWidth=Minecraft window width
Personalization=Personalization
MaxPermGen=Max PermGen Size(MB)
@@ -1,236 +0,0 @@
# To change this template, choose Tools | Templates
# and open the template in the editor.
\u6e38\u620f\u7248\u672c=\u6e38\u620f\u7248\u672c
\u8fd9\u4e2aMINECRAFT\u6587\u4ef6\u5939\u65e2\u4e0d\u662f1.6\u7248\u4e5f\u4e0d\u662f\u65e7\u7248\u7684\u600e\u4e48\u5bfc\u5165\u561b0V0\u3002=\u8fd9\u4e2aminecraft\u6587\u4ef6\u5939\u65e2\u4e0d\u662f1.6\u7248\u4e5f\u4e0d\u662f\u65e7\u7248\u7684\u600e\u4e48\u5bfc\u5165\u561b0v0\u3002
\u672a\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u7248\u672c=\u672a\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u7248\u672c
\u5bfc\u5165\u5931\u8d25\:\ {0}=\u5bfc\u5165\u5931\u8d25: {0}
\u627e\u5230\u540c\u540d\u7684MINECRAFT\u7248\u672c\uff0c\u8bf7\u6362\u7528\u53e6\u4e00\u4e2a\u540d\u79f0=\u627e\u5230\u540c\u540d\u7684Minecraft\u7248\u672c\uff0c\u8bf7\u6362\u7528\u53e6\u4e00\u4e2a\u540d\u79f0
\u8bf7\u8f93\u5165\u8be5\u65e7\u7248\u672c\u7684\u540d\u79f0=\u8bf7\u8f93\u5165\u8be5\u65e7\u7248\u672c\u7684\u540d\u79f0
\u627e\u4e0d\u5230MINECRAFT.JAR=\u627e\u4e0d\u5230minecraft.jar
\u9009\u62e9MINECRAFT\u8def\u5f84=\u9009\u62e9Minecraft\u8def\u5f84
\u542f\u52a8\u5931\u8d25=\u542f\u52a8\u5931\u8d25
\u590d\u5236\u914d\u7f6e\u6587\u4ef6\u5931\u8d25\:\ =\u590d\u5236\u914d\u7f6e\u6587\u4ef6\u5931\u8d25:
\u590d\u5236\u6838\u5fc3\u6a21\u7ec4\u5931\u8d25\:\ =\u590d\u5236\u6838\u5fc3\u6a21\u7ec4\u5931\u8d25:
\u590d\u5236\u666e\u901a\u6a21\u7ec4\u5931\u8d25\:\ =\u590d\u5236\u666e\u901a\u6a21\u7ec4\u5931\u8d25:
\u4e0b\u8f7d\u7f3a\u5931\u5e93\uff1a{0}=\u4e0b\u8f7d\u7f3a\u5931\u5e93\uff1a{0}
\u6ca1\u6709\u9009\u62e9\u4efb\u4f55\u4e00\u4e2aMINECRAFT\u7248\u672c=\u6ca1\u6709\u9009\u62e9\u4efb\u4f55\u4e00\u4e2aMinecraft\u7248\u672c
\u9519\u8bef\u7684MINECRAFT\u8def\u5f84=\u9519\u8bef\u7684Minecraft\u8def\u5f84
\u5173\u4e8e=\u5173\u4e8e
\u4e0b\u8f7d=\u4e0b\u8f7d
\u5bc6\u7801=\u5bc6\u7801
\u624b\u52a8\u8bbe\u7f6e=\u624b\u52a8\u8bbe\u7f6e
\u4e0d\u9650\u5236=\u4e0d\u9650\u5236
32\u4f4d=32\u4f4d
64\u4f4d=64\u4f4d
\u542f\u52a8\u6a21\u5f0f=\u542f\u52a8\u6a21\u5f0f
\u6700\u5927\u5185\u5b58=\u6700\u5927\u5185\u5b58
\u6e38\u620f\u540d\u79f0=\u540d\u5b57
\u6e38\u620f\u8def\u5f84=\u6e38\u620f\u8def\u5f84
\u5bfc\u5165\u6587\u4ef6\u5939=\u5bfc\u5165\u6587\u4ef6\u5939
\u65b0\u5efa=\u65b0\u5efa
\u5220\u9664=\u5220\u9664
\u7f16\u8f91=\u7f16\u8f91
\u590d\u5236=\u590d\u5236
\u5bfc\u5165\u65e7\u7248\u672c=\u5bfc\u5165\u65e7\u7248\u672c
\u5236\u4f5c\u4e00\u952e\u542f\u52a8=\u5236\u4f5c\u4e00\u952e\u542f\u52a8
\u51c6\u5907\u4e2d=\u51c6\u5907\u4e2d
\u5f00\u59cbMINECRAFT\u4e4b\u65c5!=\u5f00\u59cbMinecraft\u4e4b\u65c5!
\u5237\u65b0=\u5237\u65b0
public_settings=\u5168\u5c40\u8bbe\u7f6e
game_download=\u6e38\u620f\u4e0b\u8f7d
\u8bbe\u7f6e\u5931\u8d25\uff1a=\u8bbe\u7f6e\u5931\u8d25\uff1a
\u7f3a\u5931\u5e93\u4e0b\u8f7d=\u7f3a\u5931\u5e93\u4e0b\u8f7d
\u9009\u62e9\u80cc\u666f\u8def\u5f84=\u9009\u62e9\u80cc\u666f\u8def\u5f84
MineLogin0=\u7f51\u7edc\u9519\u8bef
MineLogin1=\u7528\u6237\u540d\u6216\u5bc6\u7801\u4e0d\u5408\u6cd5
MineLogin2=\u5185\u90e8\u9519\u8bef
MineLogin3=\u7528\u6237\u4e0d\u5b58\u5728
MineLogin4=\u9700\u8981\u9a8c\u8bc1
MineLogin5=\u5bc6\u7801\u9519\u8bef
ForgeMod=Forge mod
ModLoaderMod=ModLoader mod
Forge=Forge
ModLoader=ModLoader
Unknown=\u672a\u77e5
Mods\u6587\u4ef6\u5939=Mods\u6587\u4ef6\u5939
Coremods\u6587\u4ef6\u5939=Coremods\u6587\u4ef6\u5939
Mod\u72ec\u7acb\u6587\u4ef6\u5939=Mod\u72ec\u7acb\u6587\u4ef6\u5939
\u914d\u7f6e\u6587\u4ef6\u5939=\u914d\u7f6e\u6587\u4ef6\u5939
\u767b\u5f55\u5931\u8d25\uff1a=\u767b\u5f55\u5931\u8d25\uff1a
\u9009\u62e9\u5931\u8d25=\u9009\u62e9\u5931\u8d25
\u63d2\u4ef6\u9519\u8bef\uff1a=\u63d2\u4ef6\u9519\u8bef\uff1a
\u767b\u5f55\u5931\u8d25\uff1a=\u767b\u5f55\u5931\u8d25\uff1a
\u6ca1\u6709\u767b\u5165\u65b9\u5f0f...=\u6ca1\u6709\u767b\u5165\u65b9\u5f0f...
\u4fdd\u5b58=\u4fdd\u5b58
\u767b\u5f55\u6a21\u5f0f=\u767b\u5f55\u6a21\u5f0f
\u7248\u672c\u7f16\u8f91=\u7248\u672c\u7f16\u8f91
\u7248\u672c\u53f7=\u7248\u672c\u53f7
\u5bfc\u5165=\u5bfc\u5165
\u64cd\u4f5c=\u64cd\u4f5c
\u4e0b\u8f7d\u4fe1\u606f=\u4e0b\u8f7d\u4fe1\u606f
\u5b89\u88c5=\u5b89\u88c5
\u6dfb\u52a0=\u6dfb\u52a0
\u5168\u90e8\u4e0b\u8f7d=\u5168\u90e8\u4e0b\u8f7d
\u52a0\u5165MINECRAFT.JAR=\u52a0\u5165minecraft.jar
\u7ba1\u7406=\u7ba1\u7406
\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4=\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4
\u5e93=\u5e93
AdvancedSettings=\u9ad8\u7ea7\u8bbe\u7f6e
\u6700\u5927\u5316=\u6700\u5927\u5316
\u68c0\u67e5\u66f4\u65b0=\u68c0\u67e5\u66f4\u65b0
\u67e5\u770b\u65e5\u5fd7=\u67e5\u770b\u65e5\u5fd7
\u80cc\u666f\u5730\u5740=\u80cc\u666f\u5730\u5740
UNEXPECTED\ EXCEPTION\ LOADING\ =Unexpected exception loading
\u5f53\u524d\u662f\u6700\u65b0\u7248\u672c=\u5f53\u524d\u662f\u6700\u65b0\u7248\u672c
\u65e0\u6cd5\u6253\u5f00\u6d4f\u89c8\u5668\uff0c\u7f51\u5740\u5df2\u7ecf\u590d\u5236\u5230\u526a\u8d34\u677f\u4e86\uff0c\u60a8\u53ef\u4ee5\u624b\u52a8\u7c98\u8d34\u7f51\u5740\u6253\u5f00\u9875\u9762=\u65e0\u6cd5\u6253\u5f00\u6d4f\u89c8\u5668\uff0c\u7f51\u5740\u5df2\u7ecf\u590d\u5236\u5230\u526a\u8d34\u677f\u4e86\uff0c\u60a8\u53ef\u4ee5\u624b\u52a8\u7c98\u8d34\u7f51\u5740\u6253\u5f00\u9875\u9762
\u662f\u5426\u524d\u5f80\u53d1\u5e03\u9875\u9762\u66f4\u65b0\uff1f=\u662f\u5426\u524d\u5f80\u53d1\u5e03\u9875\u9762\u66f4\u65b0\uff1f
\u66f4\u65b0\u4fe1\u606f\u4e3a\:\ =\u66f4\u65b0\u4fe1\u606f\u4e3a:
\u6700\u65b0\u7248\u672c\u4e3a\uff1a=\u6700\u65b0\u7248\u672c\u4e3a\uff1a
\u68c0\u67e5\u66f4\u65b0\u5931\u8d25=\u68c0\u67e5\u66f4\u65b0\u5931\u8d25
\u8fde\u63a5\u4e2d=\u8fde\u63a5\u4e2d
\u83b7\u53d6\u5217\u8868\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u91cd\u8bd5=\u83b7\u53d6\u5217\u8868\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u91cd\u8bd5
INVALID\ PLUGIN=Invalid plugin
\u65e0\u6cd5\u8fde\u63a5=\u65e0\u6cd5\u8fde\u63a5
\ \u5dee\ ORANGERED=\ \u5dee orangered
\ \u8f83\u5dee\ ORANGE=\ \u8f83\u5dee orange
\ \u4e2d\ YELLOGREEN=\ \u4e2d yellogreen
\ \u8f83\u597d\ BLUE=\ \u8f83\u597d blue
\ \u597d\ GREEN=\ \u597d green
\u670d\u52a1\u5668{0}\u7684\u56de\u590d\u65e0\u6548=\u670d\u52a1\u5668{0}\u7684\u56de\u590d\u65e0\u6548
\u63a5\u4e0b\u6765\u5f39\u51fa\u6765\u7684\u7a97\u53e3\u91cc\u8bf7\u9009\u62e9\u8def\u5f84\u4e3a\u6e38\u620f\u8def\u5f84\u3002\u7a0b\u5e8f\u5df2\u7ecf\u5c06\u76ee\u5f55\u590d\u5236\u5230\u4e86\u526a\u8d34\u677f\uff0c\u76f4\u63a5\u5728\u7a97\u53e3\u91cc\u9009\u62e9\\"...\\"\u6309\u94ae\uff0c\u7c98\u8d34\u8def\u5f84\uff0c\u786e\u5b9a\u5373\u53ef=\u63a5\u4e0b\u6765\u5f39\u51fa\u6765\u7684\u7a97\u53e3\u91cc\u8bf7\u9009\u62e9\u8def\u5f84\u4e3a\u6e38\u620f\u8def\u5f84\u3002\u7a0b\u5e8f\u5df2\u7ecf\u5c06\u76ee\u5f55\u590d\u5236\u5230\u4e86\u526a\u8d34\u677f\uff0c\u76f4\u63a5\u5728\u7a97\u53e3\u91cc\u9009\u62e9\\"...\\"\u6309\u94ae\uff0c\u7c98\u8d34\u8def\u5f84\uff0c\u786e\u5b9a\u5373\u53ef
\u65e0\u6cd5\u6253\u5f00\u8d44\u6e90\u7ba1\u7406\u5668\:\ =\u65e0\u6cd5\u6253\u5f00\u8d44\u6e90\u7ba1\u7406\u5668:
\u63d0\u793a=\u63d0\u793a
\u8f93\u5165\u65b0\u7248\u672c\u540d\u79f0=\u8f93\u5165\u65b0\u7248\u672c\u540d\u79f0
\u540d\u79f0=\u540d\u79f0
\u4fdd\u5b58\u5931\u8d25=\u4fdd\u5b58\u5931\u8d25
\u4fdd\u5b58\u538b\u7f29\u5305\u5230=\u4fdd\u5b58\u538b\u7f29\u5305\u5230
\u9009\u62e9\u6750\u8d28\u5305=\u9009\u62e9\u6750\u8d28\u5305
\u9009\u62e9\u8d44\u6e90\u5305=\u9009\u62e9\u8d44\u6e90\u5305
\u9009\u62e9\u5e93/\u6a21\u7ec4=\u9009\u62e9\u5e93/\u6a21\u7ec4
\u6ca1\u6709\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u5e93/\u6a21\u7ec4\u3002=\u6ca1\u6709\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u5e93/\u6a21\u7ec4\u3002
\u5220\u9664\u5931\u8d25=\u5220\u9664\u5931\u8d25
\u6dfb\u52a0\u5931\u8d25=\u6dfb\u52a0\u5931\u8d25
\u9009\u62e9\u6a21\u7ec4=\u9009\u62e9\u6a21\u7ec4
\u7248\u672c\u540d\u79f0\u4e0d\u80fd\u4e3a\u7a7a=\u7248\u672c\u540d\u79f0\u4e0d\u80fd\u4e3a\u7a7a
\u5907\u4efd\u5230=\u5907\u4efd\u5230
\u662fCOREODS\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6838\u5fc3\u6a21\u7ec4=\u662fCoremods\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6838\u5fc3\u6a21\u7ec4
\u662fMODS\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6a21\u7ec4=\u662fMods\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6a21\u7ec4
\u901a\u5e38\u662f\u6a21\u7ec4=\u901a\u5e38\u662f\u6a21\u7ec4
\u4e0b\u79fb=\u4e0b\u79fb
\u4e0a\u79fb=\u4e0a\u79fb
\u5220\u9664=\u5220\u9664
\u589e\u52a0=\u589e\u52a0
\u901a\u5e38\u662fFORGE,MODLOADER\u4ee5\u53caMINECRAFT\u6240\u4f9d\u8d56\u7684\u5e93=\u901a\u5e38\u662fForge,Modloader\u4ee5\u53caMinecraft\u6240\u4f9d\u8d56\u7684\u5e93
\u9644\u52a0\u542f\u52a8\u53c2\u6570=\u9644\u52a0\u542f\u52a8\u53c2\u6570
\u81ea\u5b9a\u4e49\u5e93\u6587\u4ef6\u5939(LIBRARIES\u6587\u4ef6\u5939)=\u81ea\u5b9a\u4e49\u5e93\u6587\u4ef6\u5939(libraries\u6587\u4ef6\u5939)
\u4e3b\u7c7b=\u4e3b\u7c7b
\u81ea\u5b9a\u4e49\u8d44\u6e90\u6587\u4ef6\u5939(ASSETS\u6587\u4ef6\u5939)=\u81ea\u5b9a\u4e49\u8d44\u6e90\u6587\u4ef6\u5939(assets\u6587\u4ef6\u5939)
\u624b\u52a8\u8bbe\u7f6e=\u624b\u52a8\u8bbe\u7f6e
\u4e0d\u5f3a\u5236=\u4e0d\u5f3a\u5236
32\u4f4d=32\u4f4d
64\u4f4d=64\u4f4d
\u542f\u52a8\u6a21\u5f0f=\u542f\u52a8\u6a21\u5f0f
\u73a9\u5bb6\u540d=\u73a9\u5bb6\u540d
1.6\u53ca\u4ee5\u4e0a\u7248\u672c\u4ee5\u53ca\u5bfc\u5165\u7684\u65e7\u7248\u672c=1.6\u53ca\u4ee5\u4e0a\u7248\u672c\u4ee5\u53ca\u5bfc\u5165\u7684\u65e7\u7248\u672c
\u6700\u5927\u5185\u5b58=\u6700\u5927\u5185\u5b58
JAVA\u865a\u62df\u673a\u53c2\u6570=Java\u865a\u62df\u673a\u53c2\u6570
JAVA\u8def\u5f84=Java\u8def\u5f84
\u5168\u5c4f=\u5168\u5c4f
\u5206\u8fa8\u7387=\u5206\u8fa8\u7387
\u6e38\u620f\u8def\u5f84=\u6e38\u620f\u8def\u5f84
\u4ee5\u4e0b\u8bbe\u7f6e\u5b57\u6bb5\u4e3a\u7a7a\u4ee3\u8868\u7740\u4f7f\u7528\u9ed8\u8ba4\u8bbe\u7f6e=\u9664\u540d\u79f0\u4ee5\u4e0b\u5b57\u6bb5\u53ef\u4ee5\u4e0d\u586b
\u53d6\u6d88=\u53d6\u6d88
\u786e\u5b9a=\u786e\u5b9a
game_download=\u6e38\u620f\u4e0b\u8f7d
public_settings=\u5168\u5c40\u8bbe\u7f6e
invalid=\u65e0\u6548\u7684
invalid_jar=\u65e0\u6548\u7684jar\u5305
not_a_file=\u4e0d\u662f\u6587\u4ef6
not_found=\u627e\u4e0d\u5230minecraft.jar
not_readable=minecraft.jar\u4e0d\u53ef\u8bfb
modified=(\u4fee\u6539\u7684!)
\u83b7\u53d6\u4e2d=\u83b7\u53d6\u4e2d
\u63d2\u4ef6\u9519\u8bef=\u63d2\u4ef6\u9519\u8bef
CannotLoadPluginsBecauseOfAnError=\u65e0\u6cd5\u52a0\u8f7d\u63d2\u4ef6\uff0c\u56e0\u4e3a\u53d1\u751f\u4e86\u4e00\u4e2a\u9519\u8bef\u3002
CRASH\ REPORT\ DETECTED,\ BUT\ UNKNOWN\ FORMAT\:=Crash report detected, but unknown format:
COULDN'T\ OPEN\ CRASH\ REPORT=Couldn't open crash report
CRASH\ REPORT\ DETECTED,\ OPENING\:=Crash report detected, opening:
MinecraftCrashed=Minecraft\u5d29\u6e83\u4e86\uff01(\u9519\u8bef\u4ee3\u7801:{0})
RememberMe=\u8bb0\u4f4f\u6211
Logout=\u767b\u51fa
ShowIfIsLoaded=\u663e\u793a\u63d2\u4ef6\u662f\u5426\u52a0\u8f7d\uff0c\u70b9\u51fb\u67e5\u770b\u9519\u8bef
IsLoaded=\u662f\u5426\u52a0\u8f7d
PluginSettings=\u63d2\u4ef6\u8bbe\u7f6e
Details=\u4fe1\u606f
Authors=\u4f5c\u8005
Version=\u7248\u672c
Name=\u540d\u79f0
CheckUpdate=\u68c0\u67e5\u672c\u542f\u52a8\u5668\u7684\u66f4\u65b0
DownloadSource=\u4e0b\u8f7d\u6e90
DisableMoveMods=\u7981\u6b62\u7248\u672c\u81ea\u6709\u6a21\u7ec4\uff08\u79fb\u52a8\u6a21\u7ec4\uff09\u529f\u80fd
ShowConsoleOutput=\u5c31\u662fMinecraft\u7684\u63a7\u5236\u53f0\u8f93\u51fa
MinecraftLocation=Minecraft\u8def\u5f84\uff08\u5373.minecraft\u6587\u4ef6\u5939\uff09
MaxMemoryTooltip=\u5141\u8bb8Minecraft\u6700\u591a\u5141\u8bb8\u4f7f\u7528\u7684\u5185\u5b58\uff08\u770b\u4e0d\u61c2\u5c31\u4f7f\u7528\u9ed8\u8ba4\u76841024\u5427\uff09
FailedToLoad=\u52a0\u8f7d\u5931\u8d25
Loaded=\u5df2\u52a0\u8f7d
NoCharacter=\u8be5\u5e10\u53f7\u6ca1\u6709\u89d2\u8272
LegacyLogin=\u65e7\u7248\u6b63\u7248\u767b\u5f55
YggdrasilLogin=\u65b0\u7248\u6b63\u7248\u767b\u5f55
PleaseChooseCharacter=\u8bf7\u9009\u62e9\u60a8\u8981\u4f7f\u7528\u7684\u89d2\u8272
WrongPassword=\u53ef\u80fd\u662f\u60a8\u7684\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef
OfflineLogin=\u79bb\u7ebf\u6a21\u5f0f
GameDownload=\u6e38\u620f\u4e0b\u8f7d
IntegrateDownload=\u6574\u5408\u5305\u4e0b\u8f7d
AssetsDownload=\u8d44\u6e90\u4e0b\u8f7d
Installers=\u81ea\u52a8\u5b89\u88c5
WorldSaving=\u5907\u4efd\u5730\u56fe
ServerEditor=\u670d\u52a1\u5668\u7f16\u8f91
TexturepackEditor=\u6750\u8d28\u5305\u7ba1\u7406
Refresh=\u5237\u65b0\u5217\u8868
Install=\u5b89\u88c5
AssetsType=\u8d44\u6e90\u7c7b\u578b
InstallOptifine=\u5b89\u88c5\u9009\u4e2d\u7684Optifine
Changelog=\u66f4\u65b0\u4fe1\u606f
InstallForge=\u5b89\u88c5\u9009\u4e2d\u7684Forge
ModManaging=\u6a21\u7ec4\u7ba1\u7406
PluginCenter=\u63d2\u4ef6\u4e2d\u5fc3
ExtMods=\u5916\u90e8\u6a21\u7ec4
CoreMods=\u6838\u5fc3\u6a21\u7ec4
NormalSettings=\u666e\u901a\u8bbe\u7f6e
1.6AndAbove=1.6\u53ca\u4ee5\u4e0a
1.5AndBelow=1.5\u53ca\u4ee5\u4e0b
IsActive=\u6d3b\u52a8
Location=\u8def\u5f84
Type=\u7c7b\u578b
ReleaseTime=\u91ca\u653e\u65f6\u95f4
Time=\u53d1\u5e03\u65f6\u95f4
Version=\u7248\u672c
MCVersion=MC\u7248\u672c
IntegrateName=\u6574\u5408\u5305\u540d\u79f0
IntegrateVersion=\u6574\u5408\u5305\u7248\u672c
ServerName=\u670d\u52a1\u5668\u540d\u79f0
HideAddress=\u9690\u85cf\u5730\u5740
Address=\u5730\u5740
Introduction=\u4ecb\u7ecd
Online=\u5728\u7ebf
Delay=\u5ef6\u8fdf
Clear=\u6e05\u9664
Close=\u5173\u95ed
Save=\u4fdd\u5b58
JoinMinecraftJar=\u52a0\u5165minecraft.jar
ExternalMods=\u5916\u90e8\u6a21\u7ec4
DynamicLoadingMods=\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4
Libraries=\u5e93
TagArguments=\u9644\u52a0\u7ed9\u4e88Minecraft\u7684\u53c2\u6570
MainClass=Minecraft\u7684\u4e3b\u7c7b\uff08\u4e0d\u77e5\u9053\u4ec0\u4e48\u610f\u601d\u7684\u8bdd\u4e5f\u5c31\u7528\u4e0d\u4e0a\u4e86\uff09
DefaultLibrariesFolder=\u9ed8\u8ba4\u4e3a.minecraft/libraries\u6587\u4ef6\u5939
DefaultAssetsFolder=\u9ed8\u8ba4\u4e3a.minecraft/assets\u6587\u4ef6\u5939
MakeMCMaximum=\u4f7fMinecraft\u7a97\u53e3\u6700\u5927\u5316
MCFolderFormat=\u5c31\u662fMinecraft\u6587\u4ef6\u5939\u683c\u5f0f
MakeMCFullscreen=\u4f7fMinecraft\u7a97\u53e3\u5168\u5c4f
MCHeight=Minecraft\u7a97\u53e3\u9ad8
MCWidth=Minecraft\u7a97\u53e3\u5bbd
Personalization=\u4e2a\u6027\u5316
MaxPermGen=\u6700\u5927\u6c38\u4e45\u4fdd\u5b58\u533a\u57df\uff08MB\uff09
@@ -1,236 +0,0 @@
# To change this template, choose Tools | Templates
# and open the template in the editor.
\u6e38\u620f\u7248\u672c=\u904a\u6232\u7248\u672c
\u8fd9\u4e2aMINECRAFT\u6587\u4ef6\u5939\u65e2\u4e0d\u662f1.6\u7248\u4e5f\u4e0d\u662f\u65e7\u7248\u7684\u600e\u4e48\u5bfc\u5165\u561b0V0\u3002=\u9019\u500bminecraft\u8cc7\u6599\u593e\u65e2\u4e0d\u662f1.6\u7248\u4e5f\u4e0d\u662f\u820a\u7248\u7684\u600e\u9ebc\u5c0e\u5165\u561b0v0\u3002
\u672a\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u7248\u672c=\u672a\u9078\u4e2d\u4efb\u4f55\u4e00\u500b\u7248\u672c
\u5bfc\u5165\u5931\u8d25\:\ {0}=\u5c0e\u5165\u5931\u6557: {0}
\u627e\u5230\u540c\u540d\u7684MINECRAFT\u7248\u672c\uff0c\u8bf7\u6362\u7528\u53e6\u4e00\u4e2a\u540d\u79f0=\u627e\u5230\u540c\u540d\u7684Minecraft\u7248\u672c\uff0c\u8acb\u63db\u7528\u53e6\u4e00\u500b\u540d\u7a31
\u8bf7\u8f93\u5165\u8be5\u65e7\u7248\u672c\u7684\u540d\u79f0=\u8acb\u8f38\u5165\u8a72\u820a\u7248\u672c\u7684\u540d\u7a31
\u627e\u4e0d\u5230MINECRAFT.JAR=\u627e\u4e0d\u5230minecraft.jar
\u9009\u62e9MINECRAFT\u8def\u5f84=\u9078\u64c7Minecraft\u8def\u5f91
\u542f\u52a8\u5931\u8d25=\u555f\u52d5\u5931\u6557
\u590d\u5236\u914d\u7f6e\u6587\u4ef6\u5931\u8d25\:\ =\u8907\u88fd\u914d\u7f6e\u6587\u4ef6\u5931\u6557:
\u590d\u5236\u6838\u5fc3\u6a21\u7ec4\u5931\u8d25\:\ =\u8907\u88fd\u6838\u5fc3\u6a21\u7d44\u5931\u6557:
\u590d\u5236\u666e\u901a\u6a21\u7ec4\u5931\u8d25\:\ =\u8907\u88fd\u666e\u901a\u6a21\u7d44\u5931\u6557:
\u4e0b\u8f7d\u7f3a\u5931\u5e93\uff1a{0}=\u4e0b\u8f09\u7f3a\u5931\u5eab\uff1a{0}
\u6ca1\u6709\u9009\u62e9\u4efb\u4f55\u4e00\u4e2aMINECRAFT\u7248\u672c=\u6c92\u6709\u9078\u64c7\u4efb\u4f55\u4e00\u500bMinecraft\u7248\u672c
\u9519\u8bef\u7684MINECRAFT\u8def\u5f84=\u932f\u8aa4\u7684Minecraft\u8def\u5f91
\u5173\u4e8e=\u5173\u4e8e
\u4e0b\u8f7d=\u4e0b\u8f09
\u5bc6\u7801=\u5bc6\u78bc
\u624b\u52a8\u8bbe\u7f6e=\u624b\u52d5\u8a2d\u5b9a
\u4e0d\u9650\u5236=\u4e0d\u9650\u5236
32\u4f4d=32\u4f4d
64\u4f4d=64\u4f4d
\u542f\u52a8\u6a21\u5f0f=\u555f\u52d5\u6a21\u5f0f
\u6700\u5927\u5185\u5b58=\u6700\u5927\u5167\u5b58
\u6e38\u620f\u540d\u79f0=\u904a\u6232\u540d\u7a31
\u6e38\u620f\u8def\u5f84=\u904a\u6232\u8def\u5f91
\u5bfc\u5165\u6587\u4ef6\u5939=\u5c0e\u5165\u8cc7\u6599\u593e
\u65b0\u5efa=\u65b0\u5efa
\u5220\u9664=\u522a\u9664
\u7f16\u8f91=\u7de8\u8f2f
\u590d\u5236=\u8907\u88fd
\u5bfc\u5165\u65e7\u7248\u672c=\u5c0e\u5165\u820a\u7248\u672c
\u5236\u4f5c\u4e00\u952e\u542f\u52a8=\u88fd\u4f5c\u4e00\u9375\u555f\u52d5
\u51c6\u5907\u4e2d=\u51c6\u5907\u4e2d
\u5f00\u59cbMINECRAFT\u4e4b\u65c5!=\u958b\u59cbMinecraft\u4e4b\u65c5!
\u5237\u65b0=\u5237\u65b0
public_settings=\u5168\u5c40\u8a2d\u5b9a
game_download=\u904a\u6232\u4e0b\u8f09
\u8bbe\u7f6e\u5931\u8d25\uff1a=\u8a2d\u5b9a\u5931\u6557\uff1a
\u7f3a\u5931\u5e93\u4e0b\u8f7d=\u7f3a\u5931\u5eab\u4e0b\u8f09
\u9009\u62e9\u80cc\u666f\u8def\u5f84=\u9078\u64c7\u80cc\u666f\u8def\u5f91
MineLogin0=\u7db2\u7d61\u932f\u8aa4
MineLogin1=\u7528\u6236\u540d\u6216\u5bc6\u78bc\u4e0d\u5408\u6cd5
MineLogin2=\u5167\u90e8\u932f\u8aa4
MineLogin3=\u7528\u6236\u4e0d\u5b58\u5728
MineLogin4=\u9700\u8981\u9a57\u8b49
MineLogin5=\u5bc6\u78bc\u932f\u8aa4
ForgeMod=Forge mod
ModLoaderMod=ModLoader mod
Forge=Forge
ModLoader=ModLoader
Unknown=\u672a\u77e5
Mods\u6587\u4ef6\u5939=Mods\u8cc7\u6599\u593e
Coremods\u6587\u4ef6\u5939=Coremods\u8cc7\u6599\u593e
Mod\u72ec\u7acb\u6587\u4ef6\u5939=Mod\u72ec\u7acb\u8cc7\u6599\u593e
\u914d\u7f6e\u6587\u4ef6\u5939=\u914d\u7f6e\u8cc7\u6599\u593e
\u767b\u5f55\u5931\u8d25\uff1a=\u767b\u5165\u5931\u6557\uff1a
\u9009\u62e9\u5931\u8d25=\u9078\u64c7\u5931\u6557
\u63d2\u4ef6\u9519\u8bef\uff1a=\u63d2\u4ef6\u932f\u8aa4\uff1a
\u767b\u5f55\u5931\u8d25\uff1a=\u767b\u9304\u5931\u6557\uff1a
\u6ca1\u6709\u767b\u5165\u65b9\u5f0f...=\u6c92\u6709\u767b\u5165\u65b9\u5f0f...
\u4fdd\u5b58=\u4fdd\u5b58
\u767b\u5f55\u6a21\u5f0f=\u767b\u5165\u6a21\u5f0f
\u7248\u672c\u7f16\u8f91=\u7248\u672c\u7de8\u8f2f
\u7248\u672c\u53f7=\u7248\u672c\u865f
\u5bfc\u5165=\u5c0e\u5165
\u64cd\u4f5c=\u64cd\u4f5c
\u4e0b\u8f7d\u4fe1\u606f=\u4e0b\u8f09\u4fe1\u606f
\u5b89\u88c5=\u5b89\u88c5
\u6dfb\u52a0=\u6dfb\u52a0
\u5168\u90e8\u4e0b\u8f7d=\u5168\u90e8\u4e0b\u8f09
\u52a0\u5165MINECRAFT.JAR=\u52a0\u5165minecraft.jar
\u7ba1\u7406=\u7ba1\u7406
\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4=\u52d5\u614b\u52a0\u8f09\u6a21\u7d44
\u5e93=\u5eab
AdvancedSettings=\u9ad8\u7d1a\u8a2d\u7f6e
\u6700\u5927\u5316=\u6700\u5927\u5316
\u68c0\u67e5\u66f4\u65b0=\u6aa2\u67e5\u66f4\u65b0
\u67e5\u770b\u65e5\u5fd7=\u67e5\u770b\u65e5\u8a8c
\u80cc\u666f\u5730\u5740=\u80cc\u666f\u5730\u5740
UNEXPECTED\ EXCEPTION\ LOADING\ =\u610f\u5916\u7684\u7570\u5e38
\u5f53\u524d\u662f\u6700\u65b0\u7248\u672c=\u7576\u524d\u662f\u6700\u65b0\u7248\u672c
\u65e0\u6cd5\u6253\u5f00\u6d4f\u89c8\u5668\uff0c\u7f51\u5740\u5df2\u7ecf\u590d\u5236\u5230\u526a\u8d34\u677f\u4e86\uff0c\u60a8\u53ef\u4ee5\u624b\u52a8\u7c98\u8d34\u7f51\u5740\u6253\u5f00\u9875\u9762=\u7121\u6cd5\u6253\u958b\u700f\u89bd\u5668\uff0c\u7db2\u5740\u5df2\u7d93\u5fa9\u88fd\u5230\u526a\u8cbc\u677f\u4e86\uff0c\u60a8\u53ef\u4ee5\u624b\u52d5\u7c98\u8cbc\u7db2\u5740\u6253\u958b\u9801\u9762
\u662f\u5426\u524d\u5f80\u53d1\u5e03\u9875\u9762\u66f4\u65b0\uff1f=\u662f\u5426\u524d\u5f80\u767c\u5e03\u9801\u9762\u66f4\u65b0\uff1f
\u66f4\u65b0\u4fe1\u606f\u4e3a\:\ =\u66f4\u65b0\u4fe1\u606f\u70ba:
\u6700\u65b0\u7248\u672c\u4e3a\uff1a=\u6700\u65b0\u7248\u672c\u70ba\uff1a
\u68c0\u67e5\u66f4\u65b0\u5931\u8d25=\u6aa2\u67e5\u66f4\u65b0\u5931\u6557
\u8fde\u63a5\u4e2d=\u9023\u63a5\u4e2d
\u83b7\u53d6\u5217\u8868\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u91cd\u8bd5=\u7372\u53d6\u5217\u8868\u5931\u6557\uff0c\u8acb\u5237\u65b0\u91cd\u8a66
INVALID\ PLUGIN=\u7121\u6548\u63d2\u4ef6
\u65e0\u6cd5\u8fde\u63a5=\u7121\u6cd5\u9023\u63a5
\ \u5dee\ ORANGERED=\ \u5dee orangered
\ \u8f83\u5dee\ ORANGE=\ \u8f03\u5dee orange
\ \u4e2d\ YELLOGREEN=\ \u4e2d yellogreen
\ \u8f83\u597d\ BLUE=\ \u8f03\u597d blue
\ \u597d\ GREEN=\ \u597d green
\u670d\u52a1\u5668{0}\u7684\u56de\u590d\u65e0\u6548=\u670d\u52d9\u5668{0}\u7684\u56de\u590d\u7121\u6548
\u63a5\u4e0b\u6765\u5f39\u51fa\u6765\u7684\u7a97\u53e3\u91cc\u8bf7\u9009\u62e9\u8def\u5f84\u4e3a\u6e38\u620f\u8def\u5f84\u3002\u7a0b\u5e8f\u5df2\u7ecf\u5c06\u76ee\u5f55\u590d\u5236\u5230\u4e86\u526a\u8d34\u677f\uff0c\u76f4\u63a5\u5728\u7a97\u53e3\u91cc\u9009\u62e9\\"...\\"\u6309\u94ae\uff0c\u7c98\u8d34\u8def\u5f84\uff0c\u786e\u5b9a\u5373\u53ef=\u63a5\u4e0b\u4f86\u5f48\u51fa\u4f86\u7684\u7a97\u53e3\u88e1\u8acb\u9078\u64c7\u8def\u5f91\u70ba\u904a\u6232\u8def\u5f91\u3002\u7a0b\u5e8f\u5df2\u7d93\u5c07\u76ee\u9304\u8907\u88fd\u5230\u4e86\u526a\u8cbc\u677f\uff0c\u76f4\u63a5\u5728\u7a97\u53e3\u88e1\u9078\u64c7\\"...\\"\u6309\u9215\uff0c\u7c98\u8cbc\u8def\u5f91\uff0c\u78ba\u5b9a\u5373\u53ef
\u65e0\u6cd5\u6253\u5f00\u8d44\u6e90\u7ba1\u7406\u5668\:\ =\u7121\u6cd5\u6253\u958b\u8cc7\u6e90\u7ba1\u7406\u5668:
\u63d0\u793a=\u63d0\u793a
\u8f93\u5165\u65b0\u7248\u672c\u540d\u79f0=\u8f38\u5165\u65b0\u7248\u672c\u540d\u7a31
\u540d\u79f0=\u540d\u7a31
\u4fdd\u5b58\u5931\u8d25=\u4fdd\u5b58\u5931\u6557
\u4fdd\u5b58\u538b\u7f29\u5305\u5230=\u4fdd\u5b58\u58d3\u7e2e\u5305\u5230
\u9009\u62e9\u6750\u8d28\u5305=\u9078\u64c7\u6750\u8cea\u5305
\u9009\u62e9\u8d44\u6e90\u5305=\u9078\u64c7\u8cc7\u6e90\u5305
\u9009\u62e9\u5e93/\u6a21\u7ec4=\u9078\u64c7\u5eab/\u6a21\u7d44
\u6ca1\u6709\u9009\u4e2d\u4efb\u4f55\u4e00\u4e2a\u5e93/\u6a21\u7ec4\u3002=\u6c92\u6709\u9078\u4e2d\u4efb\u4f55\u4e00\u500b\u5eab/\u6a21\u7d44\u3002
\u5220\u9664\u5931\u8d25=\u522a\u9664\u5931\u6557
\u6dfb\u52a0\u5931\u8d25=\u6dfb\u52a0\u5931\u6557
\u9009\u62e9\u6a21\u7ec4=\u9078\u64c7\u6a21\u7d44
\u7248\u672c\u540d\u79f0\u4e0d\u80fd\u4e3a\u7a7a=\u7248\u672c\u540d\u7a31\u4e0d\u80fd\u70ba\u7a7a
\u5907\u4efd\u5230=\u5099\u4efd\u5230
\u662fCOREODS\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6838\u5fc3\u6a21\u7ec4=\u662fCoremods\u6587\u4ef6\u593e\u5167\u7684\u6240\u6709\u6838\u5fc3\u6a21\u7d44
\u662fMODS\u6587\u4ef6\u5939\u5185\u7684\u6240\u6709\u6a21\u7ec4=\u662fMods\u6587\u4ef6\u593e\u5167\u7684\u6240\u6709\u6a21\u7d44
\u901a\u5e38\u662f\u6a21\u7ec4=\u901a\u5e38\u662f\u6a21\u7d44
\u4e0b\u79fb=\u4e0b\u79fb
\u4e0a\u79fb=\u4e0a\u79fb
\u5220\u9664=\u522a\u9664
\u589e\u52a0=\u589e\u52a0
\u901a\u5e38\u662fFORGE,MODLOADER\u4ee5\u53caMINECRAFT\u6240\u4f9d\u8d56\u7684\u5e93=\u901a\u5e38\u662fForge,Modloader\u4ee5\u53caMinecraft\u6240\u4f9d\u8cf4\u7684\u5eab
\u9644\u52a0\u542f\u52a8\u53c2\u6570=\u9644\u52a0\u555f\u52d5\u53c3\u6578
\u81ea\u5b9a\u4e49\u5e93\u6587\u4ef6\u5939(LIBRARIES\u6587\u4ef6\u5939)=\u81ea\u5b9a\u7fa9\u5eab\u8cc7\u6599\u593e(libraries\u8cc7\u6599\u593e)
\u4e3b\u7c7b=\u4e3b\u7c7b
\u81ea\u5b9a\u4e49\u8d44\u6e90\u6587\u4ef6\u5939(ASSETS\u6587\u4ef6\u5939)=\u81ea\u5b9a\u7fa9\u8cc7\u6e90\u8cc7\u6599\u593e(assets\u8cc7\u6599\u593e)
\u624b\u52a8\u8bbe\u7f6e=\u624b\u52d5\u8a2d\u5b9a
\u4e0d\u5f3a\u5236=\u4e0d\u5f37\u5236
32\u4f4d=32\u4f4d
64\u4f4d=64\u4f4d
\u542f\u52a8\u6a21\u5f0f=\u555f\u52d5\u6a21\u5f0f
\u73a9\u5bb6\u540d=\u73a9\u5bb6\u540d
1.6\u53ca\u4ee5\u4e0a\u7248\u672c\u4ee5\u53ca\u5bfc\u5165\u7684\u65e7\u7248\u672c=1.6\u53ca\u4ee5\u4e0a\u7248\u672c\u4ee5\u53ca\u5c0e\u5165\u7684\u820a\u7248\u672c
\u6700\u5927\u5185\u5b58=\u6700\u5927\u5167\u5b58
JAVA\u865a\u62df\u673a\u53c2\u6570=Java\u865b\u64ec\u6a5f\u53c3\u6578
JAVA\u8def\u5f84=Java\u8def\u5f91
\u5168\u5c4f=\u5168\u5c4f
\u5206\u8fa8\u7387=\u5206\u8fa8\u7387
\u6e38\u620f\u8def\u5f84=\u904a\u6232\u8def\u5f91
\u4ee5\u4e0b\u8bbe\u7f6e\u5b57\u6bb5\u4e3a\u7a7a\u4ee3\u8868\u7740\u4f7f\u7528\u9ed8\u8ba4\u8bbe\u7f6e=\u9664\u540d\u7a31\u4ee5\u4e0b\u5b57\u6bb5\u53ef\u4ee5\u4e0d\u586b
\u53d6\u6d88=\u53d6\u6d88
\u786e\u5b9a=\u78ba\u5b9a
game_download=\u904a\u6232\u4e0b\u8f09
public_settings=\u5168\u5c40\u8a2d\u5b9a
invalid=\u7121\u6548\u7684
invalid_jar=\u7121\u6548\u7684jar\u5305
not_a_file=\u4e0d\u662f\u6587\u4ef6
not_found=\u627e\u4e0d\u5230minecraft.jar
not_readable=minecraft.jar\u4e0d\u53ef\u8b80
modified=(\u4fee\u6539\u7684!)
\u83b7\u53d6\u4e2d=\u83b7\u53d6\u4e2d
\u63d2\u4ef6\u9519\u8bef=\u63d2\u4ef6\u9519\u8bef
CannotLoadPluginsBecauseOfAnError=\u65e0\u6cd5\u52a0\u8f7d\u63d2\u4ef6\uff0c\u56e0\u4e3a\u53d1\u751f\u4e86\u4e00\u4e2a\u9519\u8bef\u3002
CRASH\ REPORT\ DETECTED,\ BUT\ UNKNOWN\ FORMAT\:=Crash report detected, but unknown format:
COULDN'T\ OPEN\ CRASH\ REPORT=Couldn't open crash report
CRASH\ REPORT\ DETECTED,\ OPENING\:=Crash report detected, opening:
MinecraftCrashed=Minecraft\u5d29\u6e83\u4e86\uff01(\u9519\u8bef\u4ee3\u7801:{0})
RememberMe=\u8bb0\u4f4f\u6211
Logout=\u767b\u51fa
ShowIfIsLoaded=\u663e\u793a\u63d2\u4ef6\u662f\u5426\u52a0\u8f7d\uff0c\u70b9\u51fb\u67e5\u770b\u9519\u8bef
IsLoaded=\u662f\u5426\u52a0\u8f7d
PluginSettings=\u63d2\u4ef6\u8bbe\u7f6e
Details=\u4fe1\u606f
Authors=\u4f5c\u8005
Version=\u7248\u672c
Name=\u540d\u79f0
CheckUpdate=\u68c0\u67e5\u672c\u542f\u52a8\u5668\u7684\u66f4\u65b0
DownloadSource=\u4e0b\u8f7d\u6e90
DisableMoveMods=\u7981\u6b62\u7248\u672c\u81ea\u6709\u6a21\u7ec4\uff08\u79fb\u52a8\u6a21\u7ec4\uff09\u529f\u80fd
ShowConsoleOutput=\u5c31\u662fMinecraft\u7684\u63a7\u5236\u53f0\u8f93\u51fa
MinecraftLocation=Minecraft\u8def\u5f84\uff08\u5373.minecraft\u6587\u4ef6\u5939\uff09
MaxMemoryTooltip=\u5141\u8bb8Minecraft\u6700\u591a\u5141\u8bb8\u4f7f\u7528\u7684\u5185\u5b58\uff08\u770b\u4e0d\u61c2\u5c31\u4f7f\u7528\u9ed8\u8ba4\u76841024\u5427\uff09
FailedToLoad=\u52a0\u8f7d\u5931\u8d25
Loaded=\u5df2\u52a0\u8f7d
NoCharacter=\u8be5\u5e10\u53f7\u6ca1\u6709\u89d2\u8272
LegacyLogin=\u65e7\u7248\u6b63\u7248\u767b\u5f55
YggdrasilLogin=\u65b0\u7248\u6b63\u7248\u767b\u5f55
PleaseChooseCharacter=\u8bf7\u9009\u62e9\u60a8\u8981\u4f7f\u7528\u7684\u89d2\u8272
WrongPassword=\u53ef\u80fd\u662f\u60a8\u7684\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef
OfflineLogin=\u79bb\u7ebf\u6a21\u5f0f
GameDownload=\u6e38\u620f\u4e0b\u8f7d
IntegrateDownload=\u6574\u5408\u5305\u4e0b\u8f7d
AssetsDownload=\u8d44\u6e90\u4e0b\u8f7d
Installers=\u81ea\u52a8\u5b89\u88c5
WorldSaving=\u5907\u4efd\u5730\u56fe
ServerEditor=\u670d\u52a1\u5668\u7f16\u8f91
TexturepackEditor=\u6750\u8d28\u5305\u7ba1\u7406
Refresh=\u5237\u65b0\u5217\u8868
Install=\u5b89\u88c5
AssetsType=\u8d44\u6e90\u7c7b\u578b
InstallOptifine=\u5b89\u88c5\u9009\u4e2d\u7684Optifine
Changelog=\u66f4\u65b0\u4fe1\u606f
InstallForge=\u5b89\u88c5\u9009\u4e2d\u7684Forge
ModManaging=\u6a21\u7ec4\u7ba1\u7406
PluginCenter=\u63d2\u4ef6\u4e2d\u5fc3
ExtMods=\u5916\u90e8\u6a21\u7ec4
CoreMods=\u6838\u5fc3\u6a21\u7ec4
NormalSettings=\u666e\u901a\u8bbe\u7f6e
1.6AndAbove=1.6\u53ca\u4ee5\u4e0a
1.5AndBelow=1.5\u53ca\u4ee5\u4e0b
IsActive=\u6d3b\u52a8
Location=\u8def\u5f84
Type=\u7c7b\u578b
ReleaseTime=\u91ca\u653e\u65f6\u95f4
Time=\u53d1\u5e03\u65f6\u95f4
Version=\u7248\u672c
MCVersion=MC\u7248\u672c
IntegrateName=\u6574\u5408\u5305\u540d\u79f0
IntegrateVersion=\u6574\u5408\u5305\u7248\u672c
ServerName=\u670d\u52a1\u5668\u540d\u79f0
HideAddress=\u9690\u85cf\u5730\u5740
Address=\u5730\u5740
Introduction=\u4ecb\u7ecd
Online=\u5728\u7ebf
Delay=\u5ef6\u8fdf
Clear=\u6e05\u9664
Close=\u5173\u95ed
Save=\u4fdd\u5b58
JoinMinecraftJar=\u52a0\u5165minecraft.jar
ExternalMods=\u5916\u90e8\u6a21\u7ec4
DynamicLoadingMods=\u52a8\u6001\u52a0\u8f7d\u6a21\u7ec4
Libraries=\u5e93
TagArguments=\u9644\u52a0\u7ed9\u4e88Minecraft\u7684\u53c2\u6570
MainClass=Minecraft\u7684\u4e3b\u7c7b\uff08\u4e0d\u77e5\u9053\u4ec0\u4e48\u610f\u601d\u7684\u8bdd\u4e5f\u5c31\u7528\u4e0d\u4e0a\u4e86\uff09
DefaultLibrariesFolder=\u9ed8\u8ba4\u4e3a.minecraft/libraries\u6587\u4ef6\u5939
DefaultAssetsFolder=\u9ed8\u8ba4\u4e3a.minecraft/assets\u6587\u4ef6\u5939
MakeMCMaximum=\u4f7fMinecraft\u7a97\u53e3\u6700\u5927\u5316
MCFolderFormat=\u5c31\u662fMinecraft\u6587\u4ef6\u5939\u683c\u5f0f
MakeMCFullscreen=\u4f7fMinecraft\u7a97\u53e3\u5168\u5c4f
MCHeight=Minecraft\u7a97\u53e3\u9ad8
MCWidth=Minecraft\u7a97\u53e3\u5bbd
Personalization=\u4e2a\u6027\u5316
MaxPermGen=\u6700\u5927\u6c38\u4e45\u4fdd\u5b58\u533a\u57df\uff08MB\uff09
@@ -1,67 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import java.util.List;
import org.jackhuang.hellominecraftlauncher.utilities.LimitedCapacityList;
/**
*
* @author hyh
*/
public class JavaProcess {
private final List<String> commands;
private final Process process;
private final LimitedCapacityList<String> sysOutLines = new LimitedCapacityList<String>(String.class, 5);
public JavaProcess(List<String> commands, Process process) {
this.commands = commands;
this.process = process;
}
public Process getRawProcess() {
return this.process;
}
public List<String> getStartupCommands() {
return this.commands;
}
public String getStartupCommand() {
return this.process.toString();
}
public LimitedCapacityList<String> getSysOutLines() {
return this.sysOutLines;
}
public boolean isRunning() {
try {
this.process.exitValue();
} catch (IllegalThreadStateException ex) {
return true;
}
return false;
}
public int getExitCode() {
try {
return this.process.exitValue();
} catch (IllegalThreadStateException ex) {
ex.fillInStackTrace();
throw ex;
}
}
public String toString() {
return "JavaProcess[commands=" + this.commands + ", isRunning=" + isRunning() + "]";
}
public void stop() {
this.process.destroy();
}
}
@@ -1,336 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jackhuang.hellominecraftlauncher.apis.IPlugin;
import org.jackhuang.hellominecraftlauncher.utilities.C;
import org.jackhuang.hellominecraftlauncher.apis.utils.OperatingSystems;
import org.jackhuang.hellominecraftlauncher.apis.utils.Utils;
import org.jackhuang.hellominecraftlauncher.plugin.PluginManager;
/**
*
* @author hyh
*/
public class Launcher {
public static boolean disactivedMods = false;
public static File gameDir = null;
public static boolean ver16 = false, notMove = false;
public static String name = null;
public static void print(String s) {
System.out.println(s);
}
private static File getLocation() {
return gameDir == null ? gameDir = Utils.getLocation() : gameDir;
}
public static void main(String[] args) {
try {
print("*** " + Main.makeTitle() + " ***");
Dimension dimension = null;
boolean fullscreen = false;
String[] inactiveExtMods = null;
String[] inactiveCoreMods = null;
String classPath = "";
String mainClass = "net.minecraft.client.Minecraft";
ArrayList<String> cmdList = new ArrayList<String>();
int width = 854;
int height = 480;
getLocation();
for (int n = 0; n < args.length; n++) {
String s = args[n];
if (s.startsWith("-cp=")) {
classPath = s.substring("-cp=".length());
print(" ClassPath: " + classPath);
} else if (s.startsWith("-windowSize=")) {
String o = s.substring("-windowSize=".length());
dimension = Utils.parseDimension(o);
print(" WindowSize: " + (String) o);
if (dimension == null) {
continue;
}
width = dimension.width;
height = dimension.height;
} else if (s.equals("-windowFullscreen")) {
fullscreen = true;
print(" Fullscreen: " + true);
} else if (s.startsWith("-inactiveExtMods=")) {
s = s.substring("-inactiveExtMods=".length());
inactiveExtMods = Utils.tokenize(s, ";");
print(" InactiveExtMods: " + s);
} else if (s.startsWith("-inactiveCoreMods=")) {
s = s.substring("-inactiveCoreMods=".length());
inactiveCoreMods = Utils.tokenize(s, ";");
print(" InactiveCoreMods: " + s);
} else if (s.startsWith("-mainClass=")) {
mainClass = s.substring("-mainClass=".length());
print(" MainClass: " + mainClass);
} else if (s.equals("-ver16")) {
ver16 = true;
print(" Type: 1.6");
} else if (s.equals("-notMove")) {
notMove = true;
print(" Do not move mods: true");
} else if (s.startsWith("-name=")) {
name = s.substring("-name=".length());
print(" Name: " + name);
} else if (s.startsWith("-gameDir=")) {
gameDir = new File(s.substring("-gameDir=".length()));
print(" GameDir: " + gameDir.getPath());
} else {
cmdList.add(s);
}
}
if (fullscreen
? cmdList.add("--fullscreen")
: (width > 0) && (height > 0)) {
cmdList.add("--width=" + width);
cmdList.add("--height=" + height);
}
String[] cmds = (String[]) cmdList.toArray(new String[cmdList.size()]);
if (classPath == null) {
print("Invalid launcher classpath: " + classPath);
return;
}
String[] tokenized = Utils.tokenize(classPath, File.pathSeparator);
int len = tokenized.length;
File[] files = new File[len];
URL[] urls = new URL[len];
for (int j = 0; j < len; j++) {
files[j] = new File(tokenized[j]);
urls[j] = new File(tokenized[j]).toURI().toURL();
}
URLClassLoader loader = new URLClassLoader(urls);
Class minecraft = loader.loadClass(mainClass);
Method minecraftMain = minecraft.getMethod("main", new Class[]{String[].class});
moveMods();
moveModDir();
disactiveMods(inactiveExtMods, inactiveCoreMods);
addShutdownHook();
System.out.println("Invoking minecraft main()");
minecraftMain.invoke(null, new Object[]{cmds});
addForgeModLoaderHandler();
print("*** Main class main() finished ***");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
private static void disactiveMods(String[] inactiveExtMods, String[] inactiveCoreMods) {
disactiveModsByType(inactiveExtMods, "mods");
disactiveModsByType(inactiveCoreMods, "coremods");
disactivedMods = true;
}
private static void addShutdownHook() {
ShutdownHook hook = new ShutdownHook();
Thread thread = new Thread(hook);
Runtime.getRuntime().addShutdownHook(thread);
}
private static void addForgeModLoaderHandler() {
MinecraftHandler handler = new MinecraftHandler();
Logger localLogger = Logger.getLogger("ForgeModLoader");
localLogger.addHandler(handler);
}
private static void disactiveModsByType(String[] paramArrayOfString, String paramString) {
restoreModsByType(paramString);
print("Disable inactive mods: " + paramString);
if ((paramArrayOfString == null) || (paramArrayOfString.length <= 0)) {
return;
}
List<String> al = Arrays.asList(paramArrayOfString);
File[] files = new File(getLocation(), paramString).listFiles();
if (files == null) {
print(" No mods: " + paramString);
return;
}
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (!file.isDirectory()) {
String name = file.getName();
if ((!al.contains(name))
|| ((!name.toLowerCase().endsWith(".zip")) && (!name.toLowerCase().endsWith(".jar")))) {
continue;
}
String newName = name + "x";
File newFile = new File(file.getParentFile(), newName);
if (newFile.exists()) {
newFile.delete();
}
if (file.renameTo(newFile)) {
print(" Disabled: " + name + ", new name: " + newFile.getName());
} else {
print(" Can not disable: " + name);
}
}
}
}
private static void restoreModsByType(String paramString) {
print("Restoring disabled mods: " + paramString);
File[] files = new File(getLocation(), paramString).listFiles();
if (files == null) {
return;
}
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.isDirectory()) {
continue;
}
String name = file.getName();
String lowName = name.toLowerCase();
if ((!lowName.endsWith(".zipx")) && (!lowName.endsWith(".jarx"))) {
continue;
}
String newName = name.substring(0, name.length() - 1);
File newFile = new File(file.getParentFile(), newName);
if (newFile.exists()) {
file.delete();
} else {
if (!file.renameTo(newFile)) {
print("Can not rename: " + file.getName() + " to: " + newFile.getName() + " in: " + file.getParent());
}
}
}
}
static void restoreMods() {
if (disactivedMods) {
restoreModsByType("mods");
restoreModsByType("coremods");
disactivedMods = false;
}
}
static void moveMods() {
if(notMove) return;
String realpa = Utils.addSeparator(gameDir.getPath());
java.util.ResourceBundle bundle = C.I18N;
moveModsByType(realpa, name, "mods", bundle.getString("复制普通模组失败: "));
moveModsByType(realpa, name, "coremods", bundle.getString("复制核心模组失败: "));
moveModsByType(realpa, name, "config", bundle.getString("复制配置文件失败: "));
}
static void moveModsByType(String realpa, String name, String type, String error) {
if(notMove) return;
File file = new File(realpa + "versions" + File.separator + name + File.separator + type);
print("Moving mods: " + type);
if (file.exists()) {
File mf = new File(realpa + type);
print("Deleting folder:" + mf.getAbsolutePath());
Utils.deleteAll(mf);
try {
Utils.copyDirectiory(file, mf);
print("Copying folder:" + file.getAbsolutePath());
} catch (IOException e) {
print(error + e.getMessage());
}
} else {
print("Folder doesn't exist: " + file.getAbsolutePath());
}
}
static void moveBackMods() {
if(notMove) return;
String realpa = Utils.addSeparator(gameDir.getPath());
moveBackModsByType(realpa, "mods");
moveBackModsByType(realpa, "coremods");
moveBackModsByType(realpa, "config");
}
static void moveBackModsByType(String realpa, String type) {
if(notMove) return;
if (ver16) {
File fmods = new File(realpa + type);
if (fmods.exists()) {
try {
Utils.copyDirectiory(fmods,
new File(realpa + "versions" + File.separator
+ name + File.separator + type));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
static void moveModDir() {
if(notMove) return;
String realpa = Utils.addSeparator(gameDir.getPath());
try {
print("Moving mod directory");
Utils.copyDirectiory(realpa + "versions" + File.separator + name + File.separator + "moddir",
realpa);
} catch (IOException ex) {
print("Failed to move mod directory");
Logger.getLogger(Launcher.class.getName()).log(Level.SEVERE, null, ex);
}
}
static void moveBackModDir() {
if(notMove) return;
String realpa = Utils.addSeparator(gameDir.getPath());
File file = new File(realpa + "versions" + File.separator + name + File.separator + "moddir");
if (file.exists()) {
try {
ArrayList<String> al = Utils.findAllDir(file);
for (String s : al) {
File fileto = new File(file, s);
fileto.delete();
File moddir = new File(realpa + s);
Utils.copyDirectiory(moddir, fileto);
}
al = Utils.findAllFile(file);
for (String s : al) {
File fileto = new File(file, s);
fileto.delete();
File moddir = new File(realpa + s);
Utils.copyFile(moddir, fileto);
}
} catch (IOException ex) {
print("Failed to move back mod directory");
Logger.getLogger(Launcher.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
@@ -1,85 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import java.io.IOException;
import java.io.OutputStream;
/**
*
* @author hyh
*/
public final class LauncherOutputStream extends OutputStream {
private OutputStream a = null;
private OutputStream b = null;
private boolean c = true;
public LauncherOutputStream(OutputStream paramOutputStream1, OutputStream paramOutputStream2) {
this(paramOutputStream1, paramOutputStream2, true);
}
private LauncherOutputStream(OutputStream paramOutputStream1, OutputStream paramOutputStream2, boolean paramBoolean) {
this.a = paramOutputStream1;
this.b = paramOutputStream2;
this.c = paramBoolean;
}
public final void write(byte[] paramArrayOfByte, int paramInt1, int paramInt2) throws IOException {
if (this.a != null) {
this.a.write(paramArrayOfByte, paramInt1, paramInt2);
}
if (this.b != null) {
this.b.write(paramArrayOfByte, paramInt1, paramInt2);
}
if (this.c) {
flush();
}
}
public final void write(byte[] paramArrayOfByte) throws IOException {
if (this.a != null) {
this.a.write(paramArrayOfByte);
}
if (this.b != null) {
this.b.write(paramArrayOfByte);
}
if (this.c) {
flush();
}
}
public final void write(int paramInt) throws IOException {
if (this.a != null) {
this.a.write(paramInt);
}
if (this.b != null) {
this.b.write(paramInt);
}
if (this.c) {
flush();
}
}
public final void close() throws IOException {
flush();
if (this.a != null) {
this.a.close();
}
if (this.b != null) {
this.b.close();
}
}
public final void flush() throws IOException {
if (this.a != null) {
this.a.flush();
}
if (this.b != null) {
this.b.flush();
}
}
}
@@ -1,27 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Array;
/**
*
* @author hyh
*/
public final class LauncherPrintStream extends PrintStream {
private ModLoaderHandler handler = new ModLoaderHandler();
public LauncherPrintStream(OutputStream outputStream) {
super(outputStream);
}
public final void println(String line) {
super.println(line);
this.handler.check(line);
}
}
@@ -1,165 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import com.seaglasslookandfeel.SeaGlassLookAndFeel;
import java.awt.Font;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
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.SSLSession;
import javax.net.ssl.X509TrustManager;
import javax.swing.UIManager;
import org.jackhuang.hellominecraftlauncher.apis.PluginHandlerType;
import org.jackhuang.hellominecraftlauncher.apis.handlers.Login;
import org.jackhuang.hellominecraftlauncher.apis.utils.MonitorInfoBean;
import org.jackhuang.hellominecraftlauncher.apis.utils.MonitorServiceImpl;
import org.jackhuang.hellominecraftlauncher.apis.utils.Utils;
import org.jackhuang.hellominecraftlauncher.download.URLGet;
import org.jackhuang.hellominecraftlauncher.installers.forge.BaseLauncherProfile;
import org.jackhuang.hellominecraftlauncher.plugin.PluginManager;
import org.jackhuang.hellominecraftlauncher.utilities.SettingsManager;
import org.jackhuang.hellominecraftlauncher.views.MainWindow;
import org.jackhuang.metro.MetroLookAndFeel;
/**
*
* @author hyh
*/
public class Main {
// Create an anonymous class to trust all certificates.
// This is bad style, you should create a separate class.
private static X509TrustManager xtm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
//System.out.println("---cert: " + chain[0].toString() + ", 认证方式: " + authType);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
// Create an class to trust all hosts
private static HostnameVerifier hnv = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
//System.out.println("hostname:111111111111111111111 " + hostname);
return true;
}
};
static {
// 初始化TLS协议SSLContext
// TrustManager
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
X509TrustManager[] xtmArray = new X509TrustManager[]{xtm};
sslContext.init(null, xtmArray, new java.security.SecureRandom());
} catch (GeneralSecurityException gse) {
//打印出一些错误信息和处理这个异常
}
//设置默认的SocketFactory和HostnameVerifier
//为javax.net.ssl.HttpsURLConnection
if (sslContext != null) {
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
}
HttpsURLConnection.setDefaultHostnameVerifier(hnv);
}
public static String launcherName = "Hello Minecraft! Launcher";
public static int firstVer = 1, secondVer = 9, thirdVer = 4;
public static int minimumLauncherVersion = 13;
public static int pluginVersion = 1;
public static String makeVersion() {
return "" + firstVer + '.' + secondVer + '.' + thirdVer;
}
public static String makeTitle() {
return launcherName + ' ' + makeVersion();
}
public static void main(String[] args) {
try {
PrintStream localPrintStream = System.out;
File file = new File(Utils.addSeparator(Utils.currentDir()) + "hmcl.log");
FileOutputStream fos = new FileOutputStream(file, false);
LauncherOutputStream los = new LauncherOutputStream(localPrintStream, fos);
System.setOut(new LauncherPrintStream(los));
System.setErr(new LauncherPrintStream(los));
} catch (FileNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
try {
//UIManager.setLookAndFeel(new SeaGlassLookAndFeel());
UIManager.setLookAndFeel(new MetroLookAndFeel());
UIManager.getLookAndFeelDefaults().put("defaultFont", new Font("微软雅黑", Font.PLAIN, 12));
} catch (Exception ex) {
java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
PluginManager.unloadPlugin();
}
});
PluginHandlerType.registerPluginHandlerType("LOGIN", Login.class);
SettingsManager.load();
try {
PluginManager.preparePlugins();
PluginManager.loadPlugin();
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
BaseLauncherProfile.tryWriteProfile(SettingsManager.settings.publicSettings.gameDir);
Thread t = new Thread() {
@Override
public void run() {
long m = 0;
try {
MonitorInfoBean bean = new MonitorServiceImpl().getMonitorInfoBean();
m = bean.getTotalMemorySize() / 1024;
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
String url = "http://hellominecraftlauncher.duapp.com/count.php?os=" + URLEncoder.encode(System.getProperty("os.name")) + "&mac=" + Utils.getLocalMAC() +
"&memory=" + m + "&ver=" + makeVersion();
URLGet.get(url);
}
};
t.start();
MainWindow.show(args);
}
}
@@ -1,50 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
/**
*
* @author hyh
*/
public class MinecraftHandler extends Handler {
private boolean restore;
MinecraftHandler() {
restore = false;
}
@Override
public final void publish(LogRecord logrecord) {
if (restore) {
return;
}
String s = logrecord.getMessage();
if (s == null) {
return;
}
if (logrecord.getLevel().intValue() < Level.INFO.intValue()) {
return;
}
if (s.startsWith("Forge Mod Loader has successfully loaded") && s.endsWith("mods")) {
restore = true;
}
if (restore) {
Launcher.restoreMods();
}
}
@Override
public final void close() {
}
@Override
public final void flush() {
}
}
@@ -1,39 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import java.io.File;
import java.net.URLClassLoader;
/**
*
* @author hyh
*/
public class ModLoaderHandler {
private boolean ended = false;
public void check(String line) {
if (this.ended) {
return;
}
if (line == null) {
return;
}
if ((!line.equals("Done.")
&& (!line.startsWith("Starting up SoundSystem"))
&& (!line.startsWith("Loading: net.java.games.input."))
&& (!line.startsWith("Found animation info for:"))
? 0 : 1) != 0) {
this.ended = true;
Launcher.restoreMods();
}
}
ModLoaderHandler() {
super();
ended = false;
}
}
@@ -1,18 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
/**
*
* @author jack
*/
public class Pair<K,T> {
public K key;
public T value;
public Pair(K key, T value) {
this.key = key;
this.value = value;
}
}
@@ -1,30 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher;
import org.jackhuang.hellominecraftlauncher.apis.IPlugin;
import org.jackhuang.hellominecraftlauncher.plugin.PluginManager;
/**
*
* @author hyh
*/
public final class ShutdownHook implements Runnable {
@Override
public final void run() {
Launcher.restoreMods();
Launcher.moveBackMods();
Launcher.moveBackModDir();
try {
for(IPlugin p : PluginManager.plugins) {
p.minecraftStopped();
}
} catch(Throwable t) {
}
}
}
@@ -1,37 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.installers;
import java.io.File;
import java.util.ArrayList;
import org.jackhuang.hellominecraftlauncher.apis.utils.Utils;
import org.jackhuang.hellominecraftlauncher.apis.utils.Compressor;
/**
*
* @author hyh
*/
public class PackMinecraftInstaller {
String dest;
ArrayList<String> src;
public PackMinecraftInstaller(ArrayList<String> src, String dest) {
this.dest = dest;
this.src = src;
}
public void install() {
String path = Utils.addSeparator(Utils.currentDir())
+ "HMCL-MERGE-TEMP" + File.separator;
File file = new File(path);
file.mkdirs();
for (int i = 0; i < src.size(); i++) {
Compressor.unzip(src.get(i), path);
}
Compressor.zip(path, dest);
Utils.deleteAll(file);
}
}
@@ -1,21 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.installers.forge;
import java.io.File;
import org.jackhuang.hellominecraftlauncher.apis.utils.Utils;
/**
*
* @author hyh
*/
public class BaseLauncherProfile {
public static String profile = "{\"selectedProfile\": \"(Default)\",\"profiles\": {\"(Default)\": {\"name\": \"(Default)\"}},\"clientToken\": \"88888888-8888-8888-8888-888888888888\"}";
public static void tryWriteProfile(String gameDir) {
File file = new File(Utils.addSeparator(gameDir) + "launcher_profiles.json");
if(!file.exists())
Utils.writeToFile(file, profile);
}
}
@@ -1,185 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.installers.forge;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jackhuang.hellominecraftlauncher.apis.DoneListener;
import org.jackhuang.hellominecraftlauncher.download.URLGet;
import org.jackhuang.hellominecraftlauncher.utilities.C;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
/**
*
* @author hyh
*/
public class ForgeFormatThread extends Thread {
DoneListener<List<ForgeVersion>, Object> lis;
int type;
public ForgeFormatThread(DoneListener<List<ForgeVersion>, Object> lis, int type) {
this.lis = lis;
this.type = type;
}
public static List<ForgeVersion> formatNew() {
ArrayList<ForgeVersion> al = new ArrayList<ForgeVersion>();
try {
Document doc = Jsoup.connect("http://files.minecraftforge.net/").get();
Elements allbuilds = doc.getElementsByClass("builds");
Elements tables = new Elements();
for(Element build : allbuilds)
tables.addAll(build.getElementsByTag("table"));
Elements allforge = new Elements();
for(Element table : tables)
allforge.addAll(table.getElementsByTag("tr"));
tables = null;
for(Element e : allforge) {
Elements tds = e.getElementsByTag("td");
if(tds.isEmpty()) continue;
ForgeVersion v = new ForgeVersion();
v.ver = tds.get(0).text();
v.mcver = tds.get(1).text();
v.releasetime = tds.get(2).text();
v.installer = new String[2];
v.universal = new String[2];
v.javadoc = new String[2];
v.src = new String[2];
v.userdev = new String[2];
Elements a = tds.get(3).getElementsByTag("a");
String prev = null;
for(Element e2 : a) {
String href = e2.attributes().get("href").toLowerCase();
if(e2.text().toLowerCase().indexOf("changelog") != -1) {
v.changelog = href;
} else if(prev != null) {
int index;
if(href.indexOf("adf.ly") != -1) index = 0;
else index = 1;
if(prev.toLowerCase().indexOf("installer") != -1) {
v.installer[index] = href;
} else
if(prev.toLowerCase().indexOf("universal") != -1) {
v.universal[index] = href;
} else
if(prev.toLowerCase().indexOf("javadoc") != -1) {
v.javadoc[index] = href;
} else
if(prev.toLowerCase().indexOf("src") != -1) {
v.src[index] = href;
} else
if(prev.toLowerCase().indexOf("userdev") != -1) {
v.userdev[index] = href;
}
}
prev = e2.text();
}
al.add(v);
}
} catch (Exception ex) {
Logger.getLogger(ForgeFormatThread.class.getName()).log(Level.SEVERE, null, ex);
ForgeVersion v = new ForgeVersion();
v.ver = "获取失败";
al.add(v);
}
return al;
}
public static List<ForgeVersion> formatLegacy() {
ArrayList<ForgeVersion> al = new ArrayList<ForgeVersion>();
try {
Document doc = Jsoup.connect("http://files.minecraftforge.net/minecraftforge/index_legacy.html").get();
Element allbuilds = doc.getElementById("all_builds");
Elements mainTable = allbuilds.getElementsByTag("table");
Element table = mainTable.first();
Elements allforge = table.getElementsByTag("tr");
for(Element e : allforge) {
Elements tds = e.getElementsByTag("td");
if(tds.isEmpty()) continue;
ForgeVersion v = new ForgeVersion();
v.ver = tds.get(0).text();
v.mcver = tds.get(1).text();
v.releasetime = tds.get(2).text();
v.installer = new String[2];
v.universal = new String[2];
v.javadoc = new String[2];
Elements a = tds.get(3).getElementsByTag("a");
String prev = null;
for(Element e2 : a) {
String href = e2.attributes().get("href").toLowerCase();
if(e2.text().toLowerCase().indexOf("changelog") != -1) {
v.changelog = href;
} else if(prev != null) {
int index;
if(href.indexOf("adf.ly") != -1) index = 0;
else index = 1;
if(prev.toLowerCase().indexOf("installer") != -1) {
v.installer[index] = href;
} else
if(prev.toLowerCase().indexOf("universal") != -1) {
v.universal[index] = href;
} else
if(prev.toLowerCase().indexOf("javadoc") != -1) {
v.javadoc[index] = href;
} else
if(prev.toLowerCase().indexOf("src") != -1) {
v.src[index] = href;
}
}
prev = e2.text();
}
al.add(v);
}
} catch (Exception ex) {
//Logger.getLogger(ForgeFormatThread.class.getName()).log(Level.SEVERE, null, ex);
ForgeVersion v = new ForgeVersion();
v.ver = "获取失败";
al.add(v);
}
return al;
}
public static ForgeVersion[] formatBMCL(String url) {
String s = URLGet.get(url);
return new Gson().fromJson(s, ForgeVersion[].class);
}
@Override
public void run() {
List<ForgeVersion> al = null;
switch(type) {
case 0:
al = formatNew();
al.addAll(formatLegacy());
break;
case 1:
al = new ArrayList<ForgeVersion>();
for(ForgeVersion fv : formatBMCL(C.URL_FORGE_BMCL_NEW)) {
al.add(fv);
}
for(ForgeVersion fv : formatBMCL(C.URL_FORGE_BMCL_LEGACY)) {
al.add(fv);
}
break;
}
if(lis != null)
lis.onDone(al, null);
}
}
@@ -1,23 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.installers.forge;
import java.util.ArrayList;
import org.jackhuang.hellominecraftlauncher.installers.PackMinecraftInstaller;
/**
*
* @author hyh
*/
public class ForgeOldInstaller {
public static void install(String destMinecraftJar, String srcMinecraftJar, String forgeUniversal) {
ArrayList<String> al = new ArrayList<String>();
al.add(srcMinecraftJar);
al.add(forgeUniversal);
new PackMinecraftInstaller(al, destMinecraftJar).install();
}
}
@@ -1,15 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.installers.forge;
/**
*
* @author hyh
*/
public class ForgeVersion {
public String vername, ver, mcver, releasetime, changelog;
public String[] installer, javadoc, src, universal, userdev;
public int typeint;
}
@@ -1,69 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.installers.optifine;
import java.net.URLEncoder;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jackhuang.hellominecraftlauncher.apis.DoneListener;
import org.jackhuang.hellominecraftlauncher.download.URLGet;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
/**
*
* @author hyh
*/
public class OptifineFormatDownloadThread extends Thread {
DoneListener<String, Object> lis;
OptifineVersion source;
int type;
public OptifineFormatDownloadThread(DoneListener<String, Object> lis, OptifineVersion source, int type) {
this.lis = lis;
this.type = type;
this.source = source;
}
public static String format(String source) {
String url;
try {
Document doc = Jsoup.connect(source).get();
Element download = doc.getElementById("Download");
Element a = download.getElementsByTag("a").first();
url = "http://optifine.net/" + a.attributes().get("href");
} catch (Exception ex) {
Logger.getLogger(OptifineFormatThread.class.getName()).log(Level.SEVERE, null, ex);
OptifineVersion v = new OptifineVersion();
url = null;
}
return url;
}
public static String format_bmcl(String source) {
String url = "http://bmclapi.bangbang93.com/optifine/" + URLEncoder.encode(source);
return URLGet.get(url);
}
@Override
public void run() {
String url = null;
switch(type) {
case 0:
url = format(source.dl);
break;
case 1:
url = format_bmcl(source.ver);
break;
}
if(lis != null)
lis.onDone(url, null);
}
}
@@ -1,98 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.installers.optifine;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jackhuang.hellominecraftlauncher.apis.DoneListener;
import org.jackhuang.hellominecraftlauncher.download.URLGet;
import org.jackhuang.hellominecraftlauncher.utilities.C;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
/**
*
* @author hyh
*/
public class OptifineFormatThread extends Thread {
DoneListener<List<OptifineVersion>, Object> lis;
int type;
public OptifineFormatThread(DoneListener<List<OptifineVersion>, Object> lis, int type) {
this.lis = lis;
this.type = type;
}
public static List<OptifineVersion> format(String source) {
List<OptifineVersion> al = new ArrayList<OptifineVersion>();
try {
Document doc = Jsoup.connect(source).get();
Elements downloads = doc.getElementsByClass("downloads");
Element table = downloads.first();
Elements tds = table.getElementsByTag("td");
Element td = tds.first();
Elements allopt = td.children();
String lasth2 = "", lasth3 = "";
for(int i = 0; i < allopt.size(); i++) {
Element e = allopt.get(i);
String tagName = e.tagName().toLowerCase();
if(tagName.indexOf("h3") != -1) {
lasth3 = e.text();
String[] s = lasth3.split(" ");
lasth3 = s[s.length - 1];
} else if(tagName.indexOf("h2") != -1) {
lasth2 = e.text().split(" ")[1];
} else
if(tagName.indexOf("table") != -1) {
Elements downloadLines = e.getElementsByTag("tr");
for(Element downloadLine : downloadLines) {
OptifineVersion v = new OptifineVersion();
v.type = lasth3;
String[] ver = downloadLine.child(0).text().split(" ");
if(ver.length < 1) continue;
v.ver = ver[ver.length - 1];
v.mcver = lasth2;
Element mirror = downloadLine.child(2).child(0);
v.dl = mirror.attributes().get("href");
v.date = downloadLine.child(3).text();
al.add(v);
}
}
}
} catch (Exception ex) {
System.err.println(ex.getMessage());
//Logger.getLogger(OptifineFormatThread.class.getName()).log(Level.SEVERE, null, ex);
OptifineVersion v = new OptifineVersion();
v.ver = "获取失败";
al.add(v);
}
return al;
}
public static List<OptifineVersion> format_bmcl(String source) {
Gson gson = new Gson();
return Arrays.asList(gson.fromJson(URLGet.get(source), OptifineVersion[].class));
}
@Override
public void run() {
List<OptifineVersion> al;
if(type == 0) {
al = format(C.URL_OPTIFINE[0]);
} else {
al = format_bmcl(C.URL_OPTIFINE[1]);
}
if(lis != null)
lis.onDone(al, null);
}
}
@@ -1,13 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.installers.optifine;
/**
*
* @author hyh
*/
public class OptifineVersion {
public String dl, ver, mcver, date, type;
}
@@ -1,153 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jackhuang.hellominecraftlauncher.apis.handlers.LoginResult;
import org.jackhuang.hellominecraftlauncher.apis.utils.OperatingSystems;
import org.jackhuang.hellominecraftlauncher.apis.utils.Utils;
import org.jackhuang.hellominecraftlauncher.settings.Version;
import org.jackhuang.hellominecraftlauncher.utilities.SettingsManager;
/**
*
* @author hyh
*/
public abstract class IMinecraftLoader {
protected String minecraftJar;
protected Version v;
protected LoginResult lr;
public IMinecraftLoader(Version pub, Version ver, LoginResult lr, String minecraftJar) {
this.lr = lr;
this.minecraftJar = minecraftJar;
v = new Version(ver);
if(Utils.isEmpty(ver.gameDir)) v.gameDir = Utils.addSeparator(pub.gameDir);
if(Utils.isEmpty(ver.gameAssets)) v.gameAssets = pub.gameAssets;
if(Utils.isEmpty(v.gameAssets)) v.gameAssets = v.gameDir + "assets";
if(Utils.isEmpty(ver.gameLibraries)) v.gameLibraries = pub.gameLibraries;
if(Utils.isEmpty(ver.height)) v.height = pub.height;
if(Utils.isEmpty(ver.javaArgs)) v.javaArgs = pub.javaArgs;
if(Utils.isEmpty(ver.javaDir)) v.javaDir = pub.javaDir;
if(Utils.isEmpty(ver.mainClass)) v.mainClass = pub.mainClass;
if(Utils.isEmpty(ver.maxMemory)) v.maxMemory = pub.maxMemory;
if(Utils.isEmpty(ver.name)) v.name = pub.name;
if(Utils.isEmpty(ver.width)) v.width = pub.width;
if(Utils.isEmpty(ver.minecraftArguments)) v.minecraftArguments = pub.minecraftArguments;
}
public List<String> makeLaunchingCommand() {
System.out.println("*** Making Minecraft Launching Command ***");
ArrayList<String> res = new ArrayList<String>();
String java;
if(!Utils.isEmpty(v.javaDir.trim()))
{
if(Utils.os() == OperatingSystems.WINDOWS) {
File file = new File(Utils.addSeparator(v.javaDir) + "javaw.exe");
if(file.exists() && file.isFile())
java = "javaw.exe";
else
java = "java.exe";
} else {
java = "java";
}
java = Utils.addSeparator(v.javaDir) + java;
}
else
java = Utils.getJavaDir();
System.out.println("Java path: " + java);
res.add(java);
if(!Utils.isEmpty(v.javaArgs.trim()))
{
System.out.println("Java args: " + v.javaArgs);
res.add(v.javaArgs);
}
res.add("-Xincgc");
if(!Utils.isEmpty(v.maxMemory))
{
System.out.println("Memory: " + v.maxMemory);
res.add("-Xmx" + v.maxMemory + "m");
}
makeJavaLibraryPath(res);
res.add("-Dfml.ignoreInvalidMinecraftCertificates=true");
res.add("-Dfml.ignorePatchDiscrepancies=true");
res.add("-Dsun.java2d.noddraw=true");
res.add("-Dsun.java2d.pmoffscreen=false");
res.add("-Dsun.java2d.d3d=false");
res.add("-Dsun.java2d.opengl=false");
if(Utils.os() != OperatingSystems.WINDOWS)
{
String base = new File(v.gameDir).getParent();
System.out.println("Base folder: " + base);
res.add("-Duser.home=" + base);
}
res.add("-cp");
res.add(Utils.parseParams("", Utils.getURL(), File.pathSeparator));
res.add("org.jackhuang.hellominecraftlauncher.Launcher");
makeSelf(res);
if(!Utils.isEmpty(v.height) && !Utils.isEmpty(v.width))
{
res.add("-windowSize=" + v.width + "x" + v.height);
}
if(v.fullscreen)
res.add("-windowFullscreen");
if(v.inactiveCoreMods != null && !v.inactiveCoreMods.isEmpty()) {
String s = "-inactiveCoreMods=" + Utils.parseParams(
"",
v.inactiveCoreMods.toArray(), File.pathSeparator
);
res.add(s);
}
if(v.inactiveExtMods != null && !v.inactiveExtMods.isEmpty()) {
String s = "-inactiveExtMods=" + Utils.parseParams(
"",
v.inactiveExtMods.toArray(), File.pathSeparator);
res.add(s);
}
if(!Utils.isEmpty(v.minecraftArguments))
{
String[] splitted2 = Utils.tokenize(v.minecraftArguments);
res.addAll(Arrays.asList(splitted2));
}
res.add("-gameDir=" + v.gameDir);
if(SettingsManager.settings.disableMoveMods)
res.add("-notMove");
return res;
}
protected abstract void makeJavaLibraryPath(List<String> list);
/**
* You must do these things:<br />
* 1 minecraft class path<br />
* 2 main class<br />
* 3 minecraft arguments<br />
* @param list the command list you shoud edit.
*/
protected abstract void makeSelf(List<String> list);
public Version getUserVersion()
{
return v;
}
}
@@ -1,15 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders;
/**
*
* @author hyh
*/
public class Latest {
public String snapshot, release;
}
@@ -1,25 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders;
import java.util.List;
/**
*
* @author hyh
*/
public class LaunchRequest {
public boolean windowMaximized;
public boolean windowFullscreen;
public boolean showLog;
public int width, height;
public String classPath;
public String[] inactiveExtMods, inactiveCoreMods;
public List<String> minecraftArguments;
public List<String> launchStrings;
}
@@ -1,133 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders;
import org.jackhuang.hellominecraftlauncher.apis.utils.Utils;
import org.jackhuang.hellominecraftlauncher.apis.version.MinecraftLibrary;
import org.jackhuang.hellominecraftlauncher.apis.version.MinecraftVersion;
import org.jackhuang.hellominecraftlauncher.settings.Version;
import java.io.File;
import java.util.List;
import org.jackhuang.hellominecraftlauncher.apis.handlers.LoginResult;
/**
*
* @author hyh
*/
public class MinecraftLoader extends IMinecraftLoader {
private MinecraftVersion version;
String text;
public MinecraftLoader(MinecraftVersion mvt, Version pub, Version ver, LoginResult lr, String minecraftJar)
{
super(pub, ver, lr, minecraftJar);
version = mvt;
for(int i = 0; i < version.libraries.size(); i++)
{
MinecraftLibrary l = version.libraries.get(i);
String str = l.name;
String[] s = str.split(":");
str = s[0];
str = str.replace('.', File.separatorChar);
if(l.natives == null)
str += File.separator + s[1] + File.separator + s[2] +
File.separator + s[1] + '-' + s[2] + ".jar";
else
{
str += File.separator + s[1] + File.separator + s[2] +
File.separator + s[1] + '-' + s[2] + '-';
str += l.getNative();
str += ".jar";
}
l.formatted = str;
version.libraries.set(i, l);
}
}
@Override
protected void makeJavaLibraryPath(List<String> res) {
String library = "-Djava.library.path=";
library += Utils.addSeparator(v.gameDir) + "versions" +
File.separator + getVersion().id + File.separator + getVersion().id +
"-natives";
res.add(library);
}
@Override
protected void makeSelf(List<String> res)
{
String realpa = Utils.addSeparator(v.gameDir);
String library = "-cp=";
String librariespath = realpa + "libraries" + File.separator;
if(!v.gameLibraries.equals("")) librariespath = v.gameLibraries;
if(v.firstLoadLibraries != null)
for(int i = 0; i < v.firstLoadLibraries.size(); i++)
if(v.firstLoadLibrariesIsActive == null || v.firstLoadLibrariesIsActive.get(i))
library += v.firstLoadLibraries.get(i) + File.pathSeparator;
for(int i = 0; i < getVersion().libraries.size(); i++)
{
MinecraftLibrary l = getVersion().libraries.get(i);
if(l.allow())
{
library += librariespath + l.formatted + File.pathSeparator;
}
}
library += minecraftJar + File.pathSeparator;
if(v.lastLoadLibraries != null)
for(int i = 0; i < v.lastLoadLibraries.size(); i++)
if(v.lastLoadLibrariesIsActive == null || v.lastLoadLibrariesIsActive.get(i))
library += v.lastLoadLibraries.get(i) + File.pathSeparator;
library = library.substring(0, library.length() - File.pathSeparator.length());
res.add(library);
String mainClass;
if(Utils.isEmpty(v.mainClass))
mainClass = getVersion().mainClass;
else
mainClass = v.mainClass;
System.out.println("Main class: " + mainClass);
res.add("-mainClass=" + mainClass);
String arg = getVersion().minecraftArguments;
String[] splitted = Utils.tokenize(arg);
for(String t : splitted) {
t = t.replace("${auth_player_name}", lr.username);
t = t.replace("${auth_session}", lr.session);
t = t.replace("${auth_uuid}", lr.userId);
t = t.replace("${version_name}", getVersion().id);
t = t.replace("${game_directory}", v.gameDir);
t = t.replace("${game_assets}", v.gameAssets);
t = t.replace("${assets_root}", v.gameAssets);
t = t.replace("${auth_access_token}", lr.accessToken);
t = t.replace("${user_type}", lr.userType);
if(getVersion().assets != null)
t = t.replace("${assets_index_name}", getVersion().assets);
t = t.replace("${user_properties}", lr.userProperties);
res.add(t);
}
if(res.indexOf("--gameDir") != -1 && res.indexOf("--workDir") != -1) {
res.add("--workDir");
res.add(v.gameDir);
}
res.add("-ver16");
res.add("-name=" + v.name);
}
/**
* @return the version
*/
public MinecraftVersion getVersion() {
return version;
}
/**
* @param version the version to set
*/
public void setVersion(MinecraftVersion version) {
this.version = version;
}
}
@@ -1,67 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jackhuang.hellominecraftlauncher.apis.handlers.LoginResult;
import org.jackhuang.hellominecraftlauncher.apis.utils.Utils;
import org.jackhuang.hellominecraftlauncher.settings.Version;
/**
*
* @author hyh
*/
public class MinecraftOldLoader extends IMinecraftLoader {
public MinecraftOldLoader(Version pub, Version ver, LoginResult lr, String minecraftJar)
{
super(pub, ver, lr, minecraftJar);
}
@Override
protected void makeJavaLibraryPath(List<String> res) {
res.add("-Djava.library.path=" + v.gameDir + "bin" + File.separator + "natives");
}
@Override
protected void makeSelf(List<String> res)
{
String library = "-cp=";
if(v.firstLoadLibraries != null)
for(int i = 0; i < v.firstLoadLibraries.size(); i++)
if(v.firstLoadLibrariesIsActive == null || v.firstLoadLibrariesIsActive.get(i))
library += v.firstLoadLibraries.get(i) + File.pathSeparator;
library += v.gameDir + "bin" + File.separator + "jinput.jar" + File.pathSeparator +
v.gameDir + "bin" + File.separator + "lwjgl.jar" + File.pathSeparator +
v.gameDir + "bin" + File.separator + "lwjgl_util.jar" + File.pathSeparator;
library += minecraftJar + File.separator;
if(v.lastLoadLibraries != null)
for(int i = 0; i < v.lastLoadLibraries.size(); i++)
if(v.lastLoadLibrariesIsActive == null || v.lastLoadLibrariesIsActive.get(i))
library += v.lastLoadLibraries.get(i) + File.pathSeparator;
library = library.substring(0, library.length() - File.pathSeparator.length());
res.add(library);
String mainClass;
if(Utils.isEmpty(v.mainClass))
mainClass = "net.minecraft.client.Minecraft";
else
mainClass = v.mainClass;
System.out.println("Main class: " + mainClass);
res.add("-mainClass=" + mainClass);
res.add(lr.username);
res.add(lr.session);
res.add("--workDir");
res.add(v.gameDir);
}
}
@@ -1,19 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders;
import org.jackhuang.hellominecraftlauncher.apis.version.MinecraftVersion;
import java.util.ArrayList;
/**
*
* @author hyh
*/
public class MinecraftVersions {
public ArrayList<MinecraftVersion> versions;
public Latest latest;
}
@@ -1,33 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders;
import com.google.gson.Gson;
/**
*
* @author hyh
*/
public class MinecraftVersionsLoader {
String JSON;
Gson gson;
private MinecraftVersions versions;
public MinecraftVersionsLoader(String j) {
gson = new Gson();
JSON = j;
versions = gson.fromJson(JSON, MinecraftVersions.class);
}
/**
* @return the versions
*/
public MinecraftVersions getVersions() {
return versions;
}
}
@@ -1,13 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders.packages;
/**
*
* @author hyh
*/
public class Packages {
public String author, mcversion, version, name, type;
}
@@ -1,14 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders.serverlist;
/**
*
* @author hyh
*/
public class ServerInfo {
public String name, address;
public boolean isHide;
}
@@ -1,151 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.loaders.serverlist;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.misc.BASE64Decoder;
/**
*
* @author hyh
*/
public class ServerList {
public static String address = "AmlwAA==";
public static String header = "CgAACQAHc2VydmVycwoAAA==";
public static String hideAddress = "AAtoaWRlQWRkcmVzcw==";
public static String name = "AARuYW1lAA==";
public ArrayList<ServerInfo> list;
public File file;
public ServerList(File file) {
this.file = file;
if(!file.exists())
try {
file.getParentFile().mkdirs();
file.createNewFile();
} catch (IOException ex) {
Logger.getLogger(ServerList.class.getName()).log(Level.SEVERE, null, ex);
}
this.list = new ArrayList<ServerInfo>();
try {
FileInputStream stream = new FileInputStream(file);
byte[] header = new byte[0x13];
stream.read(header, 0, header.length);
if(stream.available() < 5) {
stream.close();
return;
}
while(stream.available() > 0) {
byte[] hideAddress = new byte[13];
stream.read(hideAddress, 0, hideAddress.length);
boolean isHide = stream.read() == 1 ? true : false;
byte[] name = new byte[9];
stream.read(name, 0, name.length);
ArrayList<Byte> nameList = new ArrayList<Byte>(20);
byte ch = (byte) stream.read();
while(ch != 0) {
if(ch == -1) break;
nameList.add(ch);
ch = (byte) stream.read();
}
if(ch == -1) break;
byte[] names = new byte[nameList.size()];
for(int i = 0; i < nameList.size(); i++) {
names[i] = nameList.get(i);
}
String Name = new String(names);
byte[] address = new byte[5];
stream.read(address, 0, address.length);
ArrayList<Byte> AddRess = new ArrayList<Byte>(20);
ch = (byte) stream.read();
while(ch != 0) {
if(ch == -1) break;
AddRess.add(ch);
ch = (byte) stream.read();
}
if(ch == -1) break;
byte[] addresses = new byte[AddRess.size()];
for(int i = 0; i < AddRess.size(); i++) {
addresses[i] = AddRess.get(i);
}
String Address = new String(addresses);
ServerInfo info = new ServerInfo();
info.address = Address;
info.isHide = isHide;
info.name = Name;
list.add(info);
if(stream.read() == 0)
break;
}
} catch (FileNotFoundException ex) {
Logger.getLogger(ServerList.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ServerList.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void write() {
try {
FileOutputStream stream = new FileOutputStream(file);
BASE64Decoder decoder = new BASE64Decoder();
stream.write(decoder.decodeBuffer(header));
int p = 0;
stream.write(0);
stream.write(list.size());
stream.write(1);
for(ServerInfo info : list) {
p++;
stream.write(decoder.decodeBuffer(hideAddress));
if(info.isHide)
stream.write(1);
else
stream.write(0);
stream.write(8);
stream.write(decoder.decodeBuffer(name));
stream.write(info.name.length());
stream.write(info.name.getBytes());
stream.write(new byte[]{8, 0});
stream.write(decoder.decodeBuffer(address));
stream.write(info.address.length());
stream.write(info.address.getBytes());
stream.write(0);
if(p != list.size())
stream.write(1);
else
stream.write(0);
}
stream.close();
} catch (FileNotFoundException ex) {
Logger.getLogger(ServerList.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ServerList.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void writeEmptyFile(File path) {
try {
FileOutputStream serverdat = new FileOutputStream(path);
BASE64Decoder decoder = new BASE64Decoder();
byte[] writes = decoder.decodeBuffer(header);
serverdat.write(writes, 0, writes.length);
serverdat.write(0);
serverdat.close();
} catch (IOException ex) {
Logger.getLogger(ServerList.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
@@ -1,30 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jackhuang.hellominecraftlauncher.models;
/**
*
* @author hyh
*/
public class ControllerAction<T> {
/**
* -1 - NULL
* 1 - delete version<br />
* 2 - new version<br />
* 3 - copy version<br />
* 4 - import version<br />
* 5 - import folder<br />
* 6 - cannot find minecraft.jar<br />
* 7 - find the same name in the list<br />
*/
int action;
T content;
public ControllerAction(int action, T content) {
this.action = action;
this.content = content;
}
}
Loaded 100 of 872 files, more files were not shown because too many files have changed in this diff. Show more