Compare commits

...
174 Commits
Author SHA1 Message Date
龙腾猫跃 a84601d99c 2.7.2 2024-05-13 18:09:30 +08:00
龙腾猫跃 a5a3800957 Merge pull request #3781 from Chiloven945/main
修改模组及整合包版本筛选列表冗余
2024-05-06 17:14:35 +08:00
龙腾猫跃 baba653a67 Update README.md 2024-05-06 17:10:37 +08:00
龙腾猫跃 5733cbdb0e Merge pull request #3768 from allMagicNB/Revive-#85-#91-#192
Revive #85 #91 #192
2024-05-06 16:09:33 +08:00
ClovenBugle 6e1072d042 修改整合包版本筛选列表冗余
删去1.20、1.20.3、1.20.5因均有被继后版本修复的bug
添加1.19.2因其为1.19最常用的模组版本
2024-05-04 11:40:42 +08:00
ClovenBugle efe58c9748 修改模组版本筛选列表冗余
删去1.20、1.20.3、1.20.5因均有被继后版本修复的bug
添加1.19.2因其为1.19最常用的模组版本
2024-05-04 11:37:50 +08:00
allMagicNB 5b58e3868d 更换爱发电主页链接 2024-05-01 16:28:24 +08:00
allMagicNB 0a48feba18 不加了不加了……都预览不了 2024-05-01 14:58:46 +08:00
allMagicNB 7d89b90ae1 换 SVG…… 2024-05-01 14:31:02 +08:00
allMagicNB f6cae4ea23 添加 “赞助-爱发电” Badge 2024-05-01 14:14:29 +08:00
allMagicNB a09baee5f8 添加 “赞助-爱发电” Badge 2024-05-01 14:13:20 +08:00
allMagicNB fa3d5bc09b 增加 “Issues” Badge 2024-05-01 13:33:39 +08:00
allMagicNB c169532794 为 Bagde 添加链接和说明 2024-05-01 10:48:38 +08:00
allMagic 37313e4d6e Update README.md
再改下
2024-05-01 10:18:04 +08:00
allMagic dd9cdaf15f Update README.md
换了下 Star 的 Logo
2024-05-01 10:17:32 +08:00
allMagic 6a2f95e96f Update README.md
Revive #85 #91 #192
2024-04-30 23:00:24 +08:00
龙腾猫跃 d682b59803 Merge pull request #3732 from allMagicNB/main
增加资源下载界面的 1.20.5(#3731)
2024-04-25 04:14:52 +08:00
allMagic 02347239b4 Add 1.20.5 2024-04-25 02:12:48 +08:00
allMagic dc4eda533c Add 1.20.5 2024-04-25 02:10:28 +08:00
龙腾猫跃 d86ad945a6 Merge pull request #3699 from zkitefly/crash
updata CrashReason.Fabric报错并给出解决方案
2024-04-19 22:04:02 +08:00
zkitefly 12be800391 updata CrashReason.Fabric报错并给出解决方案 2024-04-19 13:52:59 +00:00
龙腾猫跃 c47b80df36 2.7.1 正式版 2024-04-08 17:15:20 +08:00
龙腾猫跃 43b0acba08 2.7.1 2024-04-08 01:54:35 +08:00
龙腾猫跃 c1cad542c2 Merge pull request #3530 from wuliaodexiaoluo/main
添加 JVM 参数
2024-04-05 22:14:26 +08:00
龙腾猫跃 09f9b8f1e5 Merge branch 'main' into main 2024-04-05 22:14:18 +08:00
龙腾猫跃 4241060010 2.7.0 正式版 2024-04-05 17:36:13 +08:00
龙腾猫跃 0dab617b64 2.7.0 2024-04-04 03:26:43 +08:00
龙腾猫跃 515b7e89c5 Merge pull request #3593 from allMagicNB/main
fix #3591
2024-04-04 01:26:23 +08:00
allMagic d83f98b34a fix #3591 2024-04-02 13:32:14 +08:00
allMagic e2030970a3 fix #3591 2024-04-02 06:23:00 +08:00
allMagic e623d3464a fix #3591 2024-04-01 22:55:39 +08:00
allMagic 81346f0821 fix #3591 2024-04-01 22:37:05 +08:00
allMagic 810c6e8618 fix #3591 2024-04-01 22:17:49 +08:00
wuliaodexiaoluo a5199d32ed Update FormMain.xaml.vb 2024-03-20 08:42:54 +08:00
wuliaodexiaoluo b058e7722d Update FormMain.xaml.vb 2024-03-19 14:52:56 +08:00
wuliaodexiaoluo 4beef0fb5d Merge pull request #4 from wuliaodexiaoluo/wuliaodexiaoluo-patch-2
Update FormMain.xaml.vb
2024-03-19 13:56:29 +08:00
wuliaodexiaoluo eb195373ea Update FormMain.xaml.vb
修复 UAC 阻止文件拖拽
2024-03-19 13:56:11 +08:00
wuliaodexiaoluo 65ca2e0cf4 Update PageSetupLaunch.xaml 2024-03-16 13:10:15 +08:00
wuliaodexiaoluo 09e420ad6b Merge pull request #3 from wuliaodexiaoluo/wuliaodexiaoluo-patch-2
Update PageSetupLaunch.xaml
2024-03-16 13:01:45 +08:00
wuliaodexiaoluo 95429cc9cc Merge branch 'main' into wuliaodexiaoluo-patch-2 2024-03-16 13:01:37 +08:00
wuliaodexiaoluo 5a78a46b28 Update PageSetupLaunch.xaml
解决描述错误
2024-03-16 12:53:00 +08:00
wuliaodexiaoluo 3ae624d4fb Update PageSetupLaunch.xaml
手滑了抱歉。。。
2024-03-16 12:51:14 +08:00
wuliaodexiaoluo 91f39f2afd Merge pull request #2 from wuliaodexiaoluo/wuliaodexiaoluo-patch-1
Fix # 3511
2024-03-16 12:31:42 +08:00
wuliaodexiaoluo 65da5b67f7 Update PageSetupLaunch.xaml 2024-03-16 12:30:46 +08:00
wuliaodexiaoluo 268cb092dd Update PageSetupLaunch.xaml 2024-03-16 12:27:47 +08:00
wuliaodexiaoluo 9728af60d0 Update PageSetupLaunch.xaml 2024-03-16 12:24:48 +08:00
wuliaodexiaoluo 7affc1e24f Merge pull request #1 from Hex-Dragon/main
Update
2024-03-16 12:23:26 +08:00
龙腾猫跃 3076f3a6b7 Merge pull request #3475 from WorldHim/patch-1
修复 #3461 换行缺失
2024-03-03 04:42:17 +08:00
WorldHim 02c8b7211b fix: #3461 2024-03-02 20:30:02 +08:00
龙腾猫跃 5843649cfa 2.6.15 正式版 2024-03-02 18:04:12 +08:00
龙腾猫跃 f78250020e 2.6.15 2024-03-02 17:53:55 +08:00
龙腾猫跃 031cd898f6 Merge pull request #3427 from zkitefly/patch-4
Update bug2.yml
2024-02-26 06:14:19 +08:00
zkitefly 1b272a6f06 更新 bug2.yml 2024-02-25 17:23:50 +08:00
zkiteflyand柚子柚子 f2e9be66c1 Update .github/ISSUE_TEMPLATE/bug2.yml
Co-authored-by: 柚子柚子 <[email protected]>
2024-02-25 15:28:04 +08:00
zkitefly c719803849 Update bug2.yml
?
2024-02-25 15:15:13 +08:00
zkiteflyand何杰豪 2b485233cb Update .github/ISSUE_TEMPLATE/bug2.yml
Co-authored-by: 何杰豪 <[email protected]>
2024-02-25 15:10:49 +08:00
zkitefly 5198298336 Update bug2.yml 2024-02-25 15:07:14 +08:00
zkitefly a1a2d53d31 Update bug2.yml 2024-02-25 11:37:16 +08:00
龙腾猫跃 ec6784d57d 2.6.14 正式版 2024-02-23 17:59:24 +08:00
龙腾猫跃 83ebc61d8a 2.6.14 2024-02-22 00:04:00 +08:00
龙腾猫跃 63d48b09e3 Merge pull request #3231 from zkitefly/fabric_error-chinese
添加"Fabric报错并给出解决方案"中文检查支持
2024-02-20 04:27:32 +08:00
zkitefly 4a25b066d2 Fix https://github.com/Hex-Dragon/PCL2/issues/3228 . 添加"Fabric报错并给出解决方案"中文检查支持 2024-01-31 11:39:32 +00:00
龙腾猫跃 8c8b1066bf 2.6.13 正式版 2024-01-06 22:46:38 +08:00
龙腾猫跃 fb4386952d 2.6.13 2024-01-06 22:35:35 +08:00
龙腾猫跃 fa054d9a9e 2.6.12 正式版 2023-12-26 16:52:03 +08:00
龙腾猫跃 6705444fb4 2.6.12 2023-12-18 04:56:23 +08:00
龙腾猫跃 c98e0367d0 2.6.10 正式版重新签名 2023-11-28 18:01:30 +08:00
龙腾猫跃 2c7b532188 2.6.11 2023-11-27 00:49:59 +08:00
龙腾猫跃 e2a3dd3281 Merge pull request #2864 from zkitefly/minecraft.wiki
`https://minecraft.fandom.com/zh/wiki/` -> `https://zh.minecraft.wiki/w/`
2023-11-21 18:14:34 +08:00
zkitefly e712280c7b Update ModDownloadLib.vb 2023-11-11 11:26:52 +08:00
龙腾猫跃 8308577549 2.6.10 正式版 2023-10-25 16:36:22 +08:00
龙腾猫跃 f0c634db78 2.6.10 修正 2023-10-23 23:37:34 +08:00
龙腾猫跃 7b623dbc2d 2.6.10 2023-10-23 23:34:18 +08:00
龙腾猫跃 037e6b19b4 2.6.9 2023-10-07 05:29:24 +08:00
龙腾猫跃 5ff7aed46e Merge pull request #2724 from JingHai-Lingyun/main
Update PageLoginMs.xaml.vb
2023-09-30 04:08:43 +08:00
凌云 3779d74e93 Update PageLoginMs.xaml.vb 2023-09-29 10:16:25 +08:00
龙腾猫跃 3b8de89309 2.6.8 2023-09-12 00:55:44 +08:00
龙腾猫跃 f18ede2c7a Merge pull request #2649 from zkitefly/patch-4
Update ModCrash.vb
2023-09-07 16:58:36 +08:00
龙腾猫跃 4158e95f87 * 2023-09-06 17:36:44 +08:00
龙腾猫跃 a77c2385cd * 2023-09-06 17:32:16 +08:00
龙腾猫跃 fe5dc2d07f 修改 issue 模板 2023-09-06 17:28:27 +08:00
zkitefly 17c2049d2c Update ModCrash.vb 2023-08-31 21:33:05 +08:00
zkitefly 0eebb8ec78 Update ModCrash.vb 2023-08-31 10:15:50 +08:00
zkitefly 58d40976a7 Update ModCrash.vb 2023-08-31 10:07:12 +08:00
龙腾猫跃 b2f2bcf4b6 Merge pull request #2617 from so1ve/main-1
在issue template中添加讨论链接
2023-08-26 00:28:12 +08:00
Ray 2a6708cc08 Update config.yml 2023-08-26 00:14:35 +08:00
Ray c9c00bc23f Update config.yml 2023-08-26 00:12:42 +08:00
Ray 7fa092eb25 Update config.yml 2023-08-26 00:12:05 +08:00
Ray d4e692b69f Update config.yml 2023-08-26 00:10:15 +08:00
龙腾猫跃 8479c47da0 Merge pull request #2574 from zkitefly/issue
https://github.com/Hex-Dragon/PCL2/discussions/2572
2023-08-23 02:40:57 +08:00
zkitefly 971aa0034d 还是换回去吧( 2023-08-22 23:11:08 +08:00
龙腾猫跃 b717bb31c8 2.6.7 正式版 2023-08-22 22:47:42 +08:00
zkitefly 3037a9e384 改一下 2023-08-22 22:41:40 +08:00
zkitefly 6794b24292 https://github.com/Hex-Dragon/PCL2/discussions/2572 2023-08-22 22:39:33 +08:00
龙腾猫跃 d774de5436 2.6.7 2023-08-22 16:19:12 +08:00
龙腾猫跃 e4ae1a057a 2.6.6 正式版 2023-08-21 14:22:57 +08:00
龙腾猫跃 41250d8387 2.6.6 2023-08-21 04:02:19 +08:00
龙腾猫跃 79778490d5 2.6.5 2023-08-15 16:38:52 +08:00
龙腾猫跃 e1e084aea3 Merge pull request #2487 from SALTWOOD/main
Fix #2486
2023-08-13 19:22:36 +08:00
SALTWOOD 836d55e445 Fix #2486 2023-08-13 17:26:35 +08:00
龙腾猫跃 3574931bfb Merge pull request #2301 from zkitefly/patch-2
Update ModCrash.vb
2023-08-06 11:25:17 +08:00
zkitefly c9aabd6a55 Update ModCrash.vb 2023-07-21 09:30:39 +08:00
龙腾猫跃 e6c6975047 2.6.4 2023-07-18 04:45:38 +08:00
龙腾猫跃 9c41a807c3 Merge pull request #2271 from zkitefly/patch-2
Update ModCrash.vb
2023-07-17 18:17:15 +08:00
zkitefly a0fe5903f0 Update ModCrash.vb 2023-07-17 16:43:44 +08:00
zkitefly 06be5b5b17 Update ModCrash.vb
https://github.com/Hex-Dragon/PCL2/discussions/2270
2023-07-17 16:08:38 +08:00
龙腾猫跃 73d43310c9 Merge pull request #2173 from zkitefly/patch-2
Update PageVersionSetup.xaml
2023-07-16 00:55:53 +08:00
龙腾猫跃 9b54ea3dee Merge pull request #2148 from zkitefly/log
添加检查:Mod依赖项未完善
2023-07-16 00:53:21 +08:00
zkitefly fa5026ccd7 Update PageVersionSetup.xaml 2023-07-04 17:48:05 +08:00
zkitefly ca3e7f40e1 Update PageVersionSetup.xaml 2023-07-04 17:47:15 +08:00
zkitefly 8004385d6f Update PageVersionSetup.xaml 2023-07-04 17:46:50 +08:00
龙腾猫跃 2c2bd2d489 2.6.3 正式版 2023-07-02 22:04:24 +08:00
[email protected] 80cf5957f2 更新 ModCrash.vb 2023-06-30 11:57:25 +08:00
[email protected] 7d139cbd73 添加检查:Mod依赖项未完善
https://mclo.gs/p25LjXV
2023-06-30 11:17:10 +08:00
龙腾猫跃 8a770f63cf 2.6.3 重新上传 2023-06-24 17:32:40 +08:00
龙腾猫跃 07e824b0a1 Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-06-22 17:04:56 +08:00
龙腾猫跃 794c3003f3 2.6.3 2023-06-22 17:04:23 +08:00
龙腾猫跃 d956fb2521 Merge pull request #1954 from zkitefly/patch-4
在安装 MMC 和 MCBBS 整合包时如果加载器是 org.quiltmc.quilt-loader ,则提示不支持
2023-06-17 17:21:04 +08:00
龙腾猫跃 6005856661 Merge pull request #2055 from zkitefly/log2
部分mod需要JDK11报错时的错误分析检测优化
2023-06-17 17:17:17 +08:00
龙腾猫跃 920817cc34 Merge pull request #2057 from zkitefly/log3
`OptiFine与Forge不兼容`的新规则
2023-06-17 17:11:40 +08:00
[email protected] c1167632a6 OptiFine与Forge不兼容的新规则
1.20的qwq
2023-06-17 01:14:06 +08:00
[email protected] 352799c0ed 部分mod需要JDK11报错时的错误分析检测优化
https://mclo.gs/D5MVHDa#L30
https://mclo.gs/nWMnElV#L34
https://mclo.gs/eoO8xjH#L14
https://mclo.gs/BVagUsw#L14
https://mclo.gs/Jw1dRMZ#L27
https://mclo.gs/PYRFCj3#L21
https://mclo.gs/4dCbKcJ#L19
https://mclo.gs/NCfhHYC#L14
2023-06-17 00:47:12 +08:00
zkitefly 3e5ba70516 Update ModModpack.vb 2023-06-09 22:14:59 +08:00
zkitefly 9420c37640 在安装 MMC 整合包时如果加载器是 org.quiltmc.quilt-loader ,则提示不支持 2023-06-03 02:07:36 +08:00
龙腾猫跃 ce164dd6fd 2.6.2 2023-05-28 20:18:59 +08:00
龙腾猫跃 c1a26a119f 2.6.1(正式版重新上传) 2023-05-26 00:37:18 +08:00
龙腾猫跃 10cc561ac6 2.6.0 正式版重新上传 2023-05-26 00:30:09 +08:00
龙腾猫跃 ba883713d9 Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-05-25 18:16:18 +08:00
龙腾猫跃 d01372495b 2.6.0 正式版 2023-05-25 18:16:05 +08:00
龙腾猫跃 5c2a78e5e0 Merge pull request #1865 from WForst-Breeze/wfb-1
优化 综合 Bug 反馈 模板
2023-05-17 14:48:22 +08:00
风释清然SC 74a5e1d6ab 优化 综合 Bug 反馈 2023-05-16 21:26:01 +08:00
风释清然SC 800347fa37 优化 综合 Bug 反馈 2023-05-16 21:08:07 +08:00
龙腾猫跃 cf74de5789 2.6.0 2023-05-11 02:03:06 +08:00
龙腾猫跃 1748fec3dd Merge pull request #1773 from zkitefly/log2
更新 ModCrash.vb
2023-05-10 02:28:33 +08:00
龙腾猫跃 854546444b Merge pull request #1772 from zkitefly/patch-4
修改链接
2023-05-10 01:40:02 +08:00
[email protected] 1224c1a427 更新 ModCrash.vb
https://mclo.gs/pyYhqhx
https://mclo.gs/qCDf08i
2023-05-03 10:54:42 +08:00
[email protected] c02045bfe0 更新 ModCrash.vb
https://mclo.gs/rVgURRg
2023-05-03 10:28:17 +08:00
[email protected] 820e4c0cef 更新 ModCrash.vb 2023-05-02 19:07:17 +08:00
zkitefly e99293ecd2 修改链接 2023-05-02 18:51:27 +08:00
龙腾猫跃 fd7049ceed 2.5.4 2023-04-26 04:27:52 +08:00
龙腾猫跃 11ecc11566 2.5.3 重发布 2023-04-09 22:35:54 +08:00
龙腾猫跃 78d8a778c7 Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-04-09 02:49:47 +08:00
龙腾猫跃 f4448eddf4 2.5.3 2023-04-09 02:49:08 +08:00
龙腾猫跃 9fc2a502ef Merge pull request #1601 from zkitefly/patch-4
Update ModCrash.vb
2023-04-08 21:44:45 +08:00
zkitefly 2392752756 Update ModCrash.vb 2023-04-08 12:42:24 +08:00
龙腾猫跃 3fd6c9d483 Merge pull request #1564 from youzi-2333/main
添加常见错误
2023-04-07 18:01:39 +08:00
youzi-2333 ba0929983c 添加常见错误 2023-04-02 22:00:13 +08:00
龙腾猫跃 b5adc1175c 2.5.2 正式版 2023-03-28 14:52:45 +08:00
龙腾猫跃 7cf61bc7cd 2.5.2 2023-03-24 00:41:28 +08:00
龙腾猫跃 d886acdeac 2.5.1 2023-03-08 23:34:10 +08:00
龙腾猫跃 36c10ade8c Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-02-16 22:21:13 +08:00
龙腾猫跃 6dc8789ac0 2.5.0 2023-02-16 22:21:04 +08:00
龙腾猫跃 e6b3b8e778 Merge pull request #1121 from zkitefly/log
更新 ModCrash.vb
2023-02-13 22:52:48 +08:00
龙腾猫跃 a9bf0b682a 2.4.9 正式版 2023-02-07 16:51:28 +08:00
龙腾猫跃 d540b94448 2.4.9 2023-02-06 22:54:56 +08:00
龙腾猫跃 64539ad55c 2.4.8 正式版 2023-02-06 16:36:43 +08:00
龙腾猫跃 b06328645c 2.4.8 2023-02-04 18:35:32 +08:00
[email protected] 324d2457f7 更新 ModCrash.vb
https://github.com/huanghongxun/HMCL/discussions/1904#discussioncomment-4332485
https://github.com/huanghongxun/HMCL/discussions/1904#discussioncomment-4332522
2023-02-02 22:26:55 +08:00
龙腾猫跃 eb9e7864c9 2.4.7 正式版 2023-01-29 14:23:27 +08:00
龙腾猫跃 c2b282c8db 2.4.7 2023-01-27 01:11:26 +08:00
龙腾猫跃 48214557da Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-01-26 01:50:57 +08:00
龙腾猫跃 06b50fa74c 2.4.6 2023-01-26 01:50:52 +08:00
龙腾猫跃 7cab6b281a Merge pull request #1002 from WForst-Breeze/main
更改对于无法加载 Mod 的版本的提示
2023-01-24 20:22:09 +08:00
风释清然SC c28f05aae1 想了想还是改回来吧…… 2023-01-24 20:15:27 +08:00
风释清然SC f11aedef5d Update PageVersionModDisabled.xaml 2023-01-24 19:55:35 +08:00
风释清然SC 63e002780a PCL2 #1001 2023-01-24 19:54:04 +08:00
龙腾猫跃 8e5362e2df Merge pull request #925 from WorldHim/main
修复反馈链接问题
2023-01-24 18:47:55 +08:00
WorldHim 3129edd09f 修复反馈链接问题 2023-01-16 08:05:54 +08:00
龙腾猫跃 45a9bf1096 2.4.5 2023-01-08 20:36:30 +08:00
龙腾猫跃 bef94fa743 2.4.4 正式版 2022-12-16 16:44:47 +08:00
龙腾猫跃 fd329037e7 2.4.4 2022-12-12 02:34:19 +08:00
龙腾猫跃 5fb5a3b963 2.4.3 2022-11-26 22:39:08 +08:00
龙腾猫跃 5ef1d60e2e 由于联机已被禁用,公开联机部分代码 2022-11-10 20:22:47 +08:00
龙腾猫跃 d091e153a9 删除联机的反馈选项 2022-11-08 19:57:28 +08:00
157 changed files with 27614 additions and 12713 deletions

No files matched your search

+16 -10
View File
@@ -1,5 +1,5 @@
name: "Minecraft 崩溃"
description: "PCL2 提示 “Minecraft 出现错误”,或游戏崩溃"
description: "PCL 提示 “Minecraft 出现错误”,或游戏崩溃"
labels: [· Bug, 新反馈]
body:
- type: checkboxes
@@ -8,13 +8,11 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "**我所启动的游戏不是整合包,且未安装任何 Mod。** 安装 Mod 后的游戏崩溃不是 PCL2 的原因,请 **不要** 提交反馈。你可以在 QQ 群里或者论坛找人求助,但这里并不是你求助的地方。"
- label: "**我所启动的游戏不是整合包,且未安装任何 Mod。** 安装 Mod 后的游戏崩溃基本不是 PCL 的原因,请 **不要** 提交反馈。你可以在论坛或社区找人求助,但这里并不是你求助的地方。"
required: false
- label: "**我已尝试使用 HMCL 启动,HMCL 没有出现问题。** 如果 HMCL 也无法启动就不是 PCL 导致的问题,请 **不要** 提交反馈。[下载 HMCL](https://hmcl.huangyuhui.net/download)"
required: true
- label: "**我已尝试使用其他启动器,其他启动器没有出现问题。** 如果其他启动器也存在问题,证明是游戏本身的问题,并非 PCL2 的问题,请 **不要** 提交反馈。[下载其他启动器](https://www.mcbbs.net/forum.php?mod=forumdisplay&fid=43&filter=typeid&typeid=908)"
required: true
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未修复这个 Bug。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一 Bug 未被提交过。"
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Hex-Dragon/PCL2/discussions/1930) 中搜索,确认了这一 Bug 未被提交过。"
required: true
- type: textarea
id: "yml-2"
@@ -26,8 +24,16 @@ body:
- type: textarea
id: "yml-3"
attributes:
label: 错误报告、日志与附件
description: "上传 PCL2 提供的错误报告(在崩溃时选择导出错误报告)。如果没有,也可以上传 PCL 文件夹中的 Log1~5.txt。"
label: PCL 错误报告、日志与附件
description: "上传 PCL 提供的错误报告(在崩溃时选择导出错误报告)。如果没有,也可以上传 PCL 文件夹中的 Log1~5.txt。"
placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
validations:
required: true
required: true
- type: textarea
id: "yml-4"
attributes:
label: HMCL 启动脚本
description: "在 HMCL 中进入版本列表,点击版本右侧的三个点,选择 生成启动脚本。"
placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
validations:
required: false
+6 -8
View File
@@ -1,5 +1,5 @@
name: "下载或登录时卡住或失败"
description: "下载游戏、Mod 或整合包,登录正版账号时出现问题"
description: "下载游戏、Mod 或整合包,或登录正版账号时出现问题"
labels: [· Bug, 新反馈]
body:
- type: checkboxes
@@ -8,13 +8,11 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "**我已尝试使用其他启动器,其他启动器没有出现问题。** 如果其他启动器也存在问题,证明是网络环境不佳[(解决方法)](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-0hDr),并非 PCL2 的问题,请 **不要** 提交反馈。[下载其他启动器](https://www.mcbbs.net/forum.php?mod=forumdisplay&fid=43&filter=typeid&typeid=908)"
- label: "**我已尝试使用其他启动器,其他启动器没有出现问题。** 如果其他启动器也存在问题,证明是网络环境不佳[(解决方法)](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-0hDr),并非 PCL 的问题,请 **不要** 提交反馈。[下载 HMCL](https://hmcl.huangyuhui.net/download)"
required: false
- label: "我知晓大多数此类问题都是网络环境不佳导致的,但我确实认为我的问题可能是 PCL 导致的,和网络环境无关。"
required: true
- label: "我已知晓大多数此类问题都是网络环境不佳导致的,但我确实认为我的问题是 PCL2 导致的,和我的网络环境无关。"
required: true
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未修复这个 Bug。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一 Bug 未被提交过。"
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Hex-Dragon/PCL2/discussions/1930) 中搜索,确认了这一 Bug 未被提交过。"
required: true
- type: textarea
id: "yml-2"
@@ -40,4 +38,4 @@ body:
description: "上传 PCL 文件夹中的 Log1~5.txt。[日志在哪?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-fvZW)"
placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
validations:
required: true
required: true
+2 -4
View File
@@ -8,9 +8,7 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未修复这个 Bug。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一 Bug 未被提交过。"
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Hex-Dragon/PCL2/discussions/1930) 中搜索,确认了这一 Bug 未被提交过。"
required: true
- type: textarea
id: "yml-2"
@@ -36,4 +34,4 @@ body:
description: "上传 PCL 文件夹中的 Log1~5.txt。[日志在哪?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-fvZW)"
placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
validations:
required: true
required: true
+1 -3
View File
@@ -8,9 +8,7 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未实现这项建议。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一建议未被提交过。"
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Hex-Dragon/PCL2/discussions/1930) 中搜索,确认了这一建议未被提交过。"
required: true
- label: "我已查看 [功能投票页面](https://github.com/Hex-Dragon/PCL2/discussions/categories/%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8/),确认了这一建议未在投票列表中。"
required: true
+5 -5
View File
@@ -2,10 +2,10 @@ blank_issues_enabled: false
contact_links:
- name: 帮助文档反馈
url: https://github.com/LTCatt/PCL2Help/issues
about: 提交 PCL2 帮助系统(更多 → 帮助)相关的反馈
- name: 联机反馈与交流
url: https://shimowendang.com/docs/KrkEVXz1K0frowAJ#anchor-7qQG
about: 加入联机模块官方 QQ 群反馈联机异常,或询问联机功能的使用方式
about: 提交与 PCL 帮助文档(更多 → 帮助)中的具体内容相关的反馈
- name: 提问
url: https://github.com/Hex-Dragon/PCL2/discussions/new?category=%E6%8F%90%E9%97%AE
about: 我不想提交反馈,只是想问一些问题
about: 我想问一些 PCL 相关的问题……
- name: 讨论
url: https://github.com/Hex-Dragon/PCL2/discussions/new?category=%E8%AE%A8%E8%AE%BA
about: 我想讨论一些 PCL 相关的事情……
+2 -4
View File
@@ -8,13 +8,11 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未实现这一功能。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一提案未被提交过。"
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Hex-Dragon/PCL2/discussions/1930) 中搜索,确认了这一提案未被提交过。"
required: true
- label: "我已查看 [功能投票页面](https://github.com/Hex-Dragon/PCL2/discussions/categories/%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8/),确认了这一提案未在投票列表中。"
required: true
- label: "我已知晓还没做的新功能真的太多了,忙不过来,所以新功能提案几乎不会被处理,也不建议再提交新功能提案 qwq……"
- label: "我知晓还没做的新功能真的太多了,忙不过来,所以新功能提案几乎不会被处理,也不建议再提交新功能提案 qwq……"
required: true
- type: textarea
id: "yml-2"
-3
View File
@@ -349,9 +349,6 @@ ModSetup.vb
PageOtherAbout.*
PageOtherTest.*
PageSetupUI.*
# 公开联机代码可能导致安全风险
Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb
Plain Craft Launcher 2/Pages/PageLink/PageLinkHiPer.xaml.vb
# 开发者工具
ModDevelop.vb
# 不公开底层函数库,以免抄袭
View File
File renamed without changes.
+34 -25
View File
@@ -23,7 +23,8 @@
<SolidColorBrush x:Key="ColorBrush6">#d5e6fd</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrush7">#e0eafd</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrush8">#eaf2fe</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrush9">#80e0eafd</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushBg0">#96c0f9</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushBg1">#bee0eafd</SolidColorBrush>
<Color x:Key="ColorObject1">#343d4a</Color>
<Color x:Key="ColorObject2">#0b5bcb</Color>
<Color x:Key="ColorObject3">#1370f3</Color>
@@ -32,7 +33,8 @@
<Color x:Key="ColorObject6">#d5e6fd</Color>
<Color x:Key="ColorObject7">#e0eafd</Color>
<Color x:Key="ColorObject8">#eaf2fe</Color>
<Color x:Key="ColorObject9">#40eaf2fe</Color>
<Color x:Key="ColorObjectBg0">#96c0f9</Color>
<Color x:Key="ColorObjectBg1">#bee0eafd</Color>
<SolidColorBrush x:Key="ColorBrushGray1">#404040</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushGray2">#737373</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushGray3">#8c8c8c</SolidColorBrush>
@@ -52,7 +54,9 @@
<SolidColorBrush x:Key="ColorBrushRedBack">#80fbdddd</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushRedLight">#ff4c4c</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushRedDark">#ce2111</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushHalfWhite" Color="#44ffffff" />
<SolidColorBrush x:Key="ColorBrushHalfWhite" Color="#55ffffff" />
<SolidColorBrush x:Key="ColorBrushSemiWhite" Color="#bbffffff" />
<SolidColorBrush x:Key="ColorBrushWhite" Color="#ffffff" />
<SolidColorBrush x:Key="ColorBrushTransparent" Color="Transparent" />
<SolidColorBrush x:Key="ColorBrushSemiTransparent">#01eaf2fe</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushBackgroundTransparentSidebar" Color="#D2FFFFFF" />
@@ -63,7 +67,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<ContentPresenter/>
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
@@ -129,9 +133,9 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1.5" CornerRadius="3" MaxWidth="500" Background="White" Margin="0,0,4,4" SnapsToDevicePixels="True">
<Border Loaded="TooltipLoaded" Unloaded="TooltipUnloaded" BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1.5" CornerRadius="4" MaxWidth="500" Background="#E5FFFFFF" Margin="0,0,4,4" SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect Opacity="0.4" BlurRadius="4" ShadowDepth="2" />
<DropShadowEffect Opacity="0.3" BlurRadius="4" ShadowDepth="2" Color="{DynamicResource ColorObject1}" />
</Border.Effect>
<TextBlock Text="{TemplateBinding ContentControl.Content}" TextWrapping="Wrap" Foreground="{DynamicResource ColorBrush1}" Margin="7,5" FontSize="12"/>
</Border>
@@ -143,7 +147,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1" CornerRadius="3" Background="White" Margin="0,0,4,4" SnapsToDevicePixels="True">
<Border Loaded="TooltipLoaded" Unloaded="TooltipUnloaded" BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1" CornerRadius="3" Background="White" Margin="0,0,4,4" SnapsToDevicePixels="True">
<TextBlock Text="{TemplateBinding ContentControl.Content}" TextWrapping="Wrap" Foreground="{DynamicResource ColorBrush1}" Margin="7,5" FontSize="12"/>
</Border>
</ControlTemplate>
@@ -273,8 +277,8 @@
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="UndoLimit" Value="15" />
<Setter Property="MaxLength" Value="10000" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush1}" />
<Setter Property="MaxLength" Value="1000" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrushBg0}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
@@ -283,14 +287,14 @@
<RowDefinition MinHeight="28" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Margin="{TemplateBinding Padding}" IsHitTestVisible="False" VerticalAlignment="Center" BorderThickness="0">
<TextBlock x:Name="labHint" Foreground="{StaticResource ColorBrushGray3}" Margin="7,0,0,0" Padding="{TemplateBinding BorderThickness}" FontSize="{TemplateBinding FontSize}" FontFamily="Resources/#PCL English, Microsoft YaHei UI" />
</Border>
<Border x:Name="border" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" CornerRadius="3">
<ScrollViewer x:Name="PART_ContentHost" Style="{StaticResource ScrollViewerNoMargin}" RenderOptions.ClearTypeHint="Enabled" BorderThickness="0"
Margin="5,0,0,0" Cursor="IBeam" />
<!-- 由于未知原因,TextView 会有 2,0 的 Margin -->
</Border>
<Border Margin="{TemplateBinding Padding}" IsHitTestVisible="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" BorderThickness="0">
<TextBlock x:Name="labHint" Foreground="{DynamicResource ColorBrush1}" Opacity="0.25" Margin="7,0,0,0" Padding="{TemplateBinding BorderThickness}" FontSize="{TemplateBinding FontSize}" FontFamily="Resources/#PCL English, Microsoft YaHei UI" />
</Border>
<TextBlock Grid.Row="1" x:Name="labWrong" Height="0" Foreground="{TemplateBinding BorderBrush}" Padding="0,4,0,0" />
</Grid>
</ControlTemplate>
@@ -303,7 +307,7 @@
<Setter Property="SelectionBrush" Value="{DynamicResource ColorBrush3}" />
<Setter Property="Foreground" Value="{DynamicResource ColorBrush1}" />
<Setter Property="Background" Value="{StaticResource ColorBrushHalfWhite}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush1}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrushBg0}" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
@@ -317,19 +321,20 @@
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Trigger.Setters>
<Setter Property="Foreground" Value="{StaticResource ColorBrushGray4}" />
<Setter Property="BorderBrush" Value="{StaticResource ColorBrushGray4}" />
<Setter Property="BorderBrush" Value="{StaticResource ColorBrushGray5}" />
<Setter Property="Background" Value="{StaticResource ColorBrushGray6}" />
</Trigger.Setters>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.Setters>
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush3}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush4}" />
<Setter Property="Background" Value="{DynamicResource ColorBrush7}" />
</Trigger.Setters>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Trigger.Setters>
<Setter Property="Background" Value="{DynamicResource ColorBrush9}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush4}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush3}" />
<Setter Property="Background" Value="{DynamicResource ColorBrush7}" />
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
@@ -340,7 +345,7 @@
<!-- ComboBox -->
<DataTemplate x:Key="ComboBoxItemTemplateWithDelete">
<local:MyListItem Title="{Binding}" FontSize="13" PaddingRight="40" MaxHeight="26" IsScaleAnimationEnabled="False" Margin="-1,0,0,0">
<local:MyListItem Title="{Binding}" FontSize="13" MaxHeight="26" IsScaleAnimationEnabled="False" Margin="-3,0,0,0">
<local:MyListItem.Buttons>
<x:Array Type="local:MyIconButton">
<local:MyIconButton Grid.Column="1" Height="20" Width="20" VerticalAlignment="Center" Tag="{Binding}" Click="MyIconButton_Click" Logo="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z" />
@@ -348,16 +353,12 @@
</local:MyListItem.Buttons>
</local:MyListItem>
</DataTemplate>
<!--<DataTemplate x:Key="ComboBoxItemTemplateNormal">
<local:MyListItem Title="{Binding}" FontSize="13" PaddingRight="40" Height="26" Margin="-1,0,0,0" />
</DataTemplate>-->
<Style TargetType="local:MyComboBox">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource ColorBrush1}" />
<Setter Property="Foreground" Value="{DynamicResource ColorBrushBg0}" />
<Setter Property="Background" Value="{StaticResource ColorBrushHalfWhite}" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<!--<Setter Property="ItemTemplate" Value="{StaticResource ComboBoxItemTemplateNormal}"/>-->
<Setter Property="FontSize" Value="13" />
<Setter Property="MaxDropDownHeight" Value="160" />
<Setter Property="Template">
@@ -366,7 +367,10 @@
<Grid>
<Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="3" BorderThickness="1" BorderBrush="{TemplateBinding Foreground}" />
<ToggleButton Margin="0,0,1.5,0" Foreground="{TemplateBinding Foreground}" IsTabStop="False" SnapsToDevicePixels="False" Focusable="False" IsChecked="{Binding IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" />
<ContentPresenter Margin="8.5,0,21.5,0" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" VerticalAlignment="Center" />
<ContentPresenter x:Name="PART_Content" Margin="8.5,0,21.5,0" IsHitTestVisible="False" VerticalAlignment="Center"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" />
<Popup x:Name="PART_Popup" SnapsToDevicePixels="True" VerticalOffset="-1.5" AllowsTransparency="True" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PopupAnimation="Fade">
<Grid x:Name="PanPopup">
<Border Background="White" CornerRadius="3" />
@@ -462,6 +466,11 @@
</Style>
<Style TargetType="ComboBoxItem" x:Key="MyComboBoxItem">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="ToolTipService.Placement" Value="Relative" />
<Setter Property="ToolTipService.VerticalOffset" Value="-2" />
<Setter Property="ToolTipService.HorizontalOffset" Value="200" />
<Setter Property="ToolTipService.InitialShowDelay" Value="150" />
<Setter Property="ToolTipService.BetweenShowDelay" Value="150" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Background" Value="{StaticResource ColorBrushTransparent}" />
<Setter Property="Template">
+105 -74
View File
@@ -15,12 +15,10 @@ Public Class Application
Log(ex, "开发者模式测试出错", LogLevel.Feedback)
End Try
End Sub
#End If
'开始
Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
ApplicationStartTick = GetTimeTick()
SecretOnApplicationStart()
Try
'检查参数调用
@@ -28,18 +26,33 @@ Public Class Application
If e.Args(0) = "--update" Then
'自动更新
UpdateReplace(e.Args(1), e.Args(2).Trim(""""), e.Args(3).Trim(""""), e.Args(4))
Environment.[Exit](Result.Cancel)
Exit Sub
ElseIf e.Args(0).StartsWith("--link") Then
'稍作等待后切换到联机页面
Thread.Sleep(1000)
FormMain.IsLinkRestart = True
Environment.Exit(Result.Cancel)
'ElseIf e.Args(0).StartsWithF("--link") Then
' '稍作等待后切换到联机页面
' Thread.Sleep(1000)
' FormMain.IsLinkRestart = True
ElseIf e.Args(0).StartsWithF("--memory") Then
'内存优化
Dim Ram = My.Computer.Info.AvailablePhysicalMemory
Try
PageOtherTest.MemoryOptimizeInternal()
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "内存优化失败")
Environment.Exit(-1)
End Try
If My.Computer.Info.AvailablePhysicalMemory < Ram Then '避免 ULong 相减出现负数
Environment.Exit(0)
Else
Environment.Exit((My.Computer.Info.AvailablePhysicalMemory - Ram) / 1024) '返回清理的内存量(K)
End If
#If DEBUG Then
ElseIf e.Args(0) = "--make" Then
'制作更新包
UpdateMake(e.Args(1))
Environment.[Exit](Result.Cancel)
Exit Sub
ElseIf e.Args(0) = "--edit1" Then
ExeEdit(e.Args(1), True)
Environment.Exit(Result.Cancel)
ElseIf e.Args(0) = "--edit2" Then
ExeEdit(e.Args(1), False)
Environment.Exit(Result.Cancel)
#End If
End If
End If
@@ -48,26 +61,38 @@ Public Class Application
Directory.CreateDirectory(Path & "PCL\Musics")
Try
Directory.CreateDirectory(PathTemp)
If Not CheckPermission(PathTemp) Then Throw New Exception("PCL2 没有对 " & PathTemp & " 的访问权限")
If Not CheckPermission(PathTemp) Then Throw New Exception("PCL 没有对 " & PathTemp & " 的访问权限")
Catch ex As Exception
MyMsgBox("手动设置的缓存文件夹不可用,PCL2 将使用默认缓存文件夹。" & vbCrLf & "错误原因:" & GetString(ex, False), "缓存文件夹不可用")
Setup.Set("SystemSystemCache", "")
PathTemp = IO.Path.GetTempPath() & "PCL\"
If PathTemp = IO.Path.GetTempPath() & "PCL\" Then
MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & "错误原因:" & GetExceptionDetail(ex), "缓存文件夹不可用")
Else
MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & "错误原因:" & GetExceptionDetail(ex), "缓存文件夹不可用")
Setup.Set("SystemSystemCache", "")
PathTemp = IO.Path.GetTempPath() & "PCL\"
End If
End Try
Directory.CreateDirectory(PathTemp & "Cache")
Directory.CreateDirectory(PathTemp & "Download")
Directory.CreateDirectory(PathAppdata)
'检测单例
#If Not DEBUG Then
Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher 2 ")
Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher ")
If WindowHwnd = IntPtr.Zero Then FindWindow(Nothing, "Plain Craft Launcher 2 ")
If WindowHwnd <> IntPtr.Zero Then
'将已有的 PCL2 窗口拖出来
'将已有的 PCL 窗口拖出来
ShowWindowToTop(WindowHwnd)
'播放提示音并退出
Beep()
Environment.[Exit](Result.Cancel)
Exit Sub
End If
#End If
'设置 ToolTipService 默认值
ToolTipService.InitialShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(300))
ToolTipService.BetweenShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(400))
ToolTipService.ShowDurationProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(9999999))
ToolTipService.PlacementProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(Primitives.PlacementMode.Bottom))
ToolTipService.HorizontalOffsetProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(8.0))
ToolTipService.VerticalOffsetProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(4.0))
'设置初始窗口
If Setup.Get("UiLauncherLogo") AndAlso Not FormMain.IsLinkRestart Then
FrmStart = New SplashScreen("Images\icon.ico")
@@ -78,24 +103,23 @@ Public Class Application
'日志初始化
LogStart()
'添加日志
Log("[Start] 程序版本:" & VersionDisplayName & "(" & VersionCode & ")")
Log("[Start] 识别码:" & UniqueAddress & If(ThemeCheckOne(9), ",已解锁反馈主题", ""))
Log("[Start] 程序路径:" & PathWithName)
Log($"[Start] 程序版本:{VersionDisplayName} ({VersionCode})")
Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}")
Log($"[Start] 程序路径:{PathWithName}")
Log($"[Start] 系统编码:{Encoding.Default} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})")
'检测压缩包运行
If Path.Contains(IO.Path.GetTempPath()) OrElse Path.Contains("AppData\Local\Temp\") Then
MyMsgBox("PCL2 正在临时文件夹运行,设置、游戏存档等很可能无法保存,且部分功能会无法使用或出错。" & vbCrLf & "请将 PCL2 从压缩文件中解压,或是更换文件夹后再继续使用!", "环境警告", "我知道了", IsWarn:=True)
MyMsgBox("PCL 正在临时文件夹运行,设置、游戏存档等很可能无法保存,且部分功能会无法使用或出错。" & vbCrLf & "请将 PCL 从压缩文件中解压,或是更换文件夹后再继续使用!", "环境警告", "我知道了", IsWarn:=True)
End If
'设置初始化
Setup.Load("SystemDebugMode")
Setup.Load("SystemDebugAnim")
Setup.Load("ToolDownloadThread")
Setup.Load("ToolDownloadCert")
'网络配置初始化
ServicePointManager.Expect100Continue = True
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
ServicePointManager.DefaultConnectionLimit = 1024
ServicePointManager.ServerCertificateValidationCallback = New Security.RemoteCertificateValidationCallback(Function() As Boolean
Return True
End Function)
'计时
Log("[Start] 第一阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
ApplicationStartTick = GetTimeTick()
@@ -105,7 +129,7 @@ Public Class Application
#End If
AniControlEnabled += 1
Catch ex As Exception
MsgBox(GetString(ex, False, True), MsgBoxStyle.Critical, "PCL2 初始化错误")
MsgBox(GetExceptionDetail(ex, True), MsgBoxStyle.Critical, "PCL 初始化错误")
FormMain.EndProgramForce(Result.Exception)
End Try
End Sub
@@ -127,13 +151,13 @@ Public Class Application
Exit Sub
End If
IsCritErrored = True
Dim ExceptionString As String = GetString(e.Exception, False, True)
Dim ExceptionString As String = GetExceptionDetail(e.Exception, True)
If ExceptionString.Contains("System.Windows.Threading.Dispatcher.Invoke") OrElse
ExceptionString.Contains("MS.Internal.AppModel.ITaskbarList.HrInit") OrElse
ExceptionString.Contains(".Net Framework") OrElse ' “自动错误判断” 的结果分析
ExceptionString.Contains(".NET Framework") OrElse ' “自动错误判断” 的结果分析
ExceptionString.Contains("未能加载文件或程序集") Then
OpenWebsite("https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-offline-installer")
MsgBox("你的 .Net Framework 版本过低或损坏,请在打开的网页中重新下载并安装 .NET Framework 4.6.2 后重试!", MsgBoxStyle.Information, "运行环境错误")
MsgBox("你的 .NET Framework 版本过低或损坏,请在打开的网页中重新下载并安装 .NET Framework 4.6.2 后重试!", MsgBoxStyle.Information, "运行环境错误")
FormMain.EndProgramForce(Result.Cancel)
Else
FeedbackInfo()
@@ -149,7 +173,7 @@ Public Class Application
Private Shared ReadOnly AssemblyJsonLock As New Object
Private Shared ReadOnly AssemblyDialogLock As New Object
Public Shared Function AssemblyResolve(sender As Object, args As ResolveEventArgs) As Assembly
If args.Name.StartsWith("NAudio") Then
If args.Name.StartsWithF("NAudio") Then
SyncLock AssemblyNAudioLock
If AssemblyNAudio Is Nothing Then
Log("[Start] 加载 DLL:NAudio")
@@ -157,7 +181,7 @@ Public Class Application
End If
Return AssemblyNAudio
End SyncLock
ElseIf args.Name.StartsWith("Newtonsoft.Json") Then
ElseIf args.Name.StartsWithF("Newtonsoft.Json") Then
SyncLock AssemblyJsonLock
If AssemblyJson Is Nothing Then
Log("[Start] 加载 DLL:Json")
@@ -165,7 +189,7 @@ Public Class Application
End If
Return AssemblyJson
End SyncLock
ElseIf args.Name.StartsWith("Ookii.Dialogs.Wpf") Then
ElseIf args.Name.StartsWithF("Ookii.Dialogs.Wpf") Then
SyncLock AssemblyDialogLock
If AssemblyDialog Is Nothing Then
Log("[Start] 加载 DLL:Dialogs")
@@ -180,49 +204,56 @@ Public Class Application
'切换窗口
'控件模板事件
Private Sub MyIconButton_Click(sender As Object, e As EventArgs)
If Setup.Get("LoginType") = McLoginType.Legacy Then
'离线
Dim Names As New List(Of String)
Names.AddRange(Setup.Get("LoginLegacyName").ToString.Split("¨"))
Names.Remove(sender.Tag)
Setup.Set("LoginLegacyName", Join(Names, "¨"))
FrmLoginLegacy.ComboName.ItemsSource = Names
FrmLoginLegacy.ComboName.Text = If(Names.Count > 0, Names(0), "")
Else
'非离线
Dim Token As String = GetStringFromEnum(Setup.Get("LoginType"))
Dim Dict As New Dictionary(Of String, String)
Dim Names As New List(Of String)
Dim Passs As New List(Of String)
If Not Setup.Get("Login" & Token & "Email") = "" Then Names.AddRange(Setup.Get("Login" & Token & "Email").ToString.Split("¨"))
If Not Setup.Get("Login" & Token & "Pass") = "" Then Passs.AddRange(Setup.Get("Login" & Token & "Pass").ToString.Split("¨"))
For i = 0 To Names.Count - 1
Dict.Add(Names(i), Passs(i))
Next
Dict.Remove(sender.Tag)
Setup.Set("Login" & Token & "Email", Join(Dict.Keys.ToArray, "¨"))
Setup.Set("Login" & Token & "Pass", Join(Dict.Values.ToArray, "¨"))
Select Case Token
Case "Mojang"
FrmLoginMojang.ComboName.ItemsSource = Dict.Keys
FrmLoginMojang.ComboName.Text = If(Dict.Keys.Count > 0, Dict.Keys(0), "")
FrmLoginMojang.TextPass.Password = If(Dict.Values.Count > 0, Dict.Values(0), "")
Case "Nide"
FrmLoginNide.ComboName.ItemsSource = Dict.Keys
FrmLoginNide.ComboName.Text = If(Dict.Keys.Count > 0, Dict.Keys(0), "")
FrmLoginNide.TextPass.Password = If(Dict.Values.Count > 0, Dict.Values(0), "")
Case "Auth"
FrmLoginAuth.ComboName.ItemsSource = Dict.Keys
FrmLoginAuth.ComboName.Text = If(Dict.Keys.Count > 0, Dict.Keys(0), "")
FrmLoginAuth.TextPass.Password = If(Dict.Values.Count > 0, Dict.Values(0), "")
Case Else
DebugAssert(True)
Exit Sub
End Select
End If
Select Case Setup.Get("LoginType")
Case McLoginType.Ms
'微软
Dim MsJson As JObject = GetJson(Setup.Get("LoginMsJson"))
MsJson.Remove(sender.Tag)
Setup.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None))
FrmLoginMs.ComboAccounts.Items.Remove(sender.Parent)
Case McLoginType.Legacy
'离线
Dim Names As New List(Of String)
Names.AddRange(Setup.Get("LoginLegacyName").ToString.Split("¨"))
Names.Remove(sender.Tag)
Setup.Set("LoginLegacyName", Join(Names, "¨"))
FrmLoginLegacy.ComboName.ItemsSource = Names
FrmLoginLegacy.ComboName.Text = If(Names.Any, Names(0), "")
Case Else
'第三方
Dim Token As String = GetStringFromEnum(Setup.Get("LoginType"))
Dim Dict As New Dictionary(Of String, String)
Dim Names As New List(Of String)
Dim Passs As New List(Of String)
If Not Setup.Get("Login" & Token & "Email") = "" Then Names.AddRange(Setup.Get("Login" & Token & "Email").ToString.Split("¨"))
If Not Setup.Get("Login" & Token & "Pass") = "" Then Passs.AddRange(Setup.Get("Login" & Token & "Pass").ToString.Split("¨"))
For i = 0 To Names.Count - 1
Dict.Add(Names(i), Passs(i))
Next
Dict.Remove(sender.Tag)
Setup.Set("Login" & Token & "Email", Join(Dict.Keys, "¨"))
Setup.Set("Login" & Token & "Pass", Join(Dict.Values, "¨"))
Select Case Token
Case "Nide"
FrmLoginNide.ComboName.ItemsSource = Dict.Keys
FrmLoginNide.ComboName.Text = If(Dict.Keys.Any, Dict.Keys(0), "")
FrmLoginNide.TextPass.Password = If(Dict.Values.Any, Dict.Values(0), "")
Case "Auth"
FrmLoginAuth.ComboName.ItemsSource = Dict.Keys
FrmLoginAuth.ComboName.Text = If(Dict.Keys.Any, Dict.Keys(0), "")
FrmLoginAuth.TextPass.Password = If(Dict.Values.Any, Dict.Values(0), "")
End Select
End Select
End Sub
Public Shared ShowingTooltips As New List(Of Border)
Private Sub TooltipLoaded(sender As Border, e As EventArgs)
ShowingTooltips.Add(sender)
End Sub
Private Sub TooltipUnloaded(sender As Border, e As RoutedEventArgs)
ShowingTooltips.Remove(sender)
End Sub
End Class
@@ -134,23 +134,21 @@
'实现自定义事件
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
If IsMouseDown Then
Log("[Control] 按下按钮:" & Text)
RaiseEvent Click(sender, e)
If Not String.IsNullOrEmpty(Tag) Then
If Tag.ToString.StartsWith("链接-") OrElse Tag.ToString.StartsWith("启动-") Then
Hint("主页自定义按钮语法已更新,且不再兼容老版本语法,请查看新的自定义示例!")
End If
If Not IsMouseDown Then Exit Sub
Log("[Control] 按下按钮:" & Text)
RaiseEvent Click(sender, e)
If Not String.IsNullOrEmpty(Tag) Then
If Tag.ToString.StartsWithF("链接-") OrElse Tag.ToString.StartsWithF("启动-") Then
Hint("主页自定义按钮语法已更新,且不再兼容老版本语法,请查看新的自定义示例!")
End If
ModEvent.TryStartEvent(EventType, EventData)
End If
ModEvent.TryStartEvent(EventType, EventData)
End Sub
Public Property EventType As String
Get
Return GetValue(EventTypeProperty)
End Get
Set(ByVal value As String)
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
@@ -159,8 +157,7 @@
Get
Return GetValue(EventDataProperty)
End Get
Set(ByVal value As String)
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
@@ -177,7 +174,7 @@
}, "MyButton Scale " & Uuid)
End Sub
Private Sub Button_MouseEnter() Handles Me.MouseEnter
AniStart(AaColor(PanFore, BackgroundProperty, If(_ColorType = ColorState.Red, "ColorBrushRedBack", "ColorBrush9"), AnimationColorIn), "MyButton Background " & Uuid)
AniStart(AaColor(PanFore, BackgroundProperty, If(_ColorType = ColorState.Red, "ColorBrushRedBack", "ColorBrush7"), AnimationColorIn), "MyButton Background " & Uuid)
End Sub
Private Sub Button_MouseUp() Handles Me.MouseLeftButtonUp
If Not IsMouseDown Then Exit Sub
+50 -17
View File
@@ -41,10 +41,6 @@
End Sub
Private IsLoad As Boolean = False
Private Sub MyCard_Loaded() Handles Me.Loaded
'卡片的进入时动画已被页面通用切换动画替代
'If LoadAnimation AndAlso IsLoad Then
' StartHeightAnimation(Math.Min(50, ActualHeight), ActualHeight - Math.Min(50, ActualHeight), True)
'End If
If IsLoad Then Exit Sub
'初次加载限定
If Not Title = "" AndAlso IsNothing(MainTextBlock) Then
@@ -96,8 +92,8 @@
Return VersionSortBoolean(Left.Version, Right.Version)
End Function)
Case 8, 9
Stack.Tag = Sort(CType(Stack.Tag, List(Of DlCfFile)), Function(Left As DlCfFile, Right As DlCfFile) As Boolean
Return Left.Date > Right.Date
Stack.Tag = Sort(CType(Stack.Tag, List(Of CompFile)), Function(Left As CompFile, Right As CompFile) As Boolean
Return Left.ReleaseDate > Right.ReleaseDate
End Function)
End Select
'控件转换
@@ -113,7 +109,7 @@
Case 6
ForgeDownloadListItemPreload(Stack, Stack.Tag, AddressOf ForgeSave_Click, True)
Case 8
DlCfFilesPreload(Stack, Stack.Tag, AddressOf FrmDownloadMod.ProjectClick)
CompFilesCardPreload(Stack, Stack.Tag)
End Select
'实现控件虚拟化
For Each Data As Object In Stack.Tag
@@ -130,15 +126,33 @@
Case 6
Stack.Children.Add(ForgeDownloadListItem(Data, AddressOf ForgeSave_Click, True))
Case 7
Stack.Children.Add(McDownloadListItem(Data, AddressOf FrmDownloadInstall.MinecraftSelected, False))
Stack.Children.Add(McDownloadListItem(Data, Sub(sender, e) '不能使用 AddressOf,这导致了 #535,原因完全不明,疑似是编译器 Bug
FrmDownloadInstall.MinecraftSelected(sender, e)
End Sub, False))
Case 8
Stack.Children.Add(CType(Data, DlCfFile).ToListItem(AddressOf FrmDownloadCfDetail.Save_Click))
If Distinct(CType(Stack.Tag, List(Of CompFile)), Function(a, b) a.DisplayName = b.DisplayName).Count <>
CType(Stack.Tag, List(Of CompFile)).Count Then
'存在重复的名称(#1344)
Stack.Children.Add(CType(Data, CompFile).ToListItem(AddressOf FrmDownloadCompDetail.Save_Click, BadDisplayName:=True))
Else
'不存在重复的名称,正常加载
Stack.Children.Add(CType(Data, CompFile).ToListItem(AddressOf FrmDownloadCompDetail.Save_Click))
End If
Case 9
Stack.Children.Add(CType(Data, DlCfFile).ToListItem(AddressOf FrmDownloadCfDetail.Install_Click, AddressOf FrmDownloadCfDetail.Save_Click))
If Distinct(CType(Stack.Tag, List(Of CompFile)), Function(a, b) a.DisplayName = b.DisplayName).Count <>
CType(Stack.Tag, List(Of CompFile)).Count Then
'存在重复的名称(#1344)
Stack.Children.Add(CType(Data, CompFile).ToListItem(AddressOf FrmDownloadCompDetail.Install_Click, AddressOf FrmDownloadCompDetail.Save_Click, BadDisplayName:=True))
Else
'不存在重复的名称,正常加载
Stack.Children.Add(CType(Data, CompFile).ToListItem(AddressOf FrmDownloadCompDetail.Install_Click, AddressOf FrmDownloadCompDetail.Save_Click))
End If
Case 10
Stack.Children.Add(LiteLoaderDownloadListItem(Data, AddressOf LiteLoaderSave_Click, True))
Case 11
Stack.Children.Add(CType(Data, HelpEntry).ToListItem)
Case 12
Stack.Children.Add(FabricDownloadListItem(CType(Data, JObject), AddressOf FrmDownloadInstall.Fabric_Selected))
Case Else
Log("未知的虚拟化种类:" & Type, LogLevel.Feedback)
End Select
@@ -148,7 +162,9 @@
End Sub
'事件
Public Property HasMouseAnimation As Boolean = True
Private Sub MyCard_MouseEnter(sender As Object, e As MouseEventArgs) Handles Me.MouseEnter
If Not HasMouseAnimation Then Exit Sub
Dim AniList As New List(Of AniData)
If Not IsNothing(MainTextBlock) Then AniList.Add(AaColor(MainTextBlock, TextBlock.ForegroundProperty, "ColorBrush2", 150))
If Not IsNothing(MainSwap) Then AniList.Add(AaColor(MainSwap, Shapes.Path.FillProperty, "ColorBrush2", 150))
@@ -160,6 +176,7 @@
AniStart(AniList, "MyCard Mouse " & Uuid)
End Sub
Private Sub MyCard_MouseLeave(sender As Object, e As MouseEventArgs) Handles Me.MouseLeave
If Not HasMouseAnimation Then Exit Sub
Dim AniList As New List(Of AniData)
If Not IsNothing(MainTextBlock) Then AniList.Add(AaColor(MainTextBlock, TextBlock.ForegroundProperty, "ColorBrush1", 250))
If Not IsNothing(MainSwap) Then AniList.Add(AaColor(MainSwap, Shapes.Path.FillProperty, "ColorBrush1", 250))
@@ -171,7 +188,11 @@
AniStart(AniList, "MyCard Mouse " & Uuid)
End Sub
'高度改变动画
#Region "高度改变动画"
''' <summary>
''' 是否启用高度改变动画。
''' </summary>
Public Property UseAnimation As Boolean = True
Private IsHeightAnimating As Boolean = False
Private ActualUsedHeight As Double '回滚实际高度(例如 NaN)
@@ -188,7 +209,7 @@
Dim AnimList As New List(Of AniData)
If DeltaHeight > 10 OrElse (DeltaHeight < -10 AndAlso Not IsNothing(SwapControl)) Then '如果不是需要折叠的卡片,高度减小时的弹跳会吞掉按钮下边框
'高度增加较大,使用弹起动画
Dim Delta As Double = MathRange(Math.Abs(DeltaHeight) * 0.05, 3, 10) * Math.Sign(DeltaHeight)
Dim Delta As Double = MathClamp(Math.Abs(DeltaHeight) * 0.05, 3, 10) * Math.Sign(DeltaHeight)
AnimList.AddRange({
AaHeight(Me, DeltaHeight + Delta, 300, If(IsLoadAnimation, 30, 0), If(DeltaHeight > FrmMain.Height, New AniEaseInFluent(AniEasePower.ExtraStrong), New AniEaseOutFluent(AniEasePower.ExtraStrong))),
AaHeight(Me, -Delta, 150, 260, Ease:=New AniEaseOutFluent(AniEasePower.Strong))
@@ -196,7 +217,7 @@
Else
'普通的改变就行啦
AnimList.AddRange({
AaHeight(Me, DeltaHeight, MathRange(Math.Abs(DeltaHeight) * 4, 150, 250),, New AniEaseOutFluent)
AaHeight(Me, DeltaHeight, MathClamp(Math.Abs(DeltaHeight) * 4, 150, 250),, New AniEaseOutFluent)
})
End If
AnimList.Add(AaCode(Sub()
@@ -219,6 +240,8 @@
IsHeightAnimating = False
End Sub
#End Region
'折叠
'若设置了 CanSwap,或 SwapControl 不为空,则判定为会进行折叠
'这是因为不能直接在 XAML 中设置 SwapControl
@@ -235,7 +258,7 @@
Get
Return _IsSwaped
End Get
Set(ByVal value As Boolean)
Set(value As Boolean)
If _IsSwaped = value Then Exit Property
_IsSwaped = value
If SwapControl Is Nothing Then Exit Property
@@ -287,14 +310,15 @@
End Class
Partial Public Module ModAnimation
Public Sub AniDispose(Control As MyCard, RemoveFromChildren As Boolean, Optional CallBack As ParameterizedThreadStart = Nothing)
If Not Control.IsHitTestVisible Then Exit Sub
Control.IsHitTestVisible = False
AniStart({
If Control.IsHitTestVisible Then
Control.IsHitTestVisible = False
AniStart({
AaScaleTransform(Control, -0.08, 200,, New AniEaseInFluent),
AaOpacity(Control, -1, 200,, New AniEaseOutFluent),
AaHeight(Control, -Control.ActualHeight, 150, 100, New AniEaseOutFluent),
AaCode(Sub()
If RemoveFromChildren Then
If Control.Parent Is Nothing Then Exit Sub
CType(Control.Parent, Object).Children.Remove(Control)
Else
Control.Visibility = Visibility.Collapsed
@@ -302,5 +326,14 @@ Partial Public Module ModAnimation
If CallBack IsNot Nothing Then CallBack(Control)
End Sub,, True)
}, "MyCard Dispose " & Control.Uuid)
Else
If RemoveFromChildren Then
If Control.Parent Is Nothing Then Exit Sub
CType(Control.Parent, Object).Children.Remove(Control)
Else
Control.Visibility = Visibility.Collapsed
End If
If CallBack IsNot Nothing Then CallBack(Control)
End If
End Sub
End Module
@@ -130,7 +130,7 @@
If Not AllowMouseDown Then Exit Sub
MouseDowned = True
Focus()
AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrush9", 100), "MyCheckBox Background " & Uuid)
AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushBg1", 100), "MyCheckBox Background " & Uuid)
If Checked Then
AniStart({
AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True),
+23 -21
View File
@@ -62,44 +62,40 @@
'指向动画
Public Sub RefreshColor() Handles Me.IsEnabledChanged, Me.MouseEnter, Me.MouseLeave, Me.PreviewMouseLeftButtonDown, Me.PreviewMouseLeftButtonUp, Me.GotKeyboardFocus
'判断当前颜色
Dim ColorName As String
Dim BackName As String
Dim ForeColorName As String
Dim BackColorName As String
Dim Time As Integer
If IsEnabled Then
If IsEditable AndAlso Template.FindName("PART_EditableTextBox", Me).IsFocused Then
ColorName = "ColorBrush4"
BackName = "ColorBrush9"
Time = 60
ElseIf IsMouseDown OrElse IsDropDownOpen Then
ColorName = "ColorBrush3"
BackName = "ColorBrush9"
Time = 60
If IsMouseDown OrElse IsDropDownOpen OrElse (IsEditable AndAlso Template.FindName("PART_EditableTextBox", Me).IsFocused) Then
ForeColorName = "ColorBrush3"
BackColorName = "ColorBrush7"
Time = 10
ElseIf IsMouseOver Then
ColorName = "ColorBrush3"
BackName = "ColorBrushHalfWhite"
ForeColorName = "ColorBrush4"
BackColorName = "ColorBrush7"
Time = 100
Else
ColorName = "ColorBrush1"
BackName = "ColorBrushHalfWhite"
Time = 200
ForeColorName = "ColorBrushBg0"
BackColorName = "ColorBrushHalfWhite"
Time = 100
End If
Else
ColorName = "ColorBrushGray4"
BackName = "ColorBrushHalfWhite"
ForeColorName = "ColorBrushGray5"
BackColorName = "ColorBrushGray6"
Time = 200
End If
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
AniStart({
AaColor(Me, ForegroundProperty, ColorName, Time),
AaColor(Me, BackgroundProperty, BackName, Time)
AaColor(Me, ForegroundProperty, ForeColorName, Time),
AaColor(Me, BackgroundProperty, BackColorName, Time)
}, "MyComboBox Color " & Uuid)
Else
'无动画
AniStop("MyComboBox Color " & Uuid)
SetResourceReference(ForegroundProperty, ColorName)
SetResourceReference(BackgroundProperty, BackName)
SetResourceReference(ForegroundProperty, ForeColorName)
SetResourceReference(BackgroundProperty, BackColorName)
End If
End Sub
@@ -132,4 +128,10 @@
End If
End Sub
Public ReadOnly Property ContentPresenter As ContentPresenter
Get
Return Template.FindName("PART_Content", Me)
End Get
End Property
End Class
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="PanBack" mc:Ignorable="d" x:Class="MyExtraButton"
Width="40" RenderTransformOrigin="0.5,0.5" ToolTipService.ShowDuration="2333333" ToolTipService.Placement="Left" ToolTipService.VerticalOffset="16" ToolTipService.HorizontalOffset="-8" Height="0">
Width="40" RenderTransformOrigin="0.5,0.5" ToolTipService.Placement="Left" ToolTipService.VerticalOffset="16" ToolTipService.HorizontalOffset="-8" Height="0">
<Grid.RenderTransform>
<ScaleTransform ScaleX="0" ScaleY="0" />
</Grid.RenderTransform>
@@ -16,6 +16,11 @@
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.2" />
</Border.Effect>
</Border>
<Border x:Name="PanProgress" CornerRadius="1000" BorderThickness="0.001" Background="#2FFFFFFF" ClipToBounds="True" Visibility="Collapsed">
<Border.Clip>
<RectangleGeometry x:Name="RectProgress" Rect="0,5,40,35" />
</Border.Clip>
</Border>
<Path x:Name="Path" Stretch="Uniform" Margin="12" Fill="{DynamicResource ColorBrush8}" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<ScaleTransform />
@@ -4,6 +4,24 @@
Public Event Click(sender As Object, e As MouseButtonEventArgs) '自定义事件
Public Event RightClick(sender As Object, e As MouseButtonEventArgs)
'进度条
Private _Progress As Double = 0
Public Property Progress As Double
Get
Return _Progress
End Get
Set(value As Double)
If _Progress = value Then Exit Property
_Progress = value
If value < 0.0001 Then
PanProgress.Visibility = Visibility.Collapsed
Else
PanProgress.Visibility = Visibility.Visible
RectProgress.Rect = New Rect(0, 40 * (1 - value), 40, 40 * value)
End If
End Set
End Property
'自定义属性
Public Uuid As Integer = GetUuid()
Private _Logo As String = ""
@@ -84,7 +102,7 @@
Get
Return _CanRightClick
End Get
Set(ByVal value As Boolean)
Set(value As Boolean)
_CanRightClick = value
End Set
End Property
@@ -161,7 +179,7 @@
AniStop("MyExtraButton Color " & Uuid)
If IsMouseOver Then
PanColor.SetResourceReference(BackgroundProperty, "ColorBrush2")
PanColor.SetResourceReference(BackgroundProperty, "ColorBrush4")
Else
PanColor.SetResourceReference(BackgroundProperty, "ColorBrush3")
End If
+42 -9
View File
@@ -11,17 +11,17 @@
If _IsWarn = value Then Exit Property
_IsWarn = value
If _IsWarn Then
BorderBrush = New MyColor("#99FF4444")
Gradient1.Color = New MyColor("#88FFBBBB")
Gradient2.Color = New MyColor("#88FF8888")
BorderBrush = New MyColor("#CCFF4444")
Gradient1.Color = New MyColor("#BBFFBBBB")
Gradient2.Color = New MyColor("#BBFF8888")
Path.Fill = New MyColor("#BF0000")
LabText.Foreground = New MyColor("#BF0000")
BtnClose.Foreground = New MyColor("#BF0000")
Path.Data = (New GeometryConverter).ConvertFromString("F1 M 58.5832,55.4172L 17.4169,55.4171C 15.5619,53.5621 15.5619,50.5546 17.4168,48.6996L 35.201,15.8402C 37.056,13.9852 40.0635,13.9852 41.9185,15.8402L 58.5832,48.6997C 60.4382,50.5546 60.4382,53.5622 58.5832,55.4172 Z M 34.0417,25.7292L 36.0208,41.9584L 39.9791,41.9583L 41.9583,25.7292L 34.0417,25.7292 Z M 38,44.3333C 36.2511,44.3333 34.8333,45.7511 34.8333,47.5C 34.8333,49.2489 36.2511,50.6667 38,50.6667C 39.7489,50.6667 41.1666,49.2489 41.1666,47.5C 41.1666,45.7511 39.7489,44.3333 38,44.3333 Z ")
Else
BorderBrush = New MyColor("#994D76FF")
Gradient1.Color = New MyColor("#88B0D0FF")
Gradient2.Color = New MyColor("#889EBAFF")
BorderBrush = New MyColor("#CC4D76FF")
Gradient1.Color = New MyColor("#BBB0D0FF")
Gradient2.Color = New MyColor("#BB9EBAFF")
Path.Fill = New MyColor("#0062BF")
LabText.Foreground = New MyColor("#0062BF")
BtnClose.Foreground = New MyColor("#0062BF")
@@ -34,7 +34,7 @@
Get
Return LabText.Text
End Get
Set(ByVal value As String)
Set(value As String)
LabText.Text = value
End Set
End Property
@@ -43,13 +43,12 @@
Get
Return BtnClose.Visibility = Visibility.Visible
End Get
Set(ByVal value As Boolean)
Set(value As Boolean)
BtnClose.Visibility = If(value, Visibility.Visible, Visibility.Collapsed)
End Set
End Property
Public RelativeSetup As String = ""
Private Sub MyHint_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
If CanClose AndAlso Setup.Get(RelativeSetup) Then
Visibility = Visibility.Collapsed
@@ -60,6 +59,40 @@
AniDispose(Me, False)
End Sub
'触发点击事件
Private IsMouseDown As Boolean = False
Private Sub MyHint_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
If Not IsMouseDown Then Return
IsMouseDown = False
Log("[Control] 按下提示条" & If(String.IsNullOrEmpty(Name), "", ":" & Name))
e.Handled = True
ModEvent.TryStartEvent(EventType, EventData)
End Sub
Private Sub MyHint_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
IsMouseDown = True
End Sub
Private Sub MyHint_MouseLeave() Handles Me.MouseLeave
IsMouseDown = False
End Sub
Public Property EventType As String
Get
Return GetValue(EventTypeProperty)
End Get
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyHint), New PropertyMetadata(Nothing))
Public Property EventData As String
Get
Return GetValue(EventDataProperty)
End Get
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyHint), New PropertyMetadata(Nothing))
End Class
Partial Public Module ModAnimation
Public Sub AniDispose(Control As MyHint, RemoveFromChildren As Boolean, Optional CallBack As ParameterizedThreadStart = Nothing)
@@ -1,7 +1,7 @@
Public Class MyIconButton
'声明
Public Event Click(sender As Object, e As EventArgs) '自定义事件
'自定义事件
Public Event Click(sender As Object, e As EventArgs)
'自定义属性
@@ -50,13 +50,31 @@
'触发点击事件
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
If IsMouseDown Then
Log("[Control] 按下图标按钮" & If(String.IsNullOrEmpty(Name), "", ":" & Name))
RaiseEvent Click(sender, e)
e.Handled = True
Button_MouseUp()
End If
If Not IsMouseDown Then Return
Log("[Control] 按下图标按钮" & If(String.IsNullOrEmpty(Name), "", ":" & Name))
RaiseEvent Click(sender, e)
e.Handled = True
Button_MouseUp()
ModEvent.TryStartEvent(EventType, EventData)
End Sub
Public Property EventType As String
Get
Return GetValue(EventTypeProperty)
End Get
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyIconButton), New PropertyMetadata(Nothing))
Public Property EventData As String
Get
Return GetValue(EventDataProperty)
End Get
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyIconButton), New PropertyMetadata(Nothing))
'鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行)
Private IsMouseDown As Boolean = False
@@ -0,0 +1,9 @@
<Border x:Name="PanBack" x:Class="MyIconTextButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27">
<StackPanel Orientation="Horizontal">
<Path x:Name="ShapeLogo" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="White" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center" />
<TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="7,0,12,1" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
</StackPanel>
</Border>
@@ -0,0 +1,186 @@
Public Class MyIconTextButton
'基础
Public Uuid As Integer = GetUuid()
Public Event Check(sender As Object, raiseByMouse As Boolean)
Public Event Change(sender As Object, raiseByMouse As Boolean)
Public Sub RaiseChange()
RaiseEvent Change(Me, False)
End Sub '使外部程序可以引发本控件的 Change 事件
'自定义属性
Public Property Logo As String
Get
Return ShapeLogo.Data.ToString
End Get
Set(value As String)
ShapeLogo.Data = (New GeometryConverter).ConvertFromString(value)
End Set
End Property
Private _LogoScale As Double = 1
Public Property LogoScale() As Double
Get
Return _LogoScale
End Get
Set(value As Double)
_LogoScale = value
If Not IsNothing(ShapeLogo) Then ShapeLogo.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale}
End Set
End Property
Public Property Text As String
Get
Return GetValue(TextProperty)
End Get
Set(value As String)
SetValue(TextProperty, value)
End Set
End Property '内容
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If Not IsNothing(sender) Then CType(sender, MyIconTextButton).LabText.Text = e.NewValue
End Sub)))
Public Enum ColorState
Black
Highlight
End Enum
Private _ColorType As ColorState = ColorState.Black
Public Property ColorType As ColorState
Get
Return _ColorType
End Get
Set(value As ColorState)
_ColorType = value
RefreshColor()
End Set
End Property '颜色类别
Public Shared ReadOnly ColorTypeProperty As DependencyProperty =
DependencyProperty.Register("ColorType", GetType(ColorState), GetType(MyIconTextButton), New PropertyMetadata())
'点击事件
Public Event Click(sender As Object, e As RouteEventArgs)
Private IsMouseDown As Boolean = False
Private Sub MyIconTextButton_MouseUp() Handles Me.MouseLeftButtonUp
If Not IsMouseDown Then Exit Sub
Log("[Control] 按下带图标按钮:" & Text)
IsMouseDown = False
RaiseEvent Click(Me, New RouteEventArgs(True))
ModEvent.TryStartEvent(EventType, EventData)
RefreshColor()
End Sub
Private Sub MyIconTextButton_MouseDown() Handles Me.MouseLeftButtonDown
IsMouseDown = True
RefreshColor()
End Sub
Private Sub MyIconTextButton_MouseLeave() Handles Me.MouseLeave
IsMouseDown = False
RefreshColor()
End Sub
Public Property EventType As String
Get
Return GetValue(EventTypeProperty)
End Get
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(Nothing))
Public Property EventData As String
Get
Return GetValue(EventDataProperty)
End Get
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(Nothing))
'动画
Private Const AnimationTimeOfMouseIn As Integer = 100 '鼠标指向动画长度
Private Const AnimationTimeOfMouseOut As Integer = 150 '鼠标移出动画长度
Private Sub RefreshColor(Optional obj = Nothing, Optional e = Nothing) Handles Me.MouseEnter, Me.Loaded, Me.IsEnabledChanged
Try
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not False.Equals(e) Then '防止默认属性变更触发动画,若强制不执行动画,则 e 为 False
Select Case ColorType
Case ColorState.Black
If IsMouseDown Then
'按下
AniStart(AaColor(Me, BackgroundProperty, "ColorBrush6", 70), "MyIconTextButton Color " & Uuid)
ElseIf IsMouseOver Then
'指向
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseIn),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, "ColorBrushBg1", AnimationTimeOfMouseIn), "MyIconTextButton Color " & Uuid)
ElseIf IsEnabled Then
'正常
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush1", AnimationTimeOfMouseOut),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush1", AnimationTimeOfMouseOut)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
Else
'禁用
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrushGray5", 100),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrushGray5", 100)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
End If
Case ColorState.Highlight
If IsMouseDown Then
'按下
AniStart(AaColor(Me, BackgroundProperty, "ColorBrush6", 70), "MyIconTextButton Color " & Uuid)
ElseIf IsMouseOver Then
'指向
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseIn),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, "ColorBrushBg1", AnimationTimeOfMouseIn), "MyIconTextButton Color " & Uuid)
ElseIf IsEnabled Then
'正常
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseOut),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseOut)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
Else
'禁用
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrushGray5", 100),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrushGray5", 100)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
End If
End Select
Else
'不使用动画
AniStop("MyIconTextButton Checked " & Uuid)
AniStop("MyIconTextButton Color " & Uuid)
Select Case ColorType
Case ColorState.Black
Background = ColorSemiTransparent
ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
Case ColorState.Highlight
Background = ColorSemiTransparent
ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, If(IsEnabled, "ColorBrush3", "ColorBrushGray5"))
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush3", "ColorBrushGray5"))
End Select
End If
Catch ex As Exception
Log(ex, "刷新带图标按钮颜色出错")
End Try
End Sub
End Class
@@ -11,7 +11,7 @@
<ColumnDefinition x:Name="ColumnPaddingLeft" Width="0" />
<ColumnDefinition x:Name="ColumnLogo" Width="4" />
<ColumnDefinition Width="1*"/>
<ColumnDefinition x:Name="ColumnPaddingRight" Width="0" />
<ColumnDefinition x:Name="ColumnPaddingRight" Width="4" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
@@ -15,7 +15,7 @@
If _RectBack Is Nothing Then
Dim Rect As New Border With {
.Name = "RectBack",
.CornerRadius = New CornerRadius(If(IsScaleAnimationEnabled, 6, 0)),
.CornerRadius = New CornerRadius(If(IsScaleAnimationEnabled OrElse Height > 40, 6, 0)),
.RenderTransform = If(IsScaleAnimationEnabled, New ScaleTransform(0.8, 0.8), Nothing),
.RenderTransformOrigin = New Point(0.5, 0.5),
.BorderThickness = New Thickness(GetWPFSize(1)),
@@ -104,42 +104,34 @@
ColumnPaddingLeft.Width = New GridLength(value)
End Set
End Property
Public Property PaddingRight As Integer
Get
Return ColumnPaddingRight.Width.Value
End Get
Set(value As Integer)
ColumnPaddingRight.Width = New GridLength(value)
End Set
End Property
''' <summary>
''' 右边距的最小值。
''' 在存在右侧按钮时,右边距会被自动设置为 5 + 按钮数 * 25。
''' </summary>
Public Property MinPaddingRight As Integer = 4
'按钮
Private _Buttons As IEnumerable
Public Property Buttons As IEnumerable
Private _Buttons As IEnumerable(Of MyIconButton)
Public Property Buttons As IEnumerable(Of MyIconButton)
Get
Return _Buttons
End Get
Set(value As IEnumerable)
Set(value As IEnumerable(Of MyIconButton))
_Buttons = value
'没有特殊按钮,移除原 Stack
If Not IsNothing(ButtonStack) Then
If ButtonStack IsNot Nothing Then
Children.Remove(ButtonStack)
ButtonStack = Nothing
End If
'获取按钮数量
Dim Count As Integer = 0
For Each Counter In value
Count += 1
Next
'添加新 Stack
Select Case Count
Select Case value.Count
Case 0
'没有按钮,不添加新的
Case 1
'只有一个按钮
For Each Btn As MyIconButton In value
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 23
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 23
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 25
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 25
With Btn
.Opacity = 0
.Margin = New Thickness(0, 0, 5, 0)
@@ -149,22 +141,18 @@
.SnapsToDevicePixels = False
.UseLayoutRounding = False
End With
SetColumn(Btn, 4)
SetColumnSpan(Btn, 4)
SetRowSpan(Btn, 4)
SetColumnSpan(Btn, 10) : SetRowSpan(Btn, 10)
Children.Add(Btn)
ButtonStack = Btn
Next
Case Else
'有复数按钮,使用 StackPanel
ButtonStack = New StackPanel With {.Opacity = 0, .Margin = New Thickness(0, 0, 5, 0), .SnapsToDevicePixels = False, .Orientation = Orientation.Horizontal, .HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Center, .UseLayoutRounding = False}
SetColumn(ButtonStack, 4)
SetColumnSpan(ButtonStack, 4)
SetRowSpan(ButtonStack, 4)
SetColumnSpan(ButtonStack, 10) : SetRowSpan(ButtonStack, 10)
'构造按钮
For Each Btn As MyIconButton In value
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 23
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 23
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 25
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 25
CType(ButtonStack, StackPanel).Children.Add(Btn)
Next
Children.Add(ButtonStack)
@@ -222,19 +210,21 @@
If Not IsNothing(PathLogo) Then Children.Remove(PathLogo)
'添加新 Logo
If Not _Logo = "" Then
If _Logo.ToLower.StartsWith("http") Then
If _Logo.StartsWithF("http", True) Then
'网络图片
PathLogo = New Image With {
.Tag = Me,
.IsHitTestVisible = LogoClickable,
.Source = New ImageSourceConverter().ConvertFromString(_Logo),
.RenderTransformOrigin = New Point(0.5, 0.5),
.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale},
.SnapsToDevicePixels = True, .UseLayoutRounding = False}
RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.Linear)
ElseIf _Logo.ToLower.EndsWith(".png") Then
ElseIf _Logo.EndsWithF(".png", True) OrElse _Logo.EndsWithF(".jpg", True) Then
'位图
Dim Bitmap = New MyBitmap(_Logo)
PathLogo = New Canvas With {
.Tag = Me,
.IsHitTestVisible = LogoClickable,
.Background = Bitmap,
.RenderTransformOrigin = New Point(0.5, 0.5),
@@ -252,6 +242,7 @@
Else
'矢量图
PathLogo = New Shapes.Path With {
.Tag = Me,
.IsHitTestVisible = LogoClickable, .HorizontalAlignment = HorizontalAlignment.Center, .VerticalAlignment = VerticalAlignment.Center, .Stretch = Stretch.Uniform,
.Data = (New GeometryConverter).ConvertFromString(_Logo),
.RenderTransformOrigin = New Point(0.5, 0.5),
@@ -267,7 +258,7 @@
If LogoClickable Then
AddHandler PathLogo.MouseLeave, Sub(sender, e) IsLogoDown = False
AddHandler PathLogo.MouseLeftButtonDown, Sub(sender, e) IsLogoDown = True
AddHandler PathLogo.MouseLeftButtonUp, Sub(sender, e) If IsLogoDown Then IsLogoDown = False : RaiseEvent LogoClick(sender, e)
AddHandler PathLogo.MouseLeftButtonUp, Sub(sender, e) If IsLogoDown Then IsLogoDown = False : RaiseEvent LogoClick(sender.Tag, e)
End If
End If
'改变行距
@@ -286,6 +277,9 @@
End Property
'图标的点击
''' <summary>
''' 该 Logo 是否可用点击触发事件。需要在 Logo 属性之前设置。
''' </summary>
Public Property LogoClickable As Boolean = False
Private IsLogoDown As Boolean = False
@@ -318,7 +312,8 @@
'添加竖条控件
If IsNothing(RectCheck) Then
RectCheck = New Border With {.Width = 5, .Height = If(Checked, Double.NaN, 0), .CornerRadius = New CornerRadius(2, 2, 2, 2),
.VerticalAlignment = If(Checked, VerticalAlignment.Stretch, VerticalAlignment.Center), .HorizontalAlignment = HorizontalAlignment.Left, .UseLayoutRounding = False, .SnapsToDevicePixels = False,
.VerticalAlignment = If(Checked, VerticalAlignment.Stretch, VerticalAlignment.Center),
.HorizontalAlignment = HorizontalAlignment.Left, .UseLayoutRounding = False, .SnapsToDevicePixels = False,
.Margin = If(Checked, New Thickness(-1, 6, 0, 6), New Thickness(-1, 0, 0, 0))}
RectCheck.SetResourceReference(Border.BackgroundProperty, "ColorBrush3")
SetRowSpan(RectCheck, 4)
@@ -333,7 +328,7 @@
ColumnCheck.Width = New GridLength(If(_Type = CheckType.None OrElse _Type = CheckType.Clickable, If(Height < 40, 4, 2), 6))
ColumnLogo.Width = New GridLength(If(_Logo = "", 0, 34) + If(Height < 40, 0, 4))
If Not IsNothing(PathLogo) Then
If _Logo.EndsWith(".png") Then
If _Logo.EndsWithF(".png", True) Then
PathLogo.Margin = New Thickness(4, 5, 3, 5)
Else
PathLogo.Margin = New Thickness(If(Height < 40, 6, 8), 8, If(Height < 40, 4, 6), 8)
@@ -447,7 +442,7 @@
RectCheck.VerticalAlignment = VerticalAlignment.Center
RectCheck.Margin = New Thickness(-1, 0, 0, 0)
End If
Anim.Add(AaColor(Me, ForegroundProperty, "ColorBrush3", 200))
Anim.Add(AaColor(Me, ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"), 200))
Else
'由有变无
If Not IsNothing(RectCheck) Then
@@ -461,17 +456,16 @@
AniStart(Anim, "MyListItem Checked " & Uuid)
Else
'不使用动画
AniStop("MyListItem Checked " & Uuid)
If Checked Then
'If Not IsNothing(RectCheck) Then RectCheck.Width = 4
If Not IsNothing(RectCheck) Then
RectCheck.Height = Double.NaN
RectCheck.Margin = New Thickness(-1, 6, 0, 6)
RectCheck.Opacity = 1
RectCheck.VerticalAlignment = VerticalAlignment.Stretch
End If
SetResourceReference(ForegroundProperty, "ColorBrush3")
SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
Else
'If Not IsNothing(RectCheck) Then RectCheck.Width = 0
If Not IsNothing(RectCheck) Then
RectCheck.Height = 0
RectCheck.Margin = New Thickness(-1, 0, 0, 0)
@@ -507,31 +501,26 @@
'触发点击事件
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
If IsMouseDown Then
RaiseEvent Click(sender, e)
If e.Handled Then Exit Sub
'触发自定义事件
If Not String.IsNullOrEmpty(EventType) Then
ModEvent.TryStartEvent(EventType, EventData)
e.Handled = True
End If
If e.Handled Then Exit Sub
'实际的单击处理
Select Case Type
Case CheckType.Clickable
Log("[Control] 按下单击列表项:" & Title)
Case CheckType.RadioBox
Log("[Control] 按下单选列表项:" & Title)
If Not Checked Then SetChecked(True, True, True)
Case CheckType.CheckBox
Log("[Control] 按下复选列表项(" & (Not Checked).ToString & "):" & Title)
SetChecked(Not Checked, True, True)
End Select
If Not IsMouseDown Then Exit Sub
RaiseEvent Click(sender, e)
If e.Handled Then Exit Sub
'触发自定义事件
If Not String.IsNullOrEmpty(EventType) Then
ModEvent.TryStartEvent(EventType, EventData)
e.Handled = True
End If
'AniStart({
' AaScaleTransform(Me, 1.004 - CType(RenderTransform, ScaleTransform).ScaleX, 150,, New AniEaseOutFluent),
' AaScaleTransform(Me, -0.004, 100, 150, New AniEaseInFluent)
' }, "MyListItem Scale " & Uuid)
If e.Handled Then Exit Sub
'实际的单击处理
Select Case Type
Case CheckType.Clickable
Log("[Control] 按下单击列表项:" & Title)
Case CheckType.RadioBox
Log("[Control] 按下单选列表项:" & Title)
If Not Checked Then SetChecked(True, True, True)
Case CheckType.CheckBox
Log("[Control] 按下复选列表项(" & (Not Checked).ToString & "):" & Title)
SetChecked(Not Checked, True, True)
End Select
End Sub
'鼠标点击判定
@@ -539,15 +528,12 @@
Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
If IsMouseDirectlyOver AndAlso Not Type = CheckType.None Then
IsMouseDown = True
If Not IsNothing(ButtonStack) Then ButtonStack.IsHitTestVisible = False
If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = False
End If
'AniStart({
' AaScaleTransform(Me, 0.985 - CType(RenderTransform, ScaleTransform).ScaleX, 50,, New AniEaseOutFluent)
' }, "MyListItem Scale " & Uuid)
End Sub
Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
IsMouseDown = False
If Not IsNothing(ButtonStack) Then ButtonStack.IsHitTestVisible = True
If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = True
End Sub
'实现自定义事件
@@ -601,9 +587,13 @@
'有动画
Dim Ani As New List(Of AniData)
If IsMouseOver AndAlso IsMouseOverAnimationEnabled Then
If ButtonStack IsNot Nothing Then Ani.Add(AaOpacity(ButtonStack, 1 - ButtonStack.Opacity, Time * 0.7, Time * 0.3))
If ButtonStack IsNot Nothing Then
Ani.Add(AaOpacity(ButtonStack, 1 - ButtonStack.Opacity, Time * 0.7, Time * 0.3))
Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
Math.Max(MinPaddingRight, 5 + Buttons.Count * 25) - ColumnPaddingRight.Width.Value, Time * 0.3, Time * 0.7))
End If
Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush9"), Time),
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
})
If IsScaleAnimationEnabled Then
@@ -615,32 +605,44 @@
End If
End If
Else
If ButtonStack IsNot Nothing Then Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.5))
If ButtonStack IsNot Nothing Then
Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.4))
Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
MinPaddingRight - ColumnPaddingRight.Width.Value, Time * 0.4))
End If
Ani.Add(AaOpacity(RectBack, -RectBack.Opacity, Time))
If IsScaleAnimationEnabled Then Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
AaScaleTransform(Me, 1 - CType(Me.RenderTransform, ScaleTransform).ScaleX, Time * 3,, New AniEaseOutFluent),
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
AaScaleTransform(RectBack, -0.246, 1,,, True)
})
If IsScaleAnimationEnabled Then
Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
AaScaleTransform(Me, 1 - CType(RenderTransform, ScaleTransform).ScaleX, Time * 3,, New AniEaseOutFluent),
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
AaScaleTransform(RectBack, -0.246, 1,,, True)
})
End If
End If
AniStart(Ani, "ListItem Color " & Uuid)
Else
'无动画
If IsMouseOver AndAlso IsMouseOverAnimationEnabled Then
If ButtonStack IsNot Nothing Then ButtonStack.Opacity = 1
If ButtonStack IsNot Nothing Then
ButtonStack.Opacity = 1
ColumnPaddingRight.Width = New GridLength(Math.Max(MinPaddingRight, 5 + Buttons.Count * 25))
End If
'由于鼠标已经移入,所以直接实例化 RectBack
RectBack.Background = Color9
RectBack.Background = ColorBg1
RectBack.Opacity = 1
RectBack.RenderTransform = New ScaleTransform(1, 1)
Me.RenderTransform = New ScaleTransform(1, 1)
Else
If ButtonStack IsNot Nothing Then ButtonStack.Opacity = 0
If ButtonStack IsNot Nothing Then
ButtonStack.Opacity = 0
ColumnPaddingRight.Width = New GridLength(MinPaddingRight)
End If
Me.RenderTransform = New ScaleTransform(1, 1)
If _RectBack IsNot Nothing Then
If IsScaleAnimationEnabled Then RectBack.Background = Color7
If IsScaleAnimationEnabled Then RectBack.RenderTransform = New ScaleTransform(0.75, 0.75)
RectBack.Background = Color7
RectBack.Opacity = 0
RectBack.RenderTransform = New ScaleTransform(0.75, 0.75)
End If
End If
AniStop("ListItem Color " & Uuid)
@@ -649,10 +651,11 @@
Private Sub MyListItem_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
If Checked Then
SetResourceReference(ForegroundProperty, "ColorBrush3")
SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
Else
SetResourceReference(ForegroundProperty, "ColorBrush1")
End If
ColumnPaddingRight.Width = New GridLength(MinPaddingRight)
If EventType = "打开帮助" Then
Try
Dim NewElem = New HelpEntry(GetEventAbsoluteUrls(EventData, EventType)(0)).SetToListItem(Me)
@@ -46,7 +46,7 @@ Public Class MyLoading
Get
Return _Text
End Get
Set(ByVal value As String)
Set(value As String)
_Text = value
RefreshText()
End Set
@@ -57,7 +57,7 @@ Public Class MyLoading
Get
Return _TextError
End Get
Set(ByVal value As String)
Set(value As String)
_TextError = value
RefreshText()
End Set
@@ -67,29 +67,35 @@ Public Class MyLoading
''' </summary>
Public Property TextErrorInherit As Boolean = True
Private Sub RefreshText() Handles Me.IsErrorChanged, Me.Loaded
If InnerState = MyLoadingState.Error Then
If TextErrorInherit AndAlso State.IsLoader Then
Dim Ex As Exception = CType(State, Object).Error
If Ex Is Nothing Then
LabText.Text = "未知错误"
Private Sub RefreshText() Handles Me.IsErrorChanged, Me.Loaded, _State.ProgressChanged
RunInUi(
Sub()
If InnerState = MyLoadingState.Error Then
If TextErrorInherit AndAlso State.IsLoader Then
Dim Ex As Exception = CType(State, Object).Error
If Ex Is Nothing Then
LabText.Text = "未知错误"
Else
Do While Ex.InnerException IsNot Nothing
Ex = Ex.InnerException
Loop
LabText.Text = StrTrim(Ex.Message)
If {"远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝",
"操作已超时", "操作超时", "服务器超时", "连接超时"}.Any(Function(s) LabText.Text.Contains(s)) Then
LabText.Text = "网络环境不佳,请重试或尝试使用 VPN"
End If
End If
Else
Do While Ex.InnerException IsNot Nothing
Ex = Ex.InnerException
Loop
LabText.Text = StrTrim(Ex.Message)
If LabText.Text.Contains("远程主机强迫关闭了一个现有的连接") OrElse LabText.Text.Contains("操作已超时") OrElse LabText.Text.Contains("操作超时") OrElse LabText.Text.Contains("服务器超时") OrElse LabText.Text.Contains("连接超时") Then LabText.Text = "网络环境不佳,请重试或尝试使用 VPN"
LabText.Text = TextError
End If
Else
LabText.Text = TextError
If ShowProgress AndAlso State.IsLoader Then
LabText.Text = Text & " - " & Math.Floor(CType(State, Object).Progress * 100) & "%"
Else
LabText.Text = Text
End If
End If
Else
If ShowProgress AndAlso State.IsLoader Then
LabText.Text = Text & " - " & Math.Floor(CType(State, Object).Progress * 100) & "%"
Else
LabText.Text = Text
End If
End If
End Sub)
End Sub
#End Region
@@ -180,46 +186,7 @@ Public Class MyLoading
If Not HasAnimation OrElse IsLooping OrElse Not InnerState = MyLoadingState.Run OrElse AniSpeed > 10 OrElse Not IsLoaded Then Exit Sub
IsLooping = True
ErrorAnimationWaiting = True
If ShowProgress Then
RefreshText()
AniStart({
AaRotateTransform(PathPickaxe, -20 - CType(PathPickaxe.RenderTransform, RotateTransform).Angle, 350, 250, New AniEaseInBack(AniEasePower.Weak)),
AaCode(AddressOf RefreshText, 100), '这是为了省下一个 Timer 线程……
AaCode(AddressOf RefreshText, 200),
AaCode(AddressOf RefreshText, 300),
AaCode(AddressOf RefreshText, 400),
AaCode(AddressOf RefreshText, 500),
AaRotateTransform(PathPickaxe, 50, 900,, New AniEaseOutFluent, True),
AaRotateTransform(PathPickaxe, 25, 900,, New AniEaseOutElastic(AniEasePower.Weak)),
AaCode(Sub()
PathLeft.Opacity = 1
PathLeft.Margin = New Thickness(7, 41, 0, 0)
PathRight.Opacity = 1
PathRight.Margin = New Thickness(14, 41, 0, 0)
ErrorAnimationWaiting = False
RefreshText()
End Sub),
AaCode(AddressOf RefreshText, 100),
AaCode(AddressOf RefreshText, 200),
AaCode(AddressOf RefreshText, 300),
AaCode(AddressOf RefreshText, 400),
AaCode(AddressOf RefreshText, 500),
AaCode(AddressOf RefreshText, 600),
AaCode(AddressOf RefreshText, 700),
AaCode(AddressOf RefreshText, 800),
AaOpacity(PathLeft, -1, 100, 70),
AaX(PathLeft, -5, 180, 20, New AniEaseOutFluent),
AaY(PathLeft, -6, 180, 20, New AniEaseOutFluent),
AaOpacity(PathRight, -1, 100, 70),
AaX(PathRight, 5, 180, 20, New AniEaseOutFluent),
AaY(PathRight, -6, 180, 20, New AniEaseOutFluent),
AaCode(Sub()
IsLooping = False
AniLoop()
End Sub,, True)
}, "MyLoader Loop " & Uuid & "/" & GetUuid())
Else
AniStart({
AniStart({
AaRotateTransform(PathPickaxe, -20 - CType(PathPickaxe.RenderTransform, RotateTransform).Angle, 350, 250, New AniEaseInBack(AniEasePower.Weak)),
AaRotateTransform(PathPickaxe, 50, 900,, New AniEaseOutFluent, True),
AaRotateTransform(PathPickaxe, 25, 900,, New AniEaseOutElastic(AniEasePower.Weak)),
@@ -241,6 +208,8 @@ Public Class MyLoading
AniLoop()
End Sub,, True)
}, "MyLoader Loop " & Uuid & "/" & GetUuid())
If ShowProgress Then
End If
End Sub
@@ -291,6 +260,7 @@ Public Interface ILoadingTrigger
ReadOnly Property IsLoader As Boolean
Property LoadingState As MyLoadingState
Event LoadingStateChanged(NewState As MyLoadingState, OldState As MyLoadingState)
Event ProgressChanged(NewProgress As Double, OldProgress As Double)
End Interface
Public Class MyLoadingStateSimulator
@@ -310,4 +280,5 @@ Public Class MyLoadingStateSimulator
Public ReadOnly Property IsLoader As Boolean = False Implements ILoadingTrigger.IsLoader
Public Event LoadingStateChanged(NewState As MyLoadingState, OldState As MyLoadingState) Implements ILoadingTrigger.LoadingStateChanged
Public Event ProgressChanged(NewProgress As Double, OldProgress As Double) Implements ILoadingTrigger.ProgressChanged
End Class
@@ -6,6 +6,8 @@
Dim IconControl As Shapes.Path = GetTemplateChild("Icon")
If IconControl IsNot Nothing Then IconControl.Data = (New GeometryConverter).ConvertFromString(Icon)
End If
'对父级设置透明度
CType(Parent, ContextMenu).Opacity = Setup.Get("UiLauncherTransparent") / 1000 + 0.4
End Sub
'基础
@@ -2,22 +2,38 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:PCL"
UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="500" HorizontalAlignment="Center" VerticalAlignment="Center">
<Border Name="PanBorder" CornerRadius="5" Width="{Binding ActualWidth, ElementName=PanMain, Mode=OneWay}" Height="{Binding ActualHeight, ElementName=PanMain, Mode=OneWay}" Background="#00FBFBFB">
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="TransformRotate" Angle="-4" />
<TranslateTransform x:Name="TransformPos" X="0" Y="40" />
</TransformGroup>
</Grid.RenderTransform>
<Border Name="PanBorder" CornerRadius="7" Background="#FBFBFB">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="15" ShadowDepth="0" Opacity="0" x:Name="EffectShadow" />
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="20" ShadowDepth="4" RenderingBias="Performance" Opacity="0.8" x:Name="EffectShadow" />
</Border.Effect>
<Grid Name="PanMain" VerticalAlignment="Top" Margin="22,22,22,23">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="13" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="7,-1,70,9" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle x:Name="ShapeLine" Grid.Row="1" Height="2" Fill="{Binding Foreground, ElementName=LabTitle}" />
<my:MyScrollViewer Grid.Row="3" VerticalAlignment="Top" x:Name="PanText" Margin="0,0,0,7" Padding="7,0,15,0"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMuity="0.7">
<TextBlock VerticalAlignment="Top" TextTrimming="None" TextWrapping="Wrap" Name="LabText" FontSize="15" LineHeight="18"
Foreground="#FF5C5C5C" FontWeight="Normal" Padding="1" />
</my:MyScrollViewer>
<my:MyTextBox Grid.Row="4" Margin="7,0,7,12" x:Name="TextArea" UseLayoutRounding="False" MaxLength="1000" MinWidth="450" />
<StackPanel Grid.Row="5" Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,8,0" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Border>
<StackPanel Name="PanMain" VerticalAlignment="Top">
<TextBlock FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="27,19,28,0" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle Height="2" Fill="{DynamicResource ColorBrush2}" Margin="20,9,20,15" Name="ShapeLine" Opacity="0" />
<Border Name="PanCaption" Padding="28,0,28,15">
<my:MyTextBox x:Name="TextCaption" UseLayoutRounding="False" MaxLength="1000" Width="450" Margin="1" />
</Border>
<StackPanel Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,22,20" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮3" x:Name="Btn3" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
</StackPanel>
</StackPanel>
</Grid>
@@ -9,26 +9,21 @@
InitializeComponent()
Btn1.Name = Btn1.Name & GetUuid()
Btn2.Name = Btn2.Name & GetUuid()
Btn3.Name = Btn3.Name & GetUuid()
MyConverter = Converter
LabTitle.Text = Converter.Title
TextCaption.Text = Converter.Content
TextCaption.HintText = Converter.HintText
TextCaption.ValidateRules = Converter.ValidateRules
LabText.Text = Converter.Text
PanText.Visibility = If(Converter.Text = "", Visibility.Collapsed, Visibility.Visible)
TextArea.Text = Converter.Content
TextArea.HintText = Converter.HintText
TextArea.ValidateRules = Converter.ValidateRules
Btn1.Text = Converter.Button1
If Converter.IsWarn Then
Btn1.ColorType = MyButton.ColorState.Red
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrushRedLight")
ShapeLine.SetResourceReference(Rectangle.FillProperty, "ColorBrushRedLight")
End If
Btn2.Text = Converter.Button2
Btn3.Text = Converter.Button3
Btn2.Visibility = If(Converter.Button2 = "", Visibility.Collapsed, Visibility.Visible)
Btn3.Visibility = If(Converter.Button3 = "", Visibility.Collapsed, Visibility.Visible)
'If Converter.Caption > 0 Then
' TextCaption.Focus()
' TextCaption.Select(Converter.Caption.Length - 1, 0)
'End If
ShapeLine.StrokeThickness = GetWPFSize(1)
Catch ex As Exception
Log(ex, "输入弹窗初始化失败", LogLevel.Hint)
@@ -40,39 +35,16 @@
'UI 初始化
If Btn2.IsVisible AndAlso Not Btn1.ColorType = MyButton.ColorState.Red Then Btn1.ColorType = MyButton.ColorState.Highlight
ShapeLine.StrokeThickness = GetWPFSize(1)
Measure(New Size(FrmMain.Width, FrmMain.Height))
Arrange(New Rect(0, 0, FrmMain.Width, FrmMain.Height))
If FrmMain.Width - ActualWidth < 20 Then Width = FrmMain.Width - GetWPFSize(2)
TextCaption.Focus()
TextArea.Focus()
TextArea.SelectionStart = TextArea.Text.Length
'动画
Opacity = 0
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, If(MyConverter.IsWarn, New MyColor(140, 80, 0, 0), New MyColor(90, 0, 0, 0)) - FrmMain.PanMsg.Background, 200), "PanMsg Background")
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(60, 0, 0, 0), 250, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(255, 0, 0, 0), 150, , New AniEaseInFluent),
AaOpacity(EffectShadow, 0.75, 400, 50),
AaWidth(ShapeLine, ShapeLine.ActualWidth, 250, 100, New AniEaseOutFluent),
AaOpacity(ShapeLine, 1, 200, 100),
AaWidth(LabTitle, LabTitle.ActualWidth, 200, 100, New AniEaseOutFluent),
AaOpacity(LabTitle, 1, 150, 150),
AaOpacity(PanCaption, 1, 150, 150),
AaOpacity(Btn1, 1, 150, 100),
AaOpacity(Btn2, 1, 150, 150),
AaOpacity(Btn3, 1, 150, 200),
AaCode(Sub()
ShapeLine.MinWidth = ShapeLine.ActualWidth
ShapeLine.HorizontalAlignment = HorizontalAlignment.Stretch
ShapeLine.Width = Double.NaN
LabTitle.Width = Double.NaN
LabTitle.TextTrimming = TextTrimming.CharacterEllipsis
End Sub, 350)
}, "MyMsgBox Start " & Uuid)
'动画初始化
ShapeLine.Width = 0
ShapeLine.HorizontalAlignment = HorizontalAlignment.Center
LabTitle.Width = 0
LabTitle.Opacity = 0
LabTitle.TextWrapping = TextWrapping.NoWrap
PanCaption.Opacity = 0
AaOpacity(Me, 1, 120, 60),
AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 300, 60, New AniEaseOutBack(AniEasePower.Weak)),
AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak))
}, "MyMsgBox " & Uuid)
'记录日志
Log("[Control] 输入弹窗:" & LabTitle.Text)
@@ -84,29 +56,25 @@
'结束线程阻塞
MyConverter.WaitFrame.Continue = False
Interop.ComponentDispatcher.PopModal()
'弹窗动画
LabTitle.TextTrimming = TextTrimming.None
LabTitle.TextWrapping = TextWrapping.NoWrap
'动画
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(-60, 0, 0, 0), 350, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(-255, 0, 0, 0), 300, 100, New AniEaseInFluent),
AaOpacity(EffectShadow, -0.75, 150),
AaWidth(ShapeLine, -ShapeLine.ActualWidth, 250, , New AniEaseInFluent),
AaOpacity(ShapeLine, -1, 150, 100),
AaWidth(LabTitle, -LabTitle.ActualWidth, 250),
AaOpacity(LabTitle, -1, 200),
AaOpacity(PanCaption, -1, 200),
AaOpacity(Btn1, -1, 150),
AaOpacity(Btn2, -1, 150, 50),
AaOpacity(Btn3, -1, 150, 100),
AaCode(
Sub()
If Not WaitingMyMsgBox.Any() Then
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(0, 0, 0, 0) - FrmMain.PanMsg.Background, 200, Ease:=New AniEaseOutFluent(AniEasePower.Weak)))
End If
End Sub, 30),
AaOpacity(Me, -Opacity, 80, 20),
AaDouble(Sub(i) TransformPos.Y += i, 20 - TransformPos.Y, 150, 0, New AniEaseOutFluent),
AaDouble(Sub(i) TransformRotate.Angle += i, 6 - TransformRotate.Angle, 150, 0, New AniEaseInFluent(AniEasePower.Weak)),
AaCode(Sub() CType(Parent, Grid).Children.Remove(Me), , True)
}, "MyMsgBox Close " & Uuid)
}, "MyMsgBox " & Uuid)
End Sub
Public Sub Btn1_Click() Handles Btn1.Click
If MyConverter.IsExited OrElse Not TextCaption.ValidateResult = "" Then Exit Sub
If MyConverter.IsExited OrElse Not TextArea.ValidateResult = "" Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = TextCaption.Text
MyConverter.Result = TextArea.Text
Close()
End Sub
Public Sub Btn2_Click() Handles Btn2.Click
@@ -115,15 +83,9 @@
MyConverter.Result = Nothing
Close()
End Sub
Public Sub Btn3_Click() Handles Btn3.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = Nothing
Close()
End Sub
Private Sub TextCaption_ValidateChanged(sender As Object, e As EventArgs) Handles TextCaption.ValidateChanged
Btn1.IsEnabled = TextCaption.ValidateResult = ""
Private Sub TextCaption_ValidateChanged(sender As Object, e As EventArgs) Handles TextArea.ValidateChanged
Btn1.IsEnabled = TextArea.ValidateResult = ""
End Sub
Private Sub Drag(sender As Object, e As MouseButtonEventArgs) Handles PanBorder.MouseLeftButtonDown, LabTitle.MouseLeftButtonDown
@@ -1,27 +1,36 @@
<Grid x:Name="PanBack" x:Class="MyMsgSelect"
<Grid x:Class="MyMsgSelect"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:PCL"
UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="450" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Name="PanBorder" Grid.RowSpan="99" Width="{Binding ActualWidth, ElementName=PanBack, Mode=OneWay}" Height="{Binding ActualHeight, ElementName=PanBack, Mode=OneWay}" Background="#00FBFBFB" CornerRadius="5">
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="TransformRotate" Angle="-4" />
<TranslateTransform x:Name="TransformPos" X="0" Y="40" />
</TransformGroup>
</Grid.RenderTransform>
<Border Name="PanBorder" CornerRadius="7" Background="#FBFBFB">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="15" ShadowDepth="0" Opacity="0" x:Name="EffectShadow" />
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="20" ShadowDepth="4" RenderingBias="Performance" Opacity="0.8" x:Name="EffectShadow" />
</Border.Effect>
<Grid Name="PanMain" VerticalAlignment="Top" Margin="22,22,22,23">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="13" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="7,-1,70,9" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle x:Name="ShapeLine" Grid.Row="1" Height="2" Fill="{Binding Foreground, ElementName=LabTitle}" />
<my:MyScrollViewer Grid.Row="3" VerticalAlignment="Top" x:Name="PanCaption" Margin="0,0,0,17" Padding="7,0,15,0"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMuity="0.7">
<StackPanel x:Name="PanSelection" Orientation="Vertical" />
</my:MyScrollViewer>
<StackPanel Grid.Row="4" Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,8,0" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Border>
<TextBlock FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="28,19,28,0" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle Height="2" Grid.Row="1" Fill="{DynamicResource ColorBrush2}" Margin="20,9,20,13" Name="ShapeLine" Opacity="0" />
<my:MyScrollViewer x:Name="PanCaption" Grid.Row="2" Margin="19,0,19,20" Padding="9,0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" SnapsToDevicePixels="True" UseLayoutRounding="True" DeltaMuity="0.5">
<StackPanel x:Name="PanSelection" Orientation="Vertical" />
</my:MyScrollViewer>
<StackPanel Name="PanBtn" Grid.Row="3" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,22,20" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" IsEnabled="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="15,0,0,0" TextPadding="7" Visibility="Visible" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮3" x:Name="Btn3" TextPadding="7" Margin="15,0,0,0" Visibility="Visible" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Grid>
@@ -9,20 +9,18 @@
InitializeComponent()
Btn1.Name = Btn1.Name & GetUuid()
Btn2.Name = Btn2.Name & GetUuid()
Btn3.Name = Btn3.Name & GetUuid()
MyConverter = Converter
LabTitle.Text = Converter.Title
Btn1.Text = Converter.Button1
If Converter.IsWarn Then
Btn1.ColorType = MyButton.ColorState.Red
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrushRedLight")
ShapeLine.SetResourceReference(Rectangle.FillProperty, "ColorBrushRedLight")
End If
Btn2.Text = Converter.Button2
Btn3.Text = Converter.Button3
Btn2.Visibility = If(Converter.Button2 = "", Visibility.Collapsed, Visibility.Visible)
Btn3.Visibility = If(Converter.Button3 = "", Visibility.Collapsed, Visibility.Visible)
ShapeLine.StrokeThickness = GetWPFSize(1)
'添加选择控件
Btn1.IsEnabled = False
For Each Selection As IMyRadio In Converter.Content
PanSelection.Children.Add(Selection)
AddHandler Selection.Check, AddressOf OnChecked
@@ -30,7 +28,7 @@
CType(Selection, MyListItem).Type = MyListItem.CheckType.RadioBox
CType(Selection, MyListItem).MinHeight = 24
Else
CType(Selection, MyRadioBox).MinHeight = 26
CType(Selection, MyRadioBox).MinHeight = 24
End If
Next
@@ -44,38 +42,14 @@
'UI 初始化
If Btn2.IsVisible AndAlso Not Btn1.ColorType = MyButton.ColorState.Red Then Btn1.ColorType = MyButton.ColorState.Highlight
ShapeLine.StrokeThickness = GetWPFSize(1)
Measure(New Size(FrmMain.Width, FrmMain.Height))
Arrange(New Rect(0, 0, FrmMain.Width, FrmMain.Height))
If FrmMain.Width - ActualWidth < 20 Then Width = FrmMain.Width - GetWPFSize(2)
'动画
Opacity = 0
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, If(MyConverter.IsWarn, New MyColor(140, 80, 0, 0), New MyColor(90, 0, 0, 0)) - FrmMain.PanMsg.Background, 200), "PanMsg Background")
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(60, 0, 0, 0), 250, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(255, 0, 0, 0), 150, , New AniEaseInFluent),
AaOpacity(EffectShadow, 0.75, 400, 50),
AaWidth(ShapeLine, ShapeLine.ActualWidth, 250, 100, New AniEaseOutFluent),
AaOpacity(ShapeLine, 1, 200, 100),
AaWidth(LabTitle, LabTitle.ActualWidth, 200, 100, New AniEaseOutFluent),
AaOpacity(LabTitle, 1, 150, 150),
AaOpacity(PanCaption, 1, 150, 150),
AaOpacity(Btn1, 1, 150, 100),
AaOpacity(Btn2, 1, 150, 150),
AaOpacity(Btn3, 1, 150, 200),
AaCode(Sub()
ShapeLine.MinWidth = ShapeLine.ActualWidth
ShapeLine.HorizontalAlignment = HorizontalAlignment.Stretch
ShapeLine.Width = Double.NaN
LabTitle.Width = Double.NaN
LabTitle.TextTrimming = TextTrimming.CharacterEllipsis
End Sub, 350)
}, "MyMsgBox Start " & Uuid)
'动画初始化
ShapeLine.Width = 0
ShapeLine.HorizontalAlignment = HorizontalAlignment.Center
LabTitle.Width = 0
LabTitle.Opacity = 0
LabTitle.TextWrapping = TextWrapping.NoWrap
PanCaption.Opacity = 0
AaOpacity(Me, 1, 120, 60),
AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 300, 60, New AniEaseOutBack(AniEasePower.Weak)),
AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak))
}, "MyMsgBox " & Uuid)
'记录日志
Log("[Control] 选择弹窗:" & LabTitle.Text)
@@ -87,23 +61,19 @@
'结束线程阻塞
MyConverter.WaitFrame.Continue = False
Interop.ComponentDispatcher.PopModal()
'弹窗动画
LabTitle.TextTrimming = TextTrimming.None
LabTitle.TextWrapping = TextWrapping.NoWrap
'动画
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(-60, 0, 0, 0), 350, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(-255, 0, 0, 0), 300, 100, New AniEaseInFluent),
AaOpacity(EffectShadow, -0.75, 150),
AaWidth(ShapeLine, -ShapeLine.ActualWidth, 250, , New AniEaseInFluent),
AaOpacity(ShapeLine, -1, 150, 100),
AaWidth(LabTitle, -LabTitle.ActualWidth, 250),
AaOpacity(LabTitle, -1, 200),
AaOpacity(PanCaption, -1, 200),
AaOpacity(Btn1, -1, 150),
AaOpacity(Btn2, -1, 150, 50),
AaOpacity(Btn3, -1, 150, 100),
AaCode(
Sub()
If Not WaitingMyMsgBox.Any() Then
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(0, 0, 0, 0) - FrmMain.PanMsg.Background, 200, Ease:=New AniEaseOutFluent(AniEasePower.Weak)))
End If
End Sub, 30),
AaOpacity(Me, -Opacity, 80, 20),
AaDouble(Sub(i) TransformPos.Y += i, 20 - TransformPos.Y, 150, 0, New AniEaseOutFluent),
AaDouble(Sub(i) TransformRotate.Angle += i, 6 - TransformRotate.Angle, 150, 0, New AniEaseInFluent(AniEasePower.Weak)),
AaCode(Sub() CType(Parent, Grid).Children.Remove(Me), , True)
}, "MyMsgBox Close " & Uuid)
}, "MyMsgBox " & Uuid)
End Sub
Public Sub Btn1_Click() Handles Btn1.Click
@@ -118,12 +88,6 @@
MyConverter.Result = Nothing
Close()
End Sub
Public Sub Btn3_Click() Handles Btn3.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = Nothing
Close()
End Sub
Private SelectedIndex As Integer = -1
Private Sub OnChecked(sender As IMyRadio, e As EventArgs)
@@ -1,27 +1,38 @@
<Grid x:Name="PanBack" x:Class="MyMsgText"
<Grid x:Class="MyMsgText"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:PCL"
UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="450" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Name="PanBorder" Grid.RowSpan="99" Background="#00FBFBFB" CornerRadius="5">
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="TransformRotate" Angle="-4" />
<TranslateTransform x:Name="TransformPos" X="0" Y="40" />
</TransformGroup>
</Grid.RenderTransform>
<Border Name="PanBorder" CornerRadius="7" Background="#FBFBFB">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="15" ShadowDepth="0" Opacity="0" x:Name="EffectShadow" />
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="20" ShadowDepth="4" RenderingBias="Performance" Opacity="0.8" x:Name="EffectShadow" />
</Border.Effect>
<Grid Name="PanMain" VerticalAlignment="Top" Margin="22,22,22,23">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="13" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="7,-1,70,9" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle x:Name="ShapeLine" Grid.Row="1" Height="2" Fill="{Binding Foreground, ElementName=LabTitle}" />
<my:MyScrollViewer Grid.Row="3" VerticalAlignment="Top" x:Name="PanCaption" Margin="0,0,0,17" Padding="7,0,15,0"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMuity="0.7">
<TextBlock VerticalAlignment="Top" TextTrimming="None" TextWrapping="Wrap" Name="LabCaption" FontSize="15" LineHeight="18"
Foreground="#FF5C5C5C" FontWeight="Normal" Padding="1" />
</my:MyScrollViewer>
<StackPanel Grid.Row="4" Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,8,0" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮3" x:Name="Btn3" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Border>
<TextBlock FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="28,19,28,0" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle Height="2" Grid.Row="1" Fill="{DynamicResource ColorBrush2}" Margin="20,9,20,13" Name="ShapeLine" Opacity="0" />
<my:MyScrollViewer VerticalAlignment="Top" x:Name="PanCaption" Grid.Row="2" Margin="19,0,19,20" Padding="9,0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" SnapsToDevicePixels="True" UseLayoutRounding="True" DeltaMuity="0.5">
<TextBlock VerticalAlignment="Top" TextTrimming="None" TextWrapping="Wrap" Name="LabCaption" FontSize="15" Foreground="#FF5C5C5C" FontWeight="Normal" Padding="1" />
</my:MyScrollViewer>
<StackPanel Name="PanBtn" Grid.Row="3" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,22,20" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="15,0,0,0" TextPadding="7" Visibility="Visible" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮3" x:Name="Btn3" TextPadding="7" Margin="15,0,0,0" Visibility="Visible" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
@@ -12,12 +12,11 @@
Btn3.Name = Btn3.Name & GetUuid()
MyConverter = Converter
LabTitle.Text = Converter.Title
LabCaption.Text = Converter.Content
LabCaption.Text = Converter.Text
Btn1.Text = Converter.Button1
If Converter.IsWarn Then
Btn1.ColorType = MyButton.ColorState.Red
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrushRedLight")
ShapeLine.SetResourceReference(Rectangle.FillProperty, "ColorBrushRedLight")
End If
Btn2.Text = Converter.Button2
Btn3.Text = Converter.Button3
@@ -35,37 +34,15 @@
'UI 初始化
If Btn2.IsVisible AndAlso Not Btn1.ColorType = MyButton.ColorState.Red Then Btn1.ColorType = MyButton.ColorState.Highlight
Measure(New Size(FrmMain.Width - 20, FrmMain.Height - 20))
Arrange(New Rect(0, 0, FrmMain.Width - 20, FrmMain.Height - 20))
Btn1.Focus()
'动画
Opacity = 0
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, If(MyConverter.IsWarn, New MyColor(140, 80, 0, 0), New MyColor(90, 0, 0, 0)) - FrmMain.PanMsg.Background, 200), "PanMsg Background")
AniStart({
AaColor(FrmMain.PanMsg, BackgroundProperty, New MyColor(60, 0, 0, 0), 250, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(255, 0, 0, 0), 150, , New AniEaseInFluent),
AaOpacity(EffectShadow, 0.75, 400, 50),
AaWidth(ShapeLine, ShapeLine.ActualWidth, 250, 100, New AniEaseOutFluent),
AaOpacity(ShapeLine, 1, 200, 100),
AaWidth(LabTitle, LabTitle.ActualWidth, 200, 150, New AniEaseOutFluent),
AaOpacity(LabTitle, 1, 150, 150),
AaOpacity(PanCaption, 1, 150, 150),
AaOpacity(Btn1, 1, 150, 100),
AaOpacity(Btn2, 1, 150, 150),
AaOpacity(Btn3, 1, 150, 200),
AaCode(Sub()
ShapeLine.MinWidth = ShapeLine.ActualWidth
ShapeLine.HorizontalAlignment = HorizontalAlignment.Stretch
ShapeLine.Width = Double.NaN
LabTitle.Width = Double.NaN
LabTitle.TextTrimming = TextTrimming.CharacterEllipsis
End Sub, 350)
}, "MyMsgBox Start " & Uuid)
'动画初始化
ShapeLine.Width = 0
ShapeLine.HorizontalAlignment = HorizontalAlignment.Center
LabTitle.Width = 0
LabTitle.Opacity = 0
LabTitle.TextWrapping = TextWrapping.NoWrap
PanCaption.Opacity = 0
AaOpacity(Me, 1, 120, 60),
AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 300, 60, New AniEaseOutBack(AniEasePower.Weak)),
AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak))
}, "MyMsgBox " & Uuid)
'记录日志
Log("[Control] 普通弹窗:" & LabTitle.Text & vbCrLf & LabCaption.Text)
@@ -77,44 +54,50 @@
'结束线程阻塞
If MyConverter.ForceWait OrElse Not MyConverter.Button2 = "" Then MyConverter.WaitFrame.Continue = False
Interop.ComponentDispatcher.PopModal()
'弹窗动画
LabTitle.TextTrimming = TextTrimming.None
LabTitle.TextWrapping = TextWrapping.NoWrap
'动画
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(-60, 0, 0, 0), 350, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(-255, 0, 0, 0), 300, 100, New AniEaseInFluent),
AaOpacity(EffectShadow, -0.75, 150),
AaWidth(ShapeLine, -ShapeLine.ActualWidth, 250, , New AniEaseInFluent(AniEasePower.Weak)),
AaOpacity(ShapeLine, -1, 200),
AaWidth(LabTitle, -LabTitle.ActualWidth, 250),
AaOpacity(LabTitle, -1, 200),
AaOpacity(PanCaption, -1, 200),
AaOpacity(Btn1, -1, 150),
AaOpacity(Btn2, -1, 150, 50),
AaOpacity(Btn3, -1, 150, 100),
AaCode(
Sub()
If Not WaitingMyMsgBox.Any() Then
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(0, 0, 0, 0) - FrmMain.PanMsg.Background, 200, Ease:=New AniEaseOutFluent(AniEasePower.Weak)))
End If
End Sub, 30),
AaOpacity(Me, -Opacity, 80, 20),
AaDouble(Sub(i) TransformPos.Y += i, 20 - TransformPos.Y, 150, 0, New AniEaseOutFluent),
AaDouble(Sub(i) TransformRotate.Angle += i, 6 - TransformRotate.Angle, 150, 0, New AniEaseInFluent(AniEasePower.Weak)),
AaCode(Sub() CType(Parent, Grid).Children.Remove(Me), , True)
}, "MyMsgBox Close " & Uuid)
'动画初始化
ShapeLine.MinWidth = 0
}, "MyMsgBox " & Uuid)
End Sub
Public Sub Btn1_Click() Handles Btn1.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = 1
Close()
If MyConverter.Button1Action IsNot Nothing Then
MyConverter.Button1Action()
Else
MyConverter.IsExited = True
MyConverter.Result = 1
Close()
End If
End Sub
Public Sub Btn2_Click() Handles Btn2.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = 2
Close()
If MyConverter.Button2Action IsNot Nothing Then
MyConverter.Button2Action()
Else
MyConverter.IsExited = True
MyConverter.Result = 2
Close()
End If
End Sub
Public Sub Btn3_Click() Handles Btn3.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = 3
Close()
If MyConverter.Button3Action IsNot Nothing Then
MyConverter.Button3Action()
Else
MyConverter.IsExited = True
MyConverter.Result = 3
Close()
End If
End Sub
Private Sub Drag(sender As Object, e As MouseButtonEventArgs) Handles PanBorder.MouseLeftButtonDown, LabTitle.MouseLeftButtonDown
+27 -21
View File
@@ -29,21 +29,28 @@
'逐个进入动画
Dim AniList As New List(Of AniData)
Dim Id As Integer = 0, Delay As Integer = 0
Dim Controls = GetAllAnimControls()
For Each Element As FrameworkElement In Controls
Element.Opacity = 0
Element.RenderTransform = New TranslateTransform(-25, 0)
AniList.Add(AaOpacity(Element, If(TypeOf Element Is TextBlock, 0.6, 1), 200, Delay, New AniEaseOutFluent(AniEasePower.Weak)))
AniList.Add(AaTranslateX(Element, 5, 200, Delay, New AniEaseOutFluent))
AniList.Add(AaTranslateX(Element, 20, 300, Delay, New AniEaseOutBack(AniEasePower.Weak)))
If TypeOf Element Is MyListItem Then
AniList.Add(AaCode(Sub()
CType(Element, MyListItem).IsMouseOverAnimationEnabled = True
CType(Element, MyListItem).RefreshColor(Me, New EventArgs)
End Sub, Delay + 280))
For Each Element As FrameworkElement In GetAllAnimControls(True)
If Element.Visibility = Visibility.Collapsed Then
'还原之前的隐藏动画可能导致的改变(#2436)
Element.Opacity = 1
Element.RenderTransform = New TranslateTransform(0, 0)
If TypeOf Element Is MyListItem Then CType(Element, MyListItem).IsMouseOverAnimationEnabled = True
Else
Element.Opacity = 0
Element.RenderTransform = New TranslateTransform(-25, 0)
If TypeOf Element Is MyListItem Then CType(Element, MyListItem).IsMouseOverAnimationEnabled = False
AniList.Add(AaOpacity(Element, If(TypeOf Element Is TextBlock, 0.6, 1), 200, Delay, New AniEaseOutFluent(AniEasePower.Weak)))
AniList.Add(AaTranslateX(Element, 5, 200, Delay, New AniEaseOutFluent))
AniList.Add(AaTranslateX(Element, 20, 300, Delay, New AniEaseOutBack(AniEasePower.Weak)))
If TypeOf Element Is MyListItem Then
AniList.Add(AaCode(Sub()
CType(Element, MyListItem).IsMouseOverAnimationEnabled = True
CType(Element, MyListItem).RefreshColor(Me, New EventArgs)
End Sub, Delay + 280))
End If
Delay += Math.Max(8, 20 - Id) * 2.5
Id += 1
End If
Delay += Math.Max(8, 20 - Id) * 2.5
Id += 1
Next
AniStart(AniList, "PageLeft PageChange " & Uuid)
End If
@@ -74,23 +81,22 @@
End Sub
'遍历获取所有需要生成动画的控件
Private Function GetAllAnimControls() As List(Of FrameworkElement)
Private Function GetAllAnimControls(Optional IgnoreInvisibility As Boolean = False) As List(Of FrameworkElement)
Dim AllControls As New List(Of FrameworkElement)
GetAllAnimControls(AnimatedControl, AllControls)
GetAllAnimControls(AnimatedControl, AllControls, IgnoreInvisibility)
Return AllControls
End Function
Private Sub GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement))
If Element.Visibility = Visibility.Collapsed Then Exit Sub
Private Sub GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement), IgnoreInvisibility As Boolean)
If Not IgnoreInvisibility AndAlso Element.Visibility = Visibility.Collapsed Then Exit Sub
If TypeOf Element Is MyTextButton Then
AllControls.Add(Element)
ElseIf TypeOf Element Is MyListItem Then
CType(Element, MyListItem).IsMouseOverAnimationEnabled = False
AllControls.Add(Element)
ElseIf TypeOf Element Is ContentControl Then
GetAllAnimControls(CType(Element, ContentControl).Content, AllControls)
GetAllAnimControls(CType(Element, ContentControl).Content, AllControls, IgnoreInvisibility)
ElseIf TypeOf Element Is Panel Then
For Each Element2 As FrameworkElement In CType(Element, Panel).Children
GetAllAnimControls(Element2, AllControls)
GetAllAnimControls(Element2, AllControls, IgnoreInvisibility)
Next
Else
AllControls.Add(Element)
+56 -16
View File
@@ -2,6 +2,18 @@
Inherits AdornerDecorator
Public PageUuid As Integer = GetUuid()
'“返回顶部” 按钮检测的滚动区域
Public Property PanScroll As MyScrollViewer
Get
Return GetValue(PanScrollProperty)
End Get
Set(value As MyScrollViewer)
SetValue(PanScrollProperty, value)
End Set
End Property
Private Shared ReadOnly PanScrollProperty =
DependencyProperty.Register("PanScroll", GetType(MyScrollViewer), GetType(MyPageRight), New PropertyMetadata(Nothing))
'当前状态
Public Enum PageStates
Empty '默认状态,页面全空
@@ -65,10 +77,10 @@
Sub()
Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ContentExit
Thread.Sleep(10) '不在退出动画时执行 UI 线程操作,避免退出动画被重置
Loop
Loop
RunInUiWait(Sub() FinishedInvoke(RealLoader))
Thread.Sleep(20) '由于大量初始化控件会导致掉帧,延迟触发 State 改变事件
End Sub
End Sub
End If
AddHandler RealLoader.OnStateChangedUi, Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) RunInUi(Sub() PageLoaderState(Loader, NewState, OldState))
'隐藏 UI
@@ -77,7 +89,7 @@
If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed
'初次运行加载器
If PageLoaderAutoRun Then
If PageLoader.GetType.Name.StartsWith("LoaderTask") Then
If PageLoader.GetType.Name.StartsWithF("LoaderTask") Then
PageLoader.Start(CType(PageLoader, Object).StartGetInput(Nothing, PageLoaderInputInvoke))
Else
Dim Input = Nothing
@@ -95,7 +107,7 @@
'重试
Public Sub PageLoaderRestart(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = True) '由外部调用的重试
If Not PageLoaderAutoRun Then Exit Sub
If PageLoader.GetType.Name.StartsWith("LoaderTask") Then
If PageLoader.GetType.Name.StartsWithF("LoaderTask") Then
PageLoader.Start(CType(PageLoader, Object).StartGetInput(Input, PageLoaderInputInvoke), IsForceRestart:=IsForceRestart)
Else
If Input Is Nothing AndAlso PageLoaderInputInvoke IsNot Nothing Then Input = PageLoaderInputInvoke()
@@ -152,6 +164,7 @@
''' </summary>
Public Sub PageOnExit()
If ModeDebug Then Log("[UI] 已触发 PageOnExit")
RaiseEvent PageExit()
Select Case PageState
Case PageStates.ContentEnter, PageStates.ContentStay
PageState = PageStates.PageExit
@@ -168,6 +181,7 @@
Case PageStates.PageExit, PageStates.Empty
End Select
End Sub
Public Event PageExit()
''' <summary>
''' 即将切换到其他页面,需要强制完成页面状态清理。
''' 需要立即切换至 Empty。
@@ -325,17 +339,13 @@
'逐个进入动画
Public Sub TriggerEnterAnimation(ParamArray Elements As FrameworkElement())
'去除 Nothing 项
Dim RealElements As New List(Of FrameworkElement)
For Each Element In Elements
If Element IsNot Nothing Then RealElements.Add(Element)
Next
Dim RealElements = Elements.Where(Function(e) e IsNot Nothing)
For Each Element In RealElements
Element.Visibility = Visibility.Visible '页面均处于默认的隐藏状态
Next
Dim AniList As New List(Of AniData)
Dim Delay As Integer = 0
'基础动画
For Each Element In RealElements
For Each Control As FrameworkElement In GetAllAnimControls(Element, True)
'还原被隐藏的卡片的消失动画
@@ -351,18 +361,20 @@
Delay += 40
Next
Next
'滚动条动画
Dim Scroll As MyScrollBar = GetFirstScrollViewer(RealElements)
If Scroll IsNot Nothing Then
If TypeOf Scroll.RenderTransform IsNot TranslateTransform Then Scroll.RenderTransform = New TranslateTransform(10, 0)
AniList.Add(AaTranslateX(Scroll, -CType(Scroll.RenderTransform, TranslateTransform).X, 350, 0, New AniEaseOutFluent))
End If
'结束
AniList.Add(AaCode(Sub() PageOnEnterAnimationFinished(),, True))
AniStart(AniList, "PageRight PageChange " & PageUuid)
End Sub
'逐个退出动画
Public Sub TriggerExitAnimation(ParamArray Elements As FrameworkElement())
'去除 Nothing 项
Dim RealElements As New List(Of FrameworkElement)
For Each Element In Elements
If Element IsNot Nothing Then RealElements.Add(Element)
Next
Dim RealElements = Elements.Where(Function(e) e IsNot Nothing)
Dim AniList As New List(Of AniData)
Dim Delay As Integer = 0
For Each Element In RealElements
@@ -373,6 +385,13 @@
Delay += 20
Next
Next
'滚动条动画
Dim Scroll As MyScrollBar = GetFirstScrollViewer(RealElements)
If Scroll IsNot Nothing Then
If TypeOf Scroll.RenderTransform IsNot TranslateTransform Then Scroll.RenderTransform = New TranslateTransform
AniList.Add(AaTranslateX(Scroll, 10 - CType(Scroll.RenderTransform, TranslateTransform).X, 90, 0, New AniEaseInFluent))
End If
'结束
AniList.Add(AaCode(Sub()
For Each Element In RealElements
Element.Visibility = Visibility.Collapsed
@@ -402,6 +421,27 @@
End If
End Sub
'查找列表中的第一个滚动条
Private Function GetFirstScrollViewer(Elements As IEnumerable(Of FrameworkElement)) As MyScrollBar
Dim Viewer As MyScrollViewer = Nothing
For Each Element In Elements
If TypeOf Element Is MyScrollViewer Then
Viewer = Element
GoTo FindViewer
End If
For Each Control In LogicalTreeHelper.GetChildren(Element)
If TypeOf Control Is MyScrollViewer Then
Viewer = Control
GoTo FindViewer
End If
Next
Next
Return Nothing
FindViewer:
If Viewer.ComputedVerticalScrollBarVisibility <> Visibility.Visible Then Return Nothing
Return Viewer.ScrollBar
End Function
#End Region
End Class
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FocusVisualStyle="{x:Null}"
MinWidth="20" x:Name="PanBack" UseLayoutRounding="False" SnapsToDevicePixels="False" MinHeight="20" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True">
<TextBlock IsHitTestVisible="False" x:Name="LabText" FontSize="13" Padding="0" Margin="26,0,0,0" Text="Radiobox" Foreground="{DynamicResource ColorBrush1}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock IsHitTestVisible="False" x:Name="LabText" FontSize="13" Padding="0" Margin="26,0,0,0" Text="Radiobox" Foreground="{DynamicResource ColorBrush1}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Ellipse IsHitTestVisible="False" x:Name="ShapeBorder" StrokeThickness="1.1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="18" Height="18" Stroke="{DynamicResource ColorBrush1}" Margin="1,0,0,0" Fill="{StaticResource ColorBrushHalfWhite}" />
<Ellipse IsHitTestVisible="False" x:Name="ShapeDot" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="{Binding Stroke, ElementName=ShapeBorder}" Width="0" Height="0" Margin="10,0,0,0" StrokeThickness="0" />
<Ellipse IsHitTestVisible="False" x:Name="ShapeDot" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="{Binding Stroke, ElementName=ShapeBorder}" Width="0" Height="0" Margin="10,0,0,0" StrokeThickness="0" />
</Grid>
@@ -170,12 +170,12 @@
MouseDowned = False
Log("[Control] 按下单选框:" & Text)
SetChecked(True, True, True)
AniStart(AaColor(ShapeBorder, Shapes.Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid)
AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid)
End Sub
Private Sub Radiobox_MouseDown() Handles Me.MouseLeftButtonDown
MouseDowned = True
Focus()
AniStart(AaColor(ShapeBorder, Shapes.Ellipse.FillProperty, "ColorBrush9", 100), "MyRadioBox Background " & Uuid)
AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushBg1", 100), "MyRadioBox Background " & Uuid)
If Not Checked Then
AniStart(AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyRadioBox Border " & Uuid)
End If
@@ -183,7 +183,7 @@
Private Sub Radiobox_MouseLeave() Handles Me.MouseLeave
If Not MouseDowned Then Exit Sub
MouseDowned = False
AniStart(AaColor(ShapeBorder, Shapes.Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid)
AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid)
If Not Checked Then
AniStart(AaScale(ShapeBorder, 18 - ShapeBorder.Width, 400, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyRadioBox Border " & Uuid)
End If
@@ -223,6 +223,8 @@
AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfMouseOut), "MyRadioBox BorderColor " & Uuid)
AniStart(AaColor(LabText, TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"), AnimationTimeOfMouseOut), "MyRadioBox TextColor " & Uuid)
Else
AniStop("MyRadioBox BorderColor " & Uuid)
AniStop("MyRadioBox TextColor " & Uuid)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"))
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
End If
@@ -4,6 +4,6 @@
HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27">
<StackPanel Orientation="Horizontal">
<Path x:Name="ShapeLogo" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="White" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center" />
<TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="8,0,12,0" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="8,0,12,1" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
</StackPanel>
</Border>
@@ -252,7 +252,7 @@
End If
Catch ex As Exception
Log(ex, "刷新按钮颜色出错")
Log(ex, "刷新单选按钮颜色出错")
End Try
End Sub
+1 -1
View File
@@ -128,7 +128,7 @@ Public Class MyResizer
Private Declare Function GetMonitorInfo Lib "user32" (hMonitor As IntPtr, lpmi As MONITORINFO) As Boolean
Friend Declare Function MonitorFromWindow Lib "User32" (handle As IntPtr, flags As Integer) As IntPtr
Private Declare Function MonitorFromWindow Lib "User32" (handle As IntPtr, flags As Integer) As IntPtr
Private Sub connectMouseHandlers(element As UIElement)
AddHandler element.MouseLeftButtonDown, AddressOf Me.element_MouseLeftButtonDown
@@ -2,17 +2,31 @@
Inherits ScrollViewer
Public Property DeltaMuity As Double = 1
Private RealOffset As Double
Private Sub MyScrollViewer_PreviewMouseWheel(sender As Object, e As MouseWheelEventArgs) Handles Me.PreviewMouseWheel
If e.Delta = 0 OrElse ActualHeight = 0 OrElse ScrollableHeight = 0 Then Exit Sub
Dim SourceTypeName As String = e.Source.GetType.Name
If Content.TemplatedParent Is Nothing AndAlso (SourceTypeName.Contains("Combo") OrElse SourceTypeName = "MyTextBox") Then Exit Sub '确定可视树,防止滚动问题
PerformVerticalOffsetDelta(-e.Delta)
Dim SourceType = e.Source.GetType
If Content.TemplatedParent Is Nothing AndAlso (
(GetType(ComboBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, ComboBox).IsDropDownOpen) OrElse
(GetType(TextBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, TextBox).AcceptsReturn) OrElse
GetType(ComboBoxItem).IsAssignableFrom(SourceType) OrElse
TypeOf e.Source Is CheckBox
) Then
'如果当前是在对有滚动条的下拉框或文本框执行,则不接管操作
Exit Sub
End If
e.Handled = True
PerformVerticalOffsetDelta(-e.Delta)
'关闭 Tooltip (#2552)
For Each TooltipBorder In Application.ShowingTooltips
AniStart(AaOpacity(TooltipBorder, -1, 100), $"Hide Tooltip {GetUuid()}")
Next
End Sub
Public Sub PerformVerticalOffsetDelta(Delta As Double)
AniStart(AaDouble(Sub(AnimDelta As Double)
RealOffset = MathRange(RealOffset + AnimDelta, 0, ExtentHeight - ActualHeight)
RealOffset = MathClamp(RealOffset + AnimDelta, 0, ExtentHeight - ActualHeight)
ScrollToVerticalOffset(RealOffset)
End Sub, Delta * DeltaMuity, 300,, New AniEaseOutFluent(6)))
End Sub
@@ -24,4 +38,9 @@
FrmMain.BtnExtraBack.ShowRefresh()
End Sub
Public ScrollBar As MyScrollBar
Private Sub Load() Handles Me.Loaded
ScrollBar = GetTemplateChild("PART_VerticalScrollBar")
End Sub
End Class
@@ -1,7 +1,7 @@
Class MySearchBox
Inherits MyCard
Public Event TextChanged(ByVal sender As Object, ByVal e As EventArgs)
Public Event TextChanged(sender As Object, e As EventArgs)
Private Sub MySearchBox_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
TextBox.Focus()
End Sub
@@ -11,7 +11,7 @@
Get
Return TextBox.HintText
End Get
Set(ByVal value As String)
Set(value As String)
TextBox.HintText = value
End Set
End Property
@@ -19,7 +19,7 @@
Get
Return TextBox.Text
End Get
Set(ByVal value As String)
Set(value As String)
TextBox.Text = value
End Set
End Property
@@ -6,11 +6,13 @@
mc:Ignorable="d"
d:DesignHeight="16" d:DesignWidth="162"
FocusVisualStyle="{x:Null}"
MinHeight="16" UseLayoutRounding="False" SnapsToDevicePixels="False" BorderBrush="{DynamicResource ColorBrush1}" Name="PanBack" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True">
MinHeight="16" UseLayoutRounding="False" SnapsToDevicePixels="False" BorderBrush="{DynamicResource ColorBrushBg0}" Name="PanBack" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True">
<Grid x:Name="PanMain" MinHeight="16" MaxHeight="16" IsHitTestVisible="False">
<Line Height="4" Name="LineBack" Stroke="{StaticResource ColorBrushGray5}" StrokeThickness="1.1" X2="10000" Y1="2" Y2="2" HorizontalAlignment="Right" Width="0" SnapsToDevicePixels="True" Margin="0,0,1,0" />
<Line Height="4" Name="LineFore" Stroke="{Binding ElementName=PanBack, Path=BorderBrush}" StrokeThickness="1.1" X2="10000" Y1="2" Y2="2" Width="0" HorizontalAlignment="Left" SnapsToDevicePixels="True" Margin="1,0,0,0" />
<Ellipse HorizontalAlignment="Left" Width="16" Stroke="{Binding BorderBrush, ElementName=PanBack}" StrokeThickness="1.1" Fill="{StaticResource ColorBrushHalfWhite}" Name="ShapeDot" Height="16" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<Line Height="4" Name="LineBack" Stroke="{DynamicResource ColorBrushBg0}" Opacity="0.3" StrokeThickness="1" X2="10000" Y1="2" Y2="2" HorizontalAlignment="Right" Width="0" SnapsToDevicePixels="True" Margin="0,0,1,0" />
<Line Height="4" Name="LineFore" Stroke="{Binding ElementName=PanBack, Path=BorderBrush}" StrokeThickness="2" X2="10000" Y1="2" Y2="2" Width="0" HorizontalAlignment="Left" SnapsToDevicePixels="True" Margin="1,0,0,0" />
<Ellipse HorizontalAlignment="Left" Width="10" Height="10"
Stroke="{Binding BorderBrush, ElementName=PanBack}" StrokeThickness="1.2"
Fill="{DynamicResource ColorBrushBg0}" Name="ShapeDot" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<ScaleTransform />
</Ellipse.RenderTransform>
@@ -28,7 +28,7 @@
Set(newValue As Integer)
Try
newValue = MathRange(newValue, 0, MaxValue)
newValue = MathClamp(newValue, 0, MaxValue)
If _Value = newValue Then Exit Property
'触发 Preview 事件,修改新值
@@ -45,13 +45,13 @@
End If
If IsLoaded AndAlso AniControlEnabled = 0 Then
If ActualWidth < 16 Then Exit Property
Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - 16)
Dim DeltaProcess As Double = Math.Abs(LineFore.Width / (ActualWidth - 16) - _Value / MaxValue)
If ActualWidth < ShapeDot.Width Then Exit Property
Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - ShapeDot.Width)
Dim DeltaProcess As Double = Math.Abs(LineFore.Width / (ActualWidth - ShapeDot.Width) - _Value / MaxValue)
Dim Time As Double = (1 - Math.Pow(1 - DeltaProcess, 3)) * 300 + If(ChangeByKey, 100, 0)
AniStart({
AaWidth(LineFore, Math.Max(0, NewWidth + If(NewWidth < 0.5, 0, 0.5)) - LineFore.Width, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear)),
AaWidth(LineBack, Math.Max(0, ActualWidth - 16 - NewWidth + If(ActualWidth - 16 - NewWidth < 0.5, 0, 0.5)) - LineBack.Width, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear)),
AaWidth(LineBack, Math.Max(0, ActualWidth - ShapeDot.Width - NewWidth + If(ActualWidth - ShapeDot.Width - NewWidth < 0.5, 0, 0.5)) - LineBack.Width, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear)),
AaX(ShapeDot, NewWidth - ShapeDot.Margin.Left, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear))
}, "MySlider Progress " & Uuid)
Else
@@ -67,9 +67,9 @@
Private Sub RefreshWidth(sender As Object, e As SizeChangedEventArgs) Handles Me.SizeChanged
If Not IsNothing(e) Then PanMain.Width = e.NewSize.Width
AniStop("MySlider Progress " & Uuid)
Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - 16)
Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - ShapeDot.Width)
LineFore.Width = Math.Max(0, NewWidth + If(NewWidth < 0.5, 0, 0.5))
LineBack.Width = Math.Max(0, ActualWidth - 16 - NewWidth + If(ActualWidth - 16 - NewWidth < 0.5, 0, 0.5))
LineBack.Width = Math.Max(0, ActualWidth - ShapeDot.Width - NewWidth + If(ActualWidth - ShapeDot.Width - NewWidth < 0.5, 0, 0.5))
SetLeft(ShapeDot, NewWidth)
End Sub
@@ -79,32 +79,36 @@
Private Sub DragStart(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
e.Handled = True '防止 ScrollViewer 失焦问题
DragControl = Me
RefreshColor()
FrmMain.DragDoing()
AniStart({
AaScaleTransform(ShapeDot, 0.8 - CType(ShapeDot.RenderTransform, ScaleTransform).ScaleX, 75,, New AniEaseOutFluent)
AaScaleTransform(ShapeDot, 1.3 - CType(ShapeDot.RenderTransform, ScaleTransform).ScaleX, 40,, New AniEaseOutFluent)
}, "MySlider Scale " & Uuid)
'更新 Popup
If GetHintText IsNot Nothing Then
TextHint.Text = GetHintText.DynamicInvoke(Value)
Popup.IsOpen = True
AniStop("MySlider KeyPopup " & Uuid)
End If
RefreshPopup()
AniStop("MySlider KeyPopup " & Uuid)
End Sub
Public Sub DragDoing()
Dim Percent As Double = MathRange((Mouse.GetPosition(PanMain).X - 8) / (ActualWidth - 16), 0, 1)
Dim Percent As Double = MathClamp((Mouse.GetPosition(PanMain).X - ShapeDot.Width / 2) / (ActualWidth - ShapeDot.Width), 0, 1)
Dim NewValue As Integer = Percent * MaxValue
If Not NewValue = Value Then
Value = NewValue
End If
'更新 Popup
If GetHintText IsNot Nothing Then TextHint.Text = GetHintText.DynamicInvoke(NewValue)
RefreshPopup()
End Sub
Public Sub DragStop()
RefreshColor()
AniStart({
AaScaleTransform(ShapeDot, 1 - CType(ShapeDot.RenderTransform, ScaleTransform).ScaleX, 200,, New AniEaseOutFluent)
}, "MySlider Scale " & Uuid)
If GetHintText IsNot Nothing Then Popup.IsOpen = False
Popup.IsOpen = False
End Sub
Public Sub RefreshPopup()
If GetHintText Is Nothing Then Exit Sub
Popup.IsOpen = True
TextHint.Text = GetHintText.DynamicInvoke(Value)
Dim typeface As New Typeface(TextHint.FontFamily, TextHint.FontStyle, TextHint.FontWeight, TextHint.FontStretch)
Dim formattedText As New FormattedText(TextHint.Text, Thread.CurrentThread.CurrentCulture, TextHint.FlowDirection, typeface, TextHint.FontSize, TextHint.Foreground, DPI)
TextHint.Width = formattedText.Width '使用手动测量的宽度修复 #1057
End Sub
'指向动画
@@ -113,28 +117,39 @@
Try
'判断当前颜色
Dim ColorName As String
Dim ForegroundName As String, DotFillName As String
Dim AnimationTime As Integer
If IsEnabled Then
If IsMouseOver OrElse (Not IsNothing(DragControl) AndAlso DragControl.Equals(Me)) Then
ColorName = "ColorBrush3"
AnimationTime = 100
If Not IsNothing(DragControl) AndAlso DragControl.Equals(Me) Then
ForegroundName = "ColorBrush3"
DotFillName = "ColorBrush3"
AnimationTime = 40
ElseIf IsMouseOver Then
ForegroundName = "ColorBrush3"
DotFillName = "ColorBrush3"
AnimationTime = 40
Else
ColorName = "ColorBrush1"
AnimationTime = 200
ForegroundName = "ColorBrushBg0"
DotFillName = "ColorBrushBg0"
AnimationTime = 100
End If
Else
ColorName = "ColorBrushGray4"
ForegroundName = "ColorBrushGray5"
DotFillName = "ColorBrushGray5"
AnimationTime = 200
End If
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
AniStart({AaColor(Me, BorderBrushProperty, ColorName, AnimationTime)}, "MySlider Color " & Uuid)
AniStart({
AaColor(Me, BorderBrushProperty, ForegroundName, AnimationTime),
AaColor(ShapeDot, Ellipse.FillProperty, DotFillName, AnimationTime)
}, "MySlider Color " & Uuid)
Else
'无动画
AniStop("MySlider Color " & Uuid)
SetResourceReference(BorderBrushProperty, ColorName)
SetResourceReference(BorderBrushProperty, ForegroundName)
ShapeDot.SetResourceReference(Ellipse.FillProperty, DotFillName)
End If
Catch ex As Exception
@@ -167,8 +182,7 @@
End If
'更新 Popup
If GetHintText IsNot Nothing Then
TextHint.Text = GetHintText.DynamicInvoke(Value)
Popup.IsOpen = True
RefreshPopup()
AniStop("MySlider KeyPopup " & Uuid)
AniStart(AaCode(Sub() Popup.IsOpen = False, 700 * AniSpeed), "MySlider KeyPopup " & Uuid)
End If
+37 -48
View File
@@ -86,15 +86,15 @@
ValidateResult = ValidateRule.Validate(Text)
If IsNothing(ValidateResult) OrElse Not ValidateResult = "" Then Exit For
Next
Dim NewResult As Integer = If(ValidateResult = "", 0, 1)
Dim IsSuccessful As Boolean = ValidateResult = ""
'根据结果改变样式
If ShownValidateResult <> NewResult Then
If ShownValidateResult <> If(IsSuccessful, ValidateState.Success, ValidateState.FailedAndShowDetail) Then
If IsLoaded AndAlso labWrong IsNot Nothing Then
ChangeValidateResult(ValidateResult = "", True)
ChangeValidateResult(IsSuccessful, True)
Else
RunInNewThread(Sub()
Thread.Sleep(30)
RunInUi(Sub() ChangeValidateResult(NewResult, False))
RunInUi(Sub() ChangeValidateResult(IsSuccessful, False))
End Sub, "DelayedValidate Change")
End If
End If
@@ -119,12 +119,19 @@
End If
End If
End Sub
Private ShownValidateResult As Integer = -1
Private Sub ChangeValidateResult(NewResult As Boolean, IsLoaded As Boolean)
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso IsTextChanged AndAlso labWrong IsNot Nothing Then
If NewResult Then
''' <summary>
''' 强制显示结果为正常,类似尚未输入过文本的状态。不影响实际的检查结果。
''' </summary>
Public Sub ForceShowAsSuccess()
IsTextChanged = False
ChangeValidateResult(ValidateResult = "", True)
End Sub
Private ShownValidateResult As ValidateState = ValidateState.NotInited
Private Sub ChangeValidateResult(IsSuccessful As Boolean, IsLoaded As Boolean)
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso labWrong IsNot Nothing Then
If IsSuccessful OrElse Not IsTextChanged Then
'变为正确
ShownValidateResult = 0
ShownValidateResult = If(IsSuccessful, ValidateState.Success, ValidateState.FailedButTextNotChanged)
AniStart({
AaOpacity(labWrong, -labWrong.Opacity, 150),
AaHeight(labWrong, -labWrong.Height, 150,, New AniEaseOutFluent),
@@ -132,7 +139,7 @@
}, "MyTextBox Validate " & Uuid)
ElseIf ShowValidateResult Then
'变为错误
ShownValidateResult = 1
ShownValidateResult = ValidateState.FailedAndShowDetail
labWrong.Visibility = Visibility.Visible
AniStart({
AaOpacity(labWrong, 1 - labWrong.Opacity, 170),
@@ -140,31 +147,22 @@
}, "MyTextBox Validate " & Uuid)
Else
'变为错误,但不显示文本
ShownValidateResult = 2
ShownValidateResult = ValidateState.FailedAndHideDetail
End If
Else
ShownValidateResult = 3
'AniStop("MyTextBox Validate " & Uuid)
'If NewResult Then
' '变为正确
' labWrong.Opacity = 0
' labWrong.Height = 0
' labWrong.Visibility = Visibility.Collapsed
'Else
' '变为错误
' labWrong.Visibility = Visibility.Visible
' labWrong.Text = ValidateResult
' labWrong.Opacity = 1
' labWrong.Height = 20.5
'End If
'Dim OriginalEnabled As Integer = AniControlEnabled
'AniControlEnabled += 1
'RefreshColor()
'AniControlEnabled = OriginalEnabled
ShownValidateResult = ValidateState.NotLoaded
End If
RefreshColor()
RaiseEvent ValidateChanged(Me, New EventArgs)
End Sub
Private Enum ValidateState
NotInited
Success
FailedButTextNotChanged
FailedAndShowDetail
FailedAndHideDetail
NotLoaded
End Enum
'提示文本
@@ -212,35 +210,26 @@
If IsEnabled Then
If ValidateResult = "" OrElse Not IsTextChanged Then
If IsFocused Then
ForeColorName = "ColorBrush4"
BackColorName = "ColorBrush9"
AnimationTime = 60
ElseIf IsMouseOver Then
ForeColorName = "ColorBrush3"
BackColorName = "ColorBrush7"
AnimationTime = 10
ElseIf IsMouseOver Then
ForeColorName = "ColorBrush4"
BackColorName = "ColorBrush7"
AnimationTime = 100
Else '未选中
ForeColorName = "ColorBrushBg0"
BackColorName = "ColorBrushHalfWhite"
AnimationTime = 100
Else
ForeColorName = "ColorBrush1"
BackColorName = "ColorBrushHalfWhite"
AnimationTime = 200
End If
Else
ForeColorName = "ColorBrushRedLight"
BackColorName = "ColorBrushRedBack"
AnimationTime = 200
'If IsFocused OrElse IsMouseOver Then
' ForeColorName = "ColorBrushRedLight"
' BackColorName = "ColorBrushRedBack"
' AnimationTime = 100
'Else
' ForeColorName = "ColorBrushRedDark"
' BackColorName = "ColorBrushHalfWhite"
' AnimationTime = 200
'End If
End If
Else
ForeColorName = "ColorBrushGray4"
BackColorName = "ColorBrushHalfWhite"
ForeColorName = "ColorBrushGray5"
BackColorName = "ColorBrushGray6"
AnimationTime = 200
End If
'触发颜色动画
@@ -91,7 +91,7 @@
Return GetValue(EventTypeProperty)
End Get
Set(ByVal value As String)
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
@@ -101,7 +101,7 @@
Return GetValue(EventDataProperty)
End Get
Set(ByVal value As String)
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
+19 -13
View File
@@ -1,16 +1,22 @@
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Name="WindMain" x:Class="FormMain" Style="{StaticResource MyWindow}"
AllowDrop="True" Topmost="True" Title="Plain Craft Launcher 2 " AllowsTransparency="True" MinHeight="450" MinWidth="760" ScrollViewer.VerticalScrollBarVisibility="Disabled" Icon="/Plain Craft Launcher 2;component/Images/icon.ico" Left="-10000" WindowStyle="None" ResizeMode="CanMinimize" Background="{x:Null}" d:DesignWidth="870" d:DesignHeight="520" Width="850" Height="500" RenderTransformOrigin="0.5,0.5">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Name="WindMain" x:Class="FormMain" Style="{StaticResource MyWindow}"
AllowDrop="True" Topmost="True" Title="Plain Craft Launcher " AllowsTransparency="True" MinHeight="470" MinWidth="810"
ScrollViewer.VerticalScrollBarVisibility="Disabled" Icon="/Plain Craft Launcher 2;component/Images/icon.ico" WindowStyle="None"
ResizeMode="CanMinimize" Background="{x:Null}" d:DesignWidth="870" d:DesignHeight="520" Width="850" Height="500"
RenderTransformOrigin="0.5,0.5">
<Window.TaskbarItemInfo>
<TaskbarItemInfo ThumbnailClipMargin="{Binding Margin, ElementName=PanForm}" />
</Window.TaskbarItemInfo>
<Grid x:Name="PanBack" SnapsToDevicePixels="True" UseLayoutRounding="True" Margin="1" RenderTransformOrigin="0.5,0.5">
<Grid x:Name="PanBack" SnapsToDevicePixels="True" UseLayoutRounding="True" Margin="10" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<ScaleTransform ScaleX="0.95" ScaleY="0.95" />
<TransformGroup>
<RotateTransform x:Name="TransformRotate" Angle="-4" />
<TranslateTransform x:Name="TransformPos" X="0" Y="60" />
</TransformGroup>
</Grid.RenderTransform>
<Rectangle x:Name="ResizerT" Stroke="{x:Null}" StrokeThickness="0.0001" Height="8" VerticalAlignment="Top" Margin="13,0" Cursor="SizeNS">
<Rectangle.Fill>
@@ -116,19 +122,19 @@
<local:MyRadioButton x:Name="BtnTitleSelect0" Text="{DynamicResource LangTitleHome}" Tag="0" Margin="5,0" Checked="True" Padding="2,0"
LogoScale="0.95" Logo="M985.403 552.96C985.403 812.702 773.041 1024 512 1024S38.597 812.702 38.597 552.96c0-158.208 79.163-304.955 211.771-392.625 31.074-20.52 72.94-11.973 93.46 19.101s12.012 72.94-19.062 93.46c-94.681 62.622-151.237 167.306-151.237 280.064 0 185.344 151.788 336.108 338.471 336.108S850.471 738.304 850.471 552.96c0-114.649-57.974-220.278-155.096-282.585-31.35-20.125-40.448-61.833-20.362-93.184s61.794-40.448 93.184-20.4c135.995 87.236 217.206 235.362 217.206 396.169zM512 560.128c37.258 0 67.466-30.208 67.466-67.466V67.466C579.466 30.208 549.258 0 512 0s-67.466 30.208-67.466 67.466v425.196c0 37.258 30.208 67.466 67.466 67.466z" />
<local:MyRadioButton x:Name="BtnTitleSelect1" Text="{DynamicResource LangTitleDownload}" Tag="1" Margin="5,0" Padding="2,0"
LogoScale="0.9" Logo="M955.076923 610.461538h-59.076923c-15.753846 0-29.538462 13.784615-29.538462 29.538462v196.923077c0 15.753846-13.784615 29.538462-29.538461 29.538461h-649.846154c-15.753846 0-29.538462-13.784615-29.538461-29.538461v-196.923077c0-15.753846-13.784615-29.538462-29.538462-29.538462h-59.076923c-15.753846 0-29.538462 13.784615-29.538462 29.538462V905.846154c0 43.323077 35.446154 78.769231 78.769231 78.769231h787.692308c43.323077 0 78.769231-35.446154 78.769231-78.769231V640c0-15.753846-13.784615-29.538462-29.538462-29.538462zM492.307692 740.430769c11.815385 11.815385 29.538462 11.815385 41.353846 0l265.846154-265.846154c11.815385-11.815385 11.815385-29.538462 0-41.353846l-41.353846-41.353846c-11.815385-11.815385-29.538462-11.815385-41.353846 0l-110.276923 110.276923c-11.815385 11.815385-33.476923 3.938462-33.476923-13.784615V68.923077C571.076923 53.169231 555.323077 39.384615 541.538462 39.384615h-59.076924c-15.753846 0-29.538462 13.784615-29.538461 29.538462v417.476923c0 17.723077-21.661538 25.6-33.476923 13.784615l-110.276923-110.276923c-11.815385-11.815385-29.538462-11.815385-41.353846 0L226.461538 433.230769c-11.815385 11.815385-11.815385 29.538462 0 41.353846L492.307692 740.430769z" />
LogoScale="0.9" Logo="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
<local:MyRadioButton x:Name="BtnTitleSelect2" Text="联机" Tag="2" Margin="5,0" Padding="2,0"
LogoScale="1.05" Logo="M512 817c-48.601 0-88-39.399-88-88s39.399-88 88-88 88 39.399 88 88-39.399 88-88 88zM237.671 565.74C308.335 474.58 397.369 429 504.774 429c118.433 0 214.225 55.421 287.377 166.264l-53.407 30.369c-13.84 7.87-31.362 4.367-41.114-8.219-50.291-64.911-114.577-97.367-192.856-97.367-86.851 0-156.835 40.318-209.95 120.953l-47.995-28.02c-15.263-8.91-20.412-28.507-11.502-43.77a32 32 0 0 1 2.344-3.47zM107.691 419.47C205.24 278.491 337.805 208 505.379 208c178.77 0 317.694 80.224 416.772 240.672l-56.54 31.73c-13.686 7.68-30.922 4.303-40.697-7.975C735.581 360.213 629.07 303.009 505.38 300.815 373.997 298.485 261.637 362.88 168.3 494l-50.116-28.505c-15.362-8.738-20.732-28.275-11.994-43.637a32 32 0 0 1 1.5-2.387z"/>
<local:MyRadioButton x:Name="BtnTitleSelect3" Text="{DynamicResource LangTitleSetup}" Tag="3" Margin="5,0" Padding="2,0"
LogoScale="1.1" Logo="M940.4 463.7L773.3 174.2c-17.3-30-49.2-48.4-83.8-48.4H340.2c-34.6 0-66.5 18.5-83.8 48.4L89.2 463.7c-17.3 30-17.3 66.9 0 96.8L256.4 850c17.3 30 49.2 48.4 83.8 48.4h349.2c34.6 0 66.5-18.5 83.8-48.4l167.2-289.5c17.3-29.9 17.3-66.8 0-96.8z m-94.6 96.8L725.9 768.1c-17.3 30-49.2 48.4-83.8 48.4H387.5c-34.6 0-66.5-18.5-83.8-48.4L183.9 560.5c-17.3-30-17.3-66.9 0-96.8l119.8-207.5c17.3-30 49.2-48.4 83.8-48.4h254.6c34.6 0 66.5 18.5 83.8 48.4l119.8 207.5c17.3 30 17.3 66.9 0.1 96.8z M522.3 321.2c-2.5-0.1-5-0.2-7.5-0.2-119.9 0-214 110.3-186.3 235 15.8 70.9 71.5 126.6 142.4 142.4 17.5 3.9 34.7 5.4 51.4 4.7 102.1-3.9 183.6-87.9 183.6-191 0.1-103-81.5-187-183.6-190.9z m68.6 269.1c-18.5 18-43 28.9-68.6 30.7l-6 0.3c-30.2 0.4-58.6-11.4-79.7-33-19.5-20.1-30.7-47-30.9-75-0.3-29.6 11.1-57.4 32-78.3 20.6-20.6 48-32 77.2-32 2.5 0 5 0.1 7.5 0.3 26.7 1.8 51.5 13.2 70.5 32.5 19.6 20 30.8 46.9 31.2 74.9 0.2 30.2-11.5 58.6-33.2 79.6z"/>
<local:MyRadioButton x:Name="BtnTitleSelect4" Text="{DynamicResource LangTitleOther}" Tag="4" Margin="5,0" Padding="2,0"
LogoScale="0.93" Logo="M364.145778 0h-273.066667C40.846222 0 0 40.846222 0 91.022222v273.066667C0 414.264889 40.846222 455.111111 91.136 455.111111h273.066667C414.321778 455.111111 455.111111 414.264889 455.111111 364.032V91.022222C455.111111 40.846222 414.321778 0 364.145778 0zM341.333333 341.333333H113.777778V113.777778h227.555555v227.555555zM933.034667 0h-273.066667C609.792 0 568.888889 40.846222 568.888889 91.022222v273.066667c0 50.176 40.903111 91.022222 91.136 91.022222h273.066667C983.210667 455.111111 1024 414.264889 1024 364.032V91.022222c0-50.176-40.789333-91.022222-90.965333-91.022222zM910.222222 341.333333h-227.555555V113.777778h227.555555v227.555555zM364.145778 568.888889h-273.066667C40.846222 568.888889 0 609.735111 0 659.911111v273.066667c0 50.176 40.846222 91.022222 91.136 91.022222h273.066667C414.321778 1024 455.111111 983.153778 455.111111 932.920889v-273.066667C455.111111 609.735111 414.321778 568.888889 364.145778 568.888889zM341.333333 910.222222H113.777778v-227.555555h227.555555v227.555555zM933.034667 568.888889h-273.066667c-50.176 0-91.079111 40.846222-91.079111 91.022222v273.066667c0 50.176 40.903111 91.022222 91.136 91.022222h273.066667c50.119111 0 90.908444-40.846222 90.908444-91.079111v-273.066667c0-50.119111-40.789333-90.965333-90.965333-90.965333zM910.222222 910.222222h-227.555555v-227.555555h227.555555v227.555555z"/>
LogoScale="0.93" Logo="M364 0h-273C40 0 0 40 0 91v273C0 414 40 455 91 455h273C414 455 455 414 455 364V91C455 40 414 0 364 0zM341 341H113V113h227v227zM933 0h-273C609 0 568 40 568 91v273c0 50 40 91 91 91h273C983 455 1024 414 1024 364V91c0-50-40-91-90-91zM910 341h-227V113h227v227zM364 568h-273C40 568 0 609 0 659v273c0 50 40 91 91 91h273C414 1024 455 983 455 932v-273C455 609 414 568 364 568zM341 910H113v-227h227v227zM933 568h-273c-50 0-91 40-91 91v273c0 50 40 91 91 91h273c50 0 90-40 90-91v-273c0-50-40-90-90-90zM910 910h-227v-227h227v227z"/>
</StackPanel>
</Grid>
<Grid x:Name="PanTitleInner" Visibility="Collapsed" Margin="-16,0,0,0" Opacity="0" HorizontalAlignment="Left" Width="{Binding ActualWidth, ElementName=PanTitle, Mode=OneWay}">
<local:MyIconButton HorizontalAlignment="Left" Theme="White" x:Name="BtnTitleInner" Margin="12,0,0,0" Height="28" Width="28"
LogoScale="0.87" Logo="M1097.162313 584.707482 250.272424 584.707482 562.833701 896.95123C591.749274 925.859979 591.749274 972.659975 562.833701 1001.568724 533.91812 1030.477473 487.058315 1030.477473 458.142742 1001.568724L21.580946 565.451235C6.757449 550.631234-0.361728 531.131238 0.028357 511.679985L0.028357 511.631236 0.028357 511.582486C-0.361728 492.13124 6.757449 472.582488 21.580946 457.762487L458.142742 21.644997C487.058315-7.215002 533.91812-7.215002 562.833701 21.644997 591.749274 50.553746 591.749274 97.4025 562.833701 126.262499L250.272424 438.55499 1097.162313 438.55499C1137.585605 438.55499 1170.304578 471.266238 1170.304578 511.631236 1170.304578 551.947483 1137.585605 584.707482 1097.162313 584.707482L1097.162313 584.707482Z" />
<TextBlock SnapsToDevicePixels="False" IsHitTestVisible="False" Name="LabTitleInner" VerticalAlignment="Center" Margin="47,1,0,0" HorizontalAlignment="Left" Foreground="{DynamicResource ColorBrush8}" FontSize="15" />
<TextBlock SnapsToDevicePixels="False" IsHitTestVisible="False" Name="LabTitleInner" VerticalAlignment="Center" Margin="47,1,60,0" HorizontalAlignment="Left" Foreground="{DynamicResource ColorBrush8}" FontSize="15" />
</Grid>
</Grid>
<Grid x:Name="PanLeft" Grid.Row="1" HorizontalAlignment="Left" SnapsToDevicePixels="True">
@@ -160,12 +166,12 @@
</Border>
</Border>
</Grid>
<StackPanel x:Name="PanHint" UseLayoutRounding="True" SnapsToDevicePixels="True" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0,0,0,25" IsHitTestVisible="False" Grid.RowSpan="2" />
<StackPanel x:Name="PanHint" IsHitTestVisible="False" UseLayoutRounding="True" SnapsToDevicePixels="True" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0,0,0,25" Grid.RowSpan="2" />
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Grid.Row="1" Margin="15">
<local:MyExtraButton x:Name="BtnExtraBack" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="返回顶部" Visibility="Collapsed"
Logo="M858.496 188.9024 173.1072 188.9024c-30.2848 0-54.8352-24.5504-54.8352-54.8352L118.272 106.6496c0-30.2848 24.5504-54.8352 54.8352-54.8352l685.3888 0c30.2848 0 54.8352 24.5504 54.8352 54.8352l0 27.4176C913.3312 164.352 888.7808 188.9024 858.496 188.9024L858.496 188.9024zM150.6048 550.8608c0 0 300.0064-240.3584 303.0272-243.328 13.9776-13.5936 31.1808-21.8624 48.8192-24.7552 1.7152-0.3072 3.4304-0.5888 5.1456-0.768 2.7392-0.3072 5.4528-0.3584 8.192-0.3328 2.7392-0.0256 5.4272 0.0256 8.1664 0.3328 1.7408 0.1792 3.4304 0.4864 5.1456 0.768 17.664 2.8928 34.8672 11.1616 48.8192 24.7552 3.0464 2.944 303.0016 243.328 303.0016 243.328 32.384 31.5136 29.6192 63.9744-2.7392 95.5136-32.3328 31.5392-75.648 2.9696-108.0064-28.544l-185.8816-147.1232 0 485.8368c0 30.3104-24.5248 54.8608-54.8352 54.8608l-27.392 0c-30.2848 0-54.8352-24.5504-54.8352-54.8608L447.232 470.7072l-185.8304 147.0976c-32.3584 31.5392-75.6992 60.1344-108.032 28.5696C121.0368 614.8352 118.272 582.3744 150.6048 550.8608L150.6048 550.8608zM150.6048 550.8608" />
<local:MyExtraButton x:Name="BtnExtraDownload" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="下载管理" Visibility="Collapsed"
Logo="M955.076923 610.461538h-59.076923c-15.753846 0-29.538462 13.784615-29.538462 29.538462v196.923077c0 15.753846-13.784615 29.538462-29.538461 29.538461h-649.846154c-15.753846 0-29.538462-13.784615-29.538461-29.538461v-196.923077c0-15.753846-13.784615-29.538462-29.538462-29.538462h-59.076923c-15.753846 0-29.538462 13.784615-29.538462 29.538462V905.846154c0 43.323077 35.446154 78.769231 78.769231 78.769231h787.692308c43.323077 0 78.769231-35.446154 78.769231-78.769231V640c0-15.753846-13.784615-29.538462-29.538462-29.538462zM492.307692 740.430769c11.815385 11.815385 29.538462 11.815385 41.353846 0l265.846154-265.846154c11.815385-11.815385 11.815385-29.538462 0-41.353846l-41.353846-41.353846c-11.815385-11.815385-29.538462-11.815385-41.353846 0l-110.276923 110.276923c-11.815385 11.815385-33.476923 3.938462-33.476923-13.784615V68.923077C571.076923 53.169231 555.323077 39.384615 541.538462 39.384615h-59.076924c-15.753846 0-29.538462 13.784615-29.538461 29.538462v417.476923c0 17.723077-21.661538 25.6-33.476923 13.784615l-110.276923-110.276923c-11.815385-11.815385-29.538462-11.815385-41.353846 0L226.461538 433.230769c-11.815385 11.815385-11.815385 29.538462 0 41.353846L492.307692 740.430769z" />
Logo="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
<local:MyExtraButton x:Name="BtnExtraApril" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="投降" Visibility="Collapsed"
Logo="M124.96 32c-28.64 0-60.064 23.2-60.064 51.904v856.192c0 28.576 30.688 51.904 59.296 51.904s60.064-23.328 60.064-51.904V83.904C184.256 55.2 153.536 32 124.96 32z m616.352 71.264c-168.416 0-168.416-69.024-336.8-69.024-97.216 0-172.256 45.344-172.256 45.344l-0.736 516.736s75.776-45.28 172.96-45.28c168.416 0 168.416 69.024 336.8 69.024 105.344 0 211.168-55.328 211.168-55.328V48.064c0.032 0-105.792 55.2-211.136 55.2z m0 0" />
<local:MyExtraButton x:Name="BtnExtraShutdown" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="关闭 Minecraft" Visibility="Collapsed"
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -577,10 +577,10 @@ Public Module ModAnimation
Public Class AniEaseLinear
Inherits AniEase
Public Overrides Function GetValue(t As Double) As Double
Return MathRange(t, 0, 1)
Return MathClamp(t, 0, 1)
End Function
Public Overrides Function GetDelta(t1 As Double, t0 As Double) As Double
Return MathRange(t1, 0, 1) - MathRange(t0, 0, 1)
Return MathClamp(t1, 0, 1) - MathClamp(t0, 0, 1)
End Function
End Class
@@ -595,7 +595,7 @@ Public Module ModAnimation
p = Power
End Sub
Public Overrides Function GetValue(t As Double) As Double
Return MathRange(t, 0, 1) ^ p
Return MathClamp(t, 0, 1) ^ p
End Function
End Class
''' <summary>
@@ -608,7 +608,7 @@ Public Module ModAnimation
p = Power
End Sub
Public Overrides Function GetValue(t As Double) As Double
Return 1 - MathRange(1 - t, 0, 1) ^ p
Return 1 - MathClamp(1 - t, 0, 1) ^ p
End Function
End Class
''' <summary>
@@ -636,7 +636,7 @@ Public Module ModAnimation
p = 3 - Power * 0.5
End Sub
Public Overrides Function GetValue(t As Double) As Double
t = MathRange(t, 0, 1)
t = MathClamp(t, 0, 1)
Return t ^ p * Math.Cos(1.5 * Math.PI * (1 - t))
End Function
End Class
@@ -650,7 +650,7 @@ Public Module ModAnimation
p = 3 - Power * 0.5
End Sub
Public Overrides Function GetValue(t As Double) As Double
t = MathRange(t, 0, 1)
t = MathClamp(t, 0, 1)
Return 1 - (1 - t) ^ p * Math.Cos(1.5 * Math.PI * t)
End Function
End Class
@@ -694,7 +694,7 @@ Public Module ModAnimation
p = Power + 4
End Sub
Public Overrides Function GetValue(t As Double) As Double
t = MathRange(t, 0, 1)
t = MathClamp(t, 0, 1)
Return t ^ ((p - 1) * 0.25) * Math.Cos((p - 3.5) * Math.PI * (1 - t) ^ 1.5)
End Function
End Class
@@ -708,7 +708,7 @@ Public Module ModAnimation
p = Power + 4
End Sub
Public Overrides Function GetValue(t As Double) As Double
t = 1 - MathRange(t, 0, 1)
t = 1 - MathClamp(t, 0, 1)
Return 1 - t ^ ((p - 1) * 0.25) * Math.Cos((p - 3.5) * Math.PI * (1 - t) ^ 1.5)
End Function
End Class
@@ -766,7 +766,7 @@ Public Module ModAnimation
''' <summary>
''' 开始动画执行。
''' </summary>
Public Sub AniStartRun()
Public Sub AniStart()
'初始化计时器
AniLastTick = GetTimeTick()
AniFPSTimer = AniLastTick
@@ -777,12 +777,12 @@ Public Module ModAnimation
Log("[Animation] 动画线程开始")
Do While True
'两帧之间的间隔时间
Dim DeltaTime As Long = MathRange(GetTimeTick() - AniLastTick, 0, 100000)
Dim DeltaTime As Long = MathClamp(GetTimeTick() - AniLastTick, 0, 100000)
If DeltaTime < 3 Then GoTo Sleeper
AniLastTick = GetTimeTick()
'记录 FPS
If ModeDebug Then
If MathRange(AniLastTick - AniFPSTimer, 0, 100000) >= 500 Then
If MathClamp(AniLastTick - AniFPSTimer, 0, 100000) >= 500 Then
AniFPS = AniFPSCounter
AniFPSCounter = 0
AniFPSTimer = AniLastTick
@@ -869,7 +869,7 @@ NextAni:
Loop
'如果当前动画组都执行完毕则删除
If Entry.Data.Count = 0 Then
If Not Entry.Data.Any() Then
'为了避免新添加的动画影响顺序,不能 RemoveAt(i)
'为了允许动画在执行中添加同名动画组,不能按名字移除
For Current = 0 To AniGroups.Count - 1
@@ -904,7 +904,7 @@ NextAni:
Case AniTypeSub.Y
DeltaTop(Ani.Obj, Delta)
Case AniTypeSub.Opacity
Ani.Obj.Opacity = MathRange(Ani.Obj.Opacity + Delta, 0, 1)
Ani.Obj.Opacity = MathClamp(Ani.Obj.Opacity + Delta, 0, 1)
Case AniTypeSub.Width
Dim Obj As FrameworkElement = Ani.Obj
Obj.Width = Math.Max(If(Double.IsNaN(Obj.Width), Obj.ActualWidth, Obj.Width) + Delta, 0)
File diff suppressed because it is too large. Load diff
@@ -153,10 +153,14 @@
End Select
End Get
Set(value As Double)
If _Progress = value Then Exit Property
Dim OldValue = _Progress
_Progress = value
RaiseEvent ProgressChanged(value, OldValue)
End Set
End Property
Private _Progress As Double = -1
Public Event ProgressChanged(NewProgress As Double, OldProgress As Double) Implements ILoadingTrigger.ProgressChanged
''' <summary>
''' 计算总进度时的权重。它应该为预计时间(秒)。
''' </summary>
@@ -236,10 +240,16 @@
''' </summary>
Public ReadOnly Property IsAborted As Boolean
Get
Return LastRunningThread Is Nothing OrElse Not ReferenceEquals(Thread.CurrentThread, LastRunningThread)
Return IsAbortedWithThread(Thread.CurrentThread)
End Get
End Property
''' <summary>
''' 当前执行线程是否应当中断。需要手动提供加载器线程,用于需要跨线程检查的情况。
''' </summary>
Public Function IsAbortedWithThread(Thread As Thread) As Boolean
Return LastRunningThread Is Nothing OrElse Not ReferenceEquals(Thread, LastRunningThread) OrElse State = LoadState.Aborted
End Function
''' <summary>
''' 在输入相同时使用原有结果的超时,单位为毫秒。
''' </summary>
Public ReloadTimeout As Integer = -1
@@ -435,10 +445,6 @@
For Each Loader In Loaders
Loader.Abort()
Next
'从列表删除
SyncLock LoaderTaskbarLock
If LoaderTaskbar.Contains(Me) Then LoaderTaskbar.Remove(Me)
End SyncLock
End Sub)
End Sub
@@ -484,7 +490,7 @@
Select Case Loader.State
Case LoadState.Finished
'检查是否需要重启
If Loader.GetType.Name.StartsWith("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith
If Loader.GetType.Name.StartsWithF("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith
If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then
If ModeDebug Then Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name)
GoTo Restart
@@ -494,7 +500,7 @@
End If
Case LoadState.Loading
'检查是否需要重启
If Loader.GetType.Name.StartsWith("LoaderTask") Then
If Loader.GetType.Name.StartsWithF("LoaderTask") Then
If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then
If ModeDebug Then Log("[Loader] 由于输入条件变更,重启进行中的加载器 " & Loader.Name, LogLevel.Developer)
GoTo Restart
@@ -511,9 +517,9 @@ Restart:
If Input IsNot Nothing Then
'若输入类型与下一个加载器相同才继续
Dim LoaderType As String = Loader.GetType.Name
If LoaderType.StartsWith("LoaderTask") OrElse LoaderType.StartsWith("LoaderCombo") Then
If LoaderType.StartsWithF("LoaderTask") OrElse LoaderType.StartsWithF("LoaderCombo") Then
Loader.Start(If(Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IsForceRestarting)
ElseIf LoaderType.StartsWith("LoaderDownload") Then
ElseIf LoaderType.StartsWithF("LoaderDownload") Then
Loader.Start(If(TypeOf Input Is List(Of NetFile), Input, Nothing), IsForceRestarting)
Else
Throw New Exception("未知的加载器类型(" & LoaderType & ")")
@@ -539,7 +545,7 @@ Restart:
Public Shared Sub GetLoaderList(Loader As Object, ByRef List As List(Of LoaderBase), Optional RequireShow As Boolean = True)
For Each SubLoader In Loader.Loaders
If SubLoader.Show OrElse Not RequireShow Then List.Add(SubLoader)
If SubLoader.GetType.Name.StartsWith("LoaderCombo") Then GetLoaderList(SubLoader, List)
If SubLoader.GetType.Name.StartsWithF("LoaderCombo") Then GetLoaderList(SubLoader, List)
Next
End Sub
''' <summary>
@@ -565,10 +571,11 @@ Restart:
Public LoaderTaskbarProgress As Double = 0 '平滑后的进度
Private LoaderTaskbarProgressLast As Shell.TaskbarItemProgressState = Shell.TaskbarItemProgressState.None
Public Sub LoaderTaskbarAdd(Loader As LoaderBase)
Public Sub LoaderTaskbarAdd(Of T)(Loader As LoaderCombo(Of T))
If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRemove(Loader)
SyncLock LoaderTaskbarLock
LoaderTaskbar.Add(Loader)
Log($"[Taskbar] {Loader.Name} 已加入任务列表")
End SyncLock
End Sub
Public Sub LoaderTaskbarProgressRefresh()
@@ -580,19 +587,16 @@ Restart:
'外显任务是否已经全部完成
Dim IsAllDownloadTaskCompleted As Boolean = True
For Each Loader In LoaderTaskbar
If Loader.Show AndAlso Loader.State = LoadState.Loading Then IsAllDownloadTaskCompleted = False
If Loader.State = LoadState.Loading Then IsAllDownloadTaskCompleted = False
Next
'若单个任务已中止或全部任务已完成,则刷新并移除
Dim RemovedTask As New List(Of LoaderBase)
For i = 0 To LoaderTaskbar.Count - 1
If (IsAllDownloadTaskCompleted OrElse LoaderTaskbar(i).State = LoadState.Aborted) AndAlso LoaderTaskbar(i).Show Then
If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRefresh(LoaderTaskbar(i))
RemovedTask.Add(LoaderTaskbar(i))
For Each Task In LoaderTaskbar.ToList()
If IsAllDownloadTaskCompleted OrElse Task.State = LoadState.Aborted OrElse Task.State = LoadState.Waiting Then
If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRefresh(Task)
LoaderTaskbar.Remove(Task)
Log($"[Taskbar] {Task.Name} 已移出任务列表")
End If
Next
For Each Task In RemovedTask
LoaderTaskbar.Remove(Task)
Next
End SyncLock
'更新平滑后的进度
If NewProgress <= 0 OrElse NewProgress >= 1 OrElse LoaderTaskbarProgress > NewProgress Then
@@ -600,8 +604,9 @@ Restart:
Else
LoaderTaskbarProgress = LoaderTaskbarProgress * 0.9 + NewProgress * 0.1
End If
RunInUi(Sub() FrmMain.BtnExtraDownload.Progress = LoaderTaskbarProgress)
'更新任务栏信息
If LoaderTaskbar.Count = 0 OrElse LoaderTaskbarProgress = 1 Then
If Not LoaderTaskbar.Any() OrElse LoaderTaskbarProgress = 1 Then
NewState = Shell.TaskbarItemProgressState.None
ElseIf LoaderTaskbarProgress < 0.015 Then
NewState = Shell.TaskbarItemProgressState.Indeterminate
@@ -622,13 +627,13 @@ Restart:
Try
Dim Total As Double = 0, Count As Integer = 0
SyncLock LoaderTaskbarLock
For i = 0 To LoaderTaskbar.Count - 1
Total += LoaderTaskbar(i).Progress
For Each Task In LoaderTaskbar.ToList
Total += Task.Progress
Count += 1 '避免多线程影响导致计数出错
Next
End SyncLock
If Count = 0 Then Return 1
Return MathRange(Total / Count, 0, 1)
Return MathClamp(Total / Count, 0, 1)
Catch ex As Exception
Log(ex, "获取任务栏进度出错", LogLevel.Feedback)
Return 0.5
@@ -677,7 +682,7 @@ Restart:
Log(ex, "文件夹加载器启动检测出错")
End Try
'写入检查数据
DictionaryAdd(LoaderFolderDictionary, Loader, Value)
LoaderFolderDictionary(Loader) = Value
'开始检查
If Type = LoaderFolderRunType.UpdateOnly Then Return False
If WaitForExit Then
File diff suppressed because it is too large. Load diff
@@ -15,6 +15,8 @@ End Class
''' </summary>
Public Class ValidateNullable
Inherits Validate
Public Sub New()
End Sub
Public Overrides Function Validate(Str As String) As String
If IsNothing(Str) OrElse String.IsNullOrEmpty(Str) Then Return Nothing
Return ""
@@ -26,6 +28,8 @@ End Class
''' </summary>
Public Class ValidateNullOrEmpty
Inherits Validate
Public Sub New()
End Sub
Public Overrides Function Validate(Str As String) As String
If IsNothing(Str) OrElse String.IsNullOrEmpty(Str) Then Return "输入内容不能为空!"
Return ""
@@ -37,6 +41,8 @@ End Class
''' </summary>
Public Class ValidateNullOrWhiteSpace
Inherits Validate
Public Sub New()
End Sub
Public Overrides Function Validate(Str As String) As String
If IsNothing(Str) OrElse String.IsNullOrWhiteSpace(Str) Then Return "输入内容不能为空!"
Return ""
@@ -70,7 +76,7 @@ Public Class ValidateHttp
Public Sub New()
End Sub '用于 XAML 初始化
Public Overrides Function Validate(Str As String) As String
If Str.EndsWith("/") Then Str = Str.Substring(0, Str.Length - 1)
If Str.EndsWithF("/") Then Str = Str.Substring(0, Str.Length - 1)
If Not RegexCheck(Str, "^(http[s]?)\://") Then Return "输入的网址无效!"
Return ""
End Function
@@ -143,7 +149,7 @@ Public Class ValidateExcept
End Sub
Public Overrides Function Validate(Str As String) As String
For Each Ch As String In Excepts
If Str.IndexOf(Ch, StringComparison.OrdinalIgnoreCase) >= 0 Then
If Str.IndexOfF(Ch, StringComparison.OrdinalIgnoreCase) >= 0 Then
If IsNothing(ErrorMessage) Then ErrorMessage = ""
Return ErrorMessage.Replace("%", Ch)
End If
@@ -161,6 +167,8 @@ Public Class ValidateExceptSame
Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
Public Property ErrorMessage As String
Public Property IgnoreCase As Boolean = False
Public Sub New()
End Sub
Public Sub New(Excepts As ObjectModel.Collection(Of String), Optional ErrorMessage As String = "输入内容不能为 %!", Optional IgnoreCase As Boolean = False)
Me.Excepts = Excepts
Me.ErrorMessage = ErrorMessage
@@ -197,6 +205,8 @@ Public Class ValidateFolderName
Public Property UseMinecraftCharCheck As Boolean = True
Public Property IgnoreCase As Boolean = True
Private ReadOnly PathIgnore As IEnumerable(Of DirectoryInfo)
Public Sub New()
End Sub
Public Sub New(Path As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True)
Me.Path = Path
Me.IgnoreCase = IgnoreCase
@@ -210,18 +220,18 @@ Public Class ValidateFolderName
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
'检查空格
If Str.StartsWith(" ") Then Return "文件夹名不能以空格开头!"
If Str.EndsWith(" ") Then Return "文件夹名不能以空格结尾!"
If Str.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
If Str.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
'检查长度
LengthCheck = New ValidateLength(1, 100).Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
'检查尾部小数点
If Str.EndsWith(".") Then Return "文件夹名不能以小数点结尾!"
If Str.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
'检查特殊字符
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件夹名不可包含 % 字符!").Validate(Str)
If Not CharactCheck = "" Then Return CharactCheck
'检查特殊字符串
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(Str)
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!", True).Validate(Str)
If Not InvalidStrCheck = "" Then Return InvalidStrCheck
'检查文件夹重名
Dim Arr As New List(Of String)
@@ -240,6 +250,61 @@ Public Class ValidateFolderName
End Function
End Class
''' <summary>
''' 对文件名的粗略的特化检测。
''' </summary>
Public Class ValidateFileName
Inherits Validate
Public Property Name As String
Public Property UseMinecraftCharCheck As Boolean = True
Public Property IgnoreCase As Boolean = True
Public Property ParentFolder As String = Nothing
Public Property RequireParentFolderExists = True
Public Sub New()
End Sub
Public Sub New(Name As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True)
Me.Name = Name
Me.IgnoreCase = IgnoreCase
Me.UseMinecraftCharCheck = UseMinecraftCharCheck
End Sub
Public Overrides Function Validate(Str As String) As String
Try
'检查是否为空
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
'检查空格
If Str.StartsWithF(" ") Then Return "文件名不能以空格开头!"
If Str.EndsWithF(" ") Then Return "文件名不能以空格结尾!"
'检查长度
LengthCheck = New ValidateLength(1, 253).Validate(Str & If(ParentFolder, ""))
If Not LengthCheck = "" Then Return LengthCheck
'检查尾部小数点
If Str.EndsWithF(".") Then Return "文件名不能以小数点结尾!"
'检查特殊字符
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件名不可包含 % 字符!").Validate(Str)
If Not CharactCheck = "" Then Return CharactCheck
'检查特殊字符串
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件名不可为 %!", True).Validate(Str)
If Not InvalidStrCheck = "" Then Return InvalidStrCheck
'检查文件重名
If ParentFolder IsNot Nothing Then
Dim DirInfo As New DirectoryInfo(ParentFolder)
If DirInfo.Exists Then
Dim SameNameCheck = New ValidateExceptSame(DirInfo.EnumerateFiles("*").Select(Function(f) f.Name),
"不可与现有文件重名!", IgnoreCase).Validate(Str)
If Not SameNameCheck = "" Then Return SameNameCheck
Else
If RequireParentFolderExists Then Return $"父文件夹不存在:{ParentFolder}"
End If
End If
Return ""
Catch ex As Exception
Log(ex, "检查文件名出错")
Return "错误:" & ex.Message
End Try
End Function
End Class
''' <summary>
''' 要求输入一个可用的文件夹路径。
''' </summary>
@@ -254,7 +319,7 @@ Public Class ValidateFolderPath
Public Overrides Function Validate(Str As String) As String
'去除尾部斜线,统一为 \
Str = Str.Replace("/", "\")
If Not Str.TrimEnd("\").EndsWith(":") Then Str = Str.TrimEnd("\")
If Not Str.TrimEnd("\").EndsWithF(":") Then Str = Str.TrimEnd("\")
'检查是否为空
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
@@ -262,15 +327,15 @@ Public Class ValidateFolderPath
LengthCheck = New ValidateLength(1, 254).Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
'检查开头
If Str.StartsWith("\\Mac\") Then GoTo Fin
If Str.StartsWithF("\\Mac\") Then GoTo Fin
For Each Drive As DriveInfo In My.Computer.FileSystem.Drives
If Str.ToUpper = Drive.Name Then Return ""
If Str.ToUpper.StartsWith(Drive.Name) Then GoTo Fin
If Str.StartsWithF(Drive.Name, True) Then GoTo Fin
Next
Return "文件夹路径头存在错误!"
Fin:
'对首层以外的路径检查
For i = If(Str.StartsWith("\\Mac\"), 2, 1) To Str.Split("\").Count - 1
For i = If(Str.StartsWithF("\\Mac\"), 2, 1) To Str.Split("\").Count - 1
Dim SubStr As String = Str.Split("\")(i)
'检查是否为空
Dim SubLengthCheck As String = New ValidateNullOrWhiteSpace().Validate(SubStr)
@@ -279,10 +344,10 @@ Fin:
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "路径中存在无效字符!").Validate(SubStr)
If Not CharactCheck = "" Then Return CharactCheck
'检查头部空格
If SubStr.StartsWith(" ") Then Return "文件夹名不能以空格开头!"
If SubStr.EndsWith(" ") Then Return "文件夹名不能以空格结尾!"
If SubStr.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
If SubStr.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
'检查尾部小数点
If SubStr.EndsWith(".") Then Return "文件夹名不能以小数点结尾!"
If SubStr.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
'检查特殊字符串
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(SubStr)
If Not InvalidStrCheck = "" Then Return InvalidStrCheck
+22 -37
View File
@@ -1,5 +1,7 @@
'一个万能的自动图片类型转换工具类
Imports System.Drawing.Imaging
Public Class MyBitmap
''' <summary>
@@ -26,10 +28,10 @@ Public Class MyBitmap
Public Shared Widening Operator CType(Image As MyBitmap) As ImageSource
Dim Bitmap = Image.Pic
Dim rect = New System.Drawing.Rectangle(0, 0, Bitmap.Width, Bitmap.Height)
Dim bitmapData = Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
Dim bitmapData = Bitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
Try
Dim size = rect.Width * rect.Height * 4
Return BitmapSource.Create(Bitmap.Width, Bitmap.Height, DPI, DPI, PixelFormats.Bgra32, Nothing, bitmapData.Scan0, size, bitmapData.Stride)
Return BitmapSource.Create(Bitmap.Width, Bitmap.Height, Bitmap.HorizontalResolution, Bitmap.VerticalResolution, PixelFormats.Bgra32, Nothing, bitmapData.Scan0, size, bitmapData.Stride)
Finally
Bitmap.UnlockBits(bitmapData)
End Try
@@ -52,7 +54,8 @@ Public Class MyBitmap
End Sub
Public Sub New(FilePathOrResourceName As String)
Try
If FilePathOrResourceName.StartsWith(PathImage) Then
FilePathOrResourceName = FilePathOrResourceName.Replace("pack://application:,,,/images/", PathImage)
If FilePathOrResourceName.StartsWithF(PathImage) Then
'使用缓存
If BitmapCache.ContainsKey(FilePathOrResourceName) Then
Pic = BitmapCache(FilePathOrResourceName).Pic
@@ -71,10 +74,10 @@ Public Class MyBitmap
Pic = My.Application.TryFindResource(FilePathOrResourceName)
If Pic Is Nothing Then
Pic = New System.Drawing.Bitmap(1, 1)
Log(ex, "加载位图失败(" & FilePathOrResourceName & ")")
Log(ex, $"加载位图失败({FilePathOrResourceName})")
Throw
Else
Log(ex, "指定类型有误的位图加载(" & FilePathOrResourceName & ")", LogLevel.Developer)
Log(ex, $"指定类型有误的位图加载({FilePathOrResourceName})", LogLevel.Developer)
Exit Try
End If
End Try
@@ -102,45 +105,27 @@ Public Class MyBitmap
End Using
End Sub
''' <summary>
''' 获取旋转的图片,这个方法不会导致原对象改变且会返回一个新的对象。图片长宽必须相等。
''' </summary>
''' <param name="angle">旋转角度(单位为角度)。</param>
Public Function Rotation(angle As Double) As System.Drawing.Bitmap
With Me
Dim img As System.Drawing.Image = Me.Pic
Dim bitSize As Single = img.Width
Dim bmp As New System.Drawing.Bitmap(CInt(bitSize), CInt(bitSize))
Using g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp)
g.TranslateTransform(bitSize / 2, bitSize / 2)
g.RotateTransform(angle)
g.TranslateTransform(-bitSize / 2, -bitSize / 2)
g.DrawImage(img, New System.Drawing.Rectangle(0, 0, img.Width, img.Width))
End Using
Return bmp
End With
End Function
''' <summary>
''' 获取裁切的图片,这个方法不会导致原对象改变且会返回一个新的对象。
''' </summary>
Public Function Clip(rect As System.Drawing.Rectangle) As System.Drawing.Bitmap
With Me
Dim img As System.Drawing.Image = Pic
Dim bmp As New System.Drawing.Bitmap(rect.Width, rect.Height)
Using g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp)
g.DrawImageUnscaled(img, rect)
End Using
Return bmp
End With
Public Function Clip(X As Integer, Y As Integer, Width As Integer, Height As Integer) As MyBitmap
Dim bmp As New System.Drawing.Bitmap(Width, Height, Pic.PixelFormat)
bmp.SetResolution(Pic.HorizontalResolution, Pic.VerticalResolution)
Using g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp)
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor
g.TranslateTransform(-X, -Y)
g.DrawImage(Pic, New System.Drawing.Rectangle(0, 0, Pic.Width, Pic.Height))
End Using
Return bmp
End Function
''' <summary>
''' 获取左右翻转的图片,这个方法不会导致原对象改变。
''' 获取旋转或翻转后的图片,这个方法不会导致原对象改变且会返回一个新的对象。
''' </summary>
Public Function LeftRightFilp() As System.Drawing.Bitmap
Public Function RotateFlip(Type As System.Drawing.RotateFlipType) As MyBitmap
Dim bmp As New System.Drawing.Bitmap(Pic)
bmp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX)
bmp.SetResolution(Pic.HorizontalResolution, Pic.VerticalResolution)
bmp.RotateFlip(Type)
Return bmp
End Function
@@ -150,7 +135,7 @@ Public Class MyBitmap
Public Sub Save(FilePath As String)
Dim encoder As BitmapEncoder = New PngBitmapEncoder()
encoder.Frames.Add(BitmapFrame.Create(Me))
Using fileStream = New System.IO.FileStream(FilePath, FileMode.Create)
Using fileStream As New FileStream(FilePath, FileMode.Create)
encoder.Save(fileStream)
End Using
End Sub
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,765 @@
Public Module ModJava
Public JavaListCacheVersion As Integer = 5
''' <summary>
''' 目前所有可用的 Java。
''' </summary>
Public JavaList As New List(Of JavaEntry)
Public Class JavaEntry
'路径
''' <summary>
''' Java.exe 文件的完整路径。
''' </summary>
Public ReadOnly Property PathJava As String
Get
Return PathFolder & "java.exe"
End Get
End Property
''' <summary>
''' Javaw.exe 文件的完整路径。
''' </summary>
Public ReadOnly Property PathJavaw As String
Get
Return PathFolder & "javaw.exe"
End Get
End Property
''' <summary>
''' Javaw.exe 文件所在文件夹的路径,以 \ 结尾。
''' </summary>
Public PathFolder As String
''' <summary>
''' 是否为用户手动导入的 Java。
''' </summary>
Public IsUserImport As Boolean
'版本信息
''' <summary>
''' Java 的详细版本。若不足 4 位会在前方补 1,例如 1.16.0.1。
''' 其大版本号为 Minor。
''' </summary>
Public Version As Version
''' <summary>
''' Java 的大版本号。
''' </summary>
Public ReadOnly Property VersionCode As Integer
Get
Return Version.Minor
End Get
End Property
''' <summary>
''' 是否为 Java Runtime Environment。
''' </summary>
Public IsJre As Boolean
''' <summary>
''' 是否为 64 位 Java。
''' </summary>
Public Is64Bit As Boolean
''' <summary>
''' 是否已设置环境变量。
''' </summary>
Public ReadOnly Property HasEnvironment As Boolean
Get
If PathFolder Is Nothing OrElse PathEnv Is Nothing Then Return False
Return PathEnv.Replace("\", "").Replace("/", "").ContainsF(PathFolder.Replace("\", ""), True)
End Get
End Property
'序列化
Public Function ToJson() As JObject
Return New JObject({New JProperty("Path", PathFolder), New JProperty("VersionString", Version.ToString), New JProperty("IsJre", IsJre), New JProperty("Is64Bit", Is64Bit), New JProperty("IsUserImport", IsUserImport)})
End Function
Public Shared Function FromJson(Data As JObject) As JavaEntry
Return New JavaEntry(Data("Path"), Data("IsUserImport")) With {.Version = New Version(Data("VersionString")), .IsJre = Data("IsJre"), .Is64Bit = Data("Is64Bit")}
End Function
''' <summary>
''' 转化为用户友好的字符串输出。
''' </summary>
Public Overrides Function ToString() As String
Dim VersionString = Version.ToString
If VersionString.StartsWithF("1.") Then VersionString = Mid(VersionString, 3)
Return If(IsJre, "JRE ", "JDK ") & VersionCode & " (" & VersionString & ")" & If(Is64Bit, "", ",32 位") & If(IsUserImport, ",手动导入", "") & ":" & PathFolder
End Function
'构造
''' <summary>
''' 输入 javaw.exe 文件所在文件夹的路径,不限制结尾。
''' </summary>
Public Sub New(Folder As String, IsUserImport As Boolean)
If Not Folder.EndsWithF("\") Then Folder += "\"
PathFolder = Folder.Replace("/", "\")
Me.IsUserImport = IsUserImport
End Sub
'方法
Private IsChecked As Boolean = False
''' <summary>
''' 检查并获取 Java 详细信息。在 Java 存在异常时抛出错误。
''' </summary>
Public Sub Check()
If IsChecked Then Exit Sub
Dim Output As String = Nothing
Try
'确定文件存在
If Not File.Exists(PathJavaw) Then
Throw New FileNotFoundException("未找到 javaw.exe 文件", PathJavaw)
End If
If Not File.Exists(PathFolder & "java.exe") Then
Throw New FileNotFoundException("未找到 java.exe 文件", PathFolder & "java.exe")
End If
IsJre = Not File.Exists(PathFolder & "javac.exe")
'运行 -version
Output = ShellAndGetOutput(PathFolder & "java.exe", "-version", 15000).ToLower
If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败")
If ModeDebug Then Log("[Java] Java 检查输出:" & PathFolder & "java.exe" & vbCrLf & Output)
If Output.Contains("/lib/ext exists") Then Throw New ApplicationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试")
'获取详细信息
Dim VersionString = If(RegexSeek(Output, "(?<=version "")[^""]+"), If(RegexSeek(Output, "(?<=openjdk )[0-9]+"), "")).Replace("_", ".").Split("-").First
If VersionString.Split(".").Count > 4 Then VersionString = VersionString.Replace(".0.", ".") '#3493,VersionString = "21.0.2.0.2"
Do While VersionString.Split(".").Count < 4
If VersionString.StartsWithF("1.") Then
VersionString = VersionString & ".0"
Else
VersionString = "1." & VersionString
End If
Loop
If VersionString = "" Then Throw New ApplicationException($"未找到该 Java 的版本号{If(Output.Length < 500, $"{vbCrLf}输出为:{vbCrLf}{Output}", "")}")
Version = New Version(VersionString)
If Version.Minor = 0 Then
Log("[Java] 疑似 X.0.X.X 格式版本号:" & Version.ToString)
Version = New Version(1, Version.Major, Version.Build, Version.Revision)
End If
Is64Bit = Output.Contains("64-bit")
If Version.Minor <= 4 OrElse Version.Minor >= 25 Then Throw New Exception("分析详细信息失败,获取的版本为 " & Version.ToString)
'基于 #2249 发现 JRE 17 似乎也导致了 Forge 安装失败,干脆禁用更多版本的 JRE
If IsJre AndAlso VersionCode >= 16 Then Throw New Exception("由于高版本 JRE 对游戏的兼容性很差,因此不再允许使用。你可以使用对应版本的 JDK,而非 JRE!")
Catch ex As ApplicationException
Throw ex
Catch ex As ThreadInterruptedException
Throw ex
Catch ex As Exception
Log("[Java] 检查失败的 Java 输出:" & PathFolder & "java.exe" & vbCrLf & If(Output, "无程序输出"))
Throw New Exception("检查 Java 失败(" & If(PathJavaw, "Nothing") & ")", ex)
End Try
IsChecked = True
End Sub
End Class
''' <summary>
''' Path 环境变量。
''' </summary>
Private ReadOnly Property PathEnv As String
Get
If _PathEnv Is Nothing Then _PathEnv = If(Environment.GetEnvironmentVariable("Path"), "")
Return _PathEnv
End Get
End Property
Private _PathEnv As String = Nothing
''' <summary>
''' JAVA_HOME 环境变量。
''' </summary>
Private ReadOnly Property PathJavaHome As String
Get
If _PathJavaHome Is Nothing Then _PathJavaHome = If(Environment.GetEnvironmentVariable("JAVA_HOME"), "")
Return _PathJavaHome
End Get
End Property
Private _PathJavaHome As String = Nothing
''' <summary>
''' 初始化 Java 列表,但除非没有 Java,否则不进行检查。
''' </summary>
Public Sub JavaListInit()
JavaList = New List(Of JavaEntry)
Try
If Setup.Get("CacheJavaListVersion") < JavaListCacheVersion Then
'不使用缓存
Log("[Java] 要求 Java 列表缓存更新")
Setup.Set("CacheJavaListVersion", JavaListCacheVersion)
Else
'使用缓存
For Each JsonEntry In GetJson(Setup.Get("LaunchArgumentJavaAll"))
JavaList.Add(JavaEntry.FromJson(JsonEntry))
Next
End If
If Not JavaList.Any() Then
Log("[Java] 初始化未找到可用的 Java,将自动触发搜索", LogLevel.Developer)
JavaSearchLoader.Start(0)
Else
Log("[Java] 缓存中有 " & JavaList.Count & " 个可用的 Java:")
JavaList.ForEach(Sub(j) Log($"[Java] - {j}"))
End If
Catch ex As Exception
Log(ex, "初始化 Java 列表失败", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaAll", "[]")
End Try
End Sub
''' <summary>
''' 根据要求返回最适合的 Java,若找不到则返回 Nothing。
''' 最小与最大版本在与输入相同时也会通过。
''' 必须在工作线程调用。
''' </summary>
Public Function JavaSelect(CancelException As String, Optional MinVersion As Version = Nothing, Optional MaxVersion As Version = Nothing,
Optional RelatedVersion As McVersion = Nothing) As JavaEntry
Try
Dim AllowedJavaList As New List(Of JavaEntry)
'添加特定的 Java
Dim JavaPreList As New Dictionary(Of String, Boolean)
If PathMcFolder.Split("\").Count > 3 Then
JavaSearchFolder(GetPathFromFullPath(PathMcFolder), JavaPreList, False, True) 'Minecraft 文件夹的父文件夹(如果不是根目录的话)
End If
JavaSearchFolder(PathMcFolder, JavaPreList, False, True) 'Minecraft 文件夹
If RelatedVersion IsNot Nothing Then JavaSearchFolder(RelatedVersion.Path, JavaPreList, False, True) '所选版本文件夹
Dim TargetJavaList As New List(Of JavaEntry)
For Each Entry In JavaPreList
TargetJavaList.Add(New JavaEntry(Entry.Key, Entry.Value))
Next
'检查特定的 Java
If TargetJavaList.Any Then
TargetJavaList = JavaCheckList(TargetJavaList)
Log("[Java] 检查后找到 " & TargetJavaList.Count & " 个特定路径下的 Java:")
For Each Java In TargetJavaList
Log($"[Java] - {Java}")
Next
End If
#Region "添加用户指定的 Java,储存到 UserJava 中"
Dim UserJava As JavaEntry = Nothing
'获取版本独立设置中指定的 Java
If RelatedVersion IsNot Nothing AndAlso Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion).ToString.StartsWithF("{") Then
Try
UserJava = JavaEntry.FromJson(GetJson(Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion)))
UserJava.Check()
Catch ex As ThreadInterruptedException
Throw
Catch ex As Exception
UserJava = Nothing
Setup.Reset("VersionArgumentJavaSelect", Version:=RelatedVersion)
Log(ex, "版本独立设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint)
End Try
End If
'获取全局设置中指定的 Java
If UserJava Is Nothing AndAlso Setup.Get("LaunchArgumentJavaSelect") <> "" Then
Try
UserJava = JavaEntry.FromJson(GetJson(Setup.Get("LaunchArgumentJavaSelect")))
UserJava.Check()
Catch ex As ThreadInterruptedException
Throw
Catch ex As Exception
UserJava = Nothing
Setup.Reset("LaunchArgumentJavaSelect")
Log(ex, "全局设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint)
End Try
End If
'添加到特定 Java 列表
If UserJava IsNot Nothing Then
Log($"[Java] 用户指定的 Java:{UserJava}")
TargetJavaList.Add(UserJava)
End If
#End Region
RetryGet:
'等待进行中的搜索结束
If JavaSearchLoader.State <> LoadState.Finished AndAlso JavaSearchLoader.State <> LoadState.Waiting Then JavaSearchLoader.WaitForExit()
Select Case JavaSearchLoader.State
Case LoadState.Failed
Throw JavaSearchLoader.Error
Case LoadState.Aborted
Throw New ThreadInterruptedException("Java 搜索加载器已中断")
End Select
'生成完整的 Java 列表
Dim AllJavaList As New List(Of JavaEntry)
AllJavaList.AddRange(TargetJavaList)
AllJavaList.AddRange(JavaList)
'根据选定条件进行过滤
For Each Java In AllJavaList
If MinVersion IsNot Nothing AndAlso Java.Version < MinVersion Then Continue For
If MaxVersion IsNot Nothing AndAlso Java.Version > MaxVersion Then Continue For
If Java.Is64Bit AndAlso Is32BitSystem Then Continue For
AllowedJavaList.Add(Java)
Next
'若未找到适合的 Java,尝试触发搜索
If Not AllowedJavaList.Any() AndAlso JavaSearchLoader.State = LoadState.Waiting Then
Log("[Java] 未找到满足条件的 Java,尝试进行搜索")
JavaSearchLoader.Start(IsForceRestart:=True)
GoTo RetryGet
End If
#Region "检查用户指定的 Java 是否可用"
'确保指定的 Java 可用
If UserJava Is Nothing Then GoTo ExitUserJavaCheck
If AllowedJavaList.Any(Function(j) j.PathFolder = UserJava.PathFolder) Then
Log("[Java] 使用用户指定的 Java:" & UserJava.PathFolder)
AllowedJavaList = New List(Of JavaEntry) From {UserJava}
GoTo UserPass
End If
'指定的 Java 不可用,弹窗要求选择
Log("[Java] 发现用户指定的不兼容 Java:" & UserJava.ToString)
Log($"[Java] 目前实际可用的 Java 列表:")
For Each Java In AllowedJavaList
Log($"[Java] - {Java}")
Next
Dim Requirement As String = ""
Dim ShowRevision As Boolean = False
If (MinVersion Is Nothing OrElse MinVersion.Minor = 0) AndAlso (MaxVersion IsNot Nothing AndAlso MaxVersion.Minor < 999) Then
ShowRevision = MaxVersion.MinorRevision < 999
Requirement = "最高兼容到 Java " & MaxVersion.Minor & If(ShowRevision, "." & MaxVersion.MajorRevision & "." & MaxVersion.MinorRevision, "")
ElseIf (MinVersion IsNot Nothing AndAlso MinVersion.Minor > 0) AndAlso (MaxVersion Is Nothing OrElse MaxVersion.Minor >= 999) Then
ShowRevision = MinVersion.MinorRevision > 0 OrElse MinVersion.MajorRevision > 0
Requirement = "至少需要 Java " & MinVersion.Minor & If(ShowRevision, "." & MinVersion.MajorRevision & "." & MinVersion.MinorRevision, "")
ElseIf (MinVersion IsNot Nothing AndAlso MinVersion.Minor > 0) AndAlso (MaxVersion IsNot Nothing AndAlso MaxVersion.Minor < 999) Then
ShowRevision = MinVersion.MinorRevision > 0 OrElse MinVersion.MajorRevision > 0 OrElse MaxVersion.MinorRevision < 999
Dim Left As String = MinVersion.Minor & If(ShowRevision, "." & MinVersion.MajorRevision & "." & MinVersion.MinorRevision, "")
Dim Right As String = MaxVersion.Minor & If(ShowRevision, "." & MaxVersion.MajorRevision & "." & MaxVersion.MinorRevision, "")
Requirement = "需要 Java " & If(Left = Right, Left, Left & " ~ " & Right)
End If
Dim JavaCurrent As String = UserJava.VersionCode & If(ShowRevision, "." & UserJava.Version.MajorRevision & "." & UserJava.Version.MinorRevision, "")
If Setup.Get("LaunchAdvanceJava") OrElse (RelatedVersion IsNot Nothing AndAlso Setup.Get("VersionAdvanceJava", RelatedVersion)) Then
'直接跳过弹窗
Log("[Java] 设置中指定了使用 Java " & JavaCurrent & ",但当前版本" & Requirement & ",这可能会导致游戏崩溃!", LogLevel.Debug)
AllowedJavaList = New List(Of JavaEntry) From {UserJava}
Else
Select Case MyMsgBox("你在设置中手动指定了使用 Java " & JavaCurrent & ",但当前" & Requirement & "。" & vbCrLf &
"如果强制使用该 Java,可能导致游戏崩溃。" & vbCrLf &
"你也可以将 游戏 Java 设置修改为 自动选择合适的 Java。" & vbCrLf &
vbCrLf &
" - 指定的 Java:" & UserJava.ToString,
"Java 兼容性警告", "让 PCL 自动选择", "强制使用该 Java", "取消")
Case 1 '让 PCL 自动选择
Case 2 '强制使用指定的 Java
Log("[Java] 已强制使用用户指定的不兼容 Java")
AllowedJavaList = New List(Of JavaEntry) From {UserJava}
Case 3 '取消启动
Throw New Exception(CancelException)
End Select
End If
ExitUserJavaCheck:
#End Region
'若依然未找到适合的 Java,直接返回
If Not AllowedJavaList.Any() Then Return Nothing
'优先使用特定目录下的 Java
For Each Java In AllowedJavaList
'如果在官启文件夹启动,会将官启自带 Java 错误视作 MC 文件夹指定 Java,导致了 #2054 的第二例
If Java.PathFolder.Contains(".minecraft\cache\java") Then Continue For
If TargetJavaList.Contains(Java) Then
'直接使用指定的 Java
AllowedJavaList = New List(Of JavaEntry) From {Java}
Log("[Java] 优先使用特定路径下的 Java:" & Java.ToString)
GoTo UserPass
End If
Next
UserPass:
'对适合的 Java 进行排序
AllowedJavaList = Sort(AllowedJavaList, AddressOf JavaSorter)
Log($"[Java] 排序后的 Java 优先顺序:")
For Each Java In AllowedJavaList
Log($"[Java] - {Java}")
Next
'检查选定的 Java,若测试失败则尝试进行搜索
Dim SelectedJava = AllowedJavaList.First
Try
SelectedJava.Check()
Catch ex As ThreadInterruptedException
Throw
Catch ex As Exception
If ex.InnerException IsNot Nothing AndAlso TypeOf (ex.InnerException) Is ThreadInterruptedException Then Throw ex.InnerException
Log(ex, "最终选定的 Java 已无法使用,尝试进行搜索")
AllowedJavaList = New List(Of JavaEntry)
JavaSearchLoader.Start(IsForceRestart:=True)
GoTo RetryGet
End Try
'返回
Log("[Java] 最终选定的 Java:" & AllowedJavaList.First.ToString)
Return SelectedJava
Catch ex As ThreadInterruptedException
Log(ex, "查找符合条件的 Java 时出现加载器中断")
Return Nothing
Catch ex As Exception
If ex.Message = "$$" Then Throw ex
Log(ex, "查找符合条件的 Java 失败", LogLevel.Feedback)
Return Nothing
End Try
End Function
''' <summary>
''' 是否强制指定了 64 位 Java。如果没有强制指定,返回是否安装了 64 位 Java。
''' </summary>
Public Function JavaIs64Bit(Optional RelatedVersion As McVersion = Nothing) As Boolean
Try
'检查强制指定
Dim UserSetup As String = Setup.Get("LaunchArgumentJavaSelect")
If RelatedVersion IsNot Nothing Then
Dim UserSetupVersion As String = Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion)
If UserSetupVersion <> "使用全局设置" Then UserSetup = UserSetupVersion
End If
If UserSetup <> "" Then
Dim UserJava As JavaEntry = Nothing
Try
UserJava = JavaEntry.FromJson(GetJson(UserSetup))
Catch ex As Exception
Log(ex, "版本指定的 Java 信息已损坏,已重置版本设置中指定的 Java")
Setup.Set("VersionArgumentJavaSelect", "使用全局设置", Version:=RelatedVersion)
GoTo NoUserJava
End Try
For Each Java In JavaList
If Java.PathFolder = UserJava.PathFolder Then Return UserJava.Is64Bit
Next
End If
NoUserJava:
'检查列表
For Each Java In JavaList
If Java.Is64Bit Then Return True
Next
Return False
Catch ex As Exception
Log(ex, "检查 Java 类别时出错", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaSelect", "")
Return True
End Try
End Function
''' <summary>
''' 将 Java 按照适用性排序。
''' </summary>
Public Function JavaSorter(Left As JavaEntry, Right As JavaEntry) As Boolean
'1. 尽量在当前文件夹或当前 Minecraft 文件夹
Dim ProgramPathParent As String, MinecraftPathParent As String = ""
ProgramPathParent = If(New DirectoryInfo(Path).Parent, New DirectoryInfo(Path)).FullName
If PathMcFolder <> "" Then MinecraftPathParent = If(New DirectoryInfo(PathMcFolder).Parent, New DirectoryInfo(PathMcFolder)).FullName
If Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Not Right.PathFolder.StartsWithF(ProgramPathParent) Then Return True
If Not Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Right.PathFolder.StartsWithF(ProgramPathParent) Then Return False
If PathMcFolder <> "" Then
If Left.PathFolder.StartsWithF(MinecraftPathParent) AndAlso Not Right.PathFolder.StartsWithF(MinecraftPathParent) Then Return True
If Not Left.PathFolder.StartsWithF(MinecraftPathParent) AndAlso Right.PathFolder.StartsWithF(MinecraftPathParent) Then Return False
End If
'2. 尽量使用 64 位
If Left.Is64Bit AndAlso Not Right.Is64Bit Then Return True
If Not Left.Is64Bit AndAlso Right.Is64Bit Then Return False
'3. 尽量不使用 JDK
If Left.IsJre AndAlso Not Right.IsJre Then Return True
If Not Left.IsJre AndAlso Right.IsJre Then Return False
'4. Java 大版本
If Left.VersionCode <> Right.VersionCode Then
' Java 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21...
Dim Weight = {0, 1, 2, 3, 4, 5, 6, 14, 30, 10, 12, 15, 13, 9, 8, 7, 11, 31, 29, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}
Return Weight.ElementAtOrDefault(Left.VersionCode) >= Weight.ElementAtOrDefault(Right.VersionCode)
End If
'5. 最次级版本号更接近 51
Return Math.Abs(Left.Version.Revision - 51) <= Math.Abs(Right.Version.Revision - 51)
End Function
#Region "搜索"
''' <summary>
''' 模糊搜索并获取所有可用的 Java,并在结束后更新设置页面显示。输出将直接写入 JavaList。
''' </summary>
Public JavaSearchLoader As New LoaderTask(Of Integer, Integer)("查找 Java", AddressOf JavaSearchLoaderSub) With {.ProgressWeight = 2}
Private Sub JavaSearchLoaderSub(Loader As LoaderTask(Of Integer, Integer))
If FrmSetupLaunch IsNot Nothing Then
RunInUiWait(Sub()
FrmSetupLaunch.ComboArgumentJava.Items.Clear()
FrmSetupLaunch.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True})
End Sub)
End If
If FrmVersionSetup IsNot Nothing Then
RunInUiWait(Sub()
FrmVersionSetup.ComboArgumentJava.Items.Clear()
FrmVersionSetup.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True})
End Sub)
End If
Try
'可能包含 Java 的文件夹列表,以 “\” 结尾,且仅包含 “\”
'Key:文件夹地址
'Value: 是否为玩家手动导入
Dim JavaPreList As New Dictionary(Of String, Boolean)
#Region "模糊查找可能可用的 Java"
'查找环境变量中的 Java
For Each PathInEnv As String In Split((PathEnv & ";" & PathJavaHome).Replace("\\", "\").Replace("/", "\"), ";")
PathInEnv = PathInEnv.Trim(" """.ToCharArray())
If PathInEnv = "" Then Continue For
If Not PathInEnv.EndsWithF("\") Then PathInEnv += "\"
'粗略检查有效性
If File.Exists(PathInEnv & "javaw.exe") Then JavaPreList(PathInEnv) = False
Next
'查找磁盘中的 Java
For Each Disk As DriveInfo In DriveInfo.GetDrives()
JavaSearchFolder(Disk.Name, JavaPreList, False)
Next
'查找 APPDATA 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\", JavaPreList, False)
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) & "\", JavaPreList, False)
'查找启动器目录中的 Java
JavaSearchFolder(Path, JavaPreList, False, IsFullSearch:=True)
'查找所选 Minecraft 文件夹中的 Java
If Not String.IsNullOrWhiteSpace(PathMcFolder) AndAlso Path <> PathMcFolder Then
JavaSearchFolder(PathMcFolder, JavaPreList, False, IsFullSearch:=True)
End If
'若不全为符号链接,则清除符号链接的地址
Dim JavaWithoutReparse As New Dictionary(Of String, Boolean)
For Each Pair In JavaPreList
Dim Folder As String = Pair.Key.Replace("\\", "\").Replace("/", "\")
Dim Info As FileSystemInfo = New FileInfo(Folder & "javaw.exe")
Do
If Info.Attributes.HasFlag(FileAttributes.ReparsePoint) Then
Log("[Java] 位于 " & Folder & " 的 Java 包含符号链接")
Continue For
End If
Info = If(TypeOf Info Is FileInfo, CType(Info, FileInfo).Directory, CType(Info, DirectoryInfo).Parent)
Loop While Info IsNot Nothing
Log("[Java] 位于 " & Folder & " 的 Java 不含符号链接")
JavaWithoutReparse.Add(Pair.Key, Pair.Value)
Next
If JavaWithoutReparse.Any Then JavaPreList = JavaWithoutReparse
'若不全为特殊引用,则清除特殊引用的地址
Dim JavaWithoutInherit As New Dictionary(Of String, Boolean)
For Each Pair In JavaPreList
If Pair.Key.Contains("javapath_target_") OrElse Pair.Key.Contains("javatmp") Then
Log("[Java] 位于 " & Pair.Key & " 的 Java 包含特殊引用")
Else
Log("[Java] 位于 " & Pair.Key & " 的 Java 不含特殊引用")
JavaWithoutInherit.Add(Pair.Key, Pair.Value)
End If
Next
If JavaWithoutInherit.Any Then JavaPreList = JavaWithoutInherit
#End Region
#Region "添加玩家手动导入的 Java"
Dim ImportedJava As String = Setup.Get("LaunchArgumentJavaAll")
Try
For Each JavaJsonObject In GetJson(ImportedJava)
Dim Entry = JavaEntry.FromJson(JavaJsonObject)
If Entry.IsUserImport Then JavaPreList(Entry.PathFolder) = True
Next
Catch ex As Exception
Log(ex, "Java 列表已损坏", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaAll", "[]")
End Try
#End Region
'确保可用并获取详细信息,转入正式列表
Dim NewJavaList As New List(Of JavaEntry)
For Each Entry In Distinct(JavaPreList.ToList, Function(a, b) a.Key.ToLower = b.Key.ToLower) '#794
NewJavaList.Add(New JavaEntry(Entry.Key, Entry.Value))
Next
NewJavaList = Sort(JavaCheckList(NewJavaList), AddressOf JavaSorter)
'修改设置项
Dim AllList As New JArray
For Each Java In NewJavaList
AllList.Add(Java.ToJson)
Next
Setup.Set("LaunchArgumentJavaAll", AllList.ToString(Newtonsoft.Json.Formatting.None))
JavaList = NewJavaList
Catch ex As Exception
Log(ex, "搜索 Java 时出错", LogLevel.Feedback)
JavaList = New List(Of JavaEntry)
End Try
Log("[Java] Java 搜索完成,发现 " & JavaList.Count & " 个 Java")
If FrmSetupLaunch IsNot Nothing Then RunInUi(Sub() FrmSetupLaunch.RefreshJavaComboBox())
If FrmVersionSetup IsNot Nothing Then RunInUi(Sub() FrmVersionSetup.RefreshJavaComboBox())
End Sub
''' <summary>
''' 多线程检查列表中的所有 Java 项。
''' </summary>
Private Function JavaCheckList(JavaEntries As List(Of JavaEntry)) As List(Of JavaEntry)
Log("[Java] 开始确认列表 Java 状态,共 " & JavaEntries.Count & " 项")
JavaCheckList = New List(Of JavaEntry)
Dim ListLock As New Object
'启动检查线程
Dim CheckThreads As New List(Of Thread)
For Each Entry In JavaEntries
Dim CheckThread As New Thread(Sub()
Try
Entry.Check()
If ModeDebug Then Log("[Java] - " & Entry.ToString)
SyncLock ListLock
JavaCheckList.Add(Entry)
End SyncLock
Catch ex As ThreadInterruptedException
Catch ex As Exception
If Entry.IsUserImport Then
Log(ex, "位于 " & Entry.PathFolder & " 的 Java 存在异常,将被自动移除", LogLevel.Hint)
Else
Log(ex, "位于 " & Entry.PathFolder & " 的 Java 存在异常")
End If
End Try
End Sub)
CheckThreads.Add(CheckThread)
CheckThread.Start()
Next
'等待构造线程完成
Wait:
Thread.Sleep(10)
For Each CheckThread In CheckThreads
If CheckThread.IsAlive Then GoTo Wait
Next
End Function
''' <summary>
''' 模糊搜索指定文件夹下的 Java,并只进行粗略的检查。这不会搜索全部路径。
''' </summary>
''' <param name="OriginalPath">开始搜索的起始路径,不限制结尾。</param>
''' <param name="IsFullSearch">搜索当前文件夹下的全部文件夹(此参数不会传递到子文件夹)。</param>
Private Sub JavaSearchFolder(OriginalPath As String, ByRef Results As Dictionary(Of String, Boolean), Source As Boolean, Optional IsFullSearch As Boolean = False)
Try
Log("[Java] 开始" & If(IsFullSearch, "完全", "部分") & "遍历查找:" & OriginalPath)
JavaSearchFolder(New DirectoryInfo(OriginalPath), Results, Source, IsFullSearch)
Catch ex As UnauthorizedAccessException
Log("[Java] 遍历查找 Java 时遭遇无权限的文件夹:" & OriginalPath)
Catch ex As Exception
Log(ex, "遍历查找 Java 时出错(" & OriginalPath & ")")
End Try
End Sub
''' <summary>
''' 模糊搜索指定文件夹下的 Java,并只进行粗略的检查。这不会搜索全部路径。
''' </summary>
''' <param name="OriginalPath">开始搜索的起始路径,不限制结尾。</param>
''' <param name="IsFullSearch">搜索当前文件夹下的全部文件夹(此参数不会传递到子文件夹)。</param>
Private Sub JavaSearchFolder(OriginalPath As DirectoryInfo, ByRef Results As Dictionary(Of String, Boolean), Source As Boolean, Optional IsFullSearch As Boolean = False)
Try
'确认目录存在
If Not OriginalPath.Exists Then Exit Sub
Dim Path As String = OriginalPath.FullName.Replace("\\", "\")
If Not Path.EndsWithF("\") Then Path += "\"
'若该目录有 Java,则加入结果
If File.Exists(Path & "javaw.exe") Then Results(Path) = Source
'查找其下的所有文件夹
For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories
If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接
Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).ToLower '用于搜索的字符串
If IsFullSearch OrElse
FolderInfo.Parent.Name.ToLower = "users" OrElse
SearchEntry.Contains("java") OrElse SearchEntry.Contains("jdk") OrElse SearchEntry.Contains("env") OrElse
SearchEntry.Contains("环境") OrElse SearchEntry.Contains("run") OrElse SearchEntry.Contains("软件") OrElse
SearchEntry.Contains("jre") OrElse SearchEntry = "bin" OrElse SearchEntry.Contains("mc") OrElse
SearchEntry.Contains("soft") OrElse SearchEntry.Contains("cache") OrElse SearchEntry.Contains("temp") OrElse
SearchEntry.Contains("corretto") OrElse SearchEntry.Contains("roaming") OrElse SearchEntry.Contains("users") OrElse
SearchEntry.Contains("craft") OrElse SearchEntry.Contains("program") OrElse SearchEntry.Contains("世界") OrElse
SearchEntry.Contains("net") OrElse SearchEntry.Contains("游戏") OrElse SearchEntry.Contains("oracle") OrElse
SearchEntry.Contains("game") OrElse SearchEntry.Contains("file") OrElse SearchEntry.Contains("data") OrElse
SearchEntry.Contains("jvm") OrElse SearchEntry.Contains("服务") OrElse SearchEntry.Contains("server") OrElse
SearchEntry.Contains("客户") OrElse SearchEntry.Contains("client") OrElse SearchEntry.Contains("整合") OrElse
SearchEntry.Contains("应用") OrElse SearchEntry.Contains("运行") OrElse SearchEntry.Contains("前置") OrElse
SearchEntry.Contains("mojang") OrElse SearchEntry.Contains("官启") OrElse SearchEntry.Contains("新建文件夹") OrElse
SearchEntry.Contains("eclipse") OrElse SearchEntry.Contains("microsoft") OrElse SearchEntry.Contains("hotspot") OrElse
SearchEntry.Contains("runtime") OrElse SearchEntry.Contains("x86") OrElse SearchEntry.Contains("x64") OrElse
SearchEntry.Contains("forge") OrElse SearchEntry.Contains("原版") OrElse SearchEntry.Contains("optifine") OrElse
SearchEntry.Contains("官方") OrElse SearchEntry.Contains("启动") OrElse SearchEntry.Contains("hmcl") OrElse
SearchEntry.Contains("mod") OrElse SearchEntry.Contains("高清") OrElse SearchEntry.Contains("download") OrElse
SearchEntry.Contains("launch") OrElse SearchEntry.Contains("程序") OrElse SearchEntry.Contains("path") OrElse
SearchEntry.Contains("version") OrElse SearchEntry.Contains("baka") OrElse SearchEntry.Contains("pcl") OrElse
SearchEntry.Contains("zulu") OrElse
SearchEntry.Contains("local") OrElse SearchEntry.Contains("packages") OrElse SearchEntry.Contains("4297127d64ec6") OrElse '官启文件夹
SearchEntry.Contains("国服") OrElse SearchEntry.Contains("网易") OrElse SearchEntry.Contains("ext") OrElse '网易 Java 文件夹名
SearchEntry.Contains("netease") OrElse SearchEntry.Contains("1.") OrElse SearchEntry.Contains("启动") Then
JavaSearchFolder(FolderInfo, Results, Source)
End If
Next
Catch ex As UnauthorizedAccessException
Log("[Java] 遍历查找 Java 时遭遇无权限的文件夹:" & OriginalPath.FullName)
Catch ex As Exception
Log(ex, "遍历查找 Java 时出错(" & OriginalPath.FullName & ")")
End Try
End Sub
#End Region
#Region "下载"
''' <summary>
''' 提示 Java 缺失,并弹窗确认是否自动下载。返回玩家选择是否下载。
''' </summary>
Public Function JavaDownloadConfirm(VersionDescription As String, Optional ForcedManualDownload As Boolean = False) As Boolean
If ForcedManualDownload Then
MyMsgBox($"PCL 未找到 {VersionDescription}。" & vbCrLf &
$"请自行搜索并安装 {VersionDescription},安装后在 设置 → 启动选项 → 游戏 Java 中重新搜索或导入。",
"未找到 Java")
Return False
Else
Return MyMsgBox($"PCL 未找到 {VersionDescription},是否需要 PCL 自动下载?" & vbCrLf &
$"如果你已经安装了 {VersionDescription},请在 设置 → 启动选项 → 游戏 Java 中手动导入。",
"未找到 Java", "自动下载", "取消") = 1
End If
End Function
''' <summary>
''' 获取下载 Java 8/14/17/21 的加载器。需要开启 IsForceRestart 以正常刷新 Java 列表。
''' </summary>
Public Function JavaFixLoaders(Version As Integer) As LoaderCombo(Of Integer)
Return New LoaderCombo(Of Integer)($"下载 Java {Version}", {
New LoaderTask(Of Integer, List(Of NetFile))("获取 Java 下载信息", AddressOf JavaFileList) With {.ProgressWeight = 2},
New LoaderDownload("下载 Java 文件", New List(Of NetFile)) With {.ProgressWeight = 10},
JavaSearchLoader
})
End Function
Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile)))
Log("[Java] 开始获取 Java 下载信息")
Dim IndexFileStr As String = NetGetCodeByDownload(
{"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json",
"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
IsJson:=True)
'获取下载地址
Dim MainEntry As JObject = CType(GetJson(IndexFileStr), JObject)($"windows-x{If(Is32BitSystem, "86", "64")}")
Dim Entries = MainEntry.Children.Reverse. '选择最靠后的一项(最新)
SelectMany(Function(e As JProperty) CType(e.Value, JArray).Select(Function(v) New KeyValuePair(Of String, JObject)(e.Name, v)))
Dim TargetEntry = Entries.First(Function(t) t.Value("version")("name").ToString.StartsWithF(Loader.Input))
Dim Address As String = TargetEntry.Value("manifest")("url")
Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}")
'获取文件列表
Dim ListFileStr As String = NetGetCodeByDownload(
{Address.Replace("piston-meta.mojang.com", "bmclapi2.bangbang93.com"),
Address},
IsJson:=True)
Dim BaseDir As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\runtime\" & TargetEntry.Key & "\"
Dim Results As New List(Of NetFile)
For Each File As JProperty In CType(GetJson(ListFileStr), JObject)("files")
If CType(File.Value, JObject)("downloads")?("raw") Is Nothing Then Continue For
Dim Info As JObject = CType(File.Value, JObject)("downloads")("raw")
Dim Checker As New FileChecker(ActualSize:=Info("size"), Hash:=Info("sha1"))
If Checker.Check(BaseDir & File.Name) Is Nothing Then Continue For '跳过已存在的文件
Dim Url As String = Info("url")
Results.Add(New NetFile(
{Url.Replace("piston-data.mojang.com", "bmclapi2.bangbang93.com"),
Url},
BaseDir & File.Name, Checker))
Next
Loader.Output = Results
Log($"[Java] 需要下载 {Results.Count} 个文件,目标文件夹:{BaseDir}")
End Sub
#End Region
End Module
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,28 +1,31 @@
Public Module ModModpack
Imports System.IO.Compression
Public Module ModModpack
'触发整合包安装的外部接口
''' <summary>
''' 弹窗要求选择一个整合包文件并进行安装。
''' </summary>
Public Sub ModpackInstall()
Dim File As String = SelectFile("压缩包文件(*.rar;*.zip)|*.rar;*.zip", "选择整合包压缩文件") '选择整合包文件
Dim File As String = SelectFile("整合包文件(*.rar;*.zip;*.mrpack)|*.rar;*.zip;*.mrpack", "选择整合包压缩文件") '选择整合包文件
If String.IsNullOrEmpty(File) Then Exit Sub
RunInThread(Sub() ModpackInstall(File))
End Sub
''' <summary>
''' 安装一个给定的整合包文件,返回是否安装成功。必须在工作线程执行。
''' </summary>
Public Function ModpackInstall(File As String, Optional VersionName As String = Nothing, Optional ShowHint As Boolean = True) As Boolean
Public Function ModpackInstall(File As String, Optional VersionName As String = Nothing, Optional ShowHint As Boolean = True, Optional Logo As String = Nothing) As Boolean
Log("[ModPack] 整合包安装请求:" & If(File, "null"))
Dim Archive As Compression.ZipArchive = Nothing
Dim Archive As ZipArchive = Nothing
Dim ArchiveBaseFolder As String = ""
Try
'获取整合包种类与关键 Json
Dim PackType As Integer = -1
Try
Archive = New Compression.ZipArchive(New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
Archive = New ZipArchive(New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
'从根目录判断整合包类型
If Archive.GetEntry("mcbbs.packmeta") IsNot Nothing Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断)
If Archive.GetEntry("modrinth.index.json") IsNot Nothing Then PackType = 4 : Exit Try 'Modrinth 整合包
If Archive.GetEntry("manifest.json") IsNot Nothing Then
Dim Json As JObject = GetJson(ReadFile(Archive.GetEntry("manifest.json").Open, Encoding.UTF8))
If Json("addons") Is Nothing Then
@@ -37,11 +40,12 @@
For Each Entry In Archive.Entries
Dim FullNames As String() = Entry.FullName.Split("/")
ArchiveBaseFolder = FullNames(0) & "/"
If Entry.FullName.EndsWith("/versions/") AndAlso FullNames.Count = 3 Then PackType = 9 : Exit Try '压缩包
If Entry.FullName.EndsWithF("/versions/") AndAlso FullNames.Count = 3 Then PackType = 9 : Exit Try '压缩包
'确定为一级目录下
If FullNames.Count <> 2 Then Continue For
'判断是否为关键文件
If FullNames(1) = "mcbbs.packmeta" Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断)
If FullNames(1) = "modrinth.index.json" Then PackType = 4 : Exit Try 'Modrinth 整合包
If FullNames(1) = "manifest.json" Then
Dim Json As JObject = GetJson(ReadFile(Entry.Open, Encoding.UTF8))
If Json("addons") Is Nothing Then
@@ -54,11 +58,11 @@
If FullNames(1) = "mmc-pack.json" Then PackType = 2 : Exit Try 'MMC 整合包
Next
Catch ex As Exception
If GetString(ex, False, True).Contains("Error.WinIOError") Then
If GetExceptionDetail(ex, True).Contains("Error.WinIOError") Then
Log(ex, "打开整合包文件失败", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
Return False
ElseIf File.ToLower.EndsWith(".rar") Then
Log(ex, "PCL2 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
ElseIf File.EndsWithF(".rar", True) Then
Log(ex, "PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
Return False
Else
Log(ex, "打开整合包文件失败,文件可能损坏或为不支持的压缩包格式", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
@@ -69,7 +73,7 @@
Select Case PackType
Case 0
Log("[ModPack] 整合包种类:CurseForge")
InstallPackCurseForge(File, Archive, ArchiveBaseFolder, VersionName)
InstallPackCurseForge(File, Archive, ArchiveBaseFolder, VersionName, Logo)
Case 1
Log("[ModPack] 整合包种类:HMCL")
InstallPackHMCL(File, Archive, ArchiveBaseFolder)
@@ -79,6 +83,9 @@
Case 3
Log("[ModPack] 整合包种类:MCBBS")
InstallPackMCBBS(File, Archive, ArchiveBaseFolder)
Case 4
Log("[ModPack] 整合包种类:Modrinth")
InstallPackModrinth(File, Archive, ArchiveBaseFolder, VersionName, Logo)
Case 9
Log("[ModPack] 整合包种类:压缩包")
Archive.Dispose()
@@ -104,7 +111,7 @@
'整合包缓存清理
Private IsInstallCacheCleared As Boolean = False
Private IsInstallCacheClearing As Boolean = False
Private Sub UnpackFiles(InstallTemp As String, FileAddress As String)
Private Sub UnpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase)
'清理缓存文件夹
If Not IsInstallCacheCleared Then
IsInstallCacheCleared = True
@@ -130,9 +137,8 @@
Try
Retry:
'完全不知道为啥会出现文件正在被另一进程使用的问题,总之多试试
Directory.CreateDirectory(InstallTemp)
DeleteDirectory(InstallTemp)
Compression.ZipFile.ExtractToDirectory(FileAddress, InstallTemp, Encode)
ExtractFile(FileAddress, InstallTemp, Encode)
Catch ex As Exception
Log(ex, "第 " & RetryCount & " 次解压尝试失败")
If TypeOf ex Is ArgumentException Then
@@ -141,6 +147,7 @@ Retry:
End If
If RetryCount < 5 Then
Thread.Sleep(RetryCount * 2000)
If Loader IsNot Nothing AndAlso Loader.LoadingState <> MyLoading.MyLoadingState.Run Then Exit Sub
RetryCount += 1
GoTo Retry
Else
@@ -152,11 +159,8 @@ Retry:
#Region "不同类型整合包的安装方法"
'CurseForge
''' <summary>
''' 获取安装 CurseForge 整合包的加载器,若失败或跳过则返回 Nothing。
''' 加载器以安装目标版本文件夹为输入。
''' </summary>
Private Function InstallPackCurseForgeLoader(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String, VersionName As String) As LoaderCombo(Of String)
Private Sub InstallPackCurseForge(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String, Optional VersionName As String = Nothing, Optional Logo As String = Nothing)
'读取 Json 文件
Dim Json As JObject
Try
@@ -164,18 +168,29 @@ Retry:
If Json("minecraft") Is Nothing OrElse Json("minecraft")("version") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息")
Catch ex As Exception
Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
Return Nothing
Exit Sub
End Try
'获取版本名
Dim ShowRibble As Boolean = VersionName Is Nothing
If VersionName Is Nothing Then
Dim PackName As String = If(Json("name"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(PackName) <> "" Then PackName = ""
VersionName = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
If String.IsNullOrEmpty(VersionName) Then Exit Sub
End If
'获取 Mod API 版本信息
Dim ForgeVersion As String = Nothing
Dim FabricVersion As String = Nothing
For Each Entry In If(Json("minecraft")("modLoaders"), {})
Dim Id As String = If(Entry("id"), "").ToString.ToLower
If Id.StartsWith("forge-") Then
If Id.StartsWithF("forge-") Then
'Forge 指定
If Id.Contains("recommended") Then
Log("[ModPack] 该整合包版本过老,已不支持进行安装!", LogLevel.Hint)
Return Nothing
Exit Sub
End If
Try
Log("[ModPack] 整合包 Forge 版本:" & Id)
@@ -184,7 +199,7 @@ Retry:
Catch ex As Exception
Log(ex, "读取整合包 Forge 版本失败:" & Id)
End Try
ElseIf Id.StartsWith("fabric-") Then
ElseIf Id.StartsWithF("fabric-") Then
'Fabric 指定
Try
Log("[ModPack] 整合包 Fabric 版本:" & Id)
@@ -202,13 +217,15 @@ Retry:
If OverrideHome <> "" Then
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
UnpackFiles(InstallTemp, FileAddress)
UnpackFiles(InstallTemp, FileAddress, Task)
Task.Progress = 0.5
Dim OverridePath As String = InstallTemp & ArchiveBaseFolder & OverrideHome
'复制结果
If Directory.Exists(InstallTemp & ArchiveBaseFolder & OverrideHome) Then
My.Computer.FileSystem.CopyDirectory(InstallTemp & ArchiveBaseFolder & OverrideHome, PathMcFolder & "versions\" & VersionName)
If Directory.Exists(OverridePath) Then
CopyDirectory(OverridePath, PathMcFolder & "versions\" & VersionName)
Log($"[ModPack] 整合包 override 复制:{OverridePath} -> {PathMcFolder & "versions\" & VersionName}")
Else
Log("[ModPack] 整合包中未找到 override 目录,已跳过")
Log($"[ModPack] 整合包中未找到 override 文件夹:{OverridePath}")
End If
Task.Progress = 0.9
'开启版本隔离
@@ -217,73 +234,104 @@ Retry:
.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
End If
'获取 Mod 列表
Dim ModFileList As New List(Of Integer)
Dim ModList As New List(Of Integer)
Dim ModOptionalList As New List(Of Integer)
For Each ModEntry In If(Json("files"), {})
If ModEntry("projectID") Is Nothing OrElse ModEntry("fileID") Is Nothing Then
Hint("某项 Mod 缺少必要信息,已跳过:" & ModEntry.ToString)
Continue For
End If
If ModEntry("required") IsNot Nothing AndAlso Not ModEntry("required").ToObject(Of Boolean) Then Continue For
ModFileList.Add(ModEntry("fileID"))
ModList.Add(ModEntry("fileID"))
If ModEntry("required") IsNot Nothing AndAlso Not ModEntry("required").ToObject(Of Boolean) Then ModOptionalList.Add(ModEntry("fileID"))
Next
If ModFileList.Count > 0 Then
If ModList.Any Then
Dim ModDownloadLoaders As New List(Of LoaderBase)
'获取 Mod 下载信息
InstallLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
Sub(Task As LoaderTask(Of Integer, JArray))
Task.Output = GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(ModFileList, ",") & "]}", "application/json"))("data")
Task.Output = GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json"))("data")
'如果文件已被删除,则 API 会跳过那一项
If ModFileList.Count > Task.Output.Count Then Throw New Exception("整合包所需要的部分 Mod 版本已被 Mod 作者删除,因此无法完成整合包安装,请联系整合包作者更新整合包中的 Mod 版本")
End Sub) With {.ProgressWeight = ModFileList.Count / 10}) '每 10 Mod 需要 1s
If ModList.Count > Task.Output.Count Then Throw New Exception("整合包所需要的部分 Mod 版本已被 Mod 作者删除,因此无法完成整合包安装,请联系整合包作者更新整合包中的 Mod 版本")
End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s
'构造 NetFile
InstallLoaders.Add(New LoaderTask(Of JArray, List(Of NetFile))("构造 Mod 下载信息",
ModDownloadLoaders.Add(New LoaderTask(Of JArray, List(Of NetFile))("构造 Mod 下载信息",
Sub(Task As LoaderTask(Of JArray, List(Of NetFile)))
Dim FileList As New Dictionary(Of Integer, NetFile)
For Each ModJson In Task.Input
Dim Id As Integer = ModJson("id").ToObject(Of Integer)
'跳过重复的 Mod(疑似 CurseForge Bug)
If FileList.ContainsKey(ModJson("id").ToObject(Of Integer)) Then Continue For
If FileList.ContainsKey(Id) Then Continue For
'可选 Mod 提示
If ModOptionalList.Contains(Id) Then
If MyMsgBox("是否要下载整合包中的可选文件 " & ModJson("displayName").ToString & "?",
"下载可选文件", "是", "否") = 2 Then
Continue For
End If
End If
'建立 CompFile
Dim File As New CompFile(ModJson, CompType.Mod)
If Not File.Available Then Continue For
'根据 modules 和文件名后缀判断是资源包还是 Mod
Dim IsResourcePack As Boolean
If ModJson("modules").Any Then 'modules 可能返回 null(#1006)
Dim ModuleNames = CType(ModJson("modules"), JArray).Select(Function(l) l("name").ToString).ToList
IsResourcePack =
(Not ModuleNames.Contains("META-INF")) AndAlso (Not ModuleNames.Contains("mcmod.info")) AndAlso '不包含 META-INF 或 mcmod.info
ModuleNames.Contains("pack.mcmeta") AndAlso '包含 pack.mcmeta
(Not File.FileName.EndsWithF(".jar", True)) '文件后缀不是 .jar
Else
IsResourcePack = False
End If
'实际的添加
FileList.Add(ModJson("id"), New DlCfFile(ModJson, False).GetDownloadFile(PathMcFolder & "versions\" & VersionName & "\mods\", False))
Task.Progress += 1 / (1 + ModFileList.Count)
FileList.Add(Id, File.ToNetFile($"{PathMcFolder}versions\{VersionName}\{If(IsResourcePack, "resourcepacks", "mods")}\"))
Task.Progress += 1 / (1 + ModList.Count)
Next
Task.Output = FileList.Values.ToList
End Sub) With {.ProgressWeight = ModFileList.Count / 200, .Show = False}) '每 200 Mod 需要 1s
End Sub) With {.ProgressWeight = ModList.Count / 200, .Show = False}) '每 200 Mod 需要 1s
'下载 Mod 文件
InstallLoaders.Add(New LoaderDownload("下载 Mod", New List(Of NetFile)) With {.ProgressWeight = ModFileList.Count * 1.5}) '每个 Mod 需要 1.5s
ModDownloadLoaders.Add(New LoaderDownload("下载 Mod", New List(Of NetFile)) With {.ProgressWeight = ModList.Count * 1.5}) '每个 Mod 需要 1.5s
'构造加载器
InstallLoaders.Add(New LoaderCombo(Of Integer)("下载 Mod(主加载器)", ModDownloadLoaders) With
{.Show = False, .ProgressWeight = ModDownloadLoaders.Sum(Function(l) l.ProgressWeight)})
End If
'构造加载器
Dim Request As New McInstallRequest With {
.TargetVersionName = VersionName,
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
.MinecraftName = Json("minecraft")("version").ToString,
.ForgeVersion = ForgeVersion,
.FabricVersion = FabricVersion
}
Dim InstallExpectTime As Double = 0
For Each InstallLoader In InstallLoaders
InstallExpectTime += InstallLoader.ProgressWeight
Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Return Nothing
Dim MergeExpectTime As Double = 0
For Each MergeLoader In MergeLoaders
MergeExpectTime += MergeLoader.ProgressWeight
Next
'构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
If MergeLoaders Is Nothing Then Exit Sub
'构造 Libraries 加载器
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallExpectTime})
Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeExpectTime})
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
Loaders.Add(New LoaderTask(Of String, String)("清理安装文件",
Sub(Task As LoaderTask(Of String, String))
Dim Target As String = PathMcFolder & "versions\" & VersionName & "\原始整合包.zip"
If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
Log("[Download] 根据设置要求删除原始整合包文件:" & Target)
File.Delete(Target)
End If
End Sub) With {.ProgressWeight = 0.1, .Show = False})
Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
Sub(Task As LoaderTask(Of String, String))
'设置图标
Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
Log("[ModPack] 已设置整合包 Logo:" & Logo)
End If
'删除原始整合包文件
For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target)
File.Delete(Target)
End If
Next
End Sub) With {.ProgressWeight = 0.1, .Show = False})
'重复任务检查
Dim LoaderName As String = "CurseForge 整合包安装:" & VersionName & " "
@@ -291,40 +339,160 @@ Retry:
For i = 0 To LoaderTaskbar.Count - 1
If LoaderTaskbar(i).Name = LoaderName Then
Hint("该整合包正在安装中!", HintType.Critical)
Return Nothing
Exit Sub
End If
Next
End SyncLock
'启动
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
Return Loader
End Function
Private Sub InstallPackCurseForge(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String, Optional VersionName As String = Nothing)
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
End Sub
'Modrinth
Private Sub InstallPackModrinth(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String, Optional VersionName As String = Nothing, Optional Logo As String = Nothing)
'读取 Json 文件
Dim Json As JObject
Try
Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modrinth.index.json").Open))
If Json("dependencies") Is Nothing OrElse Json("dependencies")("minecraft") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息")
Catch ex As Exception
Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
Exit Sub
End Try
'获取 Mod API 版本信息
Dim MinecraftVersion As String = Nothing
Dim ForgeVersion As String = Nothing
Dim FabricVersion As String = Nothing
For Each Entry As JProperty In If(Json("dependencies"), {})
Select Case Entry.Name.ToLower
Case "minecraft"
MinecraftVersion = Entry.Value.ToString
Case "forge" 'eg. 14.23.5.2859 / 1.19-41.1.0
ForgeVersion = Entry.Value.ToString
Log("[ModPack] 整合包 Forge 版本:" & ForgeVersion)
Case "fabric-loader" 'eg. 0.14.14
FabricVersion = Entry.Value.ToString
Log("[ModPack] 整合包 Fabric 版本:" & FabricVersion)
Case "quilt-loader" 'eg. 1.0.0
Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
Exit Sub
Case Else
Hint($"无法安装整合包,其中出现了未知的 Mod 加载器 {Entry.Value}!", HintType.Critical)
Exit Sub
End Select
Next
'获取版本名
Dim ShowRibble As Boolean = VersionName Is Nothing
If VersionName Is Nothing Then
Dim Json As JObject
Try
Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "manifest.json").Open))
If Json("minecraft") Is Nothing OrElse Json("minecraft")("version") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息")
Catch ex As Exception
Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
Exit Sub
End Try
Dim PackName As String = If(Json("name"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(PackName) <> "" Then PackName = ""
VersionName = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
Title:="输入版本名", Button2:="取消")
VersionName = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
If String.IsNullOrEmpty(VersionName) Then Exit Sub
End If
'解压和配置文件
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
Dim InstallLoaders As New List(Of LoaderBase)
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
UnpackFiles(InstallTemp, FileAddress, Task)
Task.Progress = 0.5
'复制 overrides 文件夹和 client-overrides 文件夹
If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then
CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName)
Else
Log("[ModPack] 整合包中未找到 override 目录,已跳过")
End If
Task.Progress = 0.8
If Directory.Exists(InstallTemp & ArchiveBaseFolder & "client-overrides") Then
CopyDirectory(InstallTemp & ArchiveBaseFolder & "client-overrides", PathMcFolder & "versions\" & VersionName)
End If
Task.Progress = 0.9
'开启版本隔离
WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
'获取下载文件列表
Dim FileList As New List(Of NetFile)
For Each File In If(Json("files"), {})
'检查是否需要该文件
If File("env") IsNot Nothing Then
Select Case File("env")("client").ToString
Case "optional"
If MyMsgBox("是否要下载整合包中的可选文件 " & GetFileNameFromPath(File("path").ToString) & "?",
"下载可选文件", "是", "否") = 2 Then
Continue For
End If
Case "unsupported"
Continue For
End Select
End If
'添加下载文件
FileList.Add(New NetFile(File("downloads").Select(Function(t) t.ToString.Replace("://edge.forgecdn", "://media.forgecdn")).ToArray, '修复 #2390
PathMcFolder & "versions\" & VersionName & "\" & File("path").ToString,
New FileChecker(ActualSize:=File("fileSize").ToObject(Of Long), Hash:=File("hashes")("sha1").ToString), True))
Next
If FileList.Any Then
InstallLoaders.Add(New LoaderDownload("下载额外文件", FileList) With {.ProgressWeight = FileList.Count * 1.5}) '每个 Mod 需要 1.5s
End If
'启动加载器
Dim Loader = InstallPackCurseForgeLoader(FileAddress, Archive, ArchiveBaseFolder, VersionName)
If Loader Is Nothing Then Exit Sub
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
'构造加载器
Dim Request As New McInstallRequest With {
.TargetVersionName = VersionName,
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
.MinecraftName = MinecraftVersion,
.ForgeVersion = ForgeVersion,
.FabricVersion = FabricVersion
}
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
'构造 Libraries 加载器
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
Sub(Task As LoaderTask(Of String, String))
'设置图标
Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
Log("[ModPack] 已设置整合包 Logo:" & Logo)
End If
'删除原始整合包文件
For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target)
File.Delete(Target)
End If
Next
End Sub) With {.ProgressWeight = 0.1, .Show = False})
'重复任务检查
Dim LoaderName As String = "Modrinth 整合包安装:" & VersionName & " "
SyncLock LoaderTaskbarLock
For i = 0 To LoaderTaskbar.Count - 1
If LoaderTaskbar(i).Name = LoaderName Then
Hint("该整合包正在安装中!", HintType.Critical)
Exit Sub
End If
Next
End SyncLock
'启动
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
@@ -345,19 +513,18 @@ Retry:
Dim PackName As String = If(Json("name"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(PackName) <> "" Then PackName = ""
Dim VersionName As String = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
Title:="输入版本名", Button2:="取消")
Dim VersionName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
If VersionName Is Nothing Then Exit Sub
'解压与配置文件
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
Dim InstallLoaders As New List(Of LoaderBase)
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
UnpackFiles(InstallTemp, FileAddress)
UnpackFiles(InstallTemp, FileAddress, Task)
Task.Progress = 0.5
'复制结果
If Directory.Exists(InstallTemp & ArchiveBaseFolder & "minecraft") Then
My.Computer.FileSystem.CopyDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", PathMcFolder & "versions\" & VersionName)
CopyDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", PathMcFolder & "versions\" & VersionName)
Else
Log("[ModPack] 整合包中未找到 minecraft override 目录,已跳过")
End If
@@ -366,21 +533,17 @@ Retry:
WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
'构造加载器
If Json("gameVersion") Is Nothing Then Throw New Exception("整合包未提供游戏版本信息")
If Json("gameVersion") Is Nothing Then
Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
Exit Sub
End If
Dim Request As New McInstallRequest With {
.TargetVersionName = VersionName,
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
.MinecraftName = Json("gameVersion").ToString
}
Dim InstallExpectTime As Double = 0
For Each InstallLoader In InstallLoaders
InstallExpectTime += InstallLoader.ProgressWeight
Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
Dim MergeExpectTime As Double = 0
For Each MergeLoader In MergeLoaders
MergeExpectTime += MergeLoader.ProgressWeight
Next
'构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, String)("重命名版本 Json(副加载器)",
@@ -401,8 +564,8 @@ Retry:
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase) From {
New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeExpectTime},
New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallExpectTime},
New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)},
New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)},
New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8}
}
@@ -420,7 +583,7 @@ Retry:
'启动
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
'If Archive IsNot Nothing Then Archive.Dispose() '解除占用,以免在加载器中触发 “正由另一进程使用,因此该进程无法访问此文件”
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
@@ -441,29 +604,70 @@ Retry:
Dim PackName As String = If(RegexSeek(PackInstance, "(?<=\nname\=)[^\n]+"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(PackName) <> "" Then PackName = ""
Dim VersionName As String = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
Title:="输入版本名", Button2:="取消")
Dim VersionName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
If VersionName Is Nothing Then Exit Sub
'解压与配置文件
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
'解压、配置设置文件
Dim InstallTemp As String = $"{PathTemp}PackInstall\{RandomInteger(0, 100000)}\"
Dim SetupFile As String = $"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini"
Dim InstallLoaders As New List(Of LoaderBase)
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
UnpackFiles(InstallTemp, FileAddress)
UnpackFiles(InstallTemp, FileAddress, Task)
Task.Progress = 0.5
'复制结果
If Directory.Exists(InstallTemp & ArchiveBaseFolder & ".minecraft") Then
My.Computer.FileSystem.CopyDirectory(InstallTemp & ArchiveBaseFolder & ".minecraft", PathMcFolder & "versions\" & VersionName)
CopyDirectory(InstallTemp & ArchiveBaseFolder & ".minecraft", PathMcFolder & "versions\" & VersionName)
Else
Log("[ModPack] 整合包中未找到 override .minecraft 目录,已跳过")
End If
Task.Progress = 0.9
'开启版本隔离
WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
WriteIni(SetupFile, "VersionArgumentIndie", 1)
'读取 MMC 设置文件(#2655)
Try
Dim MMCSetupFile As String = InstallTemp & ArchiveBaseFolder & "instance.cfg"
If File.Exists(MMCSetupFile) Then
'将其中的等号替换为冒号,以符合 ini 文件格式
WriteFile(MMCSetupFile, ReadFile(MMCSetupFile).Replace("=", ":"))
If ReadIni(MMCSetupFile, "OverrideCommands", False) Then
Dim PreLaunchCommand As String = ReadIni(MMCSetupFile, "PreLaunchCommand")
If PreLaunchCommand <> "" Then
PreLaunchCommand = PreLaunchCommand.Replace("\""", """").
Replace("$INST_JAVA", "{java}javaw.exe").
Replace("$INST_MC_DIR\", "{minecraft}").Replace("$INST_MC_DIR", "{minecraft}").
Replace("$INST_DIR\", "{verpath}").Replace("$INST_DIR", "{verpath}").
Replace("$INST_ID", "{name}").Replace("$INST_NAME", "{name}")
WriteIni(SetupFile, "VersionAdvanceRun", PreLaunchCommand)
Log("[ModPack] 迁移 MultiMC 版本独立设置:启动前执行命令:" & PreLaunchCommand)
End If
End If
If ReadIni(MMCSetupFile, "JoinServerOnLaunch", False) Then
Dim ServerAddress As String = ReadIni(MMCSetupFile, "JoinServerOnLaunchAddress").Replace("\""", """")
WriteIni(SetupFile, "VersionServerEnter", ServerAddress)
Log("[ModPack] 迁移 MultiMC 版本独立设置:自动进入服务器:" & ServerAddress)
End If
If ReadIni(MMCSetupFile, "IgnoreJavaCompatibility", False) Then
WriteIni(SetupFile, "VersionAdvanceJava", True)
Log("[ModPack] 迁移 MultiMC 版本独立设置:忽略 Java 兼容性警告")
End If
Dim Logo As String = ReadIni(MMCSetupFile, "iconKey", "")
If Logo <> "" AndAlso File.Exists($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png") Then
WriteIni(SetupFile, "LogoCustom", True)
WriteIni(SetupFile, "Logo", "PCL\Logo.png")
CopyFile($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png", $"{PathMcFolder}versions\{VersionName}\PCL\Logo.png")
Log($"[ModPack] 迁移 MultiMC 版本独立设置:版本图标({Logo}.png)")
End If
End If
Catch ex As Exception
Log(ex, $"读取 MMC 配置文件失败({InstallTemp}{ArchiveBaseFolder}instance.cfg)")
End Try
End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
'构造版本安装请求
If PackJson("components") Is Nothing Then Throw New Exception("整合包未提供游戏版本信息")
Dim Request As New McInstallRequest With {.TargetVersionName = VersionName}
If PackJson("components") Is Nothing Then
Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
Exit Sub
End If
Dim Request As New McInstallRequest With {.TargetVersionName = VersionName, .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\"}
For Each Component In PackJson("components")
Select Case If(Component("uid"), "").ToString
Case "org.lwjgl"
@@ -472,27 +676,24 @@ Retry:
Request.MinecraftName = Component("version")
Case "net.minecraftforge"
Request.ForgeVersion = Component("version")
Case "net.fabricmc.fabric-loader"
Request.FabricVersion = Component("version")
Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
Exit Sub
End Select
Next
'构造加载器
Dim InstallExpectTime As Double = 0
For Each InstallLoader In InstallLoaders
InstallExpectTime += InstallLoader.ProgressWeight
Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
Dim MergeExpectTime As Double = 0
For Each MergeLoader In MergeLoaders
MergeExpectTime += MergeLoader.ProgressWeight
Next
'构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
'构造 Libraries 加载器
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeExpectTime})
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallExpectTime})
Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
'重复任务检查
@@ -508,7 +709,7 @@ Retry:
'启动
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
@@ -529,19 +730,18 @@ Retry:
Dim PackName As String = If(Json("name"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(PackName) <> "" Then PackName = ""
Dim VersionName As String = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
Title:="输入版本名", Button2:="取消")
Dim VersionName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
If VersionName Is Nothing Then Exit Sub
'解压与配置文件
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
Dim InstallLoaders As New List(Of LoaderBase)
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
UnpackFiles(InstallTemp, FileAddress)
UnpackFiles(InstallTemp, FileAddress, Task)
Task.Progress = 0.5
'复制结果
If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then
My.Computer.FileSystem.CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName)
CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName)
Else
Log("[ModPack] 整合包中未找到 overrides 目录,已跳过")
End If
@@ -550,37 +750,40 @@ Retry:
WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
'构造加载器
If Json("addons") Is Nothing Then Throw New Exception("整合包未提供游戏版本信息")
If Json("addons") Is Nothing Then
Hint("该整合包未提供游戏版本附加信息,无法安装!", HintType.Critical)
Exit Sub
End If
Dim Addons As New Dictionary(Of String, String)
For Each Entry In Json("addons")
Addons.Add(Entry("id"), Entry("version"))
Next
If Not Addons.ContainsKey("game") Then Throw New Exception("整合包未提供游戏版本信息")
If Not Addons.ContainsKey("game") Then
Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
Exit Sub
End If
If Addons.ContainsKey("quilt") Then
Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
Exit Sub
End If
Dim Request As New McInstallRequest With {
.TargetVersionName = VersionName,
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
.MinecraftName = Addons("game"),
.OptiFineVersion = If(Addons.ContainsKey("optifine"), Addons("optifine"), Nothing),
.ForgeVersion = If(Addons.ContainsKey("forge"), Addons("forge"), Nothing),
.FabricVersion = If(Addons.ContainsKey("fabric"), Addons("fabric"), Nothing)
}
Dim InstallExpectTime As Double = 0
For Each InstallLoader In InstallLoaders
InstallExpectTime += InstallLoader.ProgressWeight
Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
Dim MergeExpectTime As Double = 0
For Each MergeLoader In MergeLoaders
MergeExpectTime += MergeLoader.ProgressWeight
Next
'构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
'构造 Libraries 加载器
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeExpectTime})
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallExpectTime})
Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
'重复任务检查
@@ -597,7 +800,7 @@ Retry:
'启动
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
'If Archive IsNot Nothing Then Archive.Dispose() '解除占用,以免在加载器中触发 “正由另一进程使用,因此该进程无法访问此文件”
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
@@ -612,13 +815,12 @@ Retry:
If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Exit Sub
If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Exit Sub
'要求显示名称
Dim NewName As String = MyMsgBoxInput(GetFolderNameFromPath(TargetFolder), New ObjectModel.Collection(Of Validate) From {
New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})
},, "输入它在列表中的显示名称",, "取消")
Dim NewName As String = MyMsgBoxInput("输入显示名称", "输入该文件夹在左边栏列表中显示的名称。", GetFolderNameFromPath(TargetFolder),
New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})})
If String.IsNullOrWhiteSpace(NewName) Then Exit Sub
'解压
Hint("正在解压压缩包……")
UnpackFiles(TargetFolder, FileAddress)
UnpackFiles(TargetFolder, FileAddress, Nothing)
'加入文件夹列表
PageSelectLeft.AddFolder(TargetFolder, NewName, False)
Hint("已加入游戏文件夹列表:" & NewName, HintType.Finish)
@@ -6,13 +6,13 @@
Public HasRunningMinecraft As Boolean = False
Private Sub WatcherStateChanged()
Dim IsRunning As Boolean = False
Dim IsCrashed As Boolean = False
Dim TriggerLauncherShutdown As Boolean = True
For Each Watcher In McWatcherList
If Watcher.State = Watcher.MinecraftState.Loading OrElse Watcher.State = Watcher.MinecraftState.Running Then
IsRunning = True
Exit For
ElseIf Watcher.State = Watcher.MinecraftState.Crashed Then
IsCrashed = True
ElseIf Watcher.State = Watcher.MinecraftState.Crashed OrElse Watcher.State = Watcher.MinecraftState.Canceled Then
TriggerLauncherShutdown = False
End If
Next
If IsWatcherRunning = IsRunning Then Exit Sub
@@ -20,7 +20,7 @@
If IsWatcherRunning Then
MinecraftStart()
Else
MinecraftStop(IsCrashed)
MinecraftStop(TriggerLauncherShutdown)
End If
End Sub
Private Sub MinecraftStart()
@@ -28,7 +28,7 @@
HasRunningMinecraft = True
FrmMain.BtnExtraShutdown.ShowRefresh()
End Sub
Private Sub MinecraftStop(HasMinecraftCrashed As Boolean)
Private Sub MinecraftStop(TriggerLauncherShutdown As Boolean)
McLaunchLog("[全局] 已无运行中的 Minecraft")
HasRunningMinecraft = False
FrmMain.BtnExtraShutdown.ShowRefresh()
@@ -42,10 +42,10 @@
Select Case Setup.Get("LaunchArgumentVisible")
Case 2
'直接关闭
If HasMinecraftCrashed Then
RunInUi(Sub() FrmMain.Hidden = False)
Else
If TriggerLauncherShutdown Then
RunInUi(Sub() FrmMain.EndProgram(False))
Else
RunInUi(Sub() FrmMain.Hidden = False)
End If
Case 3
'恢复
@@ -73,7 +73,7 @@
'更改列表
Dim NewWatcherList As New List(Of Watcher)
For Each Watch In McWatcherList
If Watch.State = MinecraftState.Crashed OrElse Watch.State = MinecraftState.Ended Then Continue For
If Watch.State = MinecraftState.Crashed OrElse Watch.State = MinecraftState.Ended OrElse Watch.State = MinecraftState.Canceled Then Continue For
NewWatcherList.Add(Watch)
Next
NewWatcherList.Add(Me)
@@ -90,14 +90,13 @@
'初始化时钟
RunInNewThread(Sub()
Try
MinecraftBeforeLaunch = GetAllMinecraftWindowHandle(False).Keys.ToList
Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse Loader.State = LoadState.Aborted
Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse State = MinecraftState.Canceled OrElse Loader.State = LoadState.Aborted
TimerWindow()
TimerLog()
'设置窗口标题
For i = 1 To 3
If IsWindowFinished AndAlso WindowTitle <> "" AndAlso State = MinecraftState.Running AndAlso Not GameProcess.HasExited Then
Dim RealTitle As String = WindowTitle.Replace("{time}", Date.Now.ToShortTimeString)
If IsWindowFinished AndAlso IsWindowAppeared AndAlso WindowTitle <> "" AndAlso State = MinecraftState.Running AndAlso Not GameProcess.HasExited Then
Dim RealTitle As String = WindowTitle.Replace("{date}", Date.Now.ToString("yyyy/M/d")).Replace("{time}", Date.Now.ToString("HH:mm:ss"))
SetWindowText(WindowHandle, RealTitle.ToCharArray)
End If
Thread.Sleep(64)
@@ -117,7 +116,7 @@
Get
Return _State
End Get
Set(ByVal value As MinecraftState)
Set(value As MinecraftState)
If _State = value Then Exit Property
_State = value
WatcherStateChanged()
@@ -128,6 +127,7 @@
Running
Crashed
Ended
Canceled
End Enum
'日志
@@ -143,7 +143,7 @@
'输出文本
Dim Copyed As New List(Of String)
SyncLock WaitingLogLock
If WaitingLog.Count = 0 Then Exit Sub
If Not WaitingLog.Any() Then Exit Sub
Copyed = WaitingLog
WaitingLog = New List(Of String)(1000)
End SyncLock
@@ -192,7 +192,7 @@
If LogProgress < 2 AndAlso Text.Contains("Setting user:") Then
WatcherLog("日志 2/5:游戏用户已设置") '仅确保支持 Minecraft 1.7+
LogProgress = 2
ElseIf LogProgress < 3 AndAlso Text.ToLower.Contains("lwjgl version") Then
ElseIf LogProgress < 3 AndAlso Text.ContainsF("lwjgl version", True) Then
WatcherLog("日志 3/5:LWJGL 版本已确认")
LogProgress = 3
ElseIf LogProgress < 4 AndAlso (Text.Contains("OpenAL initialized") OrElse Text.Contains("Starting up SoundSystem")) Then
@@ -206,7 +206,7 @@
'Log(Text)
'关闭与崩溃检测
If Not Text.Contains("[CHAT]") Then
If Text.Contains("Someone is closing me!") Then
If Text.Contains("Someone is closing me!") OrElse Text.Contains("Restarting Minecraft with command") Then '#1258
WatcherLog("识别为关闭的 Log:" & Text)
State = MinecraftState.Ended
ElseIf Text.Contains("Crash report saved to") OrElse Text.Contains("This crash report has been saved to:") Then
@@ -248,79 +248,90 @@
'窗口检查
Private IsWindowAppeared As Boolean = False
''' <summary>
''' 窗口检查是否已经完成。这不一定代表着找到了窗口(如果没有找到,IsWindowAppeared 仍为 False)。
''' </summary>
Private IsWindowFinished As Boolean = False
Private WindowHandle As IntPtr
Private MinecraftBeforeLaunch As List(Of IntPtr)
Private Sub TimerWindow()
Try
If GameProcess.HasExited Then Exit Sub
If Not IsWindowFinished Then
'获取全部窗口,检查是否有新增的
Dim MinecraftWindows = GetAllMinecraftWindowHandle(True)
For Each Window In MinecraftBeforeLaunch
If MinecraftWindows.ContainsKey(Window) Then MinecraftWindows.Remove(Window)
Next
If MinecraftWindows.Count = 0 Then Exit Sub
'已找到窗口
If MinecraftWindows.Values(0) Then
'已找到 Minecraft 窗口
WindowHandle = MinecraftWindows.Keys(0)
WatcherLog("Minecraft 窗口已加载:" & WindowHandle.ToInt64)
IsWindowFinished = True
'最大化
If Setup.Get("LaunchArgumentWindowType") = 4 Then
RunInNewThread(Sub()
Try
'如果最大化导致屏幕渲染大小不对,那是 MC 的 Bug,不是我的 Bug
'……虽然我很想这样说,但总有人反馈,算了
Thread.Sleep(1000)
ShowWindow(WindowHandle, 3)
Catch ex As Exception
Log(ex, "最大化 Minecraft 窗口时出现错误")
End Try
End Sub, "MinecraftWindowMaximize")
End If
ElseIf Not IsWindowAppeared Then
'已找到 FML 窗口
WatcherLog("FML 窗口已加载:" & MinecraftWindows.Keys(0).ToInt64)
If IsWindowFinished Then Exit Sub
'获取全部窗口,检查是否有新增的
Dim MinecraftWindow As KeyValuePair(Of IntPtr, String)? = Nothing
Try
MinecraftWindow = TryGetMinecraftWindow()
Catch ex As ComponentModel.Win32Exception
'拒绝访问(#1062)
Log(ex, "由于反作弊或安全软件拦截,PCL 无法操作游戏窗口", LogLevel.Hint)
IsWindowFinished = True
End Try
If MinecraftWindow Is Nothing Then Exit Sub
Dim MinecraftWindowName = MinecraftWindow.Value.Value, MinecraftWindowHandle = MinecraftWindow.Value.Key
'已找到窗口
If Not MinecraftWindowName.StartsWithF("FML") Then
'已找到 Minecraft 窗口
WindowHandle = MinecraftWindowHandle
WatcherLog($"Minecraft 窗口已加载:{MinecraftWindowName}({MinecraftWindowHandle.ToInt64})")
IsWindowFinished = True
'最大化
If Setup.Get("LaunchArgumentWindowType") = 4 Then
RunInNewThread(
Sub()
Try
'如果最大化导致屏幕渲染大小不对,那是 MC 的 Bug,不是我的 Bug
'……虽然我很想这样说,但总有人反馈,算了
Thread.Sleep(2000)
ShowWindow(WindowHandle, 3)
WatcherLog($"已最大化 Minecraft 窗口:{MinecraftWindowHandle.ToInt64}")
Catch ex As Exception
Log(ex, "最大化 Minecraft 窗口时出现错误")
End Try
End Sub, "MinecraftWindowMaximize")
End If
IsWindowAppeared = True
ElseIf Not IsWindowAppeared Then
'已找到 FML 窗口
WatcherLog("FML 窗口已加载:" & MinecraftWindowName & "(" & MinecraftWindowHandle.ToInt64 & ")")
End If
IsWindowAppeared = True
Catch ex As Exception
Log(ex, "检查 Minecraft 窗口失败", LogLevel.Feedback)
End Try
End Sub
''' <summary>
''' 获取所有 Minecraft 窗口句柄。
''' Value: 是否为 Minecraft 窗口,而不是 FML 窗口。
''' 获取可能是当前进程对应的 Minecraft 窗口的句柄和标题。
''' Nothing 代表未找到。
''' </summary>
''' <param name="CanUseFml">是否包含 FML 窗口</param>
Private Function GetAllMinecraftWindowHandle(CanUseFml As Boolean) As Dictionary(Of IntPtr, Boolean)
Dim AllList As New Dictionary(Of IntPtr, Boolean)
EnumWindows(Sub(hwnd As IntPtr, lParam As Integer)
'检查类名
Dim str As New StringBuilder(512)
GetClassName(hwnd, str, str.Capacity)
Dim ClassName As String = str.ToString
If Not (ClassName = "GLFW30" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Exit Sub
'检查窗口标题名
str = New StringBuilder(512)
GetWindowText(hwnd, str, str.Capacity)
Dim WindowText As String = str.ToString
If CanUseFml AndAlso WindowText.StartsWith("FML") Then
AllList.Add(hwnd, False)
ElseIf Not (WindowText.StartsWith("GLFW") OrElse WindowText = "PopupMessageWindow") Then
'有的 Mod 可以修改窗口标题,不能检测是否为 Minecraft 打头
'部分版本会搞个 GLFW message window 出来所以得反选
AllList.Add(hwnd, True)
End If
'If WindowText.StartsWith("Minecraft") Then
' AllList.Add(hwnd, True)
'ElseIf CanUseFml AndAlso WindowText.StartsWith("FML") Then
' AllList.Add(hwnd, False)
'End If
End Sub, 0)
Return AllList
Private Function TryGetMinecraftWindow() As KeyValuePair(Of IntPtr, String)?
TryGetMinecraftWindow = Nothing
EnumWindows(
Sub(hwnd As IntPtr, lParam As Integer)
If TryGetMinecraftWindow IsNot Nothing Then Exit Sub
'检查类名
Dim str As New StringBuilder(512)
GetClassName(hwnd, str, str.Capacity)
Dim ClassName As String = str.ToString
If Not (ClassName = "GLFW30" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Exit Sub
'获取窗口标题名
str = New StringBuilder(512)
GetWindowText(hwnd, str, str.Capacity)
Dim WindowText As String = str.ToString
'有的 Mod 可以修改窗口标题,所以不能检测是否为 Minecraft 打头,这并不准确
'部分版本会搞个 GLFW message window 出来所以得反选
If Not (WindowText.StartsWithF("FML") OrElse (WindowText <> "PopupMessageWindow") AndAlso Not WindowText.StartsWithF("GLFW")) Then Exit Sub
'获取窗口关联的进程
Dim ProcessId As Integer
GetWindowThreadProcessId(hwnd, ProcessId)
Try
If Process.GetProcessById(ProcessId).StartTime < GameProcess.StartTime Then Exit Sub '需要是此后启动的进程
Catch ex As Exception
Log(ex, "枚举 Minecraft 窗口进程失败")
Exit Sub
End Try
'返回
TryGetMinecraftWindow = New KeyValuePair(Of IntPtr, String)(hwnd, WindowText)
End Sub, 0)
Return TryGetMinecraftWindow
End Function
Private Delegate Sub EnumWindowsSub(hwnd As IntPtr, lParam As Integer)
Private Declare Function EnumWindows Lib "user32" (hWnd As EnumWindowsSub, lParam As Integer) As Boolean
@@ -328,6 +339,7 @@
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (hWnd As Integer, str As StringBuilder, maxCount As Integer) As Integer
Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (hWnd As Integer, str As String) As Boolean
Private Declare Function ShowWindow Lib "user32" (hWnd As IntPtr, cmdWindow As UInteger) As Boolean
Private Declare Function GetWindowThreadProcessId Lib "user32" (hWnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
'崩溃处理
Private Sub Crashed()
@@ -356,7 +368,7 @@
'强制关闭
Public Sub Kill()
State = MinecraftState.Ended
State = MinecraftState.Canceled
WatcherLog("尝试强制结束 Minecraft 进程")
Try
If Not GameProcess.HasExited Then GameProcess.Kill()
@@ -0,0 +1,83 @@
<Grid x:Class="MyCompItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="PanBack" Height="64"
RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="17" />
<RowDefinition Height="18" />
<RowDefinition Height="16" />
<RowDefinition Height="1.1*" />
</Grid.RowDefinitions>
<!-- Logo -->
<Border Grid.Column="1" Grid.Row="1" Grid.RowSpan="3" IsHitTestVisible="False" SnapsToDevicePixels="True" UseLayoutRounding="True"
HorizontalAlignment="Right" VerticalAlignment="Center" Width="50" Height="50">
<Border.Clip>
<RectangleGeometry Rect="0,0,50,50" RadiusX="6" RadiusY="6" />
</Border.Clip>
<Image x:Name="PathLogo" RenderOptions.BitmapScalingMode="HighQuality" />
</Border>
<!-- 标题 -->
<StackPanel Grid.Column="3" Grid.ColumnSpan="2" Grid.Row="1" VerticalAlignment="Bottom" Margin="0,1,0,0" Orientation="Horizontal"
IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False">
<TextBlock x:Name="LabTitle" TextTrimming="WordEllipsis" FontSize="14" Foreground="{DynamicResource ColorBrush1}" />
<TextBlock x:Name="LabTitleRaw" TextTrimming="WordEllipsis" FontSize="12" Foreground="{StaticResource ColorBrushGray1}" Opacity="0.4" VerticalAlignment="Bottom" Visibility="Collapsed" />
</StackPanel>
<!-- Tag 与 详情 -->
<StackPanel x:Name="PanTags" Grid.Row="2" Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Bottom" Margin="-1,0,1,0" Visibility="Collapsed">
<!--<Border Background="{DynamicResource ColorBrush6}" Padding="3,1" CornerRadius="3" Margin="0,0,4,0" SnapsToDevicePixels="True" UseLayoutRounding="False">
<TextBlock Text="科技" Foreground="{DynamicResource ColorBrush2}" FontSize="11" />
</Border>-->
</StackPanel>
<TextBlock x:Name="LabInfo" Grid.Row="2" Grid.Column="4" VerticalAlignment="Bottom" Margin="0,0,3,0.5"
TextTrimming="CharacterEllipsis" FontSize="12" Foreground="{StaticResource ColorBrushGray3}"
IsHitTestVisible="True" SnapsToDevicePixels="False" UseLayoutRounding="False"
ToolTipService.InitialShowDelay="100" ToolTipService.BetweenShowDelay="100"
ToolTipService.Placement="Relative" ToolTipService.PlacementRectangle="-16,-10,500,10000">
<TextBlock.ToolTip>
<ToolTip x:Name="ToolTipInfo" Style="{StaticResource ExtendTextToolTip}" />
</TextBlock.ToolTip>
</TextBlock>
<!-- 下边栏 -->
<Grid Grid.Row="3" Grid.Column="3" Grid.ColumnSpan="2" VerticalAlignment="Bottom"
IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnVersion1" Width="Auto" />
<ColumnDefinition x:Name="ColumnVersion2" Width="Auto" SharedSizeGroup="CompItemVersion" />
<ColumnDefinition x:Name="ColumnVersion3" Width="0.7*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="55" />
<ColumnDefinition Width="1*" />
<ColumnDefinition x:Name="ColumnTime1" Width="Auto" />
<ColumnDefinition x:Name="ColumnTime2" Width="Auto" MinWidth="57" SharedSizeGroup="CompItemTime" />
<ColumnDefinition x:Name="ColumnTime3" Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" SharedSizeGroup="CompItemSource" />
<ColumnDefinition Width="1.7*" />
</Grid.ColumnDefinitions>
<Path x:Name="PathVersion" Grid.Column="0" Fill="{StaticResource ColorBrushGray3}" Stretch="Uniform" Height="11"
Data="M940.4 463.7L773.3 174.2c-17.3-30-49.2-48.4-83.8-48.4H340.2c-34.6 0-66.5 18.5-83.8 48.4L89.2 463.7c-17.3 30-17.3 66.9 0 96.8L256.4 850c17.3 30 49.2 48.4 83.8 48.4h349.2c34.6 0 66.5-18.5 83.8-48.4l167.2-289.5c17.3-29.9 17.3-66.8 0-96.8z m-94.6 96.8L725.9 768.1c-17.3 30-49.2 48.4-83.8 48.4H387.5c-34.6 0-66.5-18.5-83.8-48.4L183.9 560.5c-17.3-30-17.3-66.9 0-96.8l119.8-207.5c17.3-30 49.2-48.4 83.8-48.4h254.6c34.6 0 66.5 18.5 83.8 48.4l119.8 207.5c17.3 30 17.3 66.9 0.1 96.8z M522.3 321.2c-2.5-0.1-5-0.2-7.5-0.2-119.9 0-214 110.3-186.3 235 15.8 70.9 71.5 126.6 142.4 142.4 17.5 3.9 34.7 5.4 51.4 4.7 102.1-3.9 183.6-87.9 183.6-191 0.1-103-81.5-187-183.6-190.9z m68.6 269.1c-18.5 18-43 28.9-68.6 30.7l-6 0.3c-30.2 0.4-58.6-11.4-79.7-33-19.5-20.1-30.7-47-30.9-75-0.3-29.6 11.1-57.4 32-78.3 20.6-20.6 48-32 77.2-32 2.5 0 5 0.1 7.5 0.3 26.7 1.8 51.5 13.2 70.5 32.5 19.6 20 30.8 46.9 31.2 74.9 0.2 30.2-11.5 58.6-33.2 79.6z" />
<TextBlock x:Name="LabVersion" Grid.Column="1" Margin="4,0,2,0" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray3}" FontSize="12"
TextTrimming="WordEllipsis" />
<Path x:Name="PathDownload" Grid.Column="3" Fill="{StaticResource ColorBrushGray4}" Stretch="Uniform" Height="10.5"
Data="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
<TextBlock x:Name="LabDownload" Grid.Column="4" Margin="5,0,2,0" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray4}" FontSize="12" />
<Path x:Name="PathTime" Grid.Column="6" Fill="{StaticResource ColorBrushGray4}" Stretch="Uniform" Height="11.5" Margin="0,0,1,0"
Data="M810 403l-39 39c-10 10-28 10-39 0l-162-162v412c0 15-12 28-28 28h-56c-15 0-28-12-28-28v-412l-162 162c-10 10-28 10-39 0l-39-39c-10-10-10-28 0-39l278-278c10-10 28-10 39 0l278 278c10 10 10 28-0 39zM568 946h-112v-112h112v112z" />
<TextBlock x:Name="LabTime" Grid.Column="7" Margin="5,0,2,0" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray4}" FontSize="12" />
<Path x:Name="PathSource" Grid.Column="9" Fill="{StaticResource ColorBrushGray4}" Stretch="Uniform" Height="11.5"
Data="M511 143c-203 0-369 165-369 369 0 203 165 369 369 369s369-165 369-369c0-203-165-369-369-369z m0 673c-29 0-68-59-89-159l178 0c-20 100-59 159-89 159z m-98-224c-2-24-3-51-3-79 0-29 1-57 4-83l197 0c2 25 4 53 4 83 0 28-1 54-3 79l-198-0z m98-383c29 0 67 58 88 156l-177-0c20-98 59-155 88-155z m164 221l128 0c7 26 11 54 11 82 0 27-3 54-10 80l-129-0c2-26 3-52 3-79 0-28-1-56-4-83z m101-64l-110-0c-7-37-16-72-28-102-4-11-9-22-15-33 66 25 121 74 155 135z m-376-135c-5 10-10 21-15 33-12 30-21 64-28 102l-110-0c34-60 89-109 154-134z m-181 199l128 0c-2 27-3 54-3 83 0 27 1 53 3 79l-127-0v6c-8-27-12-55-12-85-0-29 3-57 11-83z m24 227l112 0c7 38 16 74 29 105 4 11 9 22 15 33-67-26-122-76-156-139zM621 795c5-10 10-21 15-33 12-30 22-66 29-105l111 0c-34 62-89 111-156 137z" />
<TextBlock x:Name="LabSource" Grid.Column="10" Margin="5,0,2,0" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray4}" FontSize="12" />
</Grid>
</Grid>
@@ -0,0 +1,300 @@
Public Class MyCompItem
#Region "基础属性"
Public Uuid As Integer = GetUuid()
'Logo
Private _Logo As String = ""
Public Property Logo As String
Get
Return _Logo
End Get
Set(value As String)
If _Logo = value OrElse value Is Nothing Then Exit Property
_Logo = value
Dim FileAddress = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png"
Try
If _Logo.StartsWithF("http", True) Then
'网络图片
If File.Exists(FileAddress) Then
PathLogo.Source = New MyBitmap(FileAddress)
ElseIf _Logo.EndsWithF(".webp", True) Then 'Modrinth 林业 Mod 使用了不支持的 WebP 格式 Logo
Log($"[Comp] 发现不支持的 WebP 格式图标,已更改为默认图标:{_Logo}")
PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
Else
PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
RunInNewThread(Sub() LogoLoader(FileAddress), "Comp Logo Loader " & Uuid & "#", ThreadPriority.BelowNormal)
End If
Else
'位图
PathLogo.Source = New MyBitmap(_Logo)
End If
Catch ex As IOException
Log(ex, "加载资源工程图标时读取失败(" & FileAddress & ")")
Catch ex As ArgumentException
'考虑缓存的图片本身可能有误
Log(ex, "可视化资源工程图标失败(" & FileAddress & ")")
Try
File.Delete(FileAddress)
Log("[Comp] 已清理损坏的资源工程图标:" & FileAddress)
Catch exx As Exception
Log(exx, "清理损坏的资源工程图标缓存失败(" & FileAddress & ")", LogLevel.Hint)
End Try
Catch ex As Exception
Log(ex, "加载资源工程图标失败(" & value & ")")
End Try
End Set
End Property
'后台加载 Logo
Private Sub LogoLoader(LocalFileAddress As String)
Dim Retried As Boolean = False
Dim DownloadEnd As String = GetUuid()
RetryStart:
Try
'CurseForge 图片使用缩略图
Dim Url As String = _Logo
If Url.Contains("/256/256/") AndAlso GetPixelSize(1) <= 1.25 AndAlso Not Retried Then
Url = Url.Replace("/256/256/", "/64/64/") '#3075:部分 Mod 不存在 64x64 图标,所以重试时不再缩小
End If
'下载图片
NetDownload(Url, LocalFileAddress & DownloadEnd, True)
Dim LoadError As Exception = Nothing
RunInUiWait(
Sub()
Try
'在地址更换时取消加载
If LocalFileAddress <> $"{PathTemp}CompLogo\{GetHash(_Logo)}.png" Then Exit Sub
'在完成正常加载后才保存缓存图片
PathLogo.Source = New MyBitmap(LocalFileAddress & DownloadEnd)
Catch ex As Exception
Log(ex, $"读取资源工程图标失败({LocalFileAddress})")
File.Delete(LocalFileAddress & DownloadEnd)
LoadError = ex
End Try
End Sub)
If LoadError IsNot Nothing Then Throw LoadError
If File.Exists(LocalFileAddress) Then
File.Delete(LocalFileAddress & DownloadEnd)
Else
FileIO.FileSystem.MoveFile(LocalFileAddress & DownloadEnd, LocalFileAddress)
End If
Catch ex As Exception
If Not Retried Then
Retried = True
GoTo RetryStart
Else
Log(ex, $"下载资源工程图标失败({_Logo})")
RunInUi(Sub() PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png"))
End If
End Try
End Sub
'标题
Public Property Title As String
Get
Return LabTitle.Text
End Get
Set(value As String)
If LabTitle.Text = value Then Exit Property
LabTitle.Text = value
End Set
End Property
'副标题
Public Property SubTitle As String
Get
Return If(LabTitleRaw?.Text, "")
End Get
Set(value As String)
If LabTitleRaw.Text = value Then Exit Property
LabTitleRaw.Text = value
LabTitleRaw.Visibility = If(value = "", Visibility.Collapsed, Visibility.Visible)
End Set
End Property
'描述
Public Property Description As String
Get
Return LabInfo.Text
End Get
Set(value As String)
If LabInfo.Text = value Then Exit Property
LabInfo.Text = value
End Set
End Property
'指向时扩展描述
Private Sub LabInfo_MouseEnter(sender As Object, e As MouseEventArgs) Handles LabInfo.MouseEnter
If IsTextTrimmed(LabInfo) Then
ToolTipInfo.Content = LabInfo.Text
ToolTipInfo.Width = LabInfo.ActualWidth + 25
LabInfo.ToolTip = ToolTipInfo
Else
LabInfo.ToolTip = Nothing
End If
End Sub
Private Function IsTextTrimmed(textBlock As TextBlock) As Boolean
Dim typeface As New Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch)
Dim formattedText As New FormattedText(textBlock.Text, Thread.CurrentThread.CurrentCulture, textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground, DPI)
Return formattedText.Width > textBlock.ActualWidth
End Function
'Tag
Public WriteOnly Property Tags As List(Of String)
Set(value As List(Of String))
PanTags.Children.Clear()
PanTags.Visibility = If(value.Any(), Visibility.Visible, Visibility.Collapsed)
For Each TagText In value
Dim NewTag = GetObjectFromXML(
"<Border xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
Background=""#11000000"" Padding=""3,1"" CornerRadius=""3"" Margin=""0,0,3,0""
SnapsToDevicePixels=""True"" UseLayoutRounding=""False"">
<TextBlock Text=""" & TagText & """ Foreground=""#868686"" FontSize=""11"" />
</Border>")
PanTags.Children.Add(NewTag)
Next
End Set
End Property
#End Region
#Region "点击"
'触发点击事件
Public Event Click(sender As Object, e As MouseButtonEventArgs)
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
If IsMouseDown Then
RaiseEvent Click(sender, e)
If e.Handled Then Exit Sub
Log("[Control] 按下资源工程列表项:" & LabTitle.Text)
End If
End Sub
Private Sub ProjectClick(sender As MyCompItem, e As EventArgs) Handles Me.Click
'记录当前展开的卡片标题(#2712)
Dim Titles As New List(Of String)
If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
For Each Card As MyCard In FrmDownloadCompDetail.PanMain.Children
If Card.Title <> "" AndAlso Not Card.IsSwaped Then Titles.Add(Card.Title)
Next
Log("[Comp] 记录当前已展开的卡片:" & String.Join("、", Titles))
FrmMain.PageCurrent.Additional(1) = Titles
End If
'打开详情页
Dim TargetVersion As String
Dim TargetLoader As CompModLoaderType
If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
TargetVersion = FrmMain.PageCurrent.Additional(2)
TargetLoader = FrmMain.PageCurrent.Additional(3)
Else
Select Case CType(sender.Tag, CompProject).Type
Case CompType.Mod
TargetVersion = If(PageDownloadMod.Loader.Input.GameVersion, "")
TargetLoader = PageDownloadMod.Loader.Input.ModLoader
Case CompType.ModPack
TargetVersion = If(PageDownloadPack.Loader.Input.GameVersion, "")
Case Else 'CompType.ResourcePack
'FUTURE: Res
TargetVersion = "" 'If(PageDownloadResource.Loader.Input.GameVersion, "")
End Select
End If
If CType(sender.Tag, CompProject).Type <> CompType.Mod Then TargetLoader = CompModLoaderType.Any
FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
.Additional = {sender.Tag, New List(Of String), TargetVersion, TargetLoader}})
End Sub
'鼠标点击判定
Private IsMouseDown As Boolean = False
Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
If IsMouseOver AndAlso CanInteraction Then IsMouseDown = True
End Sub
Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
IsMouseDown = False
End Sub
#End Region
#Region "后加载指向背景"
Private _RectBack As Border = Nothing
Public ReadOnly Property RectBack As Border
Get
If _RectBack Is Nothing Then
Dim Rect As New Border With {
.Name = "RectBack",
.CornerRadius = New CornerRadius(3),
.RenderTransform = New ScaleTransform(0.8, 0.8),
.RenderTransformOrigin = New Point(0.5, 0.5),
.BorderThickness = New Thickness(GetWPFSize(1)),
.SnapsToDevicePixels = True,
.IsHitTestVisible = False,
.Opacity = 0
}
Rect.SetResourceReference(Border.BackgroundProperty, "ColorBrush7")
Rect.SetResourceReference(Border.BorderBrushProperty, "ColorBrush6")
SetColumnSpan(Rect, 999)
SetRowSpan(Rect, 999)
Children.Insert(0, Rect)
_RectBack = Rect
'<!--<Border x:Name = "RectBack" CornerRadius="3" RenderTransformOrigin="0.5,0.5" SnapsToDevicePixels="True"
'IsHitTestVisible = "False" Opacity="0" BorderThickness="1"
'Grid.ColumnSpan = "4" Background="{DynamicResource ColorBrush7}" BorderBrush="{DynamicResource ColorBrush6}"/>-->
End If
Return _RectBack
End Get
End Property
#End Region
Private StateLast As String
''' <summary>
''' 是否允许交互。目前仅用于 PageDownloadCompDetail 的顶部栏展示:若关闭碰撞检测,则无法展开 Tooltip。
''' </summary>
Public CanInteraction As Boolean = True
Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp
If Not CanInteraction Then Exit Sub
'判断当前颜色
Dim StateNew As String, Time As Integer
If IsMouseOver Then
If IsMouseDown Then
StateNew = "MouseDown"
Time = 120
Else
StateNew = "MouseOver"
Time = 120
End If
Else
StateNew = "Idle"
Time = 180
End If
If StateLast = StateNew Then Exit Sub
StateLast = StateNew
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
Dim Ani As New List(Of AniData)
If IsMouseOver Then
Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
})
If IsMouseDown Then
Ani.Add(AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
Else
Ani.Add(AaScaleTransform(RectBack, 1 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
End If
Else
Ani.AddRange({
AaOpacity(RectBack, -RectBack.Opacity, Time),
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
AaScaleTransform(RectBack, -0.196, 1,,, True)
})
End If
AniStart(Ani, "CompItem Color " & Uuid)
Else
'无动画
AniStop("CompItem Color " & Uuid)
If _RectBack IsNot Nothing Then RectBack.Opacity = 0
End If
End Sub
End Class
@@ -0,0 +1,60 @@
<Grid x:Class="MyLocalModItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL;assembly="
x:Name="PanBack" Height="44"
RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6" />
<ColumnDefinition Width="34" />
<ColumnDefinition Width="7" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="4" x:Name="ColumnPaddingRight" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="17" />
<RowDefinition Height="18" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<!-- Logo -->
<Border Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" IsHitTestVisible="False" SnapsToDevicePixels="True" UseLayoutRounding="True"
HorizontalAlignment="Right" VerticalAlignment="Center" Width="34" Height="34">
<Border.Clip>
<RectangleGeometry Rect="0,0,34,34" RadiusX="6" RadiusY="6" />
</Border.Clip>
<Image x:Name="PathLogo" RenderOptions.BitmapScalingMode="HighQuality" />
</Border>
<!-- 标题 -->
<StackPanel Grid.Column="3" Grid.ColumnSpan="2" Grid.Row="1" VerticalAlignment="Bottom" Margin="0,1,0,0" Orientation="Horizontal"
SnapsToDevicePixels="False" UseLayoutRounding="False">
<TextBlock x:Name="LabTitle" TextTrimming="WordEllipsis" FontSize="14" IsHitTestVisible="False" />
<TextBlock x:Name="LabTitleRaw" TextTrimming="WordEllipsis" FontSize="12" IsHitTestVisible="False"
Foreground="{StaticResource ColorBrushGray1}" Opacity="0.4" VerticalAlignment="Bottom" Visibility="Collapsed" />
<!-- 更新按钮 -->
<local:MyIconButton Width="21" Height="21" Margin="-2,-1.6,0,0" x:Name="BtnUpdate" Theme="Black" Opacity="0.4" Visibility="Collapsed"
ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="100" ToolTipService.VerticalOffset="-9"
Logo="M640 768H384l-32-32V509H213L190 454l298-298h45l298 298L810 509h-138v226z m-224-64h192V477l32-32h93L512 223 290 445H384l32 32zM352 831h320v64h-320z" />
</StackPanel>
<!--<Grid Grid.Column="3" Grid.ColumnSpan="2" Grid.Row="1" VerticalAlignment="Bottom" Margin="0,1,0,0" IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="LabTitle" TextTrimming="WordEllipsis" FontSize="14" Grid.Column="0" />
<TextBlock x:Name="LabTitleRaw" TextTrimming="WordEllipsis" FontSize="12" Grid.Column="1"
Foreground="{StaticResource ColorBrushGray1}" Opacity="0.4" VerticalAlignment="Bottom" Visibility="Collapsed" />
<local:MyIconTextButton Grid.Column="2" Text="更新" />
</Grid>-->
<!-- Tag 与 详情 -->
<StackPanel x:Name="PanTags" Grid.Row="2" Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Bottom" Margin="-1,0,1,0" Visibility="Collapsed" IsHitTestVisible="False">
<!--<Border Background="{DynamicResource ColorBrush6}" Padding="3,1" CornerRadius="3" Margin="0,0,4,0" SnapsToDevicePixels="True" UseLayoutRounding="False">
<TextBlock Text="科技" Foreground="{DynamicResource ColorBrush2}" FontSize="11" />
</Border>-->
</StackPanel>
<TextBlock x:Name="LabInfo" Grid.Row="2" Grid.Column="4" VerticalAlignment="Bottom" Margin="0,0,3,1"
TextTrimming="CharacterEllipsis" FontSize="12" Foreground="{StaticResource ColorBrushGray3}"
IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False" />
</Grid>
@@ -0,0 +1,536 @@
Imports System.Windows.Forms
Public Class MyLocalModItem
#Region "基础属性"
Public Uuid As Integer = GetUuid()
'Logo
Private _Logo As String = ""
Public Property Logo As String
Get
Return _Logo
End Get
Set(value As String)
If _Logo = value OrElse value Is Nothing Then Exit Property
_Logo = value
Dim FileAddress = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png"
Try
If _Logo.StartsWithF("http", True) Then
'网络图片
If File.Exists(FileAddress) Then
PathLogo.Source = New MyBitmap(FileAddress)
ElseIf _Logo.EndsWithF(".webp", True) Then 'Modrinth 林业 Mod 使用了不支持的 WebP 格式 Logo
Log($"[LocalModItem] 发现不支持的 WebP 格式图标,已更改为默认图标:{_Logo}")
PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
Else
PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
RunInNewThread(Sub() LogoLoader(FileAddress), "Comp Logo Loader " & Uuid & "#", ThreadPriority.BelowNormal)
End If
Else
'位图
PathLogo.Source = New MyBitmap(_Logo)
End If
Catch ex As IOException
Log(ex, "加载本地 Mod 图标时读取失败(" & FileAddress & ")")
Catch ex As ArgumentException
'考虑缓存的图片本身可能有误
Log(ex, "可视化本地 Mod 图标失败(" & FileAddress & ")")
Try
File.Delete(FileAddress)
Log("[LocalModItem] 已清理损坏的本地 Mod 图标:" & FileAddress)
Catch exx As Exception
Log(exx, "清理损坏的本地 Mod 图标缓存失败(" & FileAddress & ")", LogLevel.Hint)
End Try
Catch ex As Exception
Log(ex, "加载本地 Mod 图标失败(" & value & ")")
End Try
End Set
End Property
'后台加载 Logo
Private Sub LogoLoader(LocalFileAddress As String)
Dim Retried As Boolean = False
Dim DownloadEnd As String = GetUuid()
RetryStart:
Try
'CurseForge 图片使用缩略图
Dim Url As String = _Logo
If Url.Contains("/256/256/") AndAlso GetPixelSize(1) <= 1.25 AndAlso Not Retried Then
Url = Url.Replace("/256/256/", "/64/64/") '#3075:部分 Mod 不存在 64x64 图标,所以重试时不再缩小
End If
'下载图片
NetDownload(Url, LocalFileAddress & DownloadEnd, True)
Dim LoadError As Exception = Nothing
RunInUiWait(
Sub()
Try
'在地址更换时取消加载
If LocalFileAddress <> $"{PathTemp}CompLogo\{GetHash(_Logo)}.png" Then Exit Sub
'在完成正常加载后才保存缓存图片
PathLogo.Source = New MyBitmap(LocalFileAddress & DownloadEnd)
Catch ex As Exception
Log(ex, "读取本地 Mod 图标失败(" & LocalFileAddress & ")")
File.Delete(LocalFileAddress & DownloadEnd)
LoadError = ex
End Try
End Sub)
If LoadError IsNot Nothing Then Throw LoadError
If File.Exists(LocalFileAddress) Then
File.Delete(LocalFileAddress & DownloadEnd)
Else
FileIO.FileSystem.MoveFile(LocalFileAddress & DownloadEnd, LocalFileAddress)
End If
Catch ex As Exception
If Not Retried Then
Retried = True
GoTo RetryStart
Else
Log(ex, $"下载本地 Mod 图标失败({_Logo})")
RunInUi(Sub() PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png"))
End If
End Try
End Sub
'标题
Private _Title As String
Public Property Title As String
Get
Return _Title
End Get
Set(value As String)
Dim RawValue = value
Select Case Entry.State
Case McMod.McModState.Fine
LabTitle.TextDecorations = Nothing
Case McMod.McModState.Disabled
LabTitle.TextDecorations = TextDecorations.Strikethrough
Case McMod.McModState.Unavaliable
LabTitle.TextDecorations = TextDecorations.Strikethrough
value &= " [错误]"
End Select
If LabTitle.Text = value Then Exit Property
LabTitle.Text = value
_Title = RawValue
End Set
End Property
'副标题
Public Property SubTitle As String
Get
Return If(LabTitleRaw?.Text, "")
End Get
Set(value As String)
If LabTitleRaw.Text = value Then Exit Property
LabTitleRaw.Text = value
LabTitleRaw.Visibility = If(value = "", Visibility.Collapsed, Visibility.Visible)
End Set
End Property
'描述
Public Property Description As String
Get
Return LabInfo.Text
End Get
Set(value As String)
If LabInfo.Text = value Then Exit Property
LabInfo.Text = value
End Set
End Property
'Tag
Public WriteOnly Property Tags As List(Of String)
Set(value As List(Of String))
PanTags.Children.Clear()
PanTags.Visibility = If(value.Any(), Visibility.Visible, Visibility.Collapsed)
For Each TagText In value
Dim NewTag = GetObjectFromXML(
"<Border xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
Background=""#11000000"" Padding=""3,1"" CornerRadius=""3"" Margin=""0,0,3,0""
SnapsToDevicePixels=""True"" UseLayoutRounding=""False"">
<TextBlock Text=""" & TagText & """ Foreground=""#868686"" FontSize=""11"" />
</Border>")
PanTags.Children.Add(NewTag)
Next
End Set
End Property
'相关联的 Mod
Public Property Entry As McMod
Get
Return Tag
End Get
Set(value As McMod)
Tag = value
End Set
End Property
#End Region
#Region "点击与勾选"
'触发点击事件
Public Event Click(sender As Object, e As MouseButtonEventArgs)
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
If IsMouseDown Then
RaiseEvent Click(sender, e)
If e.Handled Then Exit Sub
Log("[Control] 按下本地 Mod 列表项:" & LabTitle.Text)
End If
End Sub
'鼠标点击判定
Private IsMouseDown As Boolean = False
Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
If Not IsMouseDirectlyOver Then Exit Sub
IsMouseDown = True
If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = False
End Sub
Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
IsMouseDown = False
If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = True
End Sub
'滑动选中
Private Shared SwipeStart As Integer, SwipeEnd As Integer
Private Shared Swiping As Boolean = False
Private Shared SwipToState As Boolean '被滑动到的目标应将 Checked 改为此值
Private Sub Button_MouseSwipeStart(sender As Object, e As Object) Handles Me.MouseLeftButtonDown
'开始滑动
Dim Index = CType(Parent, StackPanel).Children.IndexOf(Me)
SwipeStart = Index
SwipeEnd = Index
Swiping = True
SwipToState = Not Checked
FrmVersionMod.CardSelect.IsHitTestVisible = False '暂时禁用下边栏
End Sub
Private Sub Button_MouseSwipe(sender As Object, e As Object) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonUp
'结束滑动
If Mouse.LeftButton <> MouseButtonState.Pressed OrElse Not Swiping Then
Swiping = False
FrmVersionMod.CardSelect.IsHitTestVisible = True
Exit Sub
End If
'计算滑动范围
Dim Index = CType(Parent, StackPanel).Children.IndexOf(Me)
SwipeStart = Math.Min(SwipeStart, Index)
SwipeEnd = Math.Max(SwipeEnd, Index)
'勾选所有范围中的项
If SwipeStart = SwipeEnd Then Exit Sub
For i = SwipeStart To SwipeEnd
Dim Item As MyLocalModItem = CType(Parent, StackPanel).Children(i)
Item.InitLate(Item, e)
Item.Checked = SwipToState
Next
End Sub
'勾选状态
Public Event Check(sender As Object, e As RouteEventArgs)
Public Event Changed(sender As Object, e As RouteEventArgs)
Private _Checked As Boolean = False
Public Property Checked As Boolean
Get
Return _Checked
End Get
Set(value As Boolean)
Try
'触发属性值修改
Dim RawValue = _Checked
If value = _Checked Then Exit Property
_Checked = value
Dim ChangedEventArgs As New RouteEventArgs(False)
If IsInitialized Then
RaiseEvent Changed(Me, ChangedEventArgs)
If ChangedEventArgs.Handled Then
_Checked = RawValue
Exit Property
End If
End If
If value Then
Dim CheckEventArgs As New RouteEventArgs(False)
RaiseEvent Check(Me, CheckEventArgs)
If CheckEventArgs.Handled Then Exit Property
End If
'更改动画
If IsVisibleInForm() Then
Dim Anim As New List(Of AniData)
If Checked Then
'由无变有
Dim Delta = 32 - RectCheck.ActualHeight
Anim.Add(AaHeight(RectCheck, Delta * 0.4, 200,, New AniEaseOutFluent(AniEasePower.Weak)))
Anim.Add(AaHeight(RectCheck, Delta * 0.6, 300,, New AniEaseOutBack(AniEasePower.Weak)))
Anim.Add(AaOpacity(RectCheck, 1 - RectCheck.Opacity, 30))
RectCheck.VerticalAlignment = VerticalAlignment.Center
RectCheck.Margin = New Thickness(-3, 0, 0, 0)
Anim.Add(AaColor(LabTitle, TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush2", "ColorBrush5"), 200))
Else
'由有变无
Anim.Add(AaHeight(RectCheck, -RectCheck.ActualHeight, 120,, New AniEaseInFluent(AniEasePower.Weak)))
Anim.Add(AaOpacity(RectCheck, -RectCheck.Opacity, 70, 40))
RectCheck.VerticalAlignment = VerticalAlignment.Center
Anim.Add(AaColor(LabTitle, TextBlock.ForegroundProperty, If(LabTitle.TextDecorations Is Nothing, "ColorBrush1", "ColorBrushGray4"), 120))
End If
AniStart(Anim, "MyLocalModItem Checked " & Uuid)
Else
'不在窗口上时直接设置
RectCheck.VerticalAlignment = VerticalAlignment.Center
RectCheck.Margin = New Thickness(-3, 0, 0, 0)
If Checked Then
RectCheck.Height = 32
RectCheck.Opacity = 1
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush2", "ColorBrush5"))
Else
RectCheck.Height = 0
RectCheck.Opacity = 0
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush1", "ColorBrushGray4"))
End If
AniStop("MyLocalModItem Checked " & Uuid)
End If
Catch ex As Exception
Log(ex, "设置 Checked 失败")
End Try
End Set
End Property
#End Region
#Region "后加载内容"
'右下角状态指示图标
Private ImgState As Image
'指向背景
Private _RectBack As Border = Nothing
Public ReadOnly Property RectBack As Border
Get
If _RectBack Is Nothing Then
Dim Rect As New Border With {
.Name = "RectBack",
.CornerRadius = New CornerRadius(3),
.RenderTransform = New ScaleTransform(0.8, 0.8),
.RenderTransformOrigin = New Point(0.5, 0.5),
.BorderThickness = New Thickness(GetWPFSize(1)),
.SnapsToDevicePixels = True,
.IsHitTestVisible = False,
.Opacity = 0
}
Rect.SetResourceReference(Border.BackgroundProperty, "ColorBrush7")
Rect.SetResourceReference(Border.BorderBrushProperty, "ColorBrush6")
SetColumnSpan(Rect, 999)
SetRowSpan(Rect, 999)
Children.Insert(0, Rect)
_RectBack = Rect
'<!--<Border x:Name = "RectBack" CornerRadius="3" RenderTransformOrigin="0.5,0.5" SnapsToDevicePixels="True"
'IsHitTestVisible = "False" Opacity="0" BorderThickness="1"
'Grid.ColumnSpan = "4" Background="{DynamicResource ColorBrush7}" BorderBrush="{DynamicResource ColorBrush6}"/>-->
End If
Return _RectBack
End Get
End Property
'按钮
Public ButtonHandler As Action(Of MyLocalModItem, EventArgs)
Public ButtonStack As FrameworkElement
Private _Buttons As IEnumerable(Of MyIconButton)
Public Property Buttons As IEnumerable(Of MyIconButton)
Get
Return _Buttons
End Get
Set(value As IEnumerable(Of MyIconButton))
_Buttons = value
'移除原 Stack
If ButtonStack IsNot Nothing Then
Children.Remove(ButtonStack)
ButtonStack = Nothing
End If
If Not value.Any() Then Exit Property
'添加新 Stack
ButtonStack = New StackPanel With {.Opacity = 0, .Margin = New Thickness(0, 0, 5, 0), .SnapsToDevicePixels = False, .Orientation = Orientation.Horizontal,
.HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Center, .UseLayoutRounding = False}
SetColumnSpan(ButtonStack, 10) : SetRowSpan(ButtonStack, 10)
'构造按钮
For Each Btn As MyIconButton In value
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 25
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 25
CType(ButtonStack, StackPanel).Children.Add(Btn)
Next
Children.Add(ButtonStack)
End Set
End Property
'勾选条
Private _RectCheck As Border
Public ReadOnly Property RectCheck As Border
Get
If _RectCheck Is Nothing Then
_RectCheck = New Border With {.Width = 5, .Height = If(Checked, Double.NaN, 0), .CornerRadius = New CornerRadius(2, 2, 2, 2),
.VerticalAlignment = If(Checked, VerticalAlignment.Stretch, VerticalAlignment.Center),
.HorizontalAlignment = HorizontalAlignment.Left, .UseLayoutRounding = False, .SnapsToDevicePixels = False,
.Margin = If(Checked, New Thickness(-3, 6, 0, 6), New Thickness(-3, 0, 0, 0))}
_RectCheck.SetResourceReference(Border.BackgroundProperty, "ColorBrush3")
SetRowSpan(_RectCheck, 10)
Children.Add(_RectCheck)
End If
Return _RectCheck
End Get
End Property
#End Region
Public Sub Refresh()
RunInUi(
Sub()
'更新
If Entry.CanUpdate Then
BtnUpdate.Visibility = Visibility.Visible
Dim CurrentName = Entry.CompFile.FileName.Replace(".jar", "")
Dim NewestName = Entry.UpdateFile.FileName.Replace(".jar", "")
'简化名称对比
Dim CurrentSegs = CurrentName.Split("-"c).ToList()
Dim NewestSegs = NewestName.Split("-"c).ToList()
Dim Shortened As Boolean = False
For Each Seg In CurrentSegs.ToList()
If Not NewestSegs.Contains(Seg) Then Continue For
CurrentSegs.Remove(Seg)
NewestSegs.Remove(Seg)
Shortened = True
Next
If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then
CurrentName = Join(CurrentSegs, "-")
NewestName = Join(NewestSegs, "-")
Entry._Version = CurrentName '使用网络信息作为显示的版本号
End If
BtnUpdate.ToolTip = $"当前版本:{CurrentName} ({Entry.CompFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}最新版本:{NewestName} ({Entry.UpdateFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}点击以更新,右键查看更新日志。"
Else
BtnUpdate.Visibility = Visibility.Collapsed
End If
'标题
If Entry.Comp Is Nothing Then
Title = Entry.Name
SubTitle = If(Entry.Version Is Nothing, "", " | " & Entry.Version)
Else
Dim Titles = Entry.Comp.GetControlTitle(False)
Title = Titles.Key
SubTitle = Titles.Value & If(Entry.Version Is Nothing, "", " | " & Entry.Version)
End If
If Checked Then
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush2", "ColorBrush5"))
Else
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush1", "ColorBrushGray4"))
End If
'描述
Dim NewDescription As String
Select Case Entry.State
Case McMod.McModState.Fine
NewDescription = GetFileNameWithoutExtentionFromPath(Entry.Path)
Case McMod.McModState.Disabled
NewDescription = GetFileNameWithoutExtentionFromPath(Entry.Path.Replace(".disabled", "").Replace(".old", ""))
Case Else 'McMod.McModState.Unavaliable
NewDescription = GetFileNameFromPath(Entry.Path)
End Select
If Entry.Comp IsNot Nothing Then
NewDescription += ": " & Entry.Comp.Description.Replace(vbCr, "").Replace(vbLf, "")
ElseIf Entry.Description IsNot Nothing Then
NewDescription += ": " & Entry.Description.Replace(vbCr, "").Replace(vbLf, "")
ElseIf Not Entry.IsFileAvailable Then
NewDescription += ": " & "存在错误,无法获取信息"
End If
Description = NewDescription
'主 Logo
Logo = If(Entry.Comp Is Nothing, PathImage & "Icons/NoIcon.png", Entry.Comp.GetControlLogo())
'图标右下角的 Logo
If Entry.State = McMod.McModState.Fine Then
If ImgState IsNot Nothing Then
Children.Remove(ImgState)
ImgState = Nothing
End If
Else
If ImgState Is Nothing Then
ImgState = New Image With {
.Width = 20, .Height = 20, .Margin = New Thickness(0, 0, -5, -3), .IsHitTestVisible = False,
.HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Bottom
}
RenderOptions.SetBitmapScalingMode(ImgState, BitmapScalingMode.HighQuality)
SetColumn(ImgState, 1) : SetRow(ImgState, 1) : SetRowSpan(ImgState, 2)
Children.Add(ImgState)
'<Image x:Name="ImgState" RenderOptions.BitmapScalingMode="HighQuality" Width="16" Height="16" Margin="0,0,-3,-1"
' Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" IsHitTestVisible="False"
' HorizontalAlignment="Right" VerticalAlignment="Bottom"
' Source="/Images/Icons/Unavaliable.png" />
End If
ImgState.Source = New MyBitmap(PathImage & $"Icons/{Entry.State}.png")
End If
'标签
If Entry.Comp IsNot Nothing Then Tags = Entry.Comp.Tags
End Sub)
End Sub
Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp, Me.Changed
InitLate(sender, e)
'触发颜色动画
Dim Time As Integer = If(IsMouseOver, 120, 180)
Dim Ani As New List(Of AniData)
'ButtonStack
If ButtonStack IsNot Nothing Then
If IsMouseOver Then
Ani.Add(AaOpacity(ButtonStack, 1 - ButtonStack.Opacity, Time * 0.7, Time * 0.3))
Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
5 + Buttons.Count * 25 - ColumnPaddingRight.Width.Value, Time * 0.3, Time * 0.7))
Else
Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.4))
Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
4 - ColumnPaddingRight.Width.Value, Time * 0.4))
End If
End If
'RectBack
If IsMouseOver OrElse Checked Then
Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
})
If IsMouseDown Then
Ani.Add(AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
Else
Ani.Add(AaScaleTransform(RectBack, 1 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
End If
Else
Ani.AddRange({
AaOpacity(RectBack, -RectBack.Opacity, Time),
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
AaScaleTransform(RectBack, -0.196, 1,,, True)
})
End If
AniStart(Ani, "LocalModItem Color " & Uuid)
End Sub
'触发虚拟化内容
Private Sub InitLate(sender As Object, e As EventArgs)
If ButtonHandler IsNot Nothing Then
ButtonHandler(sender, e)
ButtonHandler = Nothing
End If
End Sub
'显示更新日志
Private Sub ShowUpdateLog(sender As Object, e As MouseButtonEventArgs) Handles BtnUpdate.PreviewMouseRightButtonUp
e.Handled = True
Dim CurseForgeUrl As String = Entry.ChangelogUrls.FirstOrDefault(Function(x) x.Contains("curseforge.com"))
Dim ModrinthUrl As String = Entry.ChangelogUrls.FirstOrDefault(Function(x) x.Contains("modrinth.com"))
If CurseForgeUrl Is Nothing OrElse ModrinthUrl Is Nothing Then
OpenWebsite(Entry.ChangelogUrls.First)
Else
Select Case MyMsgBox("要在哪个网站上查看更新日志?", "查看更新日志", "Modrinth", "CurseForge", "取消")
Case 1
OpenWebsite(ModrinthUrl)
Case 2
OpenWebsite(CurseForgeUrl)
End Select
End If
End Sub
'触发更新
Private Sub BtnUpdate_Click(sender As Object, e As EventArgs) Handles BtnUpdate.Click
FrmVersionMod.UpdateMods({Entry})
End Sub
End Class
+34 -37
View File
@@ -13,83 +13,79 @@
Case "打开网页"
Data(0) = Data(0).Replace("\", "/")
If Not (Data(0).StartsWith("http://") OrElse Data(0).StartsWith("https://")) Then
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败")
If Not Data(0).Contains("://") OrElse Data(0).StartsWithF("file", True) Then '为了支持更多协议(#2200)
MyMsgBox("EventData 必须为一个网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败")
Exit Sub
End If
Hint("正在打开网页,请稍候……")
Hint("正在开启中,请稍候……")
OpenWebsite(Data(0))
Case "打开文件", "打开帮助"
RunInThread(Sub()
Try
'确认实际路径
Dim ActualPaths = GetEventAbsoluteUrls(Data(0), Type)
Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1)
'执行
If Type = "打开文件" Then
Dim Info As New ProcessStartInfo With {
.Arguments = If(Data.Length >= 2, Data(1), ""),
.FileName = Location,
.WorkingDirectory = WorkingDir
}
.Arguments = If(Data.Length >= 2, Data(1), ""),
.FileName = Location,
.WorkingDirectory = WorkingDir
}
Process.Start(Info)
Else '打开帮助
PageOtherHelp.EnterHelpPage(Location)
End If
Catch ex As Exception
Log(ex, "执行打开类自定义事件失败", LogLevel.Msgbox)
End Try
End Sub)
Case "启动游戏"
'初始化与前置条件检测
If Not (FrmLaunchLeft.BtnLaunch.IsEnabled AndAlso FrmLaunchLeft.BtnLaunch.Visibility = Visibility.Visible AndAlso FrmLaunchLeft.BtnLaunch.IsHitTestVisible) Then
Hint("已有游戏正在启动中!", HintType.Critical) : Exit Sub
If McLaunchStart(New McLaunchOptions With
{.ServerIp = If(Data.Length >= 2, Data(1), Nothing), .Version = New McVersion(Data(0))}) Then
Hint("正在启动 " & Data(0) & "……")
End If
If Not Directory.Exists(PathMcFolder & "versions\" & Data(0)) Then
Hint("未在当前 Minecraft 文件夹找到版本 " & Data(0) & "!", HintType.Critical) : Exit Sub
End If
Dim ButtonVersion As New McVersion(Data(0))
ButtonVersion.Load()
If ButtonVersion.State = McVersionState.Error Then
Hint("无法启动 " & Data(0) & ":" & ButtonVersion.Info, HintType.Critical) : Exit Sub
End If
'实际启动
McVersionCurrent = ButtonVersion
Setup.Set("LaunchVersionSelect", McVersionCurrent.Name)
FrmLaunchLeft.PageLaunchLeft_Loaded()
FrmLaunchLeft.RefreshButtonsUI()
FrmMain.AprilGiveup()
FrmLaunchLeft.LaunchButtonClick(If(Data.Length >= 2, Data(1), ""))
FrmMain.PageChange(FormMain.PageType.Launch)
Case "复制文本"
ClipboardSet(Join(Data, "|"))
Case "刷新主页"
FrmLaunchRight.ForceRefresh()
If Data(0) = "" Then Hint("已刷新主页!", HintType.Finish)
Case "刷新帮助"
PageOtherLeft.RefreshHelp()
Case "今日人品"
PageOtherTest.Jrrp()
Case "内存优化"
RunInThread(Sub() PageOtherTest.MemoryOptimize(True))
Case "清理垃圾"
RunInThread(Sub() PageOtherTest.RubbishClear())
Case "弹出窗口"
MyMsgBox(Data(1).Replace("\n", vbCrLf), Data(0).Replace("\n", vbCrLf))
Case "切换页面"
FrmMain.PageChange(Val(Data(0)), Val(Data(1)))
Case "导入整合包"
RunInThread(Sub() ModpackInstall())
Case "下载文件"
Data(0) = Data(0).Replace("\", "/")
If Not (Data(0).StartsWith("http://") OrElse Data(0).StartsWith("https://")) Then
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL2 不支持其他乱七八糟的协议。", "事件执行失败")
If Not (Data(0).StartsWithF("http://", True) OrElse Data(0).StartsWithF("https://", True)) Then
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL 不支持其他乱七八糟的下载协议。", "事件执行失败")
Exit Sub
End If
PageOtherTest.StartCustomDownload(Data(0))
PageOtherTest.StartCustomDownload(Data(0), GetFileNameFromPath(Data(0)))
Case Else
MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL2 是否为最新版本。", "事件执行失败")
MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败")
End Select
Catch ex As Exception
Log(ex, "事件执行失败", LogLevel.Msgbox)
@@ -103,7 +99,7 @@
Public Function GetEventAbsoluteUrls(RelativeUrl As String, EventType As String) As String()
'网页确认
If RelativeUrl.ToLower.StartsWith("http") Then
If RelativeUrl.StartsWithF("http", True) Then
If RunInUi() Then
Throw New Exception("MyListItem 在界面初始化时就需要获取帮助标题等信息,这会导致程序在网络请求时卡死。" & vbCrLf &
"因此,请换用 MyListItem 以外的控件(例如 MyButton)作为联网帮助页面的入口!")
@@ -112,7 +108,7 @@
Dim RawFileName As String
Try
RawFileName = GetFileNameFromPath(RelativeUrl)
If Not RawFileName.ToLower.EndsWith(".json") Then Throw New Exception("未指向 .json 后缀的文件")
If Not RawFileName.EndsWithF(".json", True) Then Throw New Exception("未指向 .json 后缀的文件")
Catch ex As Exception
Throw New Exception("联网帮助页面须指向一个帮助 JSON 文件,并在同路径下包含相应 XAML 文件!" & vbCrLf &
"例如:" & vbCrLf &
@@ -140,6 +136,7 @@
'确认实际路径
Dim Location As String, WorkingDir As String = Path & "PCL"
HelpTryExtract()
If RelativeUrl.Contains(":\") Then
'绝对路径
Location = RelativeUrl
+48 -38
View File
@@ -1,11 +1,13 @@
Public Module ModMusic
Imports System.Security.Cryptography
Public Module ModMusic
#Region "播放列表"
''' <summary>
''' 接下来要播放的音乐文件路径。未初始化时为 Nothing。
''' </summary>
Public MusicToplayList As List(Of String) = Nothing
Public MusicWaitingList As List(Of String) = Nothing
''' <summary>
''' 全部音乐文件路径。未初始化时为 Nothing。
''' </summary>
@@ -22,20 +24,19 @@
If MusicAllList Is Nothing Then
MusicAllList = New List(Of String)
Directory.CreateDirectory(Path & "PCL\Musics\")
For Each File In My.Computer.FileSystem.GetFiles(Path & "PCL\Musics\", FileIO.SearchOption.SearchAllSubDirectories, "*.*")
For Each File In EnumerateFiles(Path & "PCL\Musics\")
'文件夹可能会被加入 .ini 文件夹配置文件、一些乱七八糟的 .jpg 文件啥的
Dim Extend As String = File.Split(".").Last.ToLower
If Not (Extend = "ini" OrElse Extend = "jpg" OrElse Extend = "txt" OrElse Extend = "cfg" OrElse Extend = "png") Then
MusicAllList.Add(File)
End If
Dim Ext As String = File.Extension.ToLower
If {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(Ext) Then Continue For
MusicAllList.Add(File.FullName)
Next
End If
'打乱顺序播放
MusicToplayList = RandomChaos(New List(Of String)(MusicAllList))
If Not IgnoreFirst = "" AndAlso Not MusicToplayList.Count = 0 AndAlso MusicToplayList(0) = IgnoreFirst Then
MusicWaitingList = If(Setup.Get("UiMusicRandom"), Shuffle(New List(Of String)(MusicAllList)), New List(Of String)(MusicAllList))
If Not IgnoreFirst = "" AndAlso Not Not MusicWaitingList.Any() AndAlso MusicWaitingList(0) = IgnoreFirst Then
'若需要避免成为第一项的为第一项,则将它放在最后
MusicToplayList.RemoveAt(0)
MusicToplayList.Add(IgnoreFirst)
MusicWaitingList.RemoveAt(0)
MusicWaitingList.Add(IgnoreFirst)
End If
Catch ex As Exception
Log(ex, "初始化音乐列表失败", LogLevel.Feedback)
@@ -46,12 +47,11 @@
''' </summary>
Private Function DequeueNextMusicAddress() As String
'初始化,确保存在音乐
If MusicAllList Is Nothing Then MusicListInit(False)
If MusicAllList.Count = 0 Then Throw New Exception("在没有音乐时尝试获取音乐路径")
If MusicAllList Is Nothing OrElse Not MusicAllList.Any() OrElse Not MusicWaitingList.Any() Then MusicListInit(False)
'出列下一个音乐,如果出列结束则生成新列表
DequeueNextMusicAddress = MusicToplayList(0)
MusicToplayList.RemoveAt(0)
If MusicToplayList.Count = 0 Then MusicListInit(False, DequeueNextMusicAddress)
DequeueNextMusicAddress = MusicWaitingList(0)
MusicWaitingList.RemoveAt(0)
If Not MusicWaitingList.Any() Then MusicListInit(False, DequeueNextMusicAddress)
End Function
#End Region
@@ -65,7 +65,7 @@
RunInUi(Sub()
Try
If MusicAllList.Count = 0 Then
If Not MusicAllList.Any() Then
'无背景音乐
FrmMain.BtnExtraMusic.Show = False
Else
@@ -106,7 +106,8 @@
Case MusicStates.Play
MusicPause()
Case Else
Hint("音乐目前为停止状态!", HintType.Critical)
Log("[Music] 音乐目前为停止状态,已强制尝试开始播放", LogLevel.Debug)
MusicRefreshPlay(False)
End Select
End If
End Sub
@@ -161,7 +162,7 @@
Try
MusicListInit(True)
If MusicAllList.Count = 0 Then
If Not MusicAllList.Any() Then
If MusicNAudio Is Nothing Then
If ShowHint Then Hint("未检测到可用的背景音乐!", HintType.Critical)
Else
@@ -187,7 +188,8 @@
''' </summary>
Private Sub MusicStartPlay(Address As String, Optional IsFirstLoad As Boolean = False)
Log("[Music] 播放开始:" & Address)
RunInNewThread(Sub() MusicLoop(Address, IsFirstLoad), "Music", ThreadPriority.BelowNormal)
MusicCurrent = Address
RunInNewThread(Sub() MusicLoop(IsFirstLoad), "Music", ThreadPriority.BelowNormal)
End Sub
'播放与暂停
@@ -211,15 +213,15 @@
''' 继续音乐播放,返回是否成功切换了状态。
''' </summary>
Public Function MusicResume() As Boolean
If MusicState = MusicStates.Pause Then
If MusicState = MusicStates.Play OrElse Not MusicAllList.Any() Then
Return False
Else
RunInThread(Sub()
MusicNAudio.Play()
MusicRefreshUI()
Log("[Music] 已恢复播放")
End Sub)
Return True
Else
Return False
End If
End Function
@@ -237,15 +239,14 @@
''' <summary>
''' 在 MusicUuid 不变的前提下,持续播放某地址的音乐,且在播放结束后随机播放下一曲。
''' </summary>
Private Sub MusicLoop(Address As String, Optional IsFirstLoad As Boolean = False)
MusicCurrent = Address
Private Sub MusicLoop(Optional IsFirstLoad As Boolean = False)
Dim CurrentWave As NAudio.Wave.WaveOut = Nothing
Dim Reader As NAudio.Wave.WaveStream = Nothing
Try
'开始播放
CurrentWave = New NAudio.Wave.WaveOut()
MusicNAudio = CurrentWave
Reader = New NAudio.Wave.AudioFileReader(Address)
Reader = New NAudio.Wave.AudioFileReader(MusicCurrent)
CurrentWave.Init(Reader)
CurrentWave.Play()
'第一次打开的暂停
@@ -259,22 +260,31 @@
PreviousVolume = Setup.Get("UiMusicVolume")
CurrentWave.Volume = PreviousVolume / 1000
End If
Thread.Sleep(50)
'更新进度条
Dim Percent = Reader.CurrentTime.TotalMilliseconds / Reader.TotalTime.TotalMilliseconds
RunInUi(Sub() FrmMain.BtnExtraMusic.Progress = Percent)
Thread.Sleep(100)
End While
'当前音乐已播放结束,继续下一曲
If CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped AndAlso MusicAllList.Count > 0 Then MusicStartPlay(DequeueNextMusicAddress)
If CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped AndAlso MusicAllList.Any Then MusicStartPlay(DequeueNextMusicAddress)
Catch ex As Exception
If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then
Hint("播放音乐失败(" & GetFileNameFromPath(Address) & "):PCL2 不支持播放音频属性在中途发生变化的音乐", HintType.Critical)
ElseIf Not (Address.ToLower.EndsWith(".wav") OrElse Address.ToLower.EndsWith(".mp3") OrElse Address.ToLower.EndsWith(".flac")) Then
Hint("播放音乐失败(" & GetFileNameFromPath(Address) & "):PCL2 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Critical)
Else
Log(ex, "播放音乐失败(" & GetFileNameFromPath(Address) & ")", LogLevel.Hint)
Log("[Music] 播放音乐失败的文件完整路径:" & MusicCurrent)
If TypeOf ex Is NAudio.MmException AndAlso (ex.Message.Contains("NoDriver") OrElse ex.Message.Contains("BadDeviceId")) Then
Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Critical)
Thread.Sleep(1000000000)
End If
Log(ex, "播放音乐失败(" & Address & ")", LogLevel.Developer)
If MusicAllList.Count > 1 Then
Thread.Sleep(1000)
MusicStartPlay(DequeueNextMusicAddress)
If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 不支持播放音频属性在中途发生变化的音乐", HintType.Critical)
ElseIf Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) Then
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Critical)
Else
Log(ex, "播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & ")", LogLevel.Hint)
End If
Thread.Sleep(1000)
If TypeOf ex Is FileNotFoundException Then
MusicRefreshPlay(True, IsFirstLoad)
ElseIf MusicAllList.Count > 1 Then
MusicStartPlay(DequeueNextMusicAddress(), IsFirstLoad)
End If
Finally
If CurrentWave IsNot Nothing Then CurrentWave.Dispose()
@@ -25,7 +25,7 @@ Public Class CookieWebClient
''' </summary>
Public Timeout As Integer = 600000
Protected Overrides Function GetWebRequest(ByVal address As Uri) As WebRequest
Protected Overrides Function GetWebRequest(address As Uri) As WebRequest
Dim r As WebRequest = MyBase.GetWebRequest(address)
Dim request = TryCast(r, HttpWebRequest)
@@ -37,19 +37,19 @@ Public Class CookieWebClient
Return r
End Function
Protected Overrides Function GetWebResponse(ByVal request As WebRequest, ByVal result As IAsyncResult) As WebResponse
Protected Overrides Function GetWebResponse(request As WebRequest, result As IAsyncResult) As WebResponse
Dim response As WebResponse = MyBase.GetWebResponse(request, result)
ReadCookies(response)
Return response
End Function
Protected Overrides Function GetWebResponse(ByVal request As WebRequest) As WebResponse
Protected Overrides Function GetWebResponse(request As WebRequest) As WebResponse
Dim response As WebResponse = MyBase.GetWebResponse(request)
ReadCookies(response)
Return response
End Function
Private Sub ReadCookies(ByVal r As WebResponse)
Private Sub ReadCookies(r As WebResponse)
Dim response = TryCast(r, HttpWebResponse)
If response IsNot Nothing Then
Dim cookies As CookieCollection = response.Cookies
@@ -8,11 +8,11 @@ Imports System.Runtime.InteropServices
'查看程序集特性的值
<Assembly: AssemblyTitle("Plain Craft Launcher 2 启动器")>
<Assembly: AssemblyTitle("Plain Craft Launcher 启动器")>
<Assembly: AssemblyDescription("Minecraft 启动器 (制作:龙腾猫跃)")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("Plain Craft Launcher 2")>
<Assembly: AssemblyCopyright("Copyright © 龙腾猫跃 2016-2022. All Rights Reserved.")>
<Assembly: AssemblyProduct("Plain Craft Launcher")>
<Assembly: AssemblyCopyright("Copyright © 龙腾猫跃 2016. All Rights Reserved.")>
<Assembly: AssemblyConfiguration("PCL2 Config Mark")>
<Assembly: ComVisible(False)>
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*”
<Assembly: AssemblyVersion("2.4.2.0")>
<Assembly: AssemblyFileVersion("2.4.2.0")>
<Assembly: AssemblyVersion("2.7.2.0")>
<Assembly: AssemblyFileVersion("2.7.2.0")>
<Assembly: NeutralResourcesLanguage("")>
File diff suppressed because it is too large. Load diff
@@ -1,45 +0,0 @@
<Grid x:Class="MyCfItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="PanBack" Height="57"
RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="9" />
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="7" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="17" />
<RowDefinition Height="14" />
<RowDefinition Height="14" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<!--<Rectangle Height="45" Width="45" RadiusX="4" RadiusY="4" Fill="White" Grid.Column="1" Grid.Row="1" IsHitTestVisible="False" SnapsToDevicePixels="True" UseLayoutRounding="False" Grid.RowSpan="3" />-->
<Border Height="45" Width="45" Grid.Column="1" Grid.Row="1" IsHitTestVisible="False" SnapsToDevicePixels="True" UseLayoutRounding="True" Grid.RowSpan="3">
<Border.Clip>
<RectangleGeometry Rect="0,0,45,45" RadiusX="4" RadiusY="4" />
</Border.Clip>
<Image x:Name="PathLogo" RenderOptions.BitmapScalingMode="HighQuality" />
</Border>
<TextBlock x:Name="LabTitle" Grid.Row="1" Grid.Column="3" Grid.ColumnSpan="2" IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False"
Margin="0,0,0,1" HorizontalAlignment="Left" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"
FontSize="14" Foreground="{StaticResource ColorBrush1}" />
<TextBlock x:Name="LabLeft" Grid.Row="2" Grid.Column="3" IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False"
HorizontalAlignment="Left" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"
FontSize="12" Foreground="{StaticResource ColorBrushGray3}" />
<!--<TextBlock x:Name="LabRight" Grid.Row="2" Grid.Column="4" IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False"
HorizontalAlignment="Right" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"
FontSize="12" Foreground="{StaticResource ColorBrushGray3}" />-->
<TextBlock x:Name="LabInfo" Grid.Row="3" Grid.Column="3" Grid.ColumnSpan="2" IsHitTestVisible="True" SnapsToDevicePixels="False" UseLayoutRounding="False"
HorizontalAlignment="Left" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"
FontSize="12" Foreground="{StaticResource ColorBrushGray3}"
ToolTipService.InitialShowDelay="80" ToolTipService.Placement="Relative" ToolTipService.PlacementRectangle="-8,-6,500,10000">
<TextBlock.ToolTip>
<ToolTip x:Name="ToolTipInfo" Style="{StaticResource ExtendTextToolTip}" />
</TextBlock.ToolTip>
</TextBlock>
</Grid>
@@ -1,200 +0,0 @@
Public Class MyCfItem
Public Uuid As Integer = GetUuid()
#Region "Logo"
'Public CacheLogo As Boolean = True '是否缓存 Logo:通过下载量确定是否为默认页
Private _Logo As String = ""
Public Property Logo As String
Get
Return _Logo
End Get
Set(value As String)
If _Logo = value OrElse value Is Nothing Then Exit Property
_Logo = value
Dim FileAddress = PathTemp & "CFLogo\" & GetHash(_Logo) & ".png"
Try
If _Logo.ToLower.StartsWith("http") Then
'网络图片
If File.Exists(FileAddress) Then
PathLogo.Source = New MyBitmap(FileAddress)
Else
PathLogo.Source = New MyBitmap("pack://application:,,,/images/Icons/NoIcon.png")
RunInNewThread(Sub() LogoLoader(FileAddress), "CurseForge Logo Loader " & Uuid & "#", ThreadPriority.BelowNormal)
End If
Else
'位图
PathLogo.Source = New MyBitmap(_Logo)
End If
Catch ex As IOException
Log(ex, "加载 CurseForge 工程图标时读取失败(" & FileAddress & ")")
Catch ex As ArgumentException
'考虑缓存的图片本身可能有误
Log(ex, "可视化 CurseForge 工程图标失败(" & FileAddress & ")")
Try
File.Delete(FileAddress)
Log("[Download] 已清理损坏的 CurseForge 工程图标:" & FileAddress)
Catch exx As Exception
Log(exx, "清理损坏的 CurseForge 工程图标缓存失败(" & FileAddress & ")", LogLevel.Hint)
End Try
Catch ex As Exception
Log(ex, "加载 CurseForge 工程图标失败(" & value & ")")
End Try
End Set
End Property
Private Sub LogoLoader(Address As String)
Dim Retry As Boolean = False
Dim DownloadEnd As String = GetUuid()
RetryStart:
Try
NetDownload(_Logo, Address & DownloadEnd)
RunInUiWait(Sub()
Try
'在地址更换时取消加载
If Not Address = PathTemp & "CFLogo\" & GetHash(_Logo) & ".png" Then Exit Sub
'在完成正常加载后才保存缓存图片
PathLogo.Source = New MyBitmap(Address & DownloadEnd)
Catch ex As Exception
Log(ex, "读取 CurseForge 工程图标失败(" & Address & ")", LogLevel.Hint)
End Try
End Sub)
If File.Exists(Address) Then
File.Delete(Address & DownloadEnd)
Else
FileIO.FileSystem.MoveFile(Address & DownloadEnd, Address)
End If
Catch ex As Exception
If Not Retry Then
Retry = True
GoTo RetryStart
Else
Log(ex, "下载 CurseForge 工程图标失败")
End If
End Try
End Sub
#End Region
#Region "点击"
'触发点击事件
Public Event Click(sender As Object, e As MouseButtonEventArgs)
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
If IsMouseDown Then
RaiseEvent Click(sender, e)
If e.Handled Then Exit Sub
Log("[Control] 按下 CurseForge 工程列表项:" & LabTitle.Text)
End If
End Sub
'鼠标点击判定
Private IsMouseDown As Boolean = False
Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
If IsMouseOver Then IsMouseDown = True
End Sub
Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
IsMouseDown = False
End Sub
#End Region
#Region "后加载指向背景"
Private _RectBack As Border = Nothing
Public ReadOnly Property RectBack As Border
Get
If _RectBack Is Nothing Then
Dim Rect As New Border With {
.Name = "RectBack",
.CornerRadius = New CornerRadius(3),
.RenderTransform = New ScaleTransform(0.8, 0.8),
.RenderTransformOrigin = New Point(0.5, 0.5),
.BorderThickness = New Thickness(GetWPFSize(1)),
.SnapsToDevicePixels = True,
.IsHitTestVisible = False,
.Opacity = 0
}
Rect.SetResourceReference(Border.BackgroundProperty, "ColorBrush7")
Rect.SetResourceReference(Border.BorderBrushProperty, "ColorBrush6")
SetColumnSpan(Rect, 999)
SetRowSpan(Rect, 999)
Children.Insert(0, Rect)
_RectBack = Rect
'<!--<Border x:Name = "RectBack" CornerRadius="3" RenderTransformOrigin="0.5,0.5" SnapsToDevicePixels="True"
'IsHitTestVisible = "False" Opacity="0" BorderThickness="1"
'Grid.ColumnSpan = "4" Background="{DynamicResource ColorBrush7}" BorderBrush="{DynamicResource ColorBrush6}"/>-->
End If
Return _RectBack
End Get
End Property
#End Region
Private StateLast As String
Public HasAnimation As Boolean = True
Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp
If Not HasAnimation Then Exit Sub
'判断当前颜色
Dim StateNew As String, Time As Integer
If IsMouseOver Then
If IsMouseDown Then
StateNew = "MouseDown"
Time = 120
Else
StateNew = "MouseOver"
Time = 120
End If
Else
StateNew = "Idle"
Time = 180
End If
If StateLast = StateNew Then Exit Sub
StateLast = StateNew
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
Dim Ani As New List(Of AniData)
If IsMouseOver Then
Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush9"), Time),
AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
})
If IsMouseDown Then
Ani.Add(AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
Else
Ani.Add(AaScaleTransform(RectBack, 1 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
End If
Else
Ani.AddRange({
AaOpacity(RectBack, -RectBack.Opacity, Time),
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
AaScaleTransform(RectBack, -0.196, 1,,, True)
})
End If
AniStart(Ani, "CfItem Color " & Uuid)
Else
'无动画
AniStop("CfItem Color " & Uuid)
If _RectBack IsNot Nothing Then RectBack.Opacity = 0
End If
End Sub
'指向时扩展描述
Private Sub LabInfo_MouseEnter(sender As Object, e As MouseEventArgs) Handles LabInfo.MouseEnter
If IsTextTrimmed(LabInfo) Then
ToolTipInfo.Content = LabInfo.Text
ToolTipInfo.Width = LabInfo.ActualWidth + 25
LabInfo.ToolTip = ToolTipInfo
Else
LabInfo.ToolTip = Nothing
End If
End Sub
Private Function IsTextTrimmed(textBlock As TextBlock) As Boolean
Dim typeface As New Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch)
Dim formattedText As New FormattedText(textBlock.Text, Thread.CurrentThread.CurrentCulture, textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground, DPI)
Return formattedText.Width > textBlock.ActualWidth
End Function
End Class
@@ -1,34 +0,0 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadCfDetail"
d:DesignWidth="778.571" d:DesignHeight="90.857">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<Grid Margin="25,25,25,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:MyCard Margin="0,0,0,25" x:Name="CardIntro">
<StackPanel Margin="22,22,22,19" x:Name="PanIntro">
<Grid Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnIntroCf" Grid.Column="0" MinWidth="140" Text="查看 CurseForge" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
<local:MyButton x:Name="BtnIntroWiki" Grid.Column="1" MinWidth="140" Text="查看百科" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
<local:MyButton x:Name="BtnIntroMCBBS" Grid.Column="2" MinWidth="140" Text="查看 MCBBS" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
</Grid>
</StackPanel>
</local:MyCard>
<StackPanel Grid.Row="1" Grid.RowSpan="2" Name="PanMain" Grid.IsSharedSizeScope="True" />
<local:MyCard Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="0,0,0,8">
<local:MyLoading Text="正在获取版本列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
</Grid>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -1,264 +0,0 @@
Public Class PageDownloadCfDetail
Private CfItem As MyCfItem = Nothing
Private Project As DlCfProject
#Region "加载器"
'初始化加载器信息
Private Sub PageDownloadCfDetail_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
Project = FrmMain.PageCurrent.Additional
PageLoaderInit(Load, PanLoad, PanMain, CardIntro, DlCfFileLoader, AddressOf Load_OnFinish, AddressOf LoaderInput)
End Sub
Private Function LoaderInput() As KeyValuePair(Of Integer, Boolean)
Return New KeyValuePair(Of Integer, Boolean)(Project.Id, Project.IsModPack)
End Function
'自动重试
Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
Select Case DlCfFileLoader.State
Case LoadState.Failed
Dim ErrorMessage As String = ""
If DlCfFileLoader.Error IsNot Nothing Then ErrorMessage = DlCfFileLoader.Error.Message
If ErrorMessage.Contains("不是有效的 Json 文件") Then
Log("[Download] 下载的 Mod 列表 Json 文件损坏,已自动重试", LogLevel.Debug)
PageLoaderRestart()
End If
End Select
End Sub
'结果 UI 化
Private Class VersionSorterWithSelect
Implements IComparer(Of String)
Public Top As String = ""
Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
If x = y Then Return 0
If x = Top Then Return -1
If y = Top Then Return 1
Return -VersionSortInteger(x, y)
End Function
Public Sub New(Optional Top As String = "")
Me.Top = If(Top, "")
End Sub
End Class
Private Sub Load_OnFinish()
'初始化字典,并将当前版本排在最上面
Dim TopVersion As String
If Project.IsModPack Then
TopVersion = If(PageDownloadPack.Loader.Input.GameVersion, "")
Else
TopVersion = If(PageDownloadMod.Loader.Input.GameVersion, "")
End If
Dim Dict As New SortedDictionary(Of String, List(Of DlCfFile))(New VersionSorterWithSelect(TopVersion))
'PCL#8826 汇报了奇怪的这个 Try 块里出现 NPE 的问题,但实在找不到,就瞎加点检测
Try
Dict.Add("未知版本", New List(Of DlCfFile))
If DlCfFileLoader.Output Is Nothing Then
Log("[Download] 列表加载输出为 Nothing,请反馈此问题", LogLevel.Feedback)
Exit Try
End If
For Each Version As DlCfFile In DlCfFileLoader.Output
If Version Is Nothing Then
Log("[Download] 列表中的一个版本为 Nothing,请反馈此问题", LogLevel.Feedback)
Continue For
End If
If Version.GameVersion Is Nothing Then
Log("[Download] 列表中的一个版本没有任何适配的游戏版本,返回为 Nothing,请反馈此问题", LogLevel.Feedback)
Continue For
End If
For Each GameVersion In Version.GameVersion
'决定添加到哪个版本
Dim TargetVersion As String
If GameVersion Is Nothing OrElse GameVersion.Split(".").Count < 2 Then
TargetVersion = "未知版本"
Else
TargetVersion = GameVersion
End If
'实际进行添加
If Not Dict.ContainsKey(TargetVersion) Then Dict.Add(TargetVersion, New List(Of DlCfFile))
If Not Dict(TargetVersion).Contains(Version) Then Dict(TargetVersion).Add(Version)
Next
Next
Catch ex As Exception
Log(ex, "准备工程下载列表出错", LogLevel.Feedback)
End Try
#Region "转化为 UI"
Try
'清空当前
PanMain.Children.Clear()
'转化为 UI
For Each Pair As KeyValuePair(Of String, List(Of DlCfFile)) In Dict
If Pair.Value.Count = 0 Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(Project.IsModPack, 9, 8)}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
NewCard.Children.Add(NewStack)
NewCard.SwapControl = NewStack
PanMain.Children.Add(NewCard)
'确定卡片是否展开
If Pair.Key = TopVersion Then
MyCard.StackInstall(NewStack, 8, Pair.Key)
Else
NewCard.IsSwaped = True
End If
'增加提示
If Pair.Key = "未知版本" Then
NewStack.Children.Add(New MyHint With {.Text = "由于 API 的版本信息更新缓慢,可能无法识别刚更新不久的 MC 版本,只需等待几天即可自动恢复正常。", .IsWarn = False, .Margin = New Thickness(0, 0, 0, 7)})
End If
Next
'如果只有一张卡片,展开第一张卡片
If PanMain.Children.Count = 1 Then
CType(PanMain.Children(0), MyCard).IsSwaped = False
End If
Catch ex As Exception
Log(ex, "可视化工程下载列表出错", LogLevel.Feedback)
End Try
#End Region
End Sub
#End Region
Private IsFirstInit As Boolean = True
Public Sub Init() Handles Me.PageEnter
AniControlEnabled += 1
Project = FrmMain.PageCurrent.Additional
PanBack.ScrollToHome()
'重启加载器
If IsFirstInit Then
'在 Me.Initialized 已经初始化了加载器,不再重复初始化
IsFirstInit = False
Else
PageLoaderRestart(IsForceRestart:=True)
End If
'放置当前工程
If CfItem IsNot Nothing Then PanIntro.Children.Remove(CfItem)
CfItem = Project.ToCfItem(True, True)
CfItem.Margin = New Thickness(-7, -7, 0, 8)
PanIntro.Children.Insert(0, CfItem)
'决定按钮显示
BtnIntroWiki.Visibility = If(Project.WikiId = 0, Visibility.Collapsed, Visibility.Visible)
BtnIntroMCBBS.Visibility = If(Project.MCBBS Is Nothing, Visibility.Collapsed, Visibility.Visible)
AniControlEnabled -= 1
End Sub
'整合包下载(安装)
Public Sub Install_Click(sender As MyListItem, e As EventArgs)
Try
'获取基本信息
Dim File As DlCfFile = sender.Tag
Dim LoaderName As String = "CurseForge 整合包下载:" & Project.ChineseName & " "
'获取版本名
Dim PackName As String = Project.ChineseName.Replace(".zip", "").Replace(".rar", "").Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(PackName) <> "" Then PackName = ""
Dim VersionName As String = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
Title:="输入版本名", Button2:="取消")
If String.IsNullOrEmpty(VersionName) Then Exit Sub
'构造步骤加载器
Dim Loaders As New List(Of LoaderBase)
Dim Target As String = PathMcFolder & "versions\" & VersionName & "\原始整合包.zip"
Loaders.Add(New LoaderDownload("下载整合包文件", New List(Of NetFile) From {File.GetDownloadFile(Target, True)}) With {.ProgressWeight = 10, .Block = True})
Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包",
Sub()
If Not ModpackInstall(Target, VersionName) Then Throw New Exception("整合包安装出现异常!")
End Sub) With {.ProgressWeight = 0.1})
'启动
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = Sub(MyLoader)
Select Case MyLoader.State
Case LoadState.Failed
Hint(MyLoader.Name & "失败:" & GetString(MyLoader.Error), HintType.Critical)
Case LoadState.Aborted
Hint(MyLoader.Name & "已取消!", HintType.Info)
Case LoadState.Loading
Exit Sub '不重新加载版本列表
End Select
McInstallFailedClearFolder(MyLoader)
End Sub}
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
Catch ex As Exception
Log(ex, "下载 CurseForge 整合包失败", LogLevel.Feedback)
End Try
End Sub
'Mod 下载;整合包另存为
Public Shared DownloadFolder = Nothing '仅在本次缓存的下载文件夹
Public Sub Save_Click(sender As Object, e As EventArgs)
Try
Dim Desc As String = If(Project.IsModPack, "整合包", "Mod ")
'确认默认保存位置
Dim DefaultFolder As String = Nothing
If Not Project.IsModPack Then
DefaultFolder = DownloadFolder
If McVersionCurrent IsNot Nothing Then
If Not McVersionCurrent.IsLoaded Then McVersionCurrent.Load()
If McVersionCurrent.Modable Then
DefaultFolder = McVersionCurrent.PathIndie & "mods\"
Directory.CreateDirectory(DefaultFolder)
End If
End If
If String.IsNullOrEmpty(DefaultFolder) Then DefaultFolder = Nothing
End If
'获取基本信息
Dim File As DlCfFile = If(TypeOf sender Is MyListItem, sender, sender.Parent).Tag
Dim ChineseName As String = If(Project.ChineseName = Project.Name, "",
Project.ChineseName.Replace(" (", "Å").Split("Å").First.Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":"))
Dim FileName As String
Select Case Setup.Get("ToolDownloadTranslate")
Case 0
FileName = If(ChineseName = "", "", "[" & ChineseName & "] ") & File.FileName
Case 1
FileName = If(ChineseName = "", "", ChineseName & "-") & File.FileName
Case 2
FileName = File.FileName & If(ChineseName = "", "", "-" & ChineseName)
Case Else
FileName = File.FileName
End Select
Dim Target As String
If File.FileName.EndsWith(".litemod") Then
Target = SelectAs("选择保存位置", FileName, Desc & "文件|" & If(Project.IsModPack, "*.zip", "*.litemod"), DefaultFolder)
Else
Target = SelectAs("选择保存位置", FileName, Desc & "文件|" & If(Project.IsModPack, "*.zip", "*.jar"), DefaultFolder)
End If
If Not Target.Contains("\") Then Exit Sub
Dim LoaderName As String = Desc & "下载:" & File.DisplayName & " "
If Target <> DefaultFolder AndAlso Not Project.IsModPack Then DownloadFolder = GetPathFromFullPath(Target)
'构造步骤加载器
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.GetDownloadFile(Target, True)}) With {.ProgressWeight = 6, .Block = True})
'启动
Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
Loader.Start(1)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
Catch ex As Exception
Log(ex, "保存 CurseForge 文件失败", LogLevel.Feedback)
End Try
End Sub
Private Sub BtnIntroCf_Click(sender As Object, e As EventArgs) Handles BtnIntroCf.Click
OpenWebsite(Project.Website)
End Sub
Private Sub BtnIntroWiki_Click(sender As Object, e As EventArgs) Handles BtnIntroWiki.Click
OpenWebsite("https://www.mcmod.cn/class/" & Project.WikiId & ".html")
End Sub
Private Sub BtnIntroMCBBS_Click(sender As Object, e As EventArgs) Handles BtnIntroMCBBS.Click
OpenWebsite("https://www.mcbbs.net/thread-" & Project.MCBBS & "-1-1.html")
End Sub
End Class
@@ -1,15 +1,15 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadClient"
d:DesignWidth="778.571" d:DesignHeight="90.857">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadClient"
PanScroll="{Binding ElementName=PanBack}">
<Grid>
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<!--<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="自动安装提示" x:Name="CardTip">
<StackPanel Margin="25,40,15,20">
<TextBlock Margin="0,0,0,2" Text="本页只提供需要在下载后手动进行安装的游戏 Jar 与 Json 下载。" TextWrapping="Wrap" />
<TextBlock Margin="0,0,0,2" Text="本页只提供需要在下载后手动进行安装的游戏 jar 与 json 下载。" TextWrapping="Wrap" />
<TextBlock Margin="0,0,0,11" Text="如果你想要进行自动安装,在游戏安装页选择游戏版本,然后直接安装即可。" TextWrapping="Wrap" />
<Grid Height="35">
<Grid.ColumnDefinitions>
@@ -39,7 +39,7 @@
Version("id") = "20w14∞"
Version("type") = "special"
Version.Add("lore", GetMcFoolName(Version("id")))
Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime"
Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime", "23w13a_or_b", "24w14potato"
Type = "愚人节版"
Version("type") = "special"
Version.Add("lore", GetMcFoolName(Version("id")))
@@ -55,9 +55,8 @@
Next
'排序
For i = 0 To Dict.Keys.Count - 1
Dict(Dict.Keys(i)) = Sort(Dict.Values(i), Function(Left As JObject, Right As JObject) As Boolean
Return Left("releaseTime").Value(Of Date) > Right("releaseTime").Value(Of Date)
End Function)
Dict(Dict.Keys(i)) = Sort(Dict.Values(i),
Function(a, b) a("releaseTime").Value(Of Date) > b("releaseTime").Value(Of Date))
Next
'清空当前
PanMain.Children.Clear()
@@ -65,11 +64,11 @@
Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 2}
Dim TopestVersions As New List(Of JObject)
Dim Release As JObject = Dict("正式版")(0).DeepClone()
Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
TopestVersions.Add(Release)
If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
TopestVersions.Add(Snapshot)
End If
Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}
@@ -78,7 +77,7 @@
PanMain.Children.Add(CardInfo)
'添加其他版本
For Each Pair As KeyValuePair(Of String, List(Of JObject)) In Dict
If Pair.Value.Count = 0 Then Continue For
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 2}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
@@ -0,0 +1,29 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadCompDetail"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<Grid Margin="25,25,25,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:MyCard Margin="0,0,0,25" x:Name="CardIntro">
<StackPanel Margin="22,18,22,19" x:Name="PanIntro">
<StackPanel Orientation="Horizontal" Height="35">
<local:MyButton x:Name="BtnIntroWeb" MinWidth="140" Text="转到 CurseForge" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
<local:MyButton x:Name="BtnIntroWiki" MinWidth="140" Text="转到 MC 百科" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
<local:MyButton x:Name="BtnIntroCopy" MinWidth="140" Text="复制名称" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
</StackPanel>
</StackPanel>
</local:MyCard>
<StackPanel Grid.Row="1" Grid.RowSpan="2" Name="PanMain" Grid.IsSharedSizeScope="True" />
<local:MyCard Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="0,0,0,8">
<local:MyLoading Text="正在获取版本列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
</Grid>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,329 @@
Public Class PageDownloadCompDetail
Private CompItem As MyCompItem = Nothing
#Region "加载器"
Private CompFileLoader As New LoaderTask(Of Integer, List(Of CompFile))(
"Comp File", Sub(Task As LoaderTask(Of Integer, List(Of CompFile))) Task.Output = CompFilesGet(Project.Id, Project.FromCurseForge))
'初始化加载器信息
Private Sub PageDownloadCompDetail_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
Project = FrmMain.PageCurrent.Additional(0)
TargetVersion = FrmMain.PageCurrent.Additional(2)
TargetLoader = FrmMain.PageCurrent.Additional(3)
PageLoaderInit(Load, PanLoad, PanMain, CardIntro, CompFileLoader, AddressOf Load_OnFinish)
End Sub
Private Sub PageDownloadCompDetail_Loaded(sender As Object, e As EventArgs) Handles Me.Loaded
'Initialized 只会执行一次
Project = FrmMain.PageCurrent.Additional(0)
TargetVersion = FrmMain.PageCurrent.Additional(2)
TargetLoader = FrmMain.PageCurrent.Additional(3)
End Sub
Private Project As CompProject
Private TargetVersion As String, TargetLoader As CompModLoaderType
'自动重试
Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
Select Case CompFileLoader.State
Case LoadState.Failed
Dim ErrorMessage As String = ""
If CompFileLoader.Error IsNot Nothing Then ErrorMessage = CompFileLoader.Error.Message
If ErrorMessage.Contains("不是有效的 json 文件") Then
Log("[Comp] 下载的文件 json 列表损坏,已自动重试", LogLevel.Debug)
PageLoaderRestart()
End If
End Select
End Sub
'结果 UI 化
Private Class VersionSorterWithSelect
Implements IComparer(Of String)
Public Top As String = ""
Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
If x = y Then Return 0
If x = Top Then Return -1
If y = Top Then Return 1
Return -VersionSortInteger(x, y)
End Function
Public Sub New(Optional Top As String = "")
Me.Top = If(Top, "")
End Sub
End Class
Private Sub Load_OnFinish()
Dim TargetCardName As String = If(TargetVersion <> "" OrElse TargetLoader <> CompModLoaderType.Any,
$"所选版本:{TargetVersion} {If(TargetLoader <> CompModLoaderType.Any, TargetLoader, "")}", "")
'初始化字典
Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New VersionSorterWithSelect(TargetCardName))
Dict.Add("未知版本", New List(Of CompFile))
For Each Version As CompFile In CompFileLoader.Output
For Each GameVersion In Version.GameVersions
'决定添加到哪个版本
Dim TargetCard As String
If GameVersion Is Nothing Then
TargetCard = "未知版本"
ElseIf GameVersion.Contains("w") OrElse GameVersion.Contains("pre") OrElse GameVersion.Contains("rc") Then
TargetCard = "快照版本"
ElseIf GameVersion.StartsWith("1.0") Then
TargetCard = "远古版本"
Else
TargetCard = GameVersion
End If
'实际进行添加
If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile))
If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
Next
Next
'添加筛选的版本的卡片
If TargetCardName <> "" Then
Dict.Add(TargetCardName, New List(Of CompFile))
For Each Version As CompFile In CompFileLoader.Output
If Version.GameVersions.Contains(TargetVersion) AndAlso
(TargetLoader = CompModLoaderType.Any OrElse Version.ModLoaders.Contains(TargetLoader)) Then
If Not Dict(TargetCardName).Contains(Version) Then Dict(TargetCardName).Add(Version)
End If
Next
End If
#Region "转化为 UI"
Try
'清空当前
PanMain.Children.Clear()
'转化为 UI
For Each Pair As KeyValuePair(Of String, List(Of CompFile)) In Dict
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(Project.Type = CompType.ModPack, 9, 8)} 'FUTURE: Res
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
NewCard.Children.Add(NewStack)
NewCard.SwapControl = NewStack
PanMain.Children.Add(NewCard)
'确定卡片是否展开
If Pair.Key = TargetCardName OrElse
(FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then
MyCard.StackInstall(NewStack, If(Project.Type = CompType.ModPack, 9, 8), Pair.Key) 'FUTURE: Res
Else
NewCard.IsSwaped = True
End If
'增加提示
If Pair.Key = "未知版本" Then
NewStack.Children.Add(New MyHint With {.Text = "由于 API 的版本信息更新缓慢,可能无法识别刚更新不久的 MC 版本,只需等待几天即可自动恢复正常。", .IsWarn = False, .Margin = New Thickness(0, 0, 0, 7)})
End If
Next
'如果只有一张卡片,展开第一张卡片
If PanMain.Children.Count = 1 Then
CType(PanMain.Children(0), MyCard).IsSwaped = False
End If
Catch ex As Exception
Log(ex, "可视化工程下载列表出错", LogLevel.Feedback)
End Try
#End Region
End Sub
#End Region
Private IsFirstInit As Boolean = True
Public Sub Init() Handles Me.PageEnter
AniControlEnabled += 1
Project = FrmMain.PageCurrent.Additional(0)
PanBack.ScrollToHome()
'重启加载器
If IsFirstInit Then
'在 Me.Initialized 已经初始化了加载器,不再重复初始化
IsFirstInit = False
Else
PageLoaderRestart(IsForceRestart:=True)
End If
'放置当前工程
If CompItem IsNot Nothing Then PanIntro.Children.Remove(CompItem)
CompItem = Project.ToCompItem(True, True)
CompItem.CanInteraction = False
CompItem.Margin = New Thickness(-7, -7, 0, 8)
PanIntro.Children.Insert(0, CompItem)
'决定按钮显示
BtnIntroWeb.Text = If(Project.FromCurseForge, "转到 CurseForge", "转到 Modrinth")
BtnIntroWiki.Visibility = If(Project.WikiId = 0, Visibility.Collapsed, Visibility.Visible)
AniControlEnabled -= 1
End Sub
'整合包下载(安装)
Public Sub Install_Click(sender As MyListItem, e As EventArgs)
Try
'获取基本信息
Dim File As CompFile = sender.Tag
Dim LoaderName As String = $"{If(Project.FromCurseForge, "CurseForge", "Modrinth")} 整合包下载:{Project.TranslatedName} "
'获取版本名
Dim PackName As String = Project.TranslatedName.Replace(".zip", "").Replace(".rar", "").Replace(".mrpack", "").Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(PackName) <> "" Then PackName = ""
Dim VersionName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
If String.IsNullOrEmpty(VersionName) Then Exit Sub
'构造步骤加载器
Dim Loaders As New List(Of LoaderBase)
Dim Target As String = $"{PathMcFolder}versions\{VersionName}\原始整合包.{If(Project.FromCurseForge, "zip", "mrpack")}"
Dim LogoFileAddress As String = PathTemp & "CompLogo\" & GetHash(CompItem.Logo) & ".png"
Loaders.Add(New LoaderDownload("下载整合包文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 10, .Block = True})
Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包",
Sub()
If Not ModpackInstall(Target, VersionName, Logo:=If(IO.File.Exists(LogoFileAddress), LogoFileAddress, Nothing)) Then
Throw New Exception("整合包安装出现异常!")
End If
End Sub) With {.ProgressWeight = 0.1})
'启动
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = Sub(MyLoader)
Select Case MyLoader.State
Case LoadState.Failed
Hint(MyLoader.Name & "失败:" & GetExceptionSummary(MyLoader.Error), HintType.Critical)
Case LoadState.Aborted
Hint(MyLoader.Name & "已取消!", HintType.Info)
Case LoadState.Loading
Exit Sub '不重新加载版本列表
End Select
McInstallFailedClearFolder(MyLoader)
End Sub}
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
Catch ex As Exception
Log(ex, "下载资源整合包失败", LogLevel.Feedback)
End Try
End Sub
'Mod 下载;整合包另存为
Public Shared CachedFolder As String = Nothing '仅在本次缓存的下载文件夹
Public Sub Save_Click(sender As Object, e As EventArgs)
Dim File As CompFile = If(TypeOf sender Is MyListItem, sender, sender.Parent).Tag
RunInNewThread(
Sub()
Try
Dim Desc As String = If(Project.Type = CompType.ModPack, "整合包", If(Project.Type = CompType.Mod, "Mod ", "资源包"))
'确认默认保存位置
Dim DefaultFolder As String = Nothing
If Project.Type = CompType.Mod Then
'获取 Mod 所需的加载器种类
Dim AllowForge As Boolean? = Nothing, AllowFabric As Boolean? = Nothing
If File.ModLoaders.Any Then '从文件中获取
AllowForge = File.ModLoaders.Contains(CompModLoaderType.Forge)
AllowFabric = File.ModLoaders.Contains(CompModLoaderType.Fabric)
ElseIf Project.ModLoaders.Any Then '从工程中获取
AllowForge = Project.ModLoaders.Contains(CompModLoaderType.Forge)
AllowFabric = Project.ModLoaders.Contains(CompModLoaderType.Fabric)
End If
If AllowForge IsNot Nothing AndAlso Not AllowForge AndAlso
AllowFabric IsNot Nothing AndAlso Not AllowFabric Then
AllowForge = Nothing : AllowFabric = Nothing
End If
Log("[Comp] 允许 Forge:" & If(AllowForge, "未知") & ",允许 Fabric:" & If(AllowFabric, "未知"))
'判断某个版本是否符合要求
Dim IsVersionSuitable As Func(Of McVersion, Boolean) =
Function(Version)
If Not Version.IsLoaded Then Version.Load()
If Not Version.Modable Then Return False
If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso
Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v.Split(".")(1) = Version.Version.McCodeMain.ToString) Then Return False
If AllowForge Is Nothing OrElse AllowFabric Is Nothing Then Return True
If AllowForge AndAlso Version.Version.HasForge Then Return True
If AllowFabric AndAlso Version.Version.HasFabric Then Return True
Return False
End Function
'获取 Mod 默认下载位置
If CachedFolder IsNot Nothing Then
DefaultFolder = CachedFolder
Log("[Comp] 使用上次下载时的文件夹作为默认下载位置")
ElseIf McVersionCurrent IsNot Nothing AndAlso IsVersionSuitable(McVersionCurrent) Then
DefaultFolder = McVersionCurrent.PathIndie & "mods\"
Directory.CreateDirectory(DefaultFolder)
Log("[Comp] 使用当前版本的 mods 文件夹作为默认下载位置(" & McVersionCurrent.Name & ")")
Else
Dim NeedLoad As Boolean = McVersionListLoader.State <> LoadState.Finished
If NeedLoad Then
Hint("正在查找适合的游戏版本……")
LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
End If
Dim SuitableVersions As New List(Of McVersion)
For Each Version As McVersion In McVersionList.Values.SelectMany(Function(l) l)
If IsVersionSuitable(Version) Then SuitableVersions.Add(Version)
Next
If Not SuitableVersions.Any() Then
DefaultFolder = PathMcFolder
If NeedLoad Then
Hint("当前 MC 文件夹中没有找到适合这个 Mod 的版本!")
Else
Log("[Comp] 由于当前版本不兼容,使用当前的 MC 文件夹作为默认下载位置")
End If
Else '选择 Mod 数量最多的版本
Dim SelectedVersion = SuitableVersions.OrderBy(Function(v)
Dim Info As New DirectoryInfo(v.PathIndie & "mods\")
Return If(Info.Exists, Info.GetFiles().Length, -1)
End Function).LastOrDefault()
DefaultFolder = SelectedVersion.PathIndie & "mods\"
Directory.CreateDirectory(DefaultFolder)
Log("[Comp] 使用适合的游戏版本作为默认下载位置(" & SelectedVersion.Name & ")")
End If
End If
End If
'获取基本信息
Dim FileName As String
If Project.TranslatedName = Project.RawName Then
FileName = File.FileName
Else
Dim ChineseName As String = Project.TranslatedName.Split(" (").First.Split(" - ").First.
Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
Select Case Setup.Get("ToolDownloadTranslate")
Case 0
FileName = $"[{ChineseName}] {File.FileName}"
Case 1
FileName = $"{ChineseName}-{File.FileName}"
Case 2
FileName = $"{File.FileName}-{ChineseName}"
Case Else
FileName = File.FileName
End Select
End If
RunInUi(
Sub()
'弹窗要求选择保存位置
Dim Target As String
Target = SelectAs("选择保存位置", FileName,
Desc & "文件|" &
If(Project.Type = CompType.Mod,
If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"),
If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
If Not Target.Contains("\") Then Exit Sub
'构造步骤加载器
Dim LoaderName As String = Desc & "下载:" & File.DisplayName & " "
If Target <> DefaultFolder AndAlso Project.Type = CompType.Mod Then CachedFolder = GetPathFromFullPath(Target)
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True})
'启动
Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
Loader.Start(1)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
End Sub)
Catch ex As Exception
Log(ex, "保存资源文件失败", LogLevel.Feedback)
End Try
End Sub, "Download CompDetail Save")
End Sub
Private Sub BtnIntroWeb_Click(sender As Object, e As EventArgs) Handles BtnIntroWeb.Click
OpenWebsite(Project.Website)
End Sub
Private Sub BtnIntroWiki_Click(sender As Object, e As EventArgs) Handles BtnIntroWiki.Click
OpenWebsite("https://www.mcmod.cn/class/" & Project.WikiId & ".html")
End Sub
Private Sub BtnIntroCopy_Click(sender As Object, e As EventArgs) Handles BtnIntroCopy.Click
ClipboardSet(CompItem.LabTitle.Text)
End Sub
End Class
@@ -1,9 +1,9 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadFabric"
d:DesignWidth="778.571" d:DesignHeight="90.857">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadFabric"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="Fabric 简介" x:Name="CardTip">
@@ -1,9 +1,9 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadForge"
d:DesignWidth="778.571" d:DesignHeight="90.857">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadForge"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="Forge 简介" x:Name="CardTip">
@@ -1,31 +1,31 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadInstall"
d:DesignWidth="778.571" d:DesignHeight="90.857">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadInstall"
PanScroll="{Binding ElementName=PanBack}">
<Grid>
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<Grid Margin="25,10,25,25">
<VirtualizingStackPanel Grid.Row="1" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" Name="PanMinecraft" Grid.IsSharedSizeScope="True">
<VirtualizingStackPanel.RenderTransform>
<StackPanel Grid.Row="1" Name="PanMinecraft" Grid.IsSharedSizeScope="True" Margin="0,0,0,-10">
<StackPanel.RenderTransform>
<TranslateTransform />
</VirtualizingStackPanel.RenderTransform>
</VirtualizingStackPanel>
</StackPanel.RenderTransform>
</StackPanel>
<StackPanel Grid.Row="1" x:Name="PanSelect" Visibility="Collapsed" Opacity="0" IsHitTestVisible="False">
<StackPanel.RenderTransform>
<TranslateTransform X="40" />
</StackPanel.RenderTransform>
<local:MyCard Title="安装预览" Margin="0,15,0,0" UseAnimation="False">
<StackPanel Margin="25,37,25,15">
<local:MyHint Text="你尚未选择安装 Fabric API,这会导致大多数 Mod 无法使用!" Margin="0,1,0,7" x:Name="HintFabricAPI" />
<local:MyHint Text="你尚未选择安装 OptiFabric,这会导致 OptiFine 无法使用!" Margin="0,1,0,7" x:Name="HintOptiFabric" />
<local:MyHint Text="你尚未选择安装 Fabric API,这会导致大多数 Mod 无法使用!" Margin="0,1,0,7" x:Name="HintFabricAPI" IsWarn="True" />
<local:MyHint Text="你尚未选择安装 OptiFabric,这会导致 OptiFine 无法使用!" Margin="0,1,0,7" x:Name="HintOptiFabric" IsWarn="True" />
<Grid Margin="0,0,0,11">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:MyListItem Grid.Column="0" x:Name="ItemSelect" IsHitTestVisible="False" Margin="-7,0,0,0" Height="42" PaddingRight="15" SnapsToDevicePixels="True" Type="None" />
<local:MyListItem Grid.Column="0" x:Name="ItemSelect" IsHitTestVisible="False" Margin="-7,0,0,0" Height="42" SnapsToDevicePixels="True" Type="None" />
<local:MyButton Grid.Column="1" HorizontalAlignment="Right" ColorType="Highlight" Text="开始安装" Margin="0,2,0,0" x:Name="BtnSelectStart" MinWidth="140" Padding="13,0" Height="35" VerticalAlignment="Center" />
</Grid>
<Grid Margin="0,0,0,5">
@@ -38,8 +38,7 @@
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Title="Minecraft" Height="40" Margin="0,15,0,0" x:Name="CardMinecraft" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<FrameworkElement Tag="用于折叠" />
<local:MyCard Title="Minecraft" Height="40" Margin="0,15,0,0" x:Name="CardMinecraft">
<Grid x:Name="PanMinecraftInfo" Height="18" Margin="175,11,15,0" VerticalAlignment="Top">
<Grid.RenderTransform>
<TranslateTransform />
@@ -47,9 +46,18 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image x:Name="ImgMinecraft" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" />
<TextBlock x:Name="LabMinecraft" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
<Path Data="M2,4 l-2,2 10,10 10,-10 -2,-2 -8,8 -8,-8 z" Height="6" Width="10" Stretch="Uniform" VerticalAlignment="Center"
Grid.Column="2" Fill="{StaticResource ColorBrushGray4}" Margin="0,1,6,0" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<RotateTransform Angle="90" />
</Path.RenderTransform>
</Path>
<TextBlock VerticalAlignment="Center" Text="返回" Grid.Column="3" Foreground="{StaticResource ColorBrushGray4}" />
</Grid>
</local:MyCard>
<local:MyCard Title="OptiFine" Height="40" Margin="0,15,0,0" x:Name="CardOptiFine" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
@@ -91,9 +99,7 @@
</Grid>
</local:MyCard>
<local:MyCard Title="Fabric" Height="40" Margin="0,15,0,0" x:Name="CardFabric" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top">
<StackPanel Name="PanFabric" />
</StackPanel>
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanFabric" />
<Grid x:Name="PanFabricInfo" Height="18" Margin="175,11,15,0" VerticalAlignment="Top" Tag="True">
<Grid.RenderTransform>
<TranslateTransform />
@@ -32,12 +32,14 @@
#Region "页面切换"
'页面切换动画
Private IsInSelectPage As Boolean = False
Public IsInSelectPage As Boolean = False
Private IsFirstLoaded As Boolean = False
Private Sub EnterSelectPage()
If IsInSelectPage Then Exit Sub
IsInSelectPage = True
AutoSelectedFabricApi = False
AutoSelectedOptiFabric = False
IsSelectNameEdited = False
PanSelect.Visibility = Visibility.Visible
PanSelect.IsHitTestVisible = True
@@ -131,7 +133,7 @@
End Sub
'页面切换触发
Public Sub MinecraftSelected(sender As MyListItem, e As Object)
Public Sub MinecraftSelected(sender As MyListItem, e As MouseButtonEventArgs)
SelectedMinecraftId = sender.Title
SelectedMinecraftJsonUrl = sender.Tag("url").ToString
SelectedMinecraftIcon = sender.Logo
@@ -232,7 +234,7 @@
End Sub
'FabricApi
Private SelectedFabricApi As DlCfFile = Nothing
Private SelectedFabricApi As CompFile = Nothing
Private Sub SetFabricApiInfoShow(IsShow As String)
If PanFabricApiInfo.Tag = IsShow Then Exit Sub
PanFabricApiInfo.Tag = IsShow
@@ -252,7 +254,7 @@
End Sub
'OptiFabric
Private SelectedOptiFabric As DlCfFile = Nothing
Private SelectedOptiFabric As CompFile = Nothing
Private Sub SetOptiFabricInfoShow(IsShow As String)
If PanOptiFabricInfo.Tag = IsShow Then Exit Sub
PanOptiFabricInfo.Tag = IsShow
@@ -271,11 +273,13 @@
End If
End Sub
Private IsReloading As Boolean = False '#3742 中,LoadOptiFineGetError 会初始化 LoadOptiFine,触发事件 LoadOptiFine.StateChanged,导致再次调用 SelectReload
''' <summary>
''' 重载已选择的项目的显示。
''' </summary>
Private Sub SelectReload() Handles CardOptiFine.Swap, LoadOptiFine.StateChanged, CardForge.Swap, LoadForge.StateChanged, CardFabric.Swap, LoadFabric.StateChanged, CardFabricApi.Swap, LoadFabricApi.StateChanged, CardOptiFabric.Swap, LoadOptiFabric.StateChanged, CardLiteLoader.Swap, LoadLiteLoader.StateChanged
If SelectedMinecraftId Is Nothing Then Exit Sub
If SelectedMinecraftId Is Nothing OrElse IsReloading Then Exit Sub
IsReloading = True
'主预览
SelectNameUpdate()
ItemSelect.Title = TextSelectName.Text
@@ -382,7 +386,13 @@
End If
'主警告
HintFabricAPI.Visibility = If(SelectedFabric IsNot Nothing AndAlso SelectedFabricApi Is Nothing, Visibility.Visible, Visibility.Collapsed)
HintOptiFabric.Visibility = If(SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso SelectedOptiFabric Is Nothing, Visibility.Visible, Visibility.Collapsed)
If SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso SelectedOptiFabric Is Nothing Then
HintOptiFabric.Visibility = Visibility.Visible
Else
HintOptiFabric.Visibility = Visibility.Collapsed
End If
'结束
IsReloading = False
End Sub
''' <summary>
''' 清空已选择的项目。
@@ -510,7 +520,7 @@
Version("id") = "20w14∞"
Version("type") = "special"
Version.Add("lore", GetMcFoolName(Version("id")))
Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime"
Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime", "23w13a_or_b", "24w14potato"
Type = "愚人节版"
Version("type") = "special"
Version.Add("lore", GetMcFoolName(Version("id")))
@@ -536,11 +546,11 @@
Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15), .SwapType = 2}
Dim TopestVersions As New List(Of JObject)
Dim Release As JObject = Dict("正式版")(0).DeepClone()
Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
TopestVersions.Add(Release)
If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
TopestVersions.Add(Snapshot)
End If
Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}
@@ -549,7 +559,7 @@
PanMinecraft.Children.Insert(0, CardInfo)
'添加其他版本
For Each Pair As KeyValuePair(Of String, List(Of JObject)) In Dict
If Pair.Value.Count = 0 Then Continue For
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 7}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
@@ -558,10 +568,23 @@
NewCard.IsSwaped = True
PanMinecraft.Children.Add(NewCard)
Next
'自动选择版本
If McVersionWaitingForSelect Is Nothing Then Exit Try
Log("[Download] 自动选择 MC 版本:" & McVersionWaitingForSelect)
For Each Version As JObject In Versions
If Version("id").ToString <> McVersionWaitingForSelect Then Continue For
Dim Item = McDownloadListItem(Version, Sub()
End Sub, False)
MinecraftSelected(Item, Nothing)
Next
Catch ex As Exception
Log(ex, "可视化安装版本列表出错", LogLevel.Feedback)
End Try
End Sub
''' <summary>
''' 当 MC 版本列表加载完时,立即自动选择的版本。用于外部调用。
''' </summary>
Public Shared McVersionWaitingForSelect As String = Nothing
#End Region
@@ -571,7 +594,7 @@
''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadOptiFineGetError() As String
If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadOptiFine Is Nothing OrElse LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFine.State, Object).Error.Message
'检查 Forge 1.13 - 1.14.3:全部不兼容
If SelectedForge IsNot Nothing AndAlso
@@ -580,18 +603,23 @@
End If
'检查最低 Forge 版本
Dim MinimalForgeVersion As String = "9999.9999"
Dim NotSuitForForge As Boolean = False
For Each OptiFineVersion As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
If Not OptiFineVersion.NameDisplay.StartsWith(SelectedMinecraftId & " ") Then Continue For '不是同一个大版本
If SelectedForge Is Nothing OrElse IsOptiFineSuitForForge(OptiFineVersion, SelectedForge) Then
Return Nothing
If SelectedForge Is Nothing Then Return Nothing '该版本可用
If IsOptiFineSuitForForge(OptiFineVersion, SelectedForge) Then
Return Nothing '该版本可用
Else
'设置用于显示的最低 Forge 版本
MinimalForgeVersion = If(VersionSortBoolean(MinimalForgeVersion, OptiFineVersion.RequiredForgeVersion),
OptiFineVersion.RequiredForgeVersion, MinimalForgeVersion)
NotSuitForForge = True
If OptiFineVersion.RequiredForgeVersion IsNot Nothing Then
'设置用于显示的最低允许的 Forge 版本
MinimalForgeVersion = If(VersionSortBoolean(MinimalForgeVersion, OptiFineVersion.RequiredForgeVersion),
OptiFineVersion.RequiredForgeVersion, MinimalForgeVersion)
End If
End If
Next
If MinimalForgeVersion = "9999.9999" Then
Return "没有可用版本"
Return If(NotSuitForForge, "与 Forge 不兼容", "没有可用版本")
Else
Return "需要 Forge " & If(MinimalForgeVersion.Contains("."), "", "#") & MinimalForgeVersion & " 或更高版本"
End If
@@ -600,6 +628,7 @@
'检查某个 OptiFine 是否与某个 Forge 兼容(最低 Forge 版本是否达到需求)
Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
If OptiFine.RequiredForgeVersion Is Nothing Then Return False '不兼容 Forge
Return (OptiFine.RequiredForgeVersion.Contains(".") AndAlso 'XX.X.XXX
VersionSortInteger(Forge.Version, OptiFine.RequiredForgeVersion) >= 0) OrElse
(Not OptiFine.RequiredForgeVersion.Contains(".") AndAlso '#XXXX
@@ -624,9 +653,11 @@
If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(Version, SelectedForge) Then Continue For
If Version.NameDisplay.StartsWith(SelectedMinecraftId & " ") Then Versions.Add(Version)
Next
If Versions.Count = 0 Then Exit Sub
If Not Versions.Any() Then Exit Sub
'排序
Versions = Sort(Versions, Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
If Not Left.IsPreview AndAlso Right.IsPreview Then Return True
If Left.IsPreview AndAlso Not Right.IsPreview Then Return False
Return VersionSortBoolean(Left.NameDisplay, Right.NameDisplay)
End Function)
'可视化
@@ -666,7 +697,7 @@
''' </summary>
Private Function LoadLiteLoaderGetError() As String
If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) > 12 Then Return "没有可用版本"
If LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadLiteLoader Is Nothing OrElse LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadLiteLoader.State, Object).Error.Message
For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
If Version.Inherit = SelectedMinecraftId Then Return Nothing
@@ -690,7 +721,7 @@
For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
If Version.Inherit = SelectedMinecraftId Then Versions.Add(Version)
Next
If Versions.Count = 0 Then Exit Sub
If Not Versions.Any() Then Exit Sub
'可视化
PanLiteLoader.Children.Clear()
For Each Version In Versions
@@ -736,13 +767,21 @@
End If
End If
If Loader.State <> LoadState.Finished Then Return "获取版本列表失败:未知错误,状态为 " & GetStringFromEnum(Loader.State)
Dim NotSuitForOptiFine As Boolean = False
For Each Version In Loader.Output
If Version.Category = "universal" OrElse Version.Category = "client" Then Continue For '跳过无法自动安装的版本
If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
If SelectedOptiFine IsNot Nothing AndAlso VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then Return "与 OptiFine 不兼容"
If SelectedOptiFine IsNot Nothing AndAlso
VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then
Return "与 OptiFine 不兼容" '1.13 ~ 1.14.3 OptiFine 检查
End If
If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, Version) Then
NotSuitForOptiFine = True '与 OptiFine 不兼容
Continue For
End If
Return Nothing
Next
Return "该版本不支持自动安装"
Return If(NotSuitForOptiFine, "与 OptiFine 不兼容", "该版本不支持自动安装")
End Function
'限制展开
@@ -759,18 +798,19 @@
Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
If SelectedMinecraftId <> Loader.Input Then Exit Sub
If Loader.State <> LoadState.Finished Then Exit Sub
'可视化
'获取要显示的版本
Dim Versions As New List(Of DlForgeVersionEntry)
Versions.AddRange(Loader.Output) '复制数组,以免 Output 在实例化后变空
If Loader.Output.Count = 0 Then Exit Sub
If Not Loader.Output.Any() Then Exit Sub
PanForge.Children.Clear()
Versions = Sort(Versions, Function(Left As DlForgeVersionEntry, Right As DlForgeVersionEntry) As Boolean
Return New Version(Left.Version) > New Version(Right.Version)
End Function)
Versions = Sort(Versions, Function(a, b) New Version(a.Version) > New Version(b.Version)).
Where(Function(v)
If v.Category = "universal" OrElse v.Category = "client" Then Return False '跳过无法自动安装的版本
If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, v) Then Return False
Return True
End Function).ToList
ForgeDownloadListItemPreload(PanForge, Versions, AddressOf Forge_Selected, False)
For Each Version In Versions
If Version.Category = "universal" OrElse Version.Category = "client" Then Continue For '跳过无法自动安装的版本
If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, Version) Then Continue For
PanForge.Children.Add(ForgeDownloadListItem(Version, AddressOf Forge_Selected, False))
Next
Catch ex As Exception
@@ -802,10 +842,10 @@
''' 获取 Fabric 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadFabricGetError() As String
If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadFabric Is Nothing OrElse LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabric.State, Object).Error.Message
For Each Version As JObject In DlFabricListLoader.Output.Value("game")
If Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite") Then
If Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") Then
If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
'If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
Return Nothing
@@ -827,28 +867,24 @@
If DlFabricListLoader.State <> LoadState.Finished Then Exit Sub
'获取版本列表
Dim Versions As JArray = DlFabricListLoader.Output.Value("loader")
If Versions.Count = 0 Then Exit Sub
If Not Versions.Any() Then Exit Sub
'可视化
PanFabric.Children.Clear()
For Each Version In Versions
PanFabric.Children.Add(FabricDownloadListItem(Version, AddressOf Fabric_Selected))
Next
PanFabric.Tag = Versions
CardFabric.SwapControl = PanFabric
CardFabric.SwapType = 12
Catch ex As Exception
Log(ex, "可视化 Fabric 安装版本列表出错", LogLevel.Feedback)
End Try
End Sub
'选择与清除
Private Sub Fabric_Selected(sender As MyListItem, e As EventArgs)
Public Sub Fabric_Selected(sender As MyListItem, e As EventArgs)
SelectedFabric = sender.Tag("version").ToString
FabricApi_Loaded()
OptiFabric_Loaded()
CardFabric.IsSwaped = True
SelectReload()
If Not Setup.Get("HintInstallFabricApi") Then
Setup.Set("HintInstallFabricApi", True)
Hint("安装 Fabric 时通常还需要安装 Fabric API,在选择 Fabric 后就会显示其安装选项!")
End If
End Sub
Private Sub Fabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricClear.MouseLeftButtonUp
SelectedFabric = Nothing
@@ -869,7 +905,7 @@
Public Shared Function IsSuitableFabricApi(DisplayName As String, MinecraftVersion As String) As Boolean
Try
If DisplayName Is Nothing OrElse MinecraftVersion Is Nothing Then Return False
DisplayName = DisplayName.ToLower : MinecraftVersion = MinecraftVersion.ToLower
DisplayName = DisplayName.ToLower : MinecraftVersion = MinecraftVersion.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").ToLower
If DisplayName.StartsWith("[" & MinecraftVersion & "]") Then Return True
If Not DisplayName.Contains("/") OrElse Not DisplayName.Contains("]") Then Return False
'直接的判断(例如 1.18.1/22w03a)
@@ -906,11 +942,16 @@
''' 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadFabricApiGetError() As String
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
If LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadFabricApi Is Nothing OrElse LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabricApi.State, Object).Error.Message
If DlFabricApiLoader.Output Is Nothing Then
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
Return "正在获取版本列表……"
End If
For Each Version In DlFabricApiLoader.Output
If IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Return Nothing
If Not IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Continue For
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
Return Nothing
Next
Return "没有可用版本"
End Function
@@ -920,6 +961,7 @@
If LoadFabricApiGetError() IsNot Nothing Then e.Handled = True
End Sub
Private AutoSelectedFabricApi As Boolean = False
''' <summary>
''' 尝试重新可视化 FabricApi 版本列表。
''' </summary>
@@ -928,7 +970,7 @@
If DlFabricApiLoader.State <> LoadState.Finished Then Exit Sub
If SelectedMinecraftId Is Nothing OrElse SelectedFabric Is Nothing Then Exit Sub
'获取版本列表
Dim Versions As New List(Of DlCfFile)
Dim Versions As New List(Of CompFile)
For Each Version In DlFabricApiLoader.Output
If IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then
If Not Version.DisplayName.StartsWith("[") Then
@@ -938,17 +980,20 @@
Versions.Add(Version)
End If
Next
If Versions.Count = 0 Then Exit Sub
'排序
Versions = Sort(Versions, Function(Left As DlCfFile, Right As DlCfFile) As Boolean
Return Left.Date > Right.Date
End Function)
If Not Versions.Any() Then Exit Sub
Versions = Sort(Versions, Function(a, b) a.ReleaseDate > b.ReleaseDate)
'可视化
PanFabricApi.Children.Clear()
For Each Version In Versions
If Not IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Continue For
PanFabricApi.Children.Add(FabricApiDownloadListItem(Version, AddressOf FabricApi_Selected))
Next
'自动选择 Fabric API
If Not AutoSelectedFabricApi Then
AutoSelectedFabricApi = True
Log($"[Download] 已自动选择 Fabric API:{CType(PanFabricApi.Children(0), MyListItem).Title}")
FabricApi_Selected(PanFabricApi.Children(0), Nothing)
End If
Catch ex As Exception
Log(ex, "可视化 Fabric API 安装版本列表出错", LogLevel.Feedback)
End Try
@@ -974,27 +1019,35 @@
''' <summary>
''' 从显示名判断该 Mod 是否与某版本适配。
''' </summary>
Private Function IsSuitableOptiFabric(ModFile As DlCfFile, MinecraftVersion As String) As Boolean
Private Function IsSuitableOptiFabric(ModFile As CompFile, MinecraftVersion As String) As Boolean
Try
If MinecraftVersion Is Nothing Then Return False
Return ModFile.GameVersion.Contains(MinecraftVersion)
Return ModFile.GameVersions.Contains(MinecraftVersion)
Catch ex As Exception
Log(ex, "判断 OptiFabric 版本适配性出错(" & MinecraftVersion & ")")
Return False
End Try
End Function
Private AutoSelectedOptiFabric As Boolean = False
''' <summary>
''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadOptiFabricGetError() As String
If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadOptiFabric Is Nothing OrElse LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFabric.State, Object).Error.Message
If DlOptiFabricLoader.Output Is Nothing Then
If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
Return "正在获取版本列表……"
End If
For Each Version In DlOptiFabricLoader.Output
If IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Return Nothing
If Not IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Continue For '2135#
If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
Return Nothing '通过检查
Next
Return "没有可用版本"
End Function
@@ -1012,23 +1065,27 @@
If DlOptiFabricLoader.State <> LoadState.Finished Then Exit Sub
If SelectedMinecraftId Is Nothing OrElse SelectedFabric Is Nothing OrElse SelectedOptiFine Is Nothing Then Exit Sub
'获取版本列表
Dim Versions As New List(Of DlCfFile)
Dim Versions As New List(Of CompFile)
For Each Version In DlOptiFabricLoader.Output
If IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Versions.Add(Version)
Next
If Versions.Count = 0 Then Exit Sub
If Not Versions.Any() Then Exit Sub
'排序
Versions = Sort(Versions, Function(Left As DlCfFile, Right As DlCfFile) As Boolean
Return Left.Date > Right.Date
End Function)
Versions = Sort(Versions, Function(a, b) a.ReleaseDate > b.ReleaseDate)
'可视化
PanOptiFabric.Children.Clear()
For Each Version In Versions
If Not IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Continue For
PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
Next
'自动选择 OptiFabric
If Not AutoSelectedOptiFabric Then
AutoSelectedOptiFabric = True
Log($"[Download] 已自动选择 OptiFabric:{CType(PanOptiFabric.Children(0), MyListItem).Title}")
OptiFabric_Selected(PanOptiFabric.Children(0), Nothing)
End If
Catch ex As Exception
Log(ex, "可视化 Fabric API 安装版本列表出错", LogLevel.Feedback)
Log(ex, "可视化 OptiFabric 安装版本列表出错", LogLevel.Feedback)
End Try
End Sub
@@ -1049,19 +1106,23 @@
#Region "安装"
Private Sub BtnSelectStart_Click(sender As Object, e As EventArgs) Handles BtnSelectStart.Click
Private Sub TextSelectName_KeyDown(sender As Object, e As KeyEventArgs) Handles TextSelectName.KeyDown
If e.Key = Key.Enter AndAlso BtnSelectStart.IsEnabled Then BtnSelectStart_Click()
End Sub
Private Sub BtnSelectStart_Click() Handles BtnSelectStart.Click
'确认版本隔离
If (SelectedForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
(Setup.Get("LaunchArgumentIndie") = 0 OrElse Setup.Get("LaunchArgumentIndie") = 2) Then
If MyMsgBox("你尚未开启版本隔离,这会导致多个 MC 共用同一个 Mod 文件夹。" & vbCrLf &
"因此在切换 MC 版本时,MC 会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
"PCL2 推荐你在开始下载前,在 设置 → 版本隔离 中开启版本隔离选项!", "版本隔离提示", "取消下载", "继续") = 1 Then
"PCL 推荐你在开始下载前,在 设置 → 版本隔离 中开启版本隔离选项!", "版本隔离提示", "取消下载", "继续") = 1 Then
Exit Sub
End If
End If
'提交安装申请
Dim Request As New McInstallRequest With {
.TargetVersionName = TextSelectName.Text,
.TargetVersionFolder = $"{PathMcFolder}versions\{TextSelectName.Text}\",
.MinecraftJson = SelectedMinecraftJsonUrl,
.MinecraftName = SelectedMinecraftId,
.OptiFineEntry = SelectedOptiFine,
@@ -4,75 +4,75 @@
xmlns:local="clr-namespace:PCL" AnimatedControl="{Binding ElementName=PanItem, Mode=OneWay}">
<StackPanel Margin="0,12,0,0" Name="PanItem">
<TextBlock x:Name="LabGame" Text="游戏组件" Margin="13,6,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemInstall" Checked="True" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="1" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="自动安装"
<TextBlock x:Name="LabGame" Text="Minecraft" Margin="13,6,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemInstall" Checked="True" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="1" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="自动安装"
LogoScale="0.87" Logo="M1091.291429 0H78.935771C35.34848 0.035109 0.029257 35.354331 0 78.935771v863.331475c0 43.534629 35.401143 78.994286 78.935771 78.994285H1091.291429c43.534629 0 78.994286-35.401143 78.994285-78.994285V78.871406C1170.156983 35.319223 1134.849463 0.064366 1091.291429 0z m-8.835658 87.771429v78.754377H87.771429v-78.760229h994.684342zM87.771429 933.425737V254.232869h994.684342v679.140205H87.771429v0.058515zM724.95104 340.00896l-206.19264 547.605943a43.903269 43.903269 0 0 1-82.154057-31.012572l206.139977-547.547428a43.944229 43.944229 0 0 1 82.20672 30.954057zM369.558674 545.909029l-85.489371 85.489371 85.489371 85.542034a43.885714 43.885714 0 0 1-62.025143 62.083657l-116.554605-116.560457a43.8272 43.8272 0 0 1 0-62.025143l116.560457-116.49024a43.885714 43.885714 0 0 1 62.019291 61.966629z m610.567315-37.566172a43.885714 43.885714 0 0 1 0 62.083657l-116.560458 116.560457a43.768686 43.768686 0 0 1-62.019291 0 43.885714 43.885714 0 0 1 0-62.083657l85.547886-85.547885-85.547886-85.542035a43.897417 43.897417 0 0 1 62.083657-62.083657l116.496092 116.618972z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="1" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="1" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemHand" IsScaleAnimationEnabled="False" Type="RadioBox" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="手动安装包"
<local:MyListItem x:Name="ItemHand" IsScaleAnimationEnabled="False" Type="RadioBox" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="手动安装包"
LogoScale="1.02" Logo="M292.693 787.627c0 30.72-24.746 55.466-55.466 55.466s-55.467-24.746-55.467-55.466 24.747-55.467 55.467-55.467c30.72-0.853 55.466 24.747 55.466 55.467z M1000.96 241.493c-2.56-5.973-4.267-11.946-6.827-17.92-0.853-6.826-4.266-12.8-8.533-17.92-7.68-9.386-18.773-15.36-31.573-15.36-6.827 0-13.654 1.707-19.627 5.12l-15.36 15.36-17.067 17.067-21.333 21.333L749.227 381.44c-14.507 14.507-38.4 14.507-52.907 0l-54.613-54.613c-14.507-14.507-14.507-38.4 0-52.907l132.266-132.267 14.507-14.506 20.48-20.48 16.213-16.214c3.414-5.973 5.12-11.946 5.12-19.626 0-12.8-5.973-24.747-16.213-32.427-5.973-4.267-11.947-6.827-18.773-7.68-5.12-2.56-10.24-4.267-16.214-5.973-36.693-12.8-76.8-19.627-117.76-19.627-7.68 0-14.506 0-22.186 0.853-188.587 11.947-337.92 168.107-337.92 360.96 0 16.214 0.853 32.427 3.413 48.64L56.32 663.04c-73.387 74.24-73.387 193.707 0 267.093l33.28 33.28c73.387 73.387 193.707 73.387 267.093 0l240.64-241.493c21.334 4.267 42.667 5.973 64 5.973 190.294 0 346.454-146.773 360.107-333.653 0.853-8.533 0.853-17.92 0.853-27.307 0.854-44.373-6.826-86.186-21.333-125.44zM658.773 639.147c-28.16 0-54.613-4.267-79.36-11.094-4.266 7.68-10.24 14.507-16.213 21.334l-258.56 258.56c-43.52 43.52-115.2 43.52-158.72 0l-29.013-29.014c-43.52-44.373-43.52-115.2 0-158.72l212.48-212.48 46.08-46.08c5.973-5.973 12.8-11.093 19.626-15.36-8.533-26.453-12.8-54.613-12.8-83.626v-1.707c0-152.747 123.734-275.627 276.48-275.627 18.774 0 37.547 1.707 55.467 5.974L597.333 207.36c-52.053 52.053-52.053 137.387 0 189.44l29.867 29.867c52.053 52.053 137.387 52.053 189.44 0L930.987 312.32c2.56 16.213 4.266 33.28 4.266 50.347 0 152.746-123.733 276.48-276.48 276.48z" />
<TextBlock x:Name="LabHand" Visibility="Collapsed" Text="▼ 手动安装包" Padding="11,18,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemClient" Visibility="Collapsed" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="Minecraft"
<local:MyListItem x:Name="ItemClient" Visibility="Collapsed" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Minecraft"
LogoScale="0.98" Logo="M989.7 510.8l-202.3-101c-10.8-5.4-17.7-16.5-17.7-28.6V172.7c0-26.7-16.6-50.6-41.6-59.9L550.5 46.3c-24.2-9-50.8-9-74.9 0.1l-176.9 66.8c-24.9 9.4-41.4 33.2-41.4 59.9v207.1c0 12.1-6.9 23.2-17.7 28.6l-204 101.9C13.9 521.6 0.1 543.8 0.2 568.1l0.5 226c0 23.2 12.6 44.5 32.9 55.8l223.8 124.6 1.2 0.7c18.9 10.5 41.9 10.4 60.8-0.2l2-1.1L497 873.2c9.9-5.7 22.1-5.6 32 0.1l176.7 102.5c18.9 10.7 42 10.8 61 0.3l3-1.7L992.4 851c20.4-11.3 33-32.8 33-56l-0.3-226.9c0-24.3-13.7-46.5-35.4-57.3zM321 192l115.3 46.1c27 10.8 44.7 36.9 44.7 66v163c0 5.9-6.2 9.8-11.6 7.2L339 409.5c-10.9-5.4-17.7-16.5-17.8-28.6L321 192z m-63.7 703.4L82.5 809.6c-10.9-5.4-17.9-16.5-17.9-28.7l-0.4-189.5L217.9 668c24.1 12 39.4 36.7 39.4 63.6v163.8z m64-274.3c-20.1 10.1-43.7 10-63.8 0l-0.2-0.1-149.1-75 149.1-74.4 16.8-8.4c9.2-4.6 20-4.5 29.1 0.3l18.1 9.4 129.8 64.3c5.8 2.9 6 11.1 0.2 14.2l-130 69.7z m141.9 203.8l-141.8 70.6-0.8-163.6c-0.1-27 15.1-51.8 39.2-63.9l108.8-54.5c5.3-2.7 11.6 1.2 11.6 7.1l0.8 175.6c0 12.1-6.9 23.2-17.8 28.7zM385 144l128-48 128 48-103 38.6c-16.1 6-33.8 6-49.9 0L385 144z m320 48l0.6 187.8c0 12.2-6.8 23.3-17.7 28.7l-131.4 65.7c-5.3 2.7-11.6-1.2-11.6-7.2V304.1c0-29.1 17.7-55.2 44.7-66L705 192z m0.7 710.3l-143.8-77.2c-10.4-5.6-16.9-16.4-16.9-28.2v-176c0-5.9 6.3-9.8 11.6-7.2l109.3 54.6c24 12 39.2 36.5 39.3 63.4l0.5 170.6z m-2-280.5l-129.2-70.5c-5.7-3.1-5.5-11.3 0.3-14.2l131-65.3 16.1-8.5c9.1-4.8 19.9-4.9 29.1-0.3l18.7 9.3L916.9 546l-146.2 76.4c-21.1 11-46.2 10.8-67-0.6z m66 279.4l-0.6-169.1c-0.1-27 15.1-51.7 39.3-63.8L961 592v188.7c0 11.9-6.6 22.7-17 28.3l-174.3 92.2z">
<!--Logo="M469.333333 213.333333V128a42.666667 42.666667 0 1 1 85.333334 0v85.333333h127.829333C847.722667 213.333333 981.333333 347.029333 981.333333 512.149333v319.936A106.496 106.496 0 0 1 874.730667 938.666667h-85.461334c-48.661333 0-107.221333-29.290667-136.469333-68.266667l-64-85.333333c-6.144-8.170667-23.957333-17.066667-34.24-17.066667h-85.12c-10.282667 0-28.096 8.896-34.24 17.066667l-64 85.333333c-29.226667 38.976-87.808 68.266667-136.469333 68.266667H149.269333A106.496 106.496 0 0 1 42.666667 832.085333V512.149333C42.666667 347.029333 176.277333 213.333333 341.504 213.333333H469.333333z m213.162667 85.333334H341.504A213.333333 213.333333 0 0 0 128 512.149333v319.936c0 11.818667 9.450667 21.248 21.269333 21.248h85.461334c21.802667 0 55.082667-16.64 68.202666-34.133333l64-85.333333c22.272-29.696 65.408-51.2 102.506667-51.2h85.12c37.098667 0 80.213333 21.504 102.506667 51.2l64 85.333333c13.12 17.493333 46.4 34.133333 68.202666 34.133333h85.461334a21.162667 21.162667 0 0 0 21.269333-21.248V512.149333A213.333333 213.333333 0 0 0 682.496 298.666667zM362.666667 469.333333h42.666666a42.666667 42.666667 0 1 1 0 85.333334h-42.666666v42.666666a42.666667 42.666667 0 1 1-85.333334 0v-42.666666h-42.666666a42.666667 42.666667 0 1 1 0-85.333334h42.666666v-42.666666a42.666667 42.666667 0 1 1 85.333334 0v42.666666z m341.333333-21.333333a42.666667 42.666667 0 1 1 0-85.333333 42.666667 42.666667 0 0 1 0 85.333333z m0 213.333333a42.666667 42.666667 0 1 1 0-85.333333 42.666667 42.666667 0 0 1 0 85.333333z m-106.666667-106.666666a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z m213.333334 0a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z">-->
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="4" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="4" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemOptiFine" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="5" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="OptiFine"
<local:MyListItem x:Name="ItemOptiFine" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="5" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="OptiFine"
LogoScale="1.00" Logo="M439.667 538.133l-323.311-174.763c-6.554-3.641-13.836-5.098-20.389-5.098-23.301 0-45.147 20.389-45.147 48.788v341.516c0 35.681 18.205 67.721 48.060 83.741l323.311 174.763c6.554 3.641 13.836 5.825 20.389 5.825 23.301 0 45.147-21.117 45.147-49.516v-341.516c0-34.953-18.205-67.721-48.060-83.741zM414.909 920.427l-281.805-152.189c-4.369-2.913-9.467-9.467-9.467-19.661v-298.553l281.805 152.189c5.825 3.641 9.467 11.651 9.467 19.661v298.553zM952.304 358.274c-6.554 0-13.836 1.456-20.389 5.098l-323.311 175.491c-29.855 16.020-48.060 48.788-48.060 84.468v340.059c0 28.399 21.845 49.516 45.147 49.516 6.554 0 13.836-1.456 20.389-5.098l323.311-175.491c29.127-16.020 48.060-48.060 48.060-83.741v-341.516c0-28.399-21.845-48.788-45.147-48.788zM924.634 747.849c0 10.194-5.098 17.476-9.467 19.661l-281.805 152.917v-297.097c0-10.194 5.098-17.476 9.467-19.661l281.805-153.646v297.825zM902.060 283.272c15.292-8.010 22.574-21.845 21.117-34.953 1.456-13.836-5.825-26.943-21.117-34.953l-329.136-171.85c-14.563-8.010-31.312-11.651-48.788-11.651 0 0 0 0 0 0 0 0 0 0 0 0s-34.224 3.641-49.516 11.651l-329.865 171.122c-15.292 8.010-21.845 21.845-21.117 35.681-0.729 13.107 5.825 26.943 21.117 34.953l329.136 171.122c14.563 8.010 32.039 11.651 49.516 11.651 0 0 0 0 0.729 0 0 0 0 0 0.729 0s34.224-3.641 49.516-11.651l327.68-171.122zM523.407 393.227c-5.825 0-11.651-1.456-16.020-3.641l-272.338-141.266 272.338-141.995c4.369-2.185 10.194-3.641 16.748-3.641 5.825 0 11.651 1.456 16.020 3.641l272.338 141.995-273.067 141.266c-3.641 2.185-9.467 3.641-16.020 3.641z">
<!--Logo="M12 0l-11 6v12.131l11 5.869 11-5.869v-12.066l-11-6.065zm-1 21.2l-6.664-3.555 4.201-2.801c1.08-.719-.066-2.359-1.243-1.575l-4.294 2.862v-7.901l8 4.363v8.607zm-6.867-14.63l6.867-3.746v4.426c0 1.323 2 1.324 2 0v-4.415l6.91 3.811-7.905 4.218-7.872-4.294zm8.867 6.03l8-4.269v7.8l-4.263-2.842c-1.181-.785-2.323.855-1.245 1.574l4.172 2.781-6.664 3.556v-8.6z">-->
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="5" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="5" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemForge" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="6" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="Forge"
<local:MyListItem x:Name="ItemForge" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="6" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Forge"
LogoScale="1.00" Logo="M402.807089 481.189274c-12.040221-6.991228-27.412326-2.797719-34.397415 9.242502l-8.387018 14.512529c-6.987135 12.035104-2.793626 27.40721 9.246595 34.392298 12.040221 6.985088 27.408233 2.797719 34.393321-9.242502l8.387018-14.511505C418.930301 503.437997 414.842193 488.063845 402.807089 481.189274L402.807089 481.189274zM495.028467 919.955342 59.056024 919.955342c-18.485003 0-33.532721 15.046694-33.532721 33.536814 0 18.485003 15.046694 33.532721 33.532721 33.532721l435.972443 0c18.49012 0 33.537837-15.046694 33.537837-33.532721C528.566304 935.002037 513.518586 919.955342 495.028467 919.955342L495.028467 919.955342zM997.431901 660.155295 590.482469 446.039729l90.935082-157.474544c18.485003-32.031531 7.520277-73.090669-24.51023-91.581812L395.496589 46.070268c-32.031531-18.485003-73.094762-7.520277-91.579765 24.51023L18.74697 564.277644c-18.485003 32.031531-7.521301 73.089645 24.51023 91.579765l261.408685 150.907988c32.031531 18.491143 73.095785 7.526417 91.581812-24.505114l91.364871-158.330028 392.332527 239.48128c16.016789 9.247618 36.544311 3.76372 45.792952-12.249999l83.838454-145.219429C1019.033895 689.930435 1013.444597 669.39882 997.431901 660.155295L997.431901 660.155295zM355.078041 719.704552c-9.242502 16.012695-29.774117 21.497617-45.787836 12.251022L105.923448 614.57826c-16.016789-9.242502-21.497617-29.774117-12.255115-45.787836l251.522524-435.653171c9.246595-16.012695 29.774117-21.497617 45.792952-12.249999l203.25624 117.376291c16.018835 9.242502 21.497617 29.774117 12.255115 45.786813L355.078041 719.704552 355.078041 719.704552zM884.568391 788.601712 522.115382 564.492538l33.537837-58.048067L934.875147 701.539844 884.568391 788.601712 884.568391 788.601712zM520.184403 277.8174c-12.040221-6.987135-27.41335-2.792603-34.399461 9.246595l-75.456552 130.702807c-6.985088 12.040221-2.791579 27.412326 9.242502 34.397415 12.040221 6.987135 27.412326 2.791579 34.397415-9.242502l75.458599-130.706901C536.307615 300.174594 532.219507 284.807604 520.184403 277.8174L520.184403 277.8174zM520.184403 277.8174">
<!--Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z">-->
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="6" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="6" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemFabric" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="7" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="Fabric"
<local:MyListItem x:Name="ItemFabric" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="7" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Fabric"
LogoScale="1.02" Logo="M826.453333 170.666667c-100.266667-93.866667-248.96-76.373333-256-75.52a31.786667 31.786667 0 0 0-26.666666 22.613333c-1.066667 3.2-101.546667 330.666667-426.666667 445.013333a29.013333 29.013333 0 0 0-7.893333 4.48l-1.493334 1.066667a29.44 29.44 0 0 0-5.973333 6.613333 31.786667 31.786667 0 0 0-3.626667 7.68 5.333333 5.333333 0 0 1 0 1.493334 30.506667 30.506667 0 0 0 0 8.96c7.466667 116.266667 45.013333 204.586667 112 262.826666a303.36 303.36 0 0 0 194.773334 71.466667h11.52a32.426667 32.426667 0 0 0 27.093333-19.626667 694.186667 694.186667 0 0 1 159.36-234.666666l-7.68 55.466666A31.786667 31.786667 0 0 0 621.44 768h4.48a32.213333 32.213333 0 0 0 31.786667-27.733333l15.573333-112.426667 112.426667 8.32a32 32 0 1 0 4.693333-64l-56.96-4.266667c36.48-25.813333 74.026667-50.56 112-75.52l51.626667-34.133333a31.573333 31.573333 0 0 0 14.08-24.746667c6.186667-115.2-21.76-203.306667-84.693334-262.826666zM620.8 573.013333l-1.706667 1.493334a219.093333 219.093333 0 0 0-87.466666-116.693334 222.933333 222.933333 0 0 0-95.146667-33.28c18.986667-21.333333 36.266667-42.666667 51.626667-64a198.613333 198.613333 0 0 1 202.453333 158.08c-20.053333 14.506667-39.893333 29.44-59.52 45.226667a29.866667 29.866667 0 0 0-10.24 9.173333z m-228.693333 292.266667a238.72 238.72 0 0 1-141.44-55.893333 213.333333 213.333333 0 0 1-34.986667-39.466667 123.946667 123.946667 0 0 0 44.373333 8.106667 168.533333 168.533333 0 0 0 69.12-16.213334 29.44 29.44 0 0 0 7.04-4.266666l106.666667-85.333334a32 32 0 1 0-39.893333-49.92L298.666667 704a78.293333 78.293333 0 0 1-69.546667 1.706667c-32.426667-17.066667-52.693333-61.653333-62.506667-93.44a709.333333 709.333333 0 0 0 202.453334-123.733334 187.52 187.52 0 0 1 128 21.333334 171.946667 171.946667 0 0 1 68.906666 109.653333 756.48 756.48 0 0 0-173.866666 245.76zM810.666667 438.4l-64 42.666667A256 256 0 0 0 529.706667 298.666667a810.666667 810.666667 0 0 0 69.12-140.8c37.973333-1.066667 123.946667 4.053333 183.68 59.946666 45.866667 42.666667 67.84 108.8 65.493333 195.84z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="7" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="7" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemLiteLoader" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="8" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="LiteLoader"
<local:MyListItem x:Name="ItemLiteLoader" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="8" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="LiteLoader"
LogoScale="1.06" Logo="M517.41 186.99l22.45 83.78h-55.04l-18.76-70.02c-2.85-10.63-13.78-16.95-24.42-14.1-10.63 2.85-16.95 13.78-14.1 24.42l16 59.71H388.5l-12.31-45.95c-10.45-38.99 12.69-79.08 51.69-89.52s79.08 12.68 89.53 51.68z M538.58 98c40.37 0 73.1 32.73 73.1 73.1v79.74h-53.16V171.1c0-11.01-8.93-19.94-19.94-19.94-11.01 0-19.94 8.93-19.94 19.94v79.74h-53.16V171.1c0-40.37 32.73-73.1 73.1-73.1z M512 224.26c191.58 0 346.88 155.3 346.88 346.88v61.8c0 28.85 3.33 59.94 9.98 93.27l1.29 6.28c12.43 59.1-21.15 118.2-78.28 137.78C691.18 904.75 597.9 922 512 922c-83.94 0-174.95-16.47-273.01-49.41l-6.85-2.32c-56.4-19.32-89.85-77.16-78.74-135.5l0.46-2.27c7.51-35.71 11.27-68.89 11.27-99.55v-61.8c0-189.66 152.21-343.77 341.14-346.83l5.73-0.06z m-4.64 66.49c-151.21 2.45-273.32 124.58-275.75 275.8l-0.04 4.59v61.8l-0.04 5.93c-0.45 33.74-4.7 69.49-12.65 107.3-5.53 26.27 9.4 52.53 34.79 61.23 94.08 32.23 180.19 48.15 258.32 48.15s164.25-15.92 258.32-48.15c25.39-8.7 40.32-34.97 34.79-61.23-7.95-37.81-12.2-73.56-12.65-107.3l-0.04-5.93v-61.8c0-153.33-123.05-277.91-275.79-280.39l-4.64-0.04-4.62 0.04z M500.66 717.38l-53.28-87.19c-3.83-6.26-1.85-14.44 4.41-18.27 0.76-0.46 1.56-0.85 2.39-1.15L512 589.74l57.82 21.03c6.9 2.51 10.46 10.13 7.95 17.03-0.3 0.83-0.69 1.63-1.15 2.39l-53.28 87.19c-3.83 6.26-12.01 8.24-18.27 4.41-1.8-1.1-3.31-2.61-4.41-4.41z M684.77 689.42m-46.52 0a46.52 46.52 0 1 0 93.04 0 46.52 46.52 0 1 0-93.04 0Z M339.23 689.42m-46.52 0a46.52 46.52 0 1 0 93.04 0 46.52 46.52 0 1 0-93.04 0Z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="8" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="8" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<TextBlock Text="CurseForge" Margin="13,18,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemMod" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="10" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod"
<TextBlock Text="资源" Margin="13,18,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemMod" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="10" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod"
LogoScale="0.97" Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="10" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="10" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="11" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="整合包"
<local:MyListItem x:Name="ItemPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="11" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="整合包"
LogoScale="0.98" Logo="M511.488 995.328a128.654222 128.654222 0 0 1-57.116444-13.112889L70.769778 791.808a126.833778 126.833778 0 0 1-70.769778-113.777778V311.608889a126.179556 126.179556 0 0 1 15.36-60.103111V248.604444c1.479111-2.901333 3.356444-5.603556 5.518222-8.021333a127.630222 127.630222 0 0 1 49.891556-42.325333L454.371556 13.368889a128.739556 128.739556 0 0 1 112.981333 0l383.601778 190.407111a126.862222 126.862222 0 0 1 72.049777 113.379556v360.874666a126.805333 126.805333 0 0 1-70.769777 115.939556L568.604444 984.32c-17.92 7.964444-37.461333 11.747556-57.116444 11.008z m42.638222-470.897778v370.204445l360.192-178.545778c14.449778-7.253333 23.552-21.987556 23.438222-38.087111v-335.928889L554.097778 524.430222zM85.248 330.666667v347.335111a42.268444 42.268444 0 0 0 23.438222 38.087111l360.192 178.545778V523.576889L85.248 330.666667zM135.537778 260.835556l375.950222 189.952 137.671111-65.564445L286.435556 188.074667 135.537778 260.864z m245.105778-118.471112l363.576888 197.973334 150.897778-71.480889-365.283555-180.224a42.922667 42.922667 0 0 0-37.518223 0l-111.672888 53.731555z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="11" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="11" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
@@ -95,21 +95,36 @@
DlFabricListLoader.Start(IsForceRestart:=True)
DlFabricApiLoader.Start(IsForceRestart:=True)
DlOptiFabricLoader.Start(IsForceRestart:=True)
ItemInstall.Checked = True
Case FormMain.PageSubType.DownloadMod
PageDownloadMod.Storage = New CompProjectStorage
PageDownloadMod.Page = 0
CompProjectCache.Clear()
If FrmDownloadMod IsNot Nothing Then FrmDownloadMod.PageLoaderRestart()
ItemMod.Checked = True
Case FormMain.PageSubType.DownloadPack
PageDownloadPack.Storage = New CompProjectStorage
PageDownloadPack.Page = 0
CompProjectCache.Clear()
If FrmDownloadPack IsNot Nothing Then FrmDownloadPack.PageLoaderRestart()
ItemPack.Checked = True
Case FormMain.PageSubType.DownloadClient
DlClientListLoader.Start(IsForceRestart:=True)
ItemClient.Checked = True
Case FormMain.PageSubType.DownloadOptiFine
DlOptiFineListLoader.Start(IsForceRestart:=True)
ItemOptiFine.Checked = True
Case FormMain.PageSubType.DownloadForge
DlForgeListLoader.Start(IsForceRestart:=True)
ItemForge.Checked = True
Case FormMain.PageSubType.DownloadLiteLoader
DlLiteLoaderListLoader.Start(IsForceRestart:=True)
ItemLiteLoader.Checked = True
Case FormMain.PageSubType.DownloadFabric
DlFabricListLoader.Start(IsForceRestart:=True)
ItemFabric.Checked = True
End Select
Hint("正在刷新……", Log:=False)
End Sub
'点击返回
@@ -126,7 +141,7 @@
If Not Setup.Get("HintHandInstall") Then
Setup.Set("HintHandInstall", True)
If MyMsgBox("手动安装包功能提供了 OptiFine、Forge 等组件的 .jar 安装文件下载,但无法自动安装。" & vbCrLf &
"在自动安装页面先选择 MC 版本,然后就可以选择 OptiFine、Forge 等组件,让 PCL2 自动进行安装了。", "自动安装提示", "返回自动安装", "继续下载手动安装包") = 1 Then
"在自动安装页面先选择 MC 版本,然后就可以选择 OptiFine、Forge 等组件,让 PCL 自动进行安装了。", "自动安装提示", "返回自动安装", "继续下载手动安装包") = 1 Then
FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.Download}, FormMain.PageSubType.DownloadInstall)
AniControlEnabled -= 1
Exit Sub
@@ -1,9 +1,9 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadLiteLoader"
d:DesignWidth="778.571" d:DesignHeight="90.857">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadLiteLoader"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="LiteLoader 简介" x:Name="CardTip">
@@ -28,7 +28,7 @@
PanMain.Children.Clear()
'转化为 UI
For Each Pair As KeyValuePair(Of String, List(Of DlLiteLoaderListEntry)) In Dict
If Pair.Value.Count = 0 Then Continue For
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 10}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
@@ -1,9 +1,9 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadMod"
d:DesignWidth="778.571" d:DesignHeight="90.857">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadMod"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="25">
<local:MyCard Title="搜索 Mod" Margin="0,0,0,15" x:Name="PanAlways">
@@ -11,81 +11,79 @@
<Grid Margin="0,0,0,11" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="1.3*" />
<ColumnDefinition Width="1.2*" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="0.9*" />
<ColumnDefinition Width="1.6*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextSearchName" Grid.Column="1" Grid.ColumnSpan="10" />
<TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboSearchTag" Grid.Column="1" Grid.Row="2" MaxDropDownHeight="320">
<local:MyComboBoxItem Content="全部" Tag="0" IsSelected="True" />
<local:MyComboBoxItem Content="世界生成" Tag="406" />
<local:MyComboBoxItem Content="生物群系" Tag="407" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="天然结构" Tag="409" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="维度" Tag="410" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="生物" Tag="411" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="科技" Tag="412" />
<local:MyComboBoxItem Content="交通与移动" Tag="414" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="管道与物流" Tag="415" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="能源" Tag="417" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="红石" Tag="4558" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="仓储" Tag="420" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="农业" Tag="416" />
<local:MyComboBoxItem Content="食物" Tag="436" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="魔法" Tag="419" />
<local:MyComboBoxItem Content="装备与工具" Tag="434" />
<local:MyComboBoxItem Content="冒险与探索" Tag="422" />
<local:MyComboBoxItem Content="建筑与装饰" Tag="424" />
<local:MyComboBoxItem Content="信息显示" Tag="423" />
<local:MyComboBoxItem Content="支持库" Tag="421" />
<local:MyComboBoxItem Content="服务器" Tag="435" />
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,18,0" />
<local:MyTextBox x:Name="TextSearchName" Grid.Column="1" Grid.ColumnSpan="2" />
<TextBlock VerticalAlignment="Center" Grid.Column="4" HorizontalAlignment="Left" Text="来源" Margin="0,0,18,0" />
<local:MyComboBox x:Name="ComboSearchSource" Grid.Column="5">
<local:MyComboBoxItem Content="全部" Tag="3" IsSelected="True" />
<local:MyComboBoxItem Content="CurseForge" Tag="1" />
<local:MyComboBoxItem Content="Modrinth" Tag="2" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left" Text="版本" Margin="0,0,25,0" />
<local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="2" IsEditable="True" MaxDropDownHeight="320" HintText="全部 (也可自行输入)">
<local:MyComboBoxItem Content="" IsSelected="True" />
<TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" />
<local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" IsEditable="True" MaxDropDownHeight="320">
<local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
<local:MyComboBoxItem Content="1.20.6" />
<local:MyComboBoxItem Content="1.20.4" />
<local:MyComboBoxItem Content="1.20.1" />
<local:MyComboBoxItem Content="1.19.4" />
<local:MyComboBoxItem Content="1.19.2" />
<local:MyComboBoxItem Content="1.19.1" />
<local:MyComboBoxItem Content="1.19" />
<local:MyComboBoxItem Content="1.18.2" />
<local:MyComboBoxItem Content="1.18.1" />
<local:MyComboBoxItem Content="1.18" />
<local:MyComboBoxItem Content="1.17.1" />
<local:MyComboBoxItem Content="1.17" />
<local:MyComboBoxItem Content="1.16.5" />
<local:MyComboBoxItem Content="1.16.4" />
<local:MyComboBoxItem Content="1.16.3" />
<local:MyComboBoxItem Content="1.16.2" />
<local:MyComboBoxItem Content="1.16.1" />
<local:MyComboBoxItem Content="1.16" />
<local:MyComboBoxItem Content="1.15.2" />
<local:MyComboBoxItem Content="1.15" />
<local:MyComboBoxItem Content="1.14.4" />
<local:MyComboBoxItem Content="1.14" />
<local:MyComboBoxItem Content="1.13.2" />
<local:MyComboBoxItem Content="1.13" />
<local:MyComboBoxItem Content="1.12.2" />
<local:MyComboBoxItem Content="1.12" />
<local:MyComboBoxItem Content="1.11.2" />
<local:MyComboBoxItem Content="1.10.2" />
<local:MyComboBoxItem Content="1.9.4" />
<local:MyComboBoxItem Content="1.8.9" />
<local:MyComboBoxItem Content="1.7.10" />
<local:MyComboBoxItem Content="1.7.2" />
<local:MyComboBoxItem Content="1.6.4" />
<local:MyComboBoxItem Content="1.5.2" />
</local:MyComboBox>
<local:MyComboBox x:Name="ComboSearchLoader" Visibility="Collapsed" Grid.Row="2" Grid.Column="5" MaxDropDownHeight="320" Margin="10,0,0,0">
<local:MyComboBoxItem Content="Forge 或 Fabric" IsSelected="True" Tag="0" />
<local:MyComboBox x:Name="ComboSearchLoader" Visibility="Collapsed" Grid.Row="2" Grid.Column="2" MaxDropDownHeight="320" Margin="10,0,0,0">
<local:MyComboBoxItem Content="任意 Mod 加载器" IsSelected="True" Tag="0" />
<local:MyComboBoxItem Content="Forge" Tag="1" />
<local:MyComboBoxItem Content="Fabric" Tag="4" />
<local:MyComboBoxItem Content="Quilt" Tag="5" />
<local:MyComboBoxItem Content="NeoForge" Tag="6" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Column="4" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
<local:MyComboBox x:Name="ComboSearchTag" Grid.Column="5" Grid.Row="2" MaxDropDownHeight="320">
<local:MyComboBoxItem Content="全部" Tag="" IsSelected="True" />
<local:MyComboBoxItem Content="世界元素" Tag="406/worldgen" />
<local:MyComboBoxItem Content="生物群系" Tag="407/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="维度" Tag="410/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="矿物与资源" Tag="408/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="天然结构" Tag="409/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="科技" Tag="412/technology" />
<local:MyComboBoxItem Content="管道与物流" Tag="415/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="自动化" Tag="4843/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="能源" Tag="417/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="红石" Tag="4558/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="食物与烹饪" Tag="436/food" />
<local:MyComboBoxItem Content="农业" Tag="416/" Margin="15,0,0,0" />
<local:MyComboBoxItem Content="游戏机制" Tag="/game-mechanics" />
<local:MyComboBoxItem Content="运输" Tag="414/transportation" />
<local:MyComboBoxItem Content="仓储" Tag="420/storage" />
<local:MyComboBoxItem Content="魔法" Tag="419/magic" />
<local:MyComboBoxItem Content="冒险" Tag="422/adventure" />
<local:MyComboBoxItem Content="装饰" Tag="424/decoration" />
<local:MyComboBoxItem Content="生物" Tag="411/mobs" />
<local:MyComboBoxItem Content="装备与工具" Tag="434/equipment" />
<local:MyComboBoxItem Content="性能优化" Tag="/optimization" />
<local:MyComboBoxItem Content="信息显示" Tag="423/" />
<local:MyComboBoxItem Content="服务器" Tag="435/social" />
<local:MyComboBoxItem Content="改良" Tag="5191/utility" />
<local:MyComboBoxItem Content="支持库" Tag="421/library" />
</local:MyComboBox>
</Grid>
<Grid Margin="0,4,0,6" Height="35">
@@ -98,9 +96,24 @@
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardProjects" Title="热门 Mod">
<StackPanel x:Name="PanProjects" Margin="20,40,18,20" />
</local:MyCard>
<StackPanel x:Name="PanContent">
<local:MyHint x:Name="HintError" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,结果可能不全。&#xa;请尝试使用 VPN 或加速器以改善网络。" IsWarn="True" Margin="0,0,0,15" />
<local:MyCard x:Name="CardProjects" UseAnimation="False">
<StackPanel x:Name="PanProjects" Margin="12" />
</local:MyCard>
<local:MyCard Margin="0,15,0,0" x:Name="CardPages" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal" Height="23" Margin="10,7">
<local:MyIconButton x:Name="BtnPageFirst" IsEnabled="False" Opacity="0.2" Margin="0,0.5,5,0.5"
Logo="M496.213333 329.856L315.306667 510.848l180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z m298.666667 0l-180.949333 180.992 180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z" />
<local:MyIconButton x:Name="BtnPageLeft" IsEnabled="False" Opacity="0.2" Margin="0,0,5,0"
Logo="M650.752 278.357333l-241.322667 241.365334 241.322667 241.365333a42.666667 42.666667 0 1 1-60.330667 60.330667l-271.530666-271.530667a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.416-27.648l271.530666-271.530666a42.666667 42.666667 0 0 1 60.330667 60.330666z" />
<TextBlock x:Name="LabPage" Text="1"
Margin="8,0,13,0" FontSize="15" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush3}" />
<local:MyIconButton x:Name="BtnPageRight" Margin="0,0,30,0"
Logo="M404.309333 278.357333l241.322667 241.365334-241.322667 241.365333a42.666667 42.666667 0 1 0 60.330667 60.330667l271.530667-271.530667a42.453333 42.453333 0 0 0 11.818666-22.613333l0.597334-5.034667v-5.034667a42.496 42.496 0 0 0-12.416-27.648L464.64 218.026667a42.666667 42.666667 0 0 0-60.330667 60.330666z" />
</StackPanel>
</local:MyCard>
</StackPanel>
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
<local:MyLoading Text="正在获取 Mod 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
@@ -1,83 +1,140 @@
Public Class PageDownloadMod
'初始化加载器信息
Public Const PageSize = 40
'加载器信息
Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject Mod", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
Public Shared Storage As New CompProjectStorage
Public Shared Page As Integer = 0
Private Sub PageDownloadMod_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
PageLoaderInit(Load, PanLoad, CardProjects, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
End Sub
Public Shared Loader As New LoaderTask(Of DlCfProjectRequest, DlCfProjectResult)("DlCfProject Mod", AddressOf DlCfProjectSub, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
Private Shared Function LoaderInput() As DlCfProjectRequest
If FrmDownloadMod IsNot Nothing AndAlso FrmDownloadMod.IsLoaded Then
Return New DlCfProjectRequest With {
.SearchFilter = FrmDownloadMod.TextSearchName.Text,
.GameVersion = If(FrmDownloadMod.TextSearchVersion.Text.Contains("."), FrmDownloadMod.TextSearchVersion.Text, Nothing),
.CategoryId = Val(FrmDownloadMod.ComboSearchTag.SelectedItem.Tag),
.IsModPack = False,
Private Shared Function LoaderInput() As CompProjectRequest
Dim Request As New CompProjectRequest(CompType.Mod, Storage, (Page + 1) * PageSize)
If FrmDownloadMod IsNot Nothing Then
With Request
.SearchText = FrmDownloadMod.TextSearchName.Text
.GameVersion = If(FrmDownloadMod.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
If(FrmDownloadMod.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadMod.TextSearchVersion.Text.Contains("w"), FrmDownloadMod.TextSearchVersion.Text, Nothing))
.Tag = FrmDownloadMod.ComboSearchTag.SelectedItem.Tag
.ModLoader = Val(FrmDownloadMod.ComboSearchLoader.SelectedItem.Tag)
} '处理列表加载失败后的点击加载器重试
Else
Return New DlCfProjectRequest With {.IsModPack = False}
.Source = CType(Val(FrmDownloadMod.ComboSearchSource.SelectedItem.Tag), CompSourceType)
End With
End If
Return Request
End Function
'结果 UI 化
Private Sub Load_OnFinish()
Try
Log($"[Comp] 开始可视化 Mod 列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
'列表项
PanProjects.Children.Clear()
If Loader.Input.SearchFilter = "" Then
CardProjects.Title = "热门 Mod"
Else
CardProjects.Title = "搜索结果 (" & Loader.Output.Projects.Count & If(Loader.Output.Projects.Count < Loader.Output.RealCount, "+", "") & ")"
End If
For Each Project In Loader.Output.Projects
PanProjects.Children.Add(Project.ToCfItem(Loader.Input.GameVersion Is Nothing, Loader.Input.ModLoader Is Nothing OrElse Loader.Input.ModLoader = 0, AddressOf ProjectClick))
For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
PanProjects.Children.Add(Storage.Results(i).ToCompItem(Loader.Input.GameVersion Is Nothing, Loader.Input.ModLoader = CompModLoaderType.Any))
Next
'页码
CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal,
Visibility.Visible, Visibility.Collapsed)
LabPage.Text = Page + 1
BtnPageFirst.IsEnabled = Page > 1
BtnPageFirst.Opacity = If(BtnPageFirst.IsEnabled, 1, 0.2)
BtnPageLeft.IsEnabled = Page > 0
BtnPageLeft.Opacity = If(BtnPageLeft.IsEnabled, 1, 0.2)
BtnPageRight.IsEnabled = Storage.Results.Count > PageSize * (Page + 1) OrElse
Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal
BtnPageRight.Opacity = If(BtnPageRight.IsEnabled, 1, 0.2)
'错误信息
If Storage.ErrorMessage Is Nothing Then
HintError.Visibility = Visibility.Collapsed
Else
HintError.Visibility = Visibility.Visible
HintError.Text = Storage.ErrorMessage
End If
'强制返回顶部
PanBack.ScrollToTop()
Catch ex As Exception
Log(ex, "可视化 Mod 列表出错", LogLevel.Feedback)
End Try
End Sub
'自动重试
Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
Select Case Loader.State
Case LoadState.Failed
Dim ErrorMessage As String = ""
If DlCfFileLoader.Error IsNot Nothing Then ErrorMessage = DlCfFileLoader.Error.Message
If ErrorMessage.Contains("不是有效的 Json 文件") Then
Log("[Download] 下载的 Mod 列表 Json 文件损坏,已自动重试", LogLevel.Debug)
If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
If ErrorMessage.Contains("不是有效的 json 文件") Then
Log("[Download] 下载的 Mod 列表 json 文件损坏,已自动重试", LogLevel.Debug)
PageLoaderRestart()
End If
End Select
End Sub
'进入详情页面
'切换页码
Public Sub ProjectClick(sender As MyCfItem, e As EventArgs)
FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CfDetail, .Additional = sender.Tag})
Private Sub BtnPageFirst_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageFirst.Click
ChangePage(0)
End Sub
Private Sub BtnPageLeft_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageLeft.Click
ChangePage(Page - 1)
End Sub
Private Sub BtnPageRight_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageRight.Click
ChangePage(Page + 1)
End Sub
Private Sub ChangePage(NewPage As Integer)
CardPages.IsEnabled = False
Page = NewPage
FrmMain.BackToTop()
Log($"[Download] Mod 切换到第 {Page + 1} 页")
RunInThread(Sub()
Thread.Sleep(100) '等待向上滚的动画结束
RunInUi(Sub() CardPages.IsEnabled = True)
Loader.Start()
End Sub)
End Sub
'搜索
#Region "搜索"
Private Sub TextSearchName_KeyUp(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyUp, TextSearchVersion.KeyUp
If e.Key = Key.Enter Then StartSearch()
End Sub
Private Shared Sub StartSearch() Handles BtnSearchRun.Click
'搜索按钮
Private Sub StartNewSearch() Handles BtnSearchRun.Click
Page = 0
If Loader.ShouldStart(LoaderInput()) Then Storage = New CompProjectStorage '避免连续搜索两次使得 CompProjectStorage 引用丢失(#1311)
Loader.Start()
End Sub
Private Sub EnterTrigger(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyDown, TextSearchVersion.KeyDown
If e.Key = Key.Enter Then StartNewSearch()
End Sub
'重置按钮
Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click
TextSearchName.Text = ""
TextSearchVersion.Text = "全部 (也可自行输入)"
TextSearchVersion.SelectedIndex = 0
TextSearchVersion.Text = ""
ComboSearchSource.SelectedIndex = 0
ComboSearchTag.SelectedIndex = 0
ComboSearchLoader.SelectedIndex = 0
Loader.LastFinishedTime = 0 '要求强制重新开始
End Sub
Private Sub TextSearchVersion_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TextSearchVersion.TextChanged
If TextSearchVersion.Text = "" Then
'版本选择
'#3067:当下拉菜单展开时,程序会被 WPF 挂起,因而无法更新 Grid 布局,所以必须延迟到下拉菜单收起后才能更新
Private Sub TextSearchVersion_TextChanged() Handles TextSearchVersion.TextChanged
If Not TextSearchVersion.IsDropDownOpen Then UpdateSearchLoaderVisibility()
End Sub
Private Sub UpdateSearchLoaderVisibility() Handles TextSearchVersion.DropDownClosed
If TextSearchVersion.Text.Contains(".") OrElse TextSearchVersion.Text.Contains("w") Then
ComboSearchLoader.Visibility = Visibility.Visible
Grid.SetColumnSpan(TextSearchVersion, 1)
Else
ComboSearchLoader.Visibility = Visibility.Collapsed
Grid.SetColumnSpan(TextSearchVersion, 2)
ComboSearchLoader.SelectedIndex = 0
Else
ComboSearchLoader.Visibility = Visibility.Visible
Grid.SetColumnSpan(TextSearchVersion, 1)
End If
End Sub
#End Region
End Class
@@ -1,9 +1,9 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadOptiFine"
d:DesignWidth="778.571" d:DesignHeight="90.857">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadOptiFine"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="OptiFine 简介" x:Name="CardTip">
@@ -32,7 +32,7 @@
PanMain.Children.Clear()
'转化为 UI
For Each Pair As KeyValuePair(Of String, List(Of DlOptiFineListEntry)) In Dict
If Pair.Value.Count = 0 Then Continue For
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 3}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
@@ -1,9 +1,9 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadPack"
d:DesignWidth="778.571" d:DesignHeight="90.857">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadPack"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="25">
<local:MyCard Title="搜索整合包" Margin="0,0,0,15" x:Name="PanAlways">
@@ -11,8 +11,8 @@
<Grid Margin="0,0,0,11" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="2.5*" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
@@ -21,72 +21,55 @@
<RowDefinition Height="9" />
<RowDefinition Height="28" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextSearchName" Grid.Column="1" Grid.ColumnSpan="10" HintText="仅支持使用英文搜索" />
<TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboSearchTag" Grid.Column="1" Grid.Row="2" MaxDropDownHeight="320">
<local:MyComboBoxItem Content="全部" Tag="0" IsSelected="True" />
<local:MyComboBoxItem IsHitTestVisible="False" Content="规格" />
<local:MyComboBoxItem Tag="4481" Content="小型整合" Margin="15,0,0,0" />
<local:MyComboBoxItem Tag="4482" Content="大型整合" Margin="15,0,0,0" />
<local:MyComboBoxItem IsHitTestVisible="False" Content="特殊" />
<local:MyComboBoxItem Tag="4487" Content="FTB" Margin="15,0,0,0" ToolTip="该整合包由 FTB 官方发布" />
<local:MyComboBoxItem Tag="4480" Content="基于地图" Margin="15,0,0,0" ToolTip="该整合包基于已有的 Minecraft 游戏地图运行" />
<local:MyComboBoxItem Tag="4479" Content="硬核" />
<local:MyComboBoxItem Tag="4471" Content="科幻" />
<local:MyComboBoxItem Tag="4483" Content="战斗" />
<local:MyComboBoxItem Tag="4478" Content="任务" />
<local:MyComboBoxItem Tag="4484" Content="多人" />
<local:MyComboBoxItem Tag="4476" Content="探索" />
<local:MyComboBoxItem Tag="4736" Content="空岛" />
<local:MyComboBoxItem Tag="4475" Content="冒险" />
<local:MyComboBoxItem Tag="4472" Content="科技" />
<local:MyComboBoxItem Tag="4473" Content="魔法" />
<local:MyComboBoxItem Tag="4477" Content="小游戏" />
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,18,0" />
<local:MyTextBox x:Name="TextSearchName" Grid.Column="1" />
<TextBlock VerticalAlignment="Center" Grid.Column="3" HorizontalAlignment="Left" Text="来源" Margin="0,0,18,0" />
<local:MyComboBox x:Name="ComboSearchSource" Grid.Column="4">
<local:MyComboBoxItem Content="全部" Tag="3" IsSelected="True" />
<local:MyComboBoxItem Content="CurseForge" Tag="1" />
<local:MyComboBoxItem Content="Modrinth" Tag="2" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left" Text="版本" Margin="0,0,25,0" />
<local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="4" IsEditable="True" MaxDropDownHeight="320" HintText="全部 (也可自行输入)">
<local:MyComboBoxItem Content="" IsSelected="True" />
<TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" />
<local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="1" IsEditable="True" MaxDropDownHeight="320">
<local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
<local:MyComboBoxItem Content="1.20.6" />
<local:MyComboBoxItem Content="1.20.4" />
<local:MyComboBoxItem Content="1.20.1" />
<local:MyComboBoxItem Content="1.19.4" />
<local:MyComboBoxItem Content="1.19.2" />
<local:MyComboBoxItem Content="1.19.1" />
<local:MyComboBoxItem Content="1.19" />
<local:MyComboBoxItem Content="1.18.2" />
<local:MyComboBoxItem Content="1.18.1" />
<local:MyComboBoxItem Content="1.18" />
<local:MyComboBoxItem Content="1.17.1" />
<local:MyComboBoxItem Content="1.17" />
<local:MyComboBoxItem Content="1.16.5" />
<local:MyComboBoxItem Content="1.16.4" />
<local:MyComboBoxItem Content="1.16.3" />
<local:MyComboBoxItem Content="1.16.2" />
<local:MyComboBoxItem Content="1.16.1" />
<local:MyComboBoxItem Content="1.16" />
<local:MyComboBoxItem Content="1.15.2" />
<local:MyComboBoxItem Content="1.15.1" />
<local:MyComboBoxItem Content="1.15" />
<local:MyComboBoxItem Content="1.14.4" />
<local:MyComboBoxItem Content="1.14.3" />
<local:MyComboBoxItem Content="1.14.2" />
<local:MyComboBoxItem Content="1.14.1" />
<local:MyComboBoxItem Content="1.14" />
<local:MyComboBoxItem Content="1.13.2" />
<local:MyComboBoxItem Content="1.13.1" />
<local:MyComboBoxItem Content="1.13" />
<local:MyComboBoxItem Content="1.12.2" />
<local:MyComboBoxItem Content="1.12.1" />
<local:MyComboBoxItem Content="1.12" />
<local:MyComboBoxItem Content="1.11.2" />
<local:MyComboBoxItem Content="1.11" />
<local:MyComboBoxItem Content="1.10.2" />
<local:MyComboBoxItem Content="1.10" />
<local:MyComboBoxItem Content="1.9.4" />
<local:MyComboBoxItem Content="1.9" />
<local:MyComboBoxItem Content="1.8.9" />
<local:MyComboBoxItem Content="1.8" />
<local:MyComboBoxItem Content="1.7.10" />
<local:MyComboBoxItem Content="1.7.2" />
<local:MyComboBoxItem Content="1.6.4" />
<local:MyComboBoxItem Content="1.5.2" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
<local:MyComboBox x:Name="ComboSearchTag" Grid.Column="4" Grid.Row="2" MaxDropDownHeight="320">
<local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
<local:MyComboBoxItem Tag="4484/" Content="多人" />
<local:MyComboBoxItem Tag="/optimization" Content="性能优化" />
<local:MyComboBoxItem Tag="4479/challenging" Content="硬核" />
<local:MyComboBoxItem Tag="4483/combat" Content="战斗" />
<local:MyComboBoxItem Tag="4478/quests" Content="任务" />
<local:MyComboBoxItem Tag="4472/technology" Content="科技" />
<local:MyComboBoxItem Tag="4473/magic" Content="魔法" />
<local:MyComboBoxItem Tag="4475/adventure" Content="冒险" />
<local:MyComboBoxItem Tag="/kitchen-sink" Content="烹饪" />
<local:MyComboBoxItem Tag="4476/" Content="探索" />
<local:MyComboBoxItem Tag="4477/" Content="小游戏" />
<local:MyComboBoxItem Tag="4471/" Content="科幻" />
<local:MyComboBoxItem Tag="4736/" Content="空岛" />
<local:MyComboBoxItem Tag="5128/" Content="原版改良" />
<local:MyComboBoxItem Tag="4487/" Content="FTB"
ToolTip="由 FTB 官方发布" ToolTipService.HorizontalOffset="70" />
<local:MyComboBoxItem Tag="4480/" Content="基于地图" />
<local:MyComboBoxItem Tag="4481/lightweight" Content="轻量整合" />
<local:MyComboBoxItem Tag="4482/" Content="大型整合" />
</local:MyComboBox>
</Grid>
<Grid Margin="0,4,0,6" Height="35">
@@ -98,13 +81,28 @@
<local:MyButton x:Name="BtnSearchRun" Text="搜索" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
<local:MyButton x:Name="BtnSearchReset" Text="重置条件" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="1" />
<local:MyButton x:Name="BtnSearchInstall" Text="安装已有整合包" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="2"
ToolTip="在当前选择的 Minecraft 文件夹下安装整合包" ToolTipService.ShowDuration="2333333" />
ToolTip="在当前选择的 Minecraft 文件夹下安装整合包" ToolTipService.HorizontalOffset="-55" ToolTipService.VerticalOffset="5" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardProjects" Title="热门整合包">
<StackPanel x:Name="PanProjects" Margin="20,40,18,20" />
</local:MyCard>
<StackPanel x:Name="PanContent">
<local:MyHint x:Name="HintError" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,结果可能不全。&#xa;请尝试使用 VPN 或加速器以改善网络。" IsWarn="True" Margin="0,0,0,15" />
<local:MyCard x:Name="CardProjects" UseAnimation="False">
<StackPanel x:Name="PanProjects" Margin="12" />
</local:MyCard>
<local:MyCard Margin="0,15,0,0" x:Name="CardPages" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal" Height="23" Margin="10,7">
<local:MyIconButton x:Name="BtnPageFirst" IsEnabled="False" Opacity="0.2" Margin="0,0.5,5,0.5"
Logo="M496.213333 329.856L315.306667 510.848l180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z m298.666667 0l-180.949333 180.992 180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z" />
<local:MyIconButton x:Name="BtnPageLeft" IsEnabled="False" Opacity="0.2" Margin="0,0,5,0"
Logo="M650.752 278.357333l-241.322667 241.365334 241.322667 241.365333a42.666667 42.666667 0 1 1-60.330667 60.330667l-271.530666-271.530667a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.416-27.648l271.530666-271.530666a42.666667 42.666667 0 0 1 60.330667 60.330666z" />
<TextBlock x:Name="LabPage" Text="1"
Margin="8,0,13,0" FontSize="15" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush3}" />
<local:MyIconButton x:Name="BtnPageRight" Margin="0,0,30,0"
Logo="M404.309333 278.357333l241.322667 241.365334-241.322667 241.365333a42.666667 42.666667 0 1 0 60.330667 60.330667l271.530667-271.530667a42.453333 42.453333 0 0 0 11.818666-22.613333l0.597334-5.034667v-5.034667a42.496 42.496 0 0 0-12.416-27.648L464.64 218.026667a42.666667 42.666667 0 0 0-60.330667 60.330666z" />
</StackPanel>
</local:MyCard>
</StackPanel>
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
<local:MyLoading Text="正在获取整合包列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
@@ -1,82 +1,126 @@
Public Class PageDownloadPack
'初始化加载器信息
Private Sub PageDownloadMod_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
PageLoaderInit(Load, PanLoad, CardProjects, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
Public Const PageSize = 40
'加载器信息
Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject ModPack", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
Public Shared Storage As New CompProjectStorage
Public Shared Page As Integer = 0
Private Sub PageDownloadPack_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
End Sub
Public Shared Loader As New LoaderTask(Of DlCfProjectRequest, DlCfProjectResult)("DlCfProject ModPack", AddressOf DlCfProjectSub, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
Private Shared Function LoaderInput() As DlCfProjectRequest
If FrmDownloadPack IsNot Nothing AndAlso FrmDownloadPack.IsLoaded Then
Return New DlCfProjectRequest With {
.SearchFilter = FrmDownloadPack.TextSearchName.Text,
.GameVersion = If(FrmDownloadPack.TextSearchVersion.Text.Contains("."), FrmDownloadPack.TextSearchVersion.Text, Nothing),
.CategoryId = Val(FrmDownloadPack.ComboSearchTag.SelectedItem.Tag),
.IsModPack = True
} '处理列表加载失败后的点击加载器重试
Else
Return New DlCfProjectRequest With {.IsModPack = True}
Private Shared Function LoaderInput() As CompProjectRequest
Dim Request As New CompProjectRequest(CompType.ModPack, Storage, (Page + 1) * PageSize)
If FrmDownloadPack IsNot Nothing Then
With Request
.SearchText = FrmDownloadPack.TextSearchName.Text
.GameVersion = If(FrmDownloadPack.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
If(FrmDownloadPack.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadPack.TextSearchVersion.Text.Contains("w"), FrmDownloadPack.TextSearchVersion.Text, Nothing))
.Tag = FrmDownloadPack.ComboSearchTag.SelectedItem.Tag
.Source = CType(Val(FrmDownloadPack.ComboSearchSource.SelectedItem.Tag), CompSourceType)
End With
End If
Return Request
End Function
'结果 UI 化
Private Sub Load_OnFinish()
Try
Log($"[Comp] 开始可视化整合包列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
'列表项
PanProjects.Children.Clear()
If Loader.Input.SearchFilter = "" Then
CardProjects.Title = "热门整合包"
Else
CardProjects.Title = "搜索结果 (" & Loader.Output.Projects.Count & If(Loader.Output.Projects.Count < Loader.Output.RealCount, "+", "") & ")"
End If
For Each Project In Loader.Output.Projects
PanProjects.Children.Add(Project.ToCfItem(Loader.Input.GameVersion Is Nothing, Loader.Input.ModLoader Is Nothing OrElse Loader.Input.ModLoader = 0, AddressOf ProjectClick))
For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
PanProjects.Children.Add(Storage.Results(i).ToCompItem(Loader.Input.GameVersion Is Nothing, True))
Next
'页码
CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal,
Visibility.Visible, Visibility.Collapsed)
LabPage.Text = Page + 1
BtnPageFirst.IsEnabled = Page > 1
BtnPageFirst.Opacity = If(BtnPageFirst.IsEnabled, 1, 0.2)
BtnPageLeft.IsEnabled = Page > 0
BtnPageLeft.Opacity = If(BtnPageLeft.IsEnabled, 1, 0.2)
BtnPageRight.IsEnabled = Storage.Results.Count > PageSize * (Page + 1) OrElse
Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal
BtnPageRight.Opacity = If(BtnPageRight.IsEnabled, 1, 0.2)
'错误信息
If Storage.ErrorMessage Is Nothing Then
HintError.Visibility = Visibility.Collapsed
Else
HintError.Visibility = Visibility.Visible
HintError.Text = Storage.ErrorMessage
End If
'强制返回顶部
PanBack.ScrollToTop()
Catch ex As Exception
Log(ex, "可视化整合包列表出错", LogLevel.Feedback)
End Try
End Sub
'自动重试
Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
Select Case Loader.State
Case LoadState.Failed
Dim ErrorMessage As String = ""
If DlCfFileLoader.Error IsNot Nothing Then ErrorMessage = DlCfFileLoader.Error.Message
If ErrorMessage.Contains("不是有效的 Json 文件") Then
Log("[Download] 下载的整合包列表 Json 文件损坏,已自动重试", LogLevel.Debug)
If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
If ErrorMessage.Contains("不是有效的 json 文件") Then
Log("[Download] 下载的整合包列表 json 文件损坏,已自动重试", LogLevel.Debug)
PageLoaderRestart()
End If
End Select
End Sub
Private Sub Load_OnStart()
PanLoad.Visibility = Visibility.Visible
AniStart({
AaOpacity(PanLoad, 1 - PanLoad.Opacity, 150),
AaOpacity(CardProjects, -CardProjects.Opacity, 150),
AaCode(Sub()
CardProjects.Visibility = Visibility.Collapsed
PanProjects.Children.Clear()
End Sub,, True)
}, "FrmDownloadPack Load Switch")
'切换页码
Private Sub BtnPageFirst_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageFirst.Click
ChangePage(0)
End Sub
Private Sub BtnPageLeft_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageLeft.Click
ChangePage(Page - 1)
End Sub
Private Sub BtnPageRight_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageRight.Click
ChangePage(Page + 1)
End Sub
Private Sub ChangePage(NewPage As Integer)
CardPages.IsEnabled = False
Page = NewPage
FrmMain.BackToTop()
Log($"[Download] 整合包切换到第 {Page + 1} 页")
RunInThread(Sub()
Thread.Sleep(100) '等待向上滚的动画结束
RunInUi(Sub() CardPages.IsEnabled = True)
Loader.Start()
End Sub)
End Sub
Public Sub ProjectClick(sender As MyCfItem, e As EventArgs)
FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CfDetail, .Additional = sender.Tag})
End Sub
Private Sub TextSearchName_KeyUp(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyUp, TextSearchVersion.KeyUp
If e.Key = Key.Enter Then StartSearch()
End Sub
Private Shared Sub StartSearch() Handles BtnSearchRun.Click
Loader.Start()
End Sub
Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click
TextSearchName.Text = ""
TextSearchVersion.SelectedIndex = 0
TextSearchVersion.Text = "全部"
ComboSearchTag.SelectedIndex = 0
Loader.LastFinishedTime = 0 '要求强制重新开始
End Sub
Private Sub BtnSearchInstall_Click(sender As Object, e As EventArgs) Handles BtnSearchInstall.Click
ModpackInstall()
End Sub
#Region "搜索"
'搜索按钮
Private Sub StartNewSearch() Handles BtnSearchRun.Click
Page = 0
If Loader.ShouldStart(LoaderInput()) Then Storage = New CompProjectStorage '避免连续搜索两次使得 CompProjectStorage 引用丢失(#1311)
Loader.Start()
End Sub
Private Sub EnterTrigger(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyDown, TextSearchVersion.KeyDown
If e.Key = Key.Enter Then StartNewSearch()
End Sub
'重置按钮
Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click
TextSearchName.Text = ""
TextSearchVersion.Text = "全部 (也可自行输入)"
TextSearchVersion.SelectedIndex = 0
ComboSearchSource.SelectedIndex = 0
ComboSearchTag.SelectedIndex = 0
Loader.LastFinishedTime = 0 '要求强制重新开始
End Sub
#End Region
End Class
@@ -17,7 +17,7 @@ Public Class FormLoginOAuth
IsLoginSuccessed = True
RaiseEvent OnLoginSuccess(Code)
ElseIf Url.Contains("github.") Then
Hint("PCL2 不支持使用 GitHub 登录微软账号!", HintType.Critical)
Hint("PCL 不支持使用 GitHub 登录微软账号!", HintType.Critical)
Close()
End If
End Sub
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
Height="64" Width="64" UseLayoutRounding="True" RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}"
ToolTipService.ShowDuration="23333333" ToolTipService.Placement="Center" ToolTipService.VerticalOffset="-50" ToolTipService.HorizontalOffset="2" ToolTipService.InitialShowDelay="100">
ToolTipService.Placement="Center" ToolTipService.VerticalOffset="-50" ToolTipService.HorizontalOffset="2" ToolTipService.InitialShowDelay="100">
<Grid.Effect>
<DropShadowEffect x:Name="ShadowSkin" BlurRadius="10" ShadowDepth="0" Color="{DynamicResource ColorObject2}" Opacity="0.2" />
</Grid.Effect>
@@ -5,7 +5,7 @@
'皮肤储存
Private _Address As String
Public Property Address() As String
Public Property Address As String
Get
Return _Address
End Get
@@ -41,7 +41,7 @@
End Sub
'保存皮肤
Private Sub BtnSkinSave_Click(sender As Object, e As RoutedEventArgs) Handles BtnSkinSave.Click
Public Sub BtnSkinSave_Click() Handles BtnSkinSave.Click
Save(Loader)
End Sub
Public Shared Sub Save(Loader As LoaderTask(Of EqualableList(Of String), String))
@@ -76,19 +76,35 @@
''' </summary>
Public Sub Load()
Try
Address = Loader.Output
'检查文件存在
If Address = "" Then Throw New Exception("皮肤加载器 " & Loader.Name & " 没有输出")
Address = Loader.Output
If String.IsNullOrEmpty(Address) Then Throw New Exception("皮肤加载器 " & Loader.Name & " 没有输出")
If Not Address.StartsWith(PathImage) AndAlso Not File.Exists(Address) Then Throw New FileNotFoundException("皮肤文件未找到", Address)
'加载
Dim Image As New MyBitmap(Address)
Dim Image As MyBitmap
Try
Image = New MyBitmap(Address)
Catch ex As Exception '#2272
Log(ex, $"皮肤文件已损坏:{Address}", LogLevel.Hint)
File.Delete(Address)
Exit Sub
End Try
ImgBack.Tag = Address
'大小检查
Dim Scale As Integer = Image.Pic.Width / 64
If Image.Pic.Width < 32 OrElse Image.Pic.Height < 32 Then
ImgFore.Source = Nothing : ImgBack.Source = Nothing
Throw New Exception("图片大小不足,长为 " & Image.Pic.Height & ",宽为 " & Image.Pic.Width)
End If
'头发层(附加层)
If Image.Pic.Width >= 64 AndAlso Image.Pic.Height >= 32 Then
'如果图片中有透明像素,或是头部颜色和透明区均不一样,则加载附加层
If (Image.Pic.GetPixel(1, 1).A = 0 OrElse Image.Pic.GetPixel(Image.Pic.Width - 1, Image.Pic.Height - 1).A = 0 OrElse Image.Pic.GetPixel(Image.Pic.Width - 2, 2).A = 0) OrElse
(Image.Pic.GetPixel(1, 1) <> Image.Pic.GetPixel(41, 9) AndAlso Image.Pic.GetPixel(Image.Pic.Width - 1, Image.Pic.Height - 1) <> Image.Pic.GetPixel(41, 9) AndAlso Image.Pic.GetPixel(Image.Pic.Width - 2, 2) <> Image.Pic.GetPixel(41, 9)) Then
ImgFore.Source = New CroppedBitmap(Image, New Int32Rect(40, 8, 8, 8))
If (Image.Pic.GetPixel(1, 1).A = 0 OrElse '如果图片中有任何透明像素(避免纯色白底)
Image.Pic.GetPixel(Image.Pic.Width - 1, Image.Pic.Height - 1).A = 0 OrElse
Image.Pic.GetPixel(Image.Pic.Width - 2, Image.Pic.Height / 2 - 2).A = 0) OrElse
(Image.Pic.GetPixel(1, 1) <> Image.Pic.GetPixel(Scale * 41, Scale * 9) AndAlso '或是头部颜色和透明区均不一样
Image.Pic.GetPixel(Image.Pic.Width - 1, Image.Pic.Height - 1) <> Image.Pic.GetPixel(Scale * 41, Scale * 9) AndAlso
Image.Pic.GetPixel(Image.Pic.Width - 2, Image.Pic.Height / 2 - 2) <> Image.Pic.GetPixel(Scale * 41, Scale * 9)) Then
ImgFore.Source = Image.Clip(Scale * 40, Scale * 8, Scale * 8, Scale * 8)
Else
ImgFore.Source = Nothing
End If
@@ -96,13 +112,8 @@
ImgFore.Source = Nothing
End If
'脸层
If Image.Pic.Width >= 32 AndAlso Image.Pic.Height >= 32 Then
ImgBack.Source = New CroppedBitmap(Image, New Int32Rect(8, 8, 8, 8))
Log("[Skin] 载入头像成功:" & Loader.Name)
Else
ImgBack.Source = Nothing
Throw New Exception("图片大小不足,长为 " & Image.Pic.Height & ",宽为 " & Image.Pic.Width)
End If
ImgBack.Source = Image.Clip(Scale * 8, Scale * 8, Scale * 8, Scale * 8)
Log("[Skin] 载入头像成功:" & Loader.Name)
Catch ex As Exception
Log(ex, "载入头像失败(" & If(Address, "null") & "," & Loader.Name & ")", LogLevel.Hint)
End Try
@@ -117,7 +128,7 @@
End Sub
'刷新缓存
Private Sub RefreshClick(sender As MyMenuItem, e As EventArgs) Handles BtnSkinRefresh.Click
Public Sub RefreshClick() Handles BtnSkinRefresh.Click
RefreshCache(Loader)
End Sub
''' <summary>
@@ -134,50 +145,50 @@
'由于 Abort 不是实时的,暂时不会释放文件,会导致删除报错,故只能取消执行
Hint("有正在获取中的皮肤,请稍后再试!", HintType.Info)
Else
RunInThread(Sub()
Try
Hint("正在刷新皮肤……")
'清空缓存
Log("[Skin] 正在清空皮肤缓存")
If Directory.Exists(PathTemp & "Cache\Skin") Then DeleteDirectory(PathTemp & "Cache\Skin")
If Directory.Exists(PathTemp & "Cache\Uuid") Then DeleteDirectory(PathTemp & "Cache\Uuid")
IniClearCache(PathTemp & "Cache\Skin\IndexMojang.ini")
IniClearCache(PathTemp & "Cache\Skin\IndexMs.ini")
IniClearCache(PathTemp & "Cache\Skin\IndexNide.ini")
IniClearCache(PathTemp & "Cache\Skin\IndexAuth.ini")
IniClearCache(PathTemp & "Cache\Uuid\Mojang.ini")
'刷新控件
For Each SkinLoader In If(sender IsNot Nothing, {sender}, {PageLaunchLeft.SkinMojang, PageLaunchLeft.SkinLegacy, PageLaunchLeft.SkinMs})
SkinLoader.WaitForExit(IsForceRestart:=True)
Next
Hint("已刷新皮肤!", HintType.Finish)
Catch ex As Exception
Log(ex, "刷新皮肤缓存失败", LogLevel.Msgbox)
End Try
End Sub)
RunInThread(
Sub()
Try
Hint("正在刷新头像……")
'清空缓存
Log("[Skin] 正在清空皮肤缓存")
If Directory.Exists(PathTemp & "Cache\Skin") Then DeleteDirectory(PathTemp & "Cache\Skin")
If Directory.Exists(PathTemp & "Cache\Uuid") Then DeleteDirectory(PathTemp & "Cache\Uuid")
IniClearCache(PathTemp & "Cache\Skin\IndexMs.ini")
IniClearCache(PathTemp & "Cache\Skin\IndexNide.ini")
IniClearCache(PathTemp & "Cache\Skin\IndexAuth.ini")
IniClearCache(PathTemp & "Cache\Uuid\Mojang.ini")
'刷新控件
For Each SkinLoader In If(sender IsNot Nothing, {sender}, {PageLaunchLeft.SkinLegacy, PageLaunchLeft.SkinMs})
SkinLoader.WaitForExit(IsForceRestart:=True)
Next
Hint("已刷新头像!", HintType.Finish)
Catch ex As Exception
Log(ex, "刷新皮肤缓存失败", LogLevel.Msgbox)
End Try
End Sub)
End If
End Sub
''' <summary>
''' 在更换正版皮肤后,刷新正版皮肤。
''' </summary>
''' <param name="SkinAddress">新的正版皮肤完整地址。</param>
Public Shared Sub ReloadCache(SkinAddress As String, IsMsLogin As Boolean)
RunInThread(Sub()
Try
'更新缓存
Dim LoginType As String = If(IsMsLogin, "Ms", "Mojang")
WriteIni(PathTemp & "Cache\Skin\Index" & LoginType & ".ini", Setup.Get("Cache" & LoginType & "Uuid"), SkinAddress)
Log(String.Format("[Skin] 已写入皮肤地址缓存 {0} -> {1}", Setup.Get("Cache" & LoginType & "Uuid"), SkinAddress))
'刷新控件
For Each SkinLoader In If(IsMsLogin, {PageLaunchLeft.SkinMs, PageLaunchLeft.SkinLegacy}, {PageLaunchLeft.SkinMojang, PageLaunchLeft.SkinLegacy})
SkinLoader.WaitForExit(IsForceRestart:=True)
Next
'完成提示
Hint("更改皮肤成功!", HintType.Finish)
Catch ex As Exception
Log(ex, "更改正版皮肤后刷新皮肤失败", LogLevel.Feedback)
End Try
End Sub)
Public Shared Sub ReloadCache(SkinAddress As String)
RunInThread(
Sub()
Try
'更新缓存
WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Setup.Get("CacheMsUuid"), SkinAddress)
Log(String.Format("[Skin] 已写入皮肤地址缓存 {0} -> {1}", Setup.Get("CacheMsUuid"), SkinAddress))
'刷新控件
For Each SkinLoader In {PageLaunchLeft.SkinMs, PageLaunchLeft.SkinLegacy}
SkinLoader.WaitForExit(IsForceRestart:=True)
Next
'完成提示
Hint("更改皮肤成功!", HintType.Finish)
Catch ex As Exception
Log(ex, "更改正版皮肤后刷新皮肤失败", LogLevel.Feedback)
End Try
End Sub)
End Sub
'披风
@@ -194,7 +205,7 @@
End Set
End Property
Private IsChanging As Boolean = False
Private Sub BtnSkinCape_Click(sender As Object, e As RoutedEventArgs) Handles BtnSkinCape.Click
Public Sub BtnSkinCape_Click() Handles BtnSkinCape.Click
'检查条件,获取新披风
If IsChanging Then
Hint("正在更改披风中,请稍候!")
@@ -207,57 +218,60 @@
Hint("正在获取披风列表,请稍候……")
IsChanging = True
'开始实际获取
RunInNewThread(Sub()
Try
RunInNewThread(
Sub()
Try
Retry:
'获取登录信息
If McLoginMsLoader.State <> LoadState.Finished Then McLoginMsLoader.WaitForExit(PageLoginMsSkin.GetLoginData())
If McLoginMsLoader.State <> LoadState.Finished Then
Hint("登录失败,无法更改披风!", HintType.Critical)
Exit Sub
End If
Dim AccessToken As String = McLoginMsLoader.Output.AccessToken
Dim Uuid As String = McLoginMsLoader.Output.Uuid
Dim SkinData As JObject = GetJson(McLoginMsLoader.Output.ProfileJson)
'获取玩家的所有披风
Dim SelId As Integer? = Nothing
RunInUiWait(Sub()
Try
Dim CapeNames As New Dictionary(Of String, String) From {
{"Migrator", "迁移者披风"}, {"MapMaker", "Realms 地图制作者披风"}, {"Moderator", "Mojira 管理员披风"},
{"Translator-Chinese", "Crowdin 中文翻译者披风"}, {"Translator", "Crowdin 翻译者披风"}, {"Cobalt", "Cobalt 披风"},
{"Vanilla", "原版披风"}, {"Minecon2011", "Minecon 2011 参与者披风"}, {"Minecon2012", "Minecon 2012 参与者披风"},
{"Minecon2013", "Minecon 2013 参与者披风"}, {"Minecon2015", "Minecon 2015 参与者披风"}, {"Minecon2016", "Minecon 2016 参与者披风"}
}
Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}}
For Each Cape In SkinData("capes")
Dim CapeName As String = Cape("alias").ToString
If CapeNames.ContainsKey(CapeName) Then CapeName = CapeNames(CapeName)
SelectionControl.Add(New MyRadioBox With {.Text = CapeName})
Next
SelId = MyMsgBoxSelect(SelectionControl, "选择披风", "确定", "取消")
Catch ex As Exception
Log(ex, "获取玩家皮肤列表失败", LogLevel.Feedback)
End Try
End Sub)
If SelId Is Nothing Then Exit Sub
'发送请求
Dim Result As String = NetRequestRetry("https://api.minecraftservices.com/minecraft/profile/capes/active",
If(SelId = 0, "DELETE", "PUT"),
If(SelId = 0, "", "{""capeId"": """ & SkinData("capes")(SelId - 1)("id").ToString & """}"),
"application/json", Headers:=New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}})
If Result.Contains("""errorMessage""") Then
Hint("更改披风失败:" & GetJson(Result)("errorMessage"), HintType.Critical)
Exit Sub
Else
Hint("更改披风成功!", HintType.Finish)
End If
Catch ex As Exception
Log(ex, "更改披风失败", LogLevel.Hint)
Finally
IsChanging = False
End Try
End Sub, "Cape Change")
'获取登录信息
If McLoginMsLoader.State <> LoadState.Finished Then McLoginMsLoader.WaitForExit(PageLoginMsSkin.GetLoginData())
If McLoginMsLoader.State <> LoadState.Finished Then
Hint("登录失败,无法更改披风!", HintType.Critical)
Exit Sub
End If
Dim AccessToken As String = McLoginMsLoader.Output.AccessToken
Dim Uuid As String = McLoginMsLoader.Output.Uuid
Dim SkinData As JObject = GetJson(McLoginMsLoader.Output.ProfileJson)
'获取玩家的所有披风
Dim SelId As Integer? = Nothing
RunInUiWait(
Sub()
Try
Dim CapeNames As New Dictionary(Of String, String) From {
{"Migrator", "迁移者披风"}, {"MapMaker", "Realms 地图制作者披风"}, {"Moderator", "Mojira 管理员披风"},
{"Translator-Chinese", "Crowdin 中文翻译者披风"}, {"Translator", "Crowdin 翻译者披风"}, {"Cobalt", "Cobalt 披风"},
{"Vanilla", "原版披风"}, {"Minecon2011", "Minecon 2011 参与者披风"}, {"Minecon2012", "Minecon 2012 参与者披风"},
{"Minecon2013", "Minecon 2013 参与者披风"}, {"Minecon2015", "Minecon 2015 参与者披风"}, {"Minecon2016", "Minecon 2016 参与者披风"},
{"Cherry Blossom", "樱花披风"}
}
Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}}
For Each Cape In SkinData("capes")
Dim CapeName As String = Cape("alias").ToString
If CapeNames.ContainsKey(CapeName) Then CapeName = CapeNames(CapeName)
SelectionControl.Add(New MyRadioBox With {.Text = CapeName})
Next
SelId = MyMsgBoxSelect(SelectionControl, "选择披风", "确定", "取消")
Catch ex As Exception
Log(ex, "获取玩家皮肤列表失败", LogLevel.Feedback)
End Try
End Sub)
If SelId Is Nothing Then Exit Sub
'发送请求
Dim Result As String = NetRequestRetry("https://api.minecraftservices.com/minecraft/profile/capes/active",
If(SelId = 0, "DELETE", "PUT"),
If(SelId = 0, "", New JObject(New JProperty("capeId", SkinData("capes")(SelId - 1)("id"))).ToString(0)),
"application/json", Headers:=New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}})
If Result.Contains("""errorMessage""") Then
Hint("更改披风失败:" & GetJson(Result)("errorMessage"), HintType.Critical)
Exit Sub
Else
Hint("更改披风成功!", HintType.Finish)
End If
Catch ex As Exception
Log(ex, "更改披风失败", LogLevel.Hint)
Finally
IsChanging = False
End Try
End Sub, "Cape Change")
End Sub
End Class
@@ -33,7 +33,7 @@
<Path Name="PathTypeOne" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="{DynamicResource ColorBrush3}" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center"
Data="">
<Path.RenderTransform>
<ScaleTransform ScaleX="1.4" ScaleY="1.4" />
<ScaleTransform ScaleX="1.05" ScaleY="1.05" />
</Path.RenderTransform>
</Path>
<TextBlock Name="LabTypeOne" Text="" FontSize="14" VerticalAlignment="Center" Grid.Column="1" Foreground="{DynamicResource ColorBrush3}" Margin="15,0,12,0" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
@@ -48,12 +48,10 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<local:MyRadioButton x:Name="RadioLoginType1" Tag="LoginType/1" Grid.Column="1" Grid.ColumnSpan="1" ColorType="Highlight" Text="Mojang" Margin="4,0"
LogoScale="1.1" Logo="M9.183,18.967c-0.109-2.239,1.336-5.119,3.92-4.96c3.657-0.027,7.319-0.044,10.977,0.005 c3.712,0.214,6.596,2.759,9.652,4.533c0.181-1.697-0.197-3.717,1.237-4.982c1.899,2.091,3.143,4.894,5.677,6.334 c1.577,0.805,2.973-0.668,4.221-1.44c1.55,2.305,2.108,5.075,2.622,7.752c0.657,3.438,0.947,6.925,1.111,10.413 c-1.734-0.733-3.355-1.708-4.971-2.671c-1.396-4.933-5.349-8.656-9.723-11.059c-3.46-1.817-7.752-2.185-11.338-0.52 c-3.761,1.593-6.285,5.666-5.891,9.75c0.121,4.577,3.17,8.765,7.391,10.456c7.746,3.285,16.407,2.234,24.521,1.243 c0.454,2.315-1.511,4.527-3.695,4.889c-10.577,0.038-21.148-0.011-31.725,0.022c-2.217,0.279-4.079-1.879-3.964-4.008 C9.167,36.141,9.216,27.556,9.183,18.967z M40.114,8.09c0.294-0.801,0.872-1.417,1.542-1.924c1.379,2.589,2.742,5.482,2.311,8.491 c-0.332,2.54-4.42,2.507-5.052,0.163C38.349,12.527,39.209,10.178,40.114,8.09z M0,53 l0.1,0 z" Checked="True" />
<local:MyRadioButton x:Name="RadioLoginType5" Tag="LoginType/5" Grid.Column="2" Grid.ColumnSpan="1" ColorType="Highlight" Text="微软" Margin="4,0"
LogoScale="0.9" Logo="M481.882353 826.428235V527.661176l402.371765 2.409412v356.592941l-402.371765-60.235294z m0-628.85647l402.371765-60.235294v330.089411H481.882353V197.571765zM137.336471 525.251765h289.129411v293.948235l-289.129411-45.778824V525.251765z m0-55.416471V248.169412l289.129411-45.778824v265.035294h-289.129411z" />
<local:MyRadioButton x:Name="RadioLoginType5" Tag="LoginType/5" Grid.Column="2" Grid.ColumnSpan="1" ColorType="Highlight" Text="正版" Margin="4,0"
LogoScale="1" Logo="M511.488256 95.184408c35.310345 22.516742 95.184408 55.78011 167.34033 84.437781 75.738131 29.681159 148.405797 40.93953 191.392304 45.033483v353.615193c0 73.691154-50.662669 164.781609-136.123938 244.101949C649.65917 901.181409 558.568716 942.12094 512 942.12094c-46.568716 0-137.65917-40.93953-222.096952-119.748126C204.441779 742.54073 153.77911 651.450275 153.77911 577.247376v-353.103448c42.474763-4.093953 116.165917-15.352324 191.904048-45.545227 75.226387-30.192904 133.565217-63.456272 165.805098-83.414293M512 0c-4.093953 0-8.187906 1.535232-11.258371 3.582209l-14.84058 10.234882c-1.023488 0.511744-67.550225 47.592204-170.410794 88.531735-100.813593 39.916042-198.556722 41.963018-199.58021 41.963018l-25.075462 0.511744c-10.746627 0.511744-18.934533 8.187906-18.934533 18.422789v414.000999c0 216.97951 286.064968 446.24088 440.09995 446.24088s440.09995-229.261369 440.09995-445.729136V163.758121c0-10.234883-8.69965-18.422789-18.934533-18.422789l-24.563718-0.511744c-1.023488 0-98.766617-2.046977-199.58021-41.963018-103.372314-40.93953-170.410795-88.01999-170.922538-88.531734L523.258371 3.582209c-3.070465-2.558721-7.164418-3.582209-11.258371-3.582209z M743.308346 410.930535l-260.477761 260.477761c-15.864068 15.864068-41.963018 15.864068-57.827087 0l-144.823588-144.823588c-15.864068-15.864068-15.864068-41.963018 0-57.827087 8.187906-8.187906 18.422789-11.770115 29.169415-11.770115 10.234883 0 20.981509 4.093953 29.169416 11.770115l115.654173 115.654173L685.993003 352.591704c15.864068-15.864068 41.963018-15.864068 57.827087 0 15.352324 16.375812 15.352324 42.474763-0.511744 58.338831z" />
<local:MyRadioButton x:Name="RadioLoginType0" Tag="LoginType/0" Grid.Column="3" Grid.ColumnSpan="1" ColorType="Highlight" Text="离线" Margin="4,0"
LogoScale="0.95" Logo="M660.338 528.065c63.61-46.825 105.131-121.964 105.131-206.83 0-141.7-115.29-256.987-256.997-256.987-141.706 0-256.998 115.288-256.998 256.987 0 85.901 42.52 161.887 107.456 208.562-152.1 59.92-260.185 207.961-260.185 381.077 0 21.276 17.253 38.53 38.53 38.53 21.278 0 38.53-17.254 38.53-38.53 0-183.426 149.232-332.671 332.667-332.671 1.589 0 3.113-0.207 4.694-0.244 0.8 0.056 1.553 0.244 2.362 0.244 183.434 0 332.664 149.245 332.664 332.671 0 21.276 17.255 38.53 38.533 38.53 21.277 0 38.53-17.254 38.53-38.53 0-174.885-110.354-324.13-264.917-382.809z m-331.803-206.83c0-99.22 80.72-179.927 179.935-179.927s179.937 80.708 179.937 179.927c0 99.203-80.721 179.91-179.937 179.91s-179.935-80.708-179.935-179.91z" />
LogoScale="0.85" Logo="M533.293176 788.841412a60.235294 60.235294 0 1 1 85.202824 85.202823l-42.616471 42.586353c-129.355294 129.385412-339.124706 129.385412-468.510117 0-129.385412-129.385412-129.385412-339.124706 0-468.510117l42.586353-42.616471a60.235294 60.235294 0 1 1 85.202823 85.202824l-42.61647 42.586352a210.823529 210.823529 0 1 0 298.164706 298.164706l42.586352-42.61647z m255.548236-255.548236l42.61647-42.586352a210.823529 210.823529 0 1 0-298.164706-298.164706l-42.586352 42.61647a60.235294 60.235294 0 1 1-85.202824-85.202823l42.616471-42.586353c129.355294-129.385412 339.124706-129.385412 468.510117 0 129.385412 129.385412 129.385412 339.124706 0 468.510117l-42.586353 42.616471a60.235294 60.235294 0 1 1-85.202823-85.202824zM192.542118 192.542118a60.235294 60.235294 0 0 1 85.202823 0l553.712941 553.712941a60.235294 60.235294 0 0 1-85.202823 85.202823L192.542118 277.744941a60.235294 60.235294 0 0 1 0-85.202823z" />
<!--<local:MyRadioButton x:Name="RadioLoginType2" Tag="LoginType/2" Grid.Column="4" ColorType="Highlight" Text="统一通行证" Visibility="Collapsed"
LogoScale="1.1" Logo="M834.5 684.1c-31.2-70.4-98.9-120.9-179.1-127.3 63.5-8.5 112.6-63 112.6-128.8 0-71.8-58.2-130-130-130s-130 58.2-130 130c0 65.9 49 120.3 112.6 128.8-80.2 6.4-148 57-179.1 127.3-8.7 19.7 6 42 27.6 42 12.1 0 22.7-7.5 27.7-18.5 24.3-53.9 78.5-91.5 141.3-91.5s117 37.6 141.3 91.5c5 11.1 15.6 18.5 27.7 18.5 21.4 0 36.1-22.3 27.4-42zM567.9 427.9c0-38.6 31.4-70 70-70s70 31.4 70 70-31.4 70-70 70-70-31.4-70-70zM460.3 347.9H216.9c-16.6 0-30 13.4-30 30s13.4 30 30 30h243.3c16.6 0 30-13.4 30-30 0.1-16.5-13.4-30-29.9-30zM367.4 459.6H216.9c-16.6 0-30 13.4-30 30s13.4 30 30 30h150.4c16.6 0 30-13.4 30-30 0.1-16.6-13.4-30-29.9-30zM297.4 571.2H217c-16.6 0-30 13.4-30 30s13.4 30 30 30h80.4c16.6 0 30-13.4 30-30 0-16.5-13.5-30-30-30zM900 236v552H124V236h776m0-60H124c-33.1 0-60 26.9-60 60v552c0 33.1 26.9 60 60 60h776c33.1 0 60-26.9 60-60V236c0-33.1-26.9-60-60-60z" />-->
</Grid>
@@ -19,55 +19,57 @@
RefreshButtonsUI()
'加载版本
RunInNewThread(Sub()
'确认 Minecraft 文件夹存在
PathMcFolder = Setup.Get("LaunchFolderSelect").ToString.Replace("$", Path)
If PathMcFolder = "" OrElse Not Directory.Exists(PathMcFolder) Then
'无效的文件夹
If PathMcFolder = "" Then
Log("[Launch] 没有已储存的 Minecraft 文件夹")
Else
Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" & PathMcFolder, LogLevel.Debug)
End If
McFolderListLoader.WaitForExit(IsForceRestart:=True)
Setup.Set("LaunchFolderSelect", McFolderList(0).Path.Replace(Path, "$"))
End If
Log("[Launch] Minecraft 文件夹:" & PathMcFolder)
If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
'确认 Minecraft 版本存在
Dim Selection As String = Setup.Get("LaunchVersionSelect")
Dim Version As McVersion
If Selection = "" Then
Version = Nothing
Else
Version = New McVersion(Selection)
End If
If IsNothing(Version) OrElse Not (Version.Path.StartsWith(PathMcFolder) AndAlso Version.Check) Then
'无效的版本
Log("[Launch] Minecraft 版本无效" & If(IsNothing(Version), ",没有有效版本", ":" & Version.Path), If(IsNothing(Version), LogLevel.Normal, LogLevel.Debug))
If Not McVersionListLoader.State = LoadState.Finished Then LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
If McVersionList.Count = 0 OrElse McVersionList.First.Value(0).Logo.Contains("RedstoneBlock") Then
Version = Nothing
Setup.Set("LaunchVersionSelect", "")
Log("[Launch] 无可用 Minecraft 版本")
Else
Version = McVersionList.First.Value(0)
Setup.Set("LaunchVersionSelect", Version.Name)
Log("[Launch] 自动选择 Minecraft 版本:" & Version.Path)
End If
End If
RunInUi(Sub()
McVersionCurrent = Version '绕这一圈是为了避免 McVersionCheck 触发第二次版本改变
IsLoadFinished = True
RefreshButtonsUI()
RefreshPage(False, False) '有可能选择的版本变化了,需要重新刷新
If McLoginAble() = "" Then McLoginLoader.Start() '自动登录
End Sub)
End Sub, "Version Check", ThreadPriority.AboveNormal)
RunInNewThread(
Sub()
'确认 Minecraft 文件夹存在
PathMcFolder = Setup.Get("LaunchFolderSelect").ToString.Replace("$", Path)
If PathMcFolder = "" OrElse Not Directory.Exists(PathMcFolder) Then
'无效的文件夹
If PathMcFolder = "" Then
Log("[Launch] 没有已储存的 Minecraft 文件夹")
Else
Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" & PathMcFolder, LogLevel.Debug)
End If
McFolderListLoader.WaitForExit(IsForceRestart:=True)
Setup.Set("LaunchFolderSelect", McFolderList(0).Path.Replace(Path, "$"))
End If
Log("[Launch] Minecraft 文件夹:" & PathMcFolder)
If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
'确认 Minecraft 版本存在
Dim Selection As String = Setup.Get("LaunchVersionSelect")
Dim Version As McVersion
If Selection = "" Then
Version = Nothing
Else
Version = New McVersion(Selection)
End If
If IsNothing(Version) OrElse Not (Version.Path.StartsWith(PathMcFolder) AndAlso Version.Check) Then
'无效的版本
Log("[Launch] Minecraft 版本无效" & If(IsNothing(Version), ",没有有效版本", ":" & Version.Path), If(IsNothing(Version), LogLevel.Normal, LogLevel.Debug))
If Not McVersionListLoader.State = LoadState.Finished Then LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
If Not McVersionList.Any() OrElse McVersionList.First.Value(0).Logo.Contains("RedstoneBlock") Then
Version = Nothing
Setup.Set("LaunchVersionSelect", "")
Log("[Launch] 无可用 Minecraft 版本")
Else
Version = McVersionList.First.Value(0)
Setup.Set("LaunchVersionSelect", Version.Name)
Log("[Launch] 自动选择 Minecraft 版本:" & Version.Path)
End If
End If
RunInUi(
Sub()
McVersionCurrent = Version '绕这一圈是为了避免 McVersionCheck 触发第二次版本改变
IsLoadFinished = True
RefreshButtonsUI()
RefreshPage(False, False) '有可能选择的版本变化了,需要重新刷新
If McLoginAble() = "" Then McLoginLoader.Start() '自动登录
End Sub)
End Sub, "Version Check", ThreadPriority.AboveNormal)
'改变页面
Dim LoginType As McLoginType = Setup.Get("LoginType")
If LoginType = McLoginType.Legacy OrElse LoginType = McLoginType.Mojang OrElse LoginType = McLoginType.Ms Then CType(FindName("RadioLoginType" & LoginType), MyRadioButton).Checked = True
If LoginType = McLoginType.Legacy OrElse LoginType = McLoginType.Ms Then CType(FindName("RadioLoginType" & LoginType), MyRadioButton).Checked = True
RefreshPage(False, False)
AniControlEnabled -= 1
@@ -79,7 +81,45 @@
''' 切换至启动中页面。
''' </summary>
Public Sub PageChangeToLaunching()
LaunchingPreload()
'修改登陆方式
Select Case Setup.Get("LoginType")
Case McLoginType.Legacy
If PageLinkHiper.HiperState = LoadState.Finished Then
LabLaunchingMethod.Text = "联机离线登录"
Else
LabLaunchingMethod.Text = "离线登录"
End If
Case McLoginType.Ms
LabLaunchingMethod.Text = "正版登录"
Case McLoginType.Nide
LabLaunchingMethod.Text = "统一通行证"
Case McLoginType.Auth
LabLaunchingMethod.Text = "Authlib-Injector"
End Select
'初始化页面
LabLaunchingName.Text = McVersionCurrent.Name
LabLaunchingStage.Text = "初始化"
LabLaunchingTitle.Text = If(McLaunchLoader.Input Is Nothing OrElse McLaunchLoader.Input.SaveBatch Is Nothing, "正在启动游戏", "正在导出启动脚本")
LabLaunchingProgress.Text = "0.00 %"
LabLaunchingProgress.Opacity = 1
LabLaunchingDownload.Visibility = Visibility.Visible
LabLaunchingProgressLeft.Opacity = 0.6
LabLaunchingDownload.Visibility = Visibility.Visible
LabLaunchingDownload.Text = "0 B/s"
LabLaunchingDownload.Opacity = 0
LabLaunchingDownload.Visibility = Visibility.Collapsed
LabLaunchingDownloadLeft.Opacity = 0
LabLaunchingDownloadLeft.Visibility = Visibility.Collapsed
ProgressLaunchingFinished.Width = New GridLength(0, GridUnitType.Star)
ProgressLaunchingUnfinished.Width = New GridLength(1, GridUnitType.Star)
PanLaunchingHint.Opacity = 0
PanLaunchingHint.Visibility = Visibility.Collapsed
PanLaunchingInfo.Width = Double.NaN '重置宽度改变动画
McLaunchProcess = Nothing
McLaunchWatcher = Nothing
'获取 “你知道吗” 提示
LabLaunchingHint.Text = PageOtherTest.GetRandomHint()
'初始化其他页面
PanInput.IsHitTestVisible = False
PanLaunching.IsHitTestVisible = False
LoadLaunching.State.LoadingState = MyLoading.MyLoadingState.Run
@@ -117,8 +157,6 @@
Private Enum PageType
None
Mojang
MojangSkin
Legacy
Nide
NideSkin
@@ -134,12 +172,6 @@
Private Function PageGet(Type As PageType)
Select Case Type
Case PageType.Mojang
If IsNothing(FrmLoginMojang) Then FrmLoginMojang = New PageLoginMojang
Return FrmLoginMojang
Case PageType.MojangSkin
If IsNothing(FrmLoginMojangSkin) Then FrmLoginMojangSkin = New PageLoginMojangSkin
Return FrmLoginMojangSkin
Case PageType.Legacy
If IsNothing(FrmLoginLegacy) Then FrmLoginLegacy = New PageLoginLegacy
Return FrmLoginLegacy
@@ -171,7 +203,7 @@
''' <param name="Type">新页面的种类。</param>
''' <param name="Anim">是否显示动画。</param>
Private Function PageChange(Type As PageType, Anim As Boolean)
Dim PageNew As Object = FrmLoginMojang '初始化一个东西,避免在执行时出现异常导致雪崩
Dim PageNew As Object = FrmLoginMs '初始化一个东西,避免在执行时出现异常导致雪崩
Try
#Region "确定更改的页面实例并实例化"
@@ -232,14 +264,7 @@
Select Case LoginPageType
Case 0 '正版或离线
UnknownType:
If RadioLoginType1.Checked Then
If Setup.Get("CacheMojangAccess") = "" Then
Type = PageType.Mojang
Else
Type = PageType.MojangSkin
End If
Setup.Set("LoginType", McLoginType.Mojang)
ElseIf RadioLoginType5.Checked Then
If RadioLoginType5.Checked Then
If Setup.Get("CacheMsAccess") = "" Then
Type = PageType.Ms
Else
@@ -252,28 +277,19 @@ UnknownType:
End If
PanType.Visibility = Visibility.Visible
PanTypeOne.Visibility = Visibility.Collapsed
RadioLoginType1.Visibility = Visibility.Visible
RadioLoginType5.Visibility = Visibility.Visible
RadioLoginType0.Visibility = Visibility.Visible
Case 1 '仅正版
If RadioLoginType5.Checked Then
If Setup.Get("CacheMsAccess") = "" Then
Type = PageType.Ms
Else
Type = PageType.MsSkin
End If
Setup.Set("LoginType", McLoginType.Ms)
If Setup.Get("CacheMsAccess") = "" Then
Type = PageType.Ms
Else
If Setup.Get("CacheMojangAccess") = "" Then
Type = PageType.Mojang
Else
Type = PageType.MojangSkin
End If
Setup.Set("LoginType", McLoginType.Mojang)
Type = PageType.MsSkin
End If
PanType.Visibility = Visibility.Visible
PanTypeOne.Visibility = Visibility.Collapsed
RadioLoginType1.Visibility = Visibility.Visible
Setup.Set("LoginType", McLoginType.Ms)
PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonShield)
LabTypeOne.Text = "正版登录"
RadioLoginType5.Visibility = Visibility.Visible
RadioLoginType0.Visibility = Visibility.Collapsed
Case 2 '仅离线
@@ -281,7 +297,7 @@ UnknownType:
Setup.Set("LoginType", McLoginType.Legacy)
PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonUser)
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonOffline)
LabTypeOne.Text = "离线登录"
Case 3 '统一通行证
If Setup.Get("CacheNideAccess") = "" Then
@@ -316,7 +332,7 @@ UnknownType:
Dim Control As MyRadioButton = FindName("RadioLoginType" & Setup.Get("LoginType"))
If Control IsNot Nothing Then Control.Checked = True
End Sub
Private Sub RadioLoginType_Change(sender As Object, raiseByMouse As Boolean) Handles RadioLoginType0.Check, RadioLoginType1.Check, RadioLoginType5.Check
Private Sub RadioLoginType_Change(sender As Object, raiseByMouse As Boolean) Handles RadioLoginType0.Check, RadioLoginType5.Check
If raiseByMouse Then RefreshPage(True, True)
End Sub
@@ -324,54 +340,6 @@ UnknownType:
#Region "皮肤"
'Mojang 正版皮肤
Public Shared SkinMojang As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Mojang", AddressOf SkinMojangLoad, AddressOf SkinMojangInput, ThreadPriority.AboveNormal)
Private Shared Function SkinMojangInput() As EqualableList(Of String)
'获取名称
Return New EqualableList(Of String) From {Setup.Get("CacheMojangName"), Setup.Get("CacheMojangUuid")}
End Function
Private Shared Sub SkinMojangLoad(Data As LoaderTask(Of EqualableList(Of String), String))
'清空已有皮肤
'如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载
RunInUi(Sub() If FrmLoginMojangSkin IsNot Nothing AndAlso FrmLoginMojangSkin.Skin IsNot Nothing Then FrmLoginMojangSkin.Skin.Clear())
'获取 Url
Dim UserName As String = Data.Input(0)
Dim Uuid As String = Data.Input(1)
If UserName = "" Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Log("[Minecraft] 获取正版皮肤失败,ID 为空")
GoTo Finish
End If
Try
Dim Result As String = McSkinGetAddress(Uuid, "Mojang")
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Result = McSkinDownload(Result)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Data.Output = Result
Catch ex As Exception
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Exit Sub
ElseIf GetString(ex).Contains("429") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Log("[Minecraft] 获取正版皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", LogLevel.Hint)
ElseIf GetString(ex).Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载")
Else
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Log(ex, "获取正版皮肤失败(" & UserName & ")", LogLevel.Hint)
End If
End Try
Finish:
'刷新显示
If FrmLoginMojangSkin IsNot Nothing Then
RunInUi(AddressOf FrmLoginMojangSkin.Skin.Load)
ElseIf Not Data.IsAborted Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If
End Sub
'微软正版皮肤
Public Shared SkinMs As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Ms", AddressOf SkinMsLoad, AddressOf SkinMsInput, ThreadPriority.AboveNormal)
Private Shared Function SkinMsInput() As EqualableList(Of String)
@@ -400,10 +368,10 @@ Finish:
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Exit Sub
ElseIf GetString(ex).Contains("429") Then
ElseIf GetExceptionSummary(ex).Contains("429") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Log("[Minecraft] 获取正版皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", LogLevel.Hint)
ElseIf GetString(ex).Contains("未设置自定义皮肤") Then
ElseIf GetExceptionSummary(ex).Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载")
Else
@@ -428,7 +396,7 @@ Finish:
Select Case Type
Case 0
If FrmLoginLegacy IsNot Nothing AndAlso FrmLoginLegacy.IsReloaded Then
Return New EqualableList(Of String) From {0, If(FrmLoginLegacy.ComboName.Text, "")}
Return New EqualableList(Of String) From {0, If(FrmLoginLegacy.ComboName.Text.Trim, "")}
ElseIf Setup.Get("LoginLegacyName") = "" Then
Return New EqualableList(Of String) From {0, ""}
Else
@@ -470,7 +438,7 @@ UseDefault:
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Exit Sub
ElseIf GetString(ex).Contains("429") Then
ElseIf GetExceptionSummary(ex).Contains("429") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(ID)) & ".png"
Log("获取离线登录使用的正版皮肤失败(" & ID & "):获取皮肤太过频繁,请 5 分钟后再试!")
Else
@@ -480,7 +448,7 @@ UseDefault:
End Try
Case 4 '自定义
If Not File.Exists(PathAppdata & "CustomSkin.png") Then
Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL2 将使用默认的 Steve 皮肤!")
Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL 将使用默认的 Steve 皮肤!")
Setup.Set("LaunchSkinType", 1)
GoTo UseDefault
End If
@@ -522,10 +490,10 @@ UseDefault:
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Exit Sub
ElseIf GetString(ex).Contains("429") Then
ElseIf GetExceptionSummary(ex).Contains("429") Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 获取统一通行证皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", LogLevel.Hint)
ElseIf GetString(ex).Contains("未设置自定义皮肤") Then
ElseIf GetExceptionSummary(ex).Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载")
Else
@@ -570,10 +538,10 @@ Finish:
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Exit Sub
ElseIf GetString(ex).Contains("429") Then
ElseIf GetExceptionSummary(ex).Contains("429") Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 获取 Authlib-Injector 皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", LogLevel.Hint)
ElseIf GetString(ex).Contains("未设置自定义皮肤") Then
ElseIf GetExceptionSummary(ex).Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载")
Else
@@ -592,35 +560,34 @@ Finish:
'全部皮肤加载器
'需要放在其中元素的后面,否则会因为它提前被加载而莫名其妙变成 Nothing
Public Shared SkinLoaders As New List(Of LoaderTask(Of EqualableList(Of String), String)) From {SkinMojang, SkinMs, SkinLegacy, SkinNide, SkinAuth}
Public Shared SkinLoaders As New List(Of LoaderTask(Of EqualableList(Of String), String)) From {SkinMs, SkinLegacy, SkinNide, SkinAuth}
#End Region
'版本选择按钮
Private Sub BtnVersion_Click(sender As Object, e As EventArgs) Handles BtnVersion.Click
If McLaunchLoader.State = LoadState.Loading Then Exit Sub
FrmMain.PageChange(FormMain.PageType.VersionSelect)
End Sub
'启动按钮
Private Sub BtnLaunch_Click() Handles BtnLaunch.Click
LaunchButtonClick()
End Sub
Public Sub LaunchButtonClick(Optional ServerIp As String = "")
If BtnLaunch.IsEnabled AndAlso BtnLaunch.Visibility = Visibility.Visible AndAlso BtnLaunch.IsHitTestVisible Then
If BtnLaunch.Text = "启动游戏" Then
McLaunchLoader.Start(ServerIp, IsForceRestart:=True)
ElseIf BtnLaunch.Text = "下载游戏" Then
FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
End If
'愚人节处理
If IsAprilEnabled AndAlso Not IsAprilGiveup Then
ThemeUnlock(12, False, "隐藏主题 滑稽彩 已解锁!")
IsAprilGiveup = True
FrmLaunchLeft.AprilScaleTrans.ScaleX = 1
FrmLaunchLeft.AprilScaleTrans.ScaleY = 1
FrmLaunchLeft.AprilPosTrans.X = 0
FrmLaunchLeft.AprilPosTrans.Y = 0
FrmMain.BtnExtraApril.ShowRefresh()
End If
Public Sub LaunchButtonClick() Handles BtnLaunch.Click
If McLaunchLoader.State = LoadState.Loading OrElse Not BtnLaunch.IsEnabled OrElse
(FrmMain.PageRight IsNot Nothing AndAlso FrmMain.PageRight.PageState <> MyPageRight.PageStates.ContentStay AndAlso FrmMain.PageRight.PageState <> MyPageRight.PageStates.ContentEnter) Then Exit Sub
'愚人节处理
If IsAprilEnabled AndAlso Not IsAprilGiveup Then
ThemeUnlock(12, False, "隐藏主题 滑稽彩 已解锁!")
IsAprilGiveup = True
FrmLaunchLeft.AprilScaleTrans.ScaleX = 1
FrmLaunchLeft.AprilScaleTrans.ScaleY = 1
FrmLaunchLeft.AprilPosTrans.X = 0
FrmLaunchLeft.AprilPosTrans.Y = 0
FrmMain.BtnExtraApril.ShowRefresh()
End If
'实际的启动
If BtnLaunch.Text = "启动游戏" Then
McLaunchStart()
ElseIf BtnLaunch.Text = "下载游戏" Then
FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
End If
End Sub
Private BtnLaunchState As Integer = 0
@@ -700,67 +667,13 @@ ExitRefresh:
End Try
End If
End Sub
'更多按钮
'版本设置按钮
Private Sub BtnMore_Click(sender As Object, e As EventArgs) Handles BtnMore.Click
If McLaunchLoader.State = LoadState.Loading Then Exit Sub
McVersionCurrent.Load()
PageVersionLeft.Version = McVersionCurrent
FrmMain.PageChange(FormMain.PageType.VersionSetup, 0)
End Sub
'刷新 UI
Public Sub LaunchingPreload()
'修改登陆方式
Select Case Setup.Get("LoginType")
Case McLoginType.Legacy
If PageLinkHiper.HiperState = LoadState.Finished Then
LabLaunchingMethod.Text = "联机离线登录"
Else
LabLaunchingMethod.Text = "离线登录"
End If
Case McLoginType.Mojang
LabLaunchingMethod.Text = "Mojang 正版登录"
Case McLoginType.Ms
LabLaunchingMethod.Text = "微软正版登录"
Case McLoginType.Nide
LabLaunchingMethod.Text = "统一通行证"
Case McLoginType.Auth
LabLaunchingMethod.Text = "Authlib-Injector"
End Select
'初始化页面
LabLaunchingName.Text = McVersionCurrent.Name
LabLaunchingStage.Text = "初始化"
LabLaunchingTitle.Text = "正在启动游戏"
LabLaunchingProgress.Text = "0.00 %"
LabLaunchingProgress.Opacity = 1
LabLaunchingDownload.Visibility = Visibility.Visible
LabLaunchingProgressLeft.Opacity = 0.6
LabLaunchingDownload.Visibility = Visibility.Visible
LabLaunchingDownload.Text = "0 B/s"
LabLaunchingDownload.Opacity = 0
LabLaunchingDownload.Visibility = Visibility.Collapsed
LabLaunchingDownloadLeft.Opacity = 0
LabLaunchingDownloadLeft.Visibility = Visibility.Collapsed
ProgressLaunchingFinished.Width = New GridLength(0, GridUnitType.Star)
ProgressLaunchingUnfinished.Width = New GridLength(1, GridUnitType.Star)
PanLaunchingHint.Opacity = 0
PanLaunchingHint.Visibility = Visibility.Collapsed
PanLaunchingInfo.Width = Double.NaN '重置宽度改变动画
McLaunchProcess = Nothing
McLaunchWatcher = Nothing
'获取 “你知道吗” 提示
Dim Hint As String = PageOtherTest.GetRandomHint()
Try
Dim RawHints = Array.FindAll(
ReadFile(Path & "PCL\hints.txt").Replace(vbLf, "").Split(vbCr),
Function(Input As String) As Boolean
Return Not String.IsNullOrWhiteSpace(Input)
End Function)
If RawHints.Count > 0 Then Hint = RandomOne(RawHints)
Catch ex As Exception
Log(ex, "获取自定义 你知道吗 提示失败", LogLevel.Hint)
End Try
LabLaunchingHint.Text = Hint
End Sub
Private ShowProgress As Double = 0
''' <summary>
''' 每 0.2s 执行一次,刷新启动的数据 UI 显示。
''' </summary>
@@ -789,7 +702,7 @@ ExitRefresh:
If ActualProgress <= ShowProgress Then ShowProgress = ActualProgress '原来或处理后变得比实际进度高,直接回退
If IsLaunched Then ShowProgress = 1 '如果已经完成了,就不卖关子了
'文本
LabLaunchingTitle.Text = If(IsLaunched, "已启动游戏", "正在启动游戏")
LabLaunchingTitle.Text = If(IsLaunched, "已启动游戏", If(McLaunchLoader.Input.SaveBatch Is Nothing, "正在启动游戏", "正在导出启动脚本"))
LabLaunchingProgress.Text = StrFillNum(ShowProgress * 100, 2) & " %"
Dim HasLaunchDownloader As Boolean = False
Try
@@ -844,6 +757,7 @@ ExitRefresh:
Log(ex, "刷新启动信息失败", LogLevel.Feedback)
End Try
End Sub
Private ShowProgress As Double = 0
'尺寸改变动画
Private IsWidthAnimating As Boolean = False
Private ActualUsedWidth As Double
Loaded 100 of 157 files, more files were not shown because too many files have changed in this diff. Show more