PageDownloadInstall.xaml.vb 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. Public Class PageDownloadInstall
  2. Private Sub LoaderInit() Handles Me.Initialized
  3. PageLoaderInit(LoadMinecraft, PanLoad, PanBack, Nothing, DlClientListLoader, AddressOf LoadMinecraft_OnFinish)
  4. End Sub
  5. Private IsLoad As Boolean = False
  6. Private Sub Init() Handles Me.Loaded
  7. PanBack.ScrollToHome()
  8. DlOptiFineListLoader.Start()
  9. DlLiteLoaderListLoader.Start()
  10. DlFabricListLoader.Start()
  11. '重载预览
  12. TextSelectName.ValidateRules = New ObjectModel.Collection(Of Validate) From {New ValidateFolderName(PathMcFolder & "versions")}
  13. TextSelectName.Validate()
  14. SelectReload()
  15. '非重复加载部分
  16. If IsLoad Then Exit Sub
  17. IsLoad = True
  18. McDownloadForgeRecommendedRefresh()
  19. LoadOptiFine.State = DlOptiFineListLoader
  20. LoadLiteLoader.State = DlLiteLoaderListLoader
  21. LoadFabric.State = DlFabricListLoader
  22. LoadFabricApi.State = DlFabricApiLoader
  23. LoadOptiFabric.State = DlOptiFabricLoader
  24. End Sub
  25. #Region "页面切换"
  26. '页面切换动画
  27. Public IsInSelectPage As Boolean = False
  28. Private IsFirstLoaded As Boolean = False
  29. Private Sub EnterSelectPage()
  30. If IsInSelectPage Then Exit Sub
  31. IsInSelectPage = True
  32. AutoSelectedFabricApi = False
  33. AutoSelectedOptiFabric = False
  34. IsSelectNameEdited = False
  35. PanSelect.Visibility = Visibility.Visible
  36. PanSelect.IsHitTestVisible = True
  37. PanMinecraft.IsHitTestVisible = False
  38. PanBack.IsHitTestVisible = False
  39. PanBack.ScrollToHome()
  40. CardMinecraft.IsSwaped = True
  41. CardOptiFine.IsSwaped = True
  42. CardLiteLoader.IsSwaped = True
  43. CardForge.IsSwaped = True
  44. CardFabric.IsSwaped = True
  45. CardFabricApi.IsSwaped = True
  46. CardOptiFabric.IsSwaped = True
  47. If Not Setup.Get("HintInstallBack") Then
  48. Setup.Set("HintInstallBack", True)
  49. Hint("点击 Minecraft 项即可返回游戏主版本选择页面!")
  50. End If
  51. '如果在选择页面按了刷新键,选择页的东西可能会由于动画被隐藏,但不会由于加载结束而再次显示,因此这里需要手动恢复
  52. For Each Card In GetAllAnimControls(PanSelect)
  53. Card.Opacity = 1
  54. Card.RenderTransform = New TranslateTransform
  55. Next
  56. '启动 Forge 加载
  57. If SelectedMinecraftId.StartsWith("1.") Then
  58. Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion " & SelectedMinecraftId, AddressOf DlForgeVersionMain)
  59. LoadForge.State = ForgeLoader
  60. ForgeLoader.Start(SelectedMinecraftId)
  61. End If
  62. '启动 Fabric API、OptiFabric 加载
  63. DlFabricApiLoader.Start()
  64. DlOptiFabricLoader.Start()
  65. AniStart({
  66. AaOpacity(PanMinecraft, -PanMinecraft.Opacity, 100, 10),
  67. AaTranslateX(PanMinecraft, -50 - CType(PanMinecraft.RenderTransform, TranslateTransform).X, 110, 10),
  68. AaCode(Sub()
  69. PanBack.ScrollToHome()
  70. TextSelectName.Validate()
  71. OptiFine_Loaded()
  72. LiteLoader_Loaded()
  73. Forge_Loaded()
  74. Fabric_Loaded()
  75. FabricApi_Loaded()
  76. OptiFabric_Loaded()
  77. SelectReload()
  78. End Sub, After:=True),
  79. AaOpacity(PanSelect, 1 - PanSelect.Opacity, 250, 150),
  80. AaTranslateX(PanSelect, -CType(PanSelect.RenderTransform, TranslateTransform).X, 500, 150, Ease:=New AniEaseOutBack(AniEasePower.Weak)),
  81. AaCode(Sub()
  82. PanMinecraft.Visibility = Visibility.Collapsed
  83. PanBack.IsHitTestVisible = True
  84. '初始化 Binding
  85. If IsFirstLoaded Then Exit Sub
  86. IsFirstLoaded = True
  87. BtnOptiFineClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFine.MainTextBlock, .Mode = BindingMode.OneWay})
  88. BtnLiteLoaderClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardLiteLoader.MainTextBlock, .Mode = BindingMode.OneWay})
  89. BtnForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardForge.MainTextBlock, .Mode = BindingMode.OneWay})
  90. BtnFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabric.MainTextBlock, .Mode = BindingMode.OneWay})
  91. BtnFabricApiClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabricApi.MainTextBlock, .Mode = BindingMode.OneWay})
  92. BtnOptiFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFabric.MainTextBlock, .Mode = BindingMode.OneWay})
  93. End Sub,, True)
  94. }, "FrmDownloadInstall SelectPageSwitch", True)
  95. End Sub
  96. Public Sub ExitSelectPage()
  97. If Not IsInSelectPage Then Exit Sub
  98. IsInSelectPage = False
  99. SelectClear() '清除已选择项
  100. PanMinecraft.Visibility = Visibility.Visible
  101. PanSelect.IsHitTestVisible = False
  102. PanMinecraft.IsHitTestVisible = True
  103. PanBack.IsHitTestVisible = False
  104. PanBack.ScrollToHome()
  105. AniStart({
  106. AaOpacity(PanSelect, -PanSelect.Opacity, 90, 10),
  107. AaTranslateX(PanSelect, 50 - CType(PanSelect.RenderTransform, TranslateTransform).X, 100, 10),
  108. AaCode(Sub() PanBack.ScrollToHome(), After:=True),
  109. AaOpacity(PanMinecraft, 1 - PanMinecraft.Opacity, 150, 100),
  110. AaTranslateX(PanMinecraft, -CType(PanMinecraft.RenderTransform, TranslateTransform).X, 400, 100, Ease:=New AniEaseOutBack(AniEasePower.Weak)),
  111. AaCode(Sub()
  112. PanSelect.Visibility = Visibility.Collapsed
  113. PanBack.IsHitTestVisible = True
  114. End Sub,, True)
  115. }, "FrmDownloadInstall SelectPageSwitch")
  116. End Sub
  117. '页面切换触发
  118. Public Sub MinecraftSelected(sender As MyListItem, e As MouseButtonEventArgs)
  119. SelectedMinecraftId = sender.Title
  120. SelectedMinecraftJsonUrl = sender.Tag("url").ToString
  121. SelectedMinecraftIcon = sender.Logo
  122. EnterSelectPage()
  123. End Sub
  124. Private Sub CardMinecraft_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardMinecraft.PreviewSwap
  125. ExitSelectPage()
  126. e.Handled = True
  127. End Sub
  128. #End Region
  129. #Region "选择"
  130. 'Minecraft
  131. Private SelectedMinecraftId As String
  132. Private SelectedMinecraftJsonUrl As String
  133. Private SelectedMinecraftIcon As String
  134. 'OptiFine
  135. Private SelectedOptiFine As DlOptiFineListEntry = Nothing
  136. Private Sub SetOptiFineInfoShow(IsShow As String)
  137. If PanOptiFineInfo.Tag = IsShow Then Exit Sub
  138. PanOptiFineInfo.Tag = IsShow
  139. If IsShow = "True" Then
  140. '显示信息栏
  141. AniStart({
  142. AaTranslateY(PanOptiFineInfo, -CType(PanOptiFineInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  143. AaOpacity(PanOptiFineInfo, 1 - PanOptiFineInfo.Opacity, 100, 90)
  144. }, "SetOptiFineInfoShow")
  145. Else
  146. '隐藏信息栏
  147. AniStart({
  148. AaTranslateY(PanOptiFineInfo, 6 - CType(PanOptiFineInfo.RenderTransform, TranslateTransform).Y, 200),
  149. AaOpacity(PanOptiFineInfo, -PanOptiFineInfo.Opacity, 100)
  150. }, "SetOptiFineInfoShow")
  151. End If
  152. End Sub
  153. 'LiteLoader
  154. Private SelectedLiteLoader As DlLiteLoaderListEntry = Nothing
  155. Private Sub SetLiteLoaderInfoShow(IsShow As String)
  156. If PanLiteLoaderInfo.Tag = IsShow Then Exit Sub
  157. PanLiteLoaderInfo.Tag = IsShow
  158. If IsShow = "True" Then
  159. '显示信息栏
  160. AniStart({
  161. AaTranslateY(PanLiteLoaderInfo, -CType(PanLiteLoaderInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  162. AaOpacity(PanLiteLoaderInfo, 1 - PanLiteLoaderInfo.Opacity, 100, 90)
  163. }, "SetLiteLoaderInfoShow")
  164. Else
  165. '隐藏信息栏
  166. AniStart({
  167. AaTranslateY(PanLiteLoaderInfo, 6 - CType(PanLiteLoaderInfo.RenderTransform, TranslateTransform).Y, 200),
  168. AaOpacity(PanLiteLoaderInfo, -PanLiteLoaderInfo.Opacity, 100)
  169. }, "SetLiteLoaderInfoShow")
  170. End If
  171. End Sub
  172. 'Forge
  173. Private SelectedForge As DlForgeVersionEntry = Nothing
  174. Private Sub SetForgeInfoShow(IsShow As String)
  175. If PanForgeInfo.Tag = IsShow Then Exit Sub
  176. PanForgeInfo.Tag = IsShow
  177. If IsShow = "True" Then
  178. '显示信息栏
  179. AniStart({
  180. AaTranslateY(PanForgeInfo, -CType(PanForgeInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  181. AaOpacity(PanForgeInfo, 1 - PanForgeInfo.Opacity, 100, 90)
  182. }, "SetForgeInfoShow")
  183. Else
  184. '隐藏信息栏
  185. AniStart({
  186. AaTranslateY(PanForgeInfo, 6 - CType(PanForgeInfo.RenderTransform, TranslateTransform).Y, 200),
  187. AaOpacity(PanForgeInfo, -PanForgeInfo.Opacity, 100)
  188. }, "SetForgeInfoShow")
  189. End If
  190. End Sub
  191. 'Fabric
  192. Private SelectedFabric As String = Nothing
  193. Private Sub SetFabricInfoShow(IsShow As String)
  194. If PanFabricInfo.Tag = IsShow Then Exit Sub
  195. PanFabricInfo.Tag = IsShow
  196. If IsShow = "True" Then
  197. '显示信息栏
  198. AniStart({
  199. AaTranslateY(PanFabricInfo, -CType(PanFabricInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  200. AaOpacity(PanFabricInfo, 1 - PanFabricInfo.Opacity, 100, 90)
  201. }, "SetFabricInfoShow")
  202. Else
  203. '隐藏信息栏
  204. AniStart({
  205. AaTranslateY(PanFabricInfo, 6 - CType(PanFabricInfo.RenderTransform, TranslateTransform).Y, 200),
  206. AaOpacity(PanFabricInfo, -PanFabricInfo.Opacity, 100)
  207. }, "SetFabricInfoShow")
  208. End If
  209. End Sub
  210. 'FabricApi
  211. Private SelectedFabricApi As CompFile = Nothing
  212. Private Sub SetFabricApiInfoShow(IsShow As String)
  213. If PanFabricApiInfo.Tag = IsShow Then Exit Sub
  214. PanFabricApiInfo.Tag = IsShow
  215. If IsShow = "True" Then
  216. '显示信息栏
  217. AniStart({
  218. AaTranslateY(PanFabricApiInfo, -CType(PanFabricApiInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  219. AaOpacity(PanFabricApiInfo, 1 - PanFabricApiInfo.Opacity, 100, 90)
  220. }, "SetFabricApiInfoShow")
  221. Else
  222. '隐藏信息栏
  223. AniStart({
  224. AaTranslateY(PanFabricApiInfo, 6 - CType(PanFabricApiInfo.RenderTransform, TranslateTransform).Y, 200),
  225. AaOpacity(PanFabricApiInfo, -PanFabricApiInfo.Opacity, 100)
  226. }, "SetFabricApiInfoShow")
  227. End If
  228. End Sub
  229. 'OptiFabric
  230. Private SelectedOptiFabric As CompFile = Nothing
  231. Private Sub SetOptiFabricInfoShow(IsShow As String)
  232. If PanOptiFabricInfo.Tag = IsShow Then Exit Sub
  233. PanOptiFabricInfo.Tag = IsShow
  234. If IsShow = "True" Then
  235. '显示信息栏
  236. AniStart({
  237. AaTranslateY(PanOptiFabricInfo, -CType(PanOptiFabricInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  238. AaOpacity(PanOptiFabricInfo, 1 - PanOptiFabricInfo.Opacity, 100, 90)
  239. }, "SetOptiFabricInfoShow")
  240. Else
  241. '隐藏信息栏
  242. AniStart({
  243. AaTranslateY(PanOptiFabricInfo, 6 - CType(PanOptiFabricInfo.RenderTransform, TranslateTransform).Y, 200),
  244. AaOpacity(PanOptiFabricInfo, -PanOptiFabricInfo.Opacity, 100)
  245. }, "SetOptiFabricInfoShow")
  246. End If
  247. End Sub
  248. Private IsReloading As Boolean = False '#3742 中,LoadOptiFineGetError 会初始化 LoadOptiFine,触发事件 LoadOptiFine.StateChanged,导致再次调用 SelectReload
  249. ''' <summary>
  250. ''' 重载已选择的项目的显示。
  251. ''' </summary>
  252. 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
  253. If SelectedMinecraftId Is Nothing OrElse IsReloading Then Exit Sub
  254. IsReloading = True
  255. '主预览
  256. SelectNameUpdate()
  257. ItemSelect.Title = TextSelectName.Text
  258. ItemSelect.Info = GetSelectInfo()
  259. ItemSelect.Logo = GetSelectLogo()
  260. 'Minecraft
  261. LabMinecraft.Text = SelectedMinecraftId
  262. ImgMinecraft.Source = New MyBitmap(SelectedMinecraftIcon)
  263. 'OptiFine
  264. Dim OptiFineError As String = LoadOptiFineGetError()
  265. CardOptiFine.MainSwap.Visibility = If(OptiFineError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  266. If OptiFineError IsNot Nothing Then CardOptiFine.IsSwaped = True '例如在同时展开卡片时选择了不兼容项则强制折叠
  267. SetOptiFineInfoShow(CardOptiFine.IsSwaped)
  268. If SelectedOptiFine Is Nothing Then
  269. BtnOptiFineClear.Visibility = Visibility.Collapsed
  270. ImgOptiFine.Visibility = Visibility.Collapsed
  271. LabOptiFine.Text = If(OptiFineError, "点击选择")
  272. LabOptiFine.Foreground = ColorGray4
  273. Else
  274. BtnOptiFineClear.Visibility = Visibility.Visible
  275. ImgOptiFine.Visibility = Visibility.Visible
  276. LabOptiFine.Text = SelectedOptiFine.NameDisplay.Replace(SelectedMinecraftId & " ", "")
  277. LabOptiFine.Foreground = ColorGray1
  278. End If
  279. 'LiteLoader
  280. If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) > 12 Then
  281. CardLiteLoader.Visibility = Visibility.Collapsed
  282. Else
  283. CardLiteLoader.Visibility = Visibility.Visible
  284. Dim LiteLoaderError As String = LoadLiteLoaderGetError()
  285. CardLiteLoader.MainSwap.Visibility = If(LiteLoaderError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  286. If LiteLoaderError IsNot Nothing Then CardLiteLoader.IsSwaped = True '例如在同时展开卡片时选择了不兼容项则强制折叠
  287. SetLiteLoaderInfoShow(CardLiteLoader.IsSwaped)
  288. If SelectedLiteLoader Is Nothing Then
  289. BtnLiteLoaderClear.Visibility = Visibility.Collapsed
  290. ImgLiteLoader.Visibility = Visibility.Collapsed
  291. LabLiteLoader.Text = If(LiteLoaderError, "点击选择")
  292. LabLiteLoader.Foreground = ColorGray4
  293. Else
  294. BtnLiteLoaderClear.Visibility = Visibility.Visible
  295. ImgLiteLoader.Visibility = Visibility.Visible
  296. LabLiteLoader.Text = SelectedLiteLoader.Inherit
  297. LabLiteLoader.Foreground = ColorGray1
  298. End If
  299. End If
  300. 'Forge
  301. Dim ForgeError As String = LoadForgeGetError()
  302. CardForge.MainSwap.Visibility = If(ForgeError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  303. If ForgeError IsNot Nothing Then CardForge.IsSwaped = True
  304. SetForgeInfoShow(CardForge.IsSwaped)
  305. If SelectedForge Is Nothing Then
  306. BtnForgeClear.Visibility = Visibility.Collapsed
  307. ImgForge.Visibility = Visibility.Collapsed
  308. LabForge.Text = If(ForgeError, "点击选择")
  309. LabForge.Foreground = ColorGray4
  310. Else
  311. BtnForgeClear.Visibility = Visibility.Visible
  312. ImgForge.Visibility = Visibility.Visible
  313. LabForge.Text = SelectedForge.Version
  314. LabForge.Foreground = ColorGray1
  315. End If
  316. 'Fabric
  317. If SelectedMinecraftId.Contains("1.") AndAlso Val(SelectedMinecraftId.Split(".")(1)) <= 13 Then
  318. CardFabric.Visibility = Visibility.Collapsed
  319. Else
  320. CardFabric.Visibility = Visibility.Visible
  321. Dim FabricError As String = LoadFabricGetError()
  322. CardFabric.MainSwap.Visibility = If(FabricError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  323. If FabricError IsNot Nothing Then CardFabric.IsSwaped = True
  324. SetFabricInfoShow(CardFabric.IsSwaped)
  325. If SelectedFabric Is Nothing Then
  326. BtnFabricClear.Visibility = Visibility.Collapsed
  327. ImgFabric.Visibility = Visibility.Collapsed
  328. LabFabric.Text = If(FabricError, "点击选择")
  329. LabFabric.Foreground = ColorGray4
  330. Else
  331. BtnFabricClear.Visibility = Visibility.Visible
  332. ImgFabric.Visibility = Visibility.Visible
  333. LabFabric.Text = SelectedFabric.Replace("+build", "")
  334. LabFabric.Foreground = ColorGray1
  335. End If
  336. End If
  337. 'FabricApi
  338. If SelectedFabric Is Nothing Then
  339. CardFabricApi.Visibility = Visibility.Collapsed
  340. Else
  341. CardFabricApi.Visibility = Visibility.Visible
  342. Dim FabricApiError As String = LoadFabricApiGetError()
  343. CardFabricApi.MainSwap.Visibility = If(FabricApiError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  344. If FabricApiError IsNot Nothing OrElse SelectedFabric Is Nothing Then CardFabricApi.IsSwaped = True
  345. SetFabricApiInfoShow(CardFabricApi.IsSwaped)
  346. If SelectedFabricApi Is Nothing Then
  347. BtnFabricApiClear.Visibility = Visibility.Collapsed
  348. ImgFabricApi.Visibility = Visibility.Collapsed
  349. LabFabricApi.Text = If(FabricApiError, "点击选择")
  350. LabFabricApi.Foreground = ColorGray4
  351. Else
  352. BtnFabricApiClear.Visibility = Visibility.Visible
  353. ImgFabricApi.Visibility = Visibility.Visible
  354. LabFabricApi.Text = SelectedFabricApi.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").Split("+").First.Trim
  355. LabFabricApi.Foreground = ColorGray1
  356. End If
  357. End If
  358. 'OptiFabric
  359. If SelectedFabric Is Nothing OrElse SelectedOptiFine Is Nothing Then
  360. CardOptiFabric.Visibility = Visibility.Collapsed
  361. Else
  362. CardOptiFabric.Visibility = Visibility.Visible
  363. Dim OptiFabricError As String = LoadOptiFabricGetError()
  364. CardOptiFabric.MainSwap.Visibility = If(OptiFabricError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  365. If OptiFabricError IsNot Nothing OrElse SelectedFabric Is Nothing Then CardOptiFabric.IsSwaped = True
  366. SetOptiFabricInfoShow(CardOptiFabric.IsSwaped)
  367. If SelectedOptiFabric Is Nothing Then
  368. BtnOptiFabricClear.Visibility = Visibility.Collapsed
  369. ImgOptiFabric.Visibility = Visibility.Collapsed
  370. LabOptiFabric.Text = If(OptiFabricError, "点击选择")
  371. LabOptiFabric.Foreground = ColorGray4
  372. Else
  373. BtnOptiFabricClear.Visibility = Visibility.Visible
  374. ImgOptiFabric.Visibility = Visibility.Visible
  375. LabOptiFabric.Text = SelectedOptiFabric.DisplayName.ToLower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v")
  376. LabOptiFabric.Foreground = ColorGray1
  377. End If
  378. End If
  379. '主警告
  380. If SelectedFabric IsNot Nothing AndAlso SelectedFabricApi Is Nothing Then
  381. HintFabricAPI.Visibility = Visibility.Visible
  382. Else
  383. HintFabricAPI.Visibility = Visibility.Collapsed
  384. End If
  385. If SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso SelectedOptiFabric Is Nothing Then
  386. HintOptiFabric.Visibility = Visibility.Visible
  387. Else
  388. HintOptiFabric.Visibility = Visibility.Collapsed
  389. End If
  390. If SelectedMinecraftId.Contains("1.") AndAlso Val(SelectedMinecraftId.Split(".")(1)) >= 16 AndAlso SelectedOptiFine IsNot Nothing AndAlso
  391. (SelectedForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) Then
  392. HintModOptiFine.Visibility = Visibility.Visible
  393. Else
  394. HintModOptiFine.Visibility = Visibility.Collapsed
  395. End If
  396. '结束
  397. IsReloading = False
  398. End Sub
  399. ''' <summary>
  400. ''' 清空已选择的项目。
  401. ''' </summary>
  402. Private Sub SelectClear()
  403. SelectedMinecraftId = Nothing
  404. SelectedMinecraftJsonUrl = Nothing
  405. SelectedMinecraftIcon = Nothing
  406. SelectedOptiFine = Nothing
  407. SelectedLiteLoader = Nothing
  408. SelectedForge = Nothing
  409. SelectedFabric = Nothing
  410. SelectedFabricApi = Nothing
  411. SelectedOptiFabric = Nothing
  412. End Sub
  413. '显示信息获取
  414. ''' <summary>
  415. ''' 获取默认版本名。
  416. ''' </summary>
  417. Private Function GetSelectName() As String
  418. Dim Name As String = SelectedMinecraftId
  419. If SelectedFabric IsNot Nothing Then
  420. Name += "-Fabric " & SelectedFabric.Replace("+build", "")
  421. End If
  422. If SelectedForge IsNot Nothing Then
  423. Name += "-Forge_" & SelectedForge.Version
  424. End If
  425. If SelectedLiteLoader IsNot Nothing Then
  426. Name += "-LiteLoader"
  427. End If
  428. If SelectedOptiFine IsNot Nothing Then
  429. Name += "-OptiFine_" & SelectedOptiFine.NameDisplay.Replace(SelectedMinecraftId & " ", "").Replace(" ", "_")
  430. End If
  431. Return Name
  432. End Function
  433. ''' <summary>
  434. ''' 获取版本描述信息。
  435. ''' </summary>
  436. Private Function GetSelectInfo() As String
  437. Dim Info As String = ""
  438. If SelectedFabric IsNot Nothing Then
  439. Info += ", Fabric " & SelectedFabric.Replace("+build", "")
  440. End If
  441. If SelectedForge IsNot Nothing Then
  442. Info += ", Forge " & SelectedForge.Version
  443. End If
  444. If SelectedLiteLoader IsNot Nothing Then
  445. Info += ", LiteLoader"
  446. End If
  447. If SelectedOptiFine IsNot Nothing Then
  448. Info += ", OptiFine " & SelectedOptiFine.NameDisplay.Replace(SelectedMinecraftId & " ", "")
  449. End If
  450. If Info = "" Then Info = ", 无附加安装"
  451. Return Info.TrimStart(", ".ToCharArray())
  452. End Function
  453. ''' <summary>
  454. ''' 获取版本图标。
  455. ''' </summary>
  456. Private Function GetSelectLogo() As String
  457. If SelectedFabric IsNot Nothing Then
  458. Return "pack://application:,,,/images/Blocks/Fabric.png"
  459. ElseIf SelectedForge IsNot Nothing Then
  460. Return "pack://application:,,,/images/Blocks/Anvil.png"
  461. ElseIf SelectedLiteLoader IsNot Nothing Then
  462. Return "pack://application:,,,/images/Blocks/Egg.png"
  463. ElseIf SelectedOptiFine IsNot Nothing Then
  464. Return "pack://application:,,,/images/Blocks/GrassPath.png"
  465. Else
  466. Return SelectedMinecraftIcon
  467. End If
  468. End Function
  469. '版本名处理
  470. Private IsSelectNameEdited As Boolean = False
  471. Private IsSelectNameChanging As Boolean = False
  472. Private Sub SelectNameUpdate()
  473. If IsSelectNameEdited OrElse IsSelectNameChanging Then Exit Sub
  474. IsSelectNameChanging = True
  475. TextSelectName.Text = GetSelectName()
  476. IsSelectNameChanging = False
  477. End Sub
  478. Private Sub TextSelectName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TextSelectName.TextChanged
  479. If IsSelectNameChanging Then Exit Sub
  480. IsSelectNameEdited = True
  481. SelectReload()
  482. End Sub
  483. Private Sub TextSelectName_ValidateChanged(sender As Object, e As EventArgs) Handles TextSelectName.ValidateChanged
  484. BtnSelectStart.IsEnabled = TextSelectName.ValidateResult = ""
  485. End Sub
  486. #End Region
  487. #Region "加载器"
  488. '结果数据化
  489. Private Sub LoadMinecraft_OnFinish()
  490. ExitSelectPage() '返回
  491. Try
  492. Dim Dict As New Dictionary(Of String, List(Of JObject)) From {
  493. {"正式版", New List(Of JObject)}, {"预览版", New List(Of JObject)}, {"远古版", New List(Of JObject)}, {"愚人节版", New List(Of JObject)}
  494. }
  495. Dim Versions As JArray = DlClientListLoader.Output.Value("versions")
  496. For Each Version As JObject In Versions
  497. '确定分类
  498. Dim Type As String = Version("type")
  499. Select Case Type
  500. Case "release"
  501. Type = "正式版"
  502. Case "snapshot"
  503. Type = "预览版"
  504. 'Mojang 误分类
  505. If Version("id").ToString.StartsWith("1.") AndAlso
  506. Not Version("id").ToString.ToLower.Contains("combat") AndAlso
  507. Not Version("id").ToString.ToLower.Contains("rc") AndAlso
  508. Not Version("id").ToString.ToLower.Contains("experimental") AndAlso
  509. Not Version("id").ToString.ToLower.Contains("pre") Then
  510. Type = "正式版"
  511. Version("type") = "release"
  512. End If
  513. '愚人节版本
  514. Select Case Version("id").ToString.ToLower
  515. Case "20w14infinite", "20w14∞"
  516. Type = "愚人节版"
  517. Version("id") = "20w14∞"
  518. Version("type") = "special"
  519. Version.Add("lore", GetMcFoolName(Version("id")))
  520. Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime", "23w13a_or_b", "24w14potato"
  521. Type = "愚人节版"
  522. Version("type") = "special"
  523. Version.Add("lore", GetMcFoolName(Version("id")))
  524. End Select
  525. '所有4月1日发布的版本视为愚人节版,但不改动版本描述
  526. Select Case Version("releaseDate").Value(Of Date).ToString("MM'/'dd")
  527. Case "04/01"
  528. If Not Version("type") == "special" Then
  529. Type = "愚人节版"
  530. Version("type") = "special"
  531. End If
  532. End Select
  533. Case "special"
  534. '已被处理的愚人节版
  535. Type = "愚人节版"
  536. Case Else
  537. Type = "远古版"
  538. End Select
  539. '加入辞典
  540. Dict(Type).Add(Version)
  541. Next
  542. '排序
  543. For i = 0 To Dict.Keys.Count - 1
  544. Dict(Dict.Keys(i)) = Sort(Dict.Values(i), Function(Left As JObject, Right As JObject) As Boolean
  545. Return Left("releaseTime").Value(Of Date) > Right("releaseTime").Value(Of Date)
  546. End Function)
  547. Next
  548. '清空当前
  549. PanMinecraft.Children.Clear()
  550. '添加最新版本
  551. Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15), .SwapType = 2}
  552. Dim TopestVersions As New List(Of JObject)
  553. Dim Release As JObject = Dict("正式版")(0).DeepClone()
  554. Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
  555. TopestVersions.Add(Release)
  556. If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
  557. Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
  558. Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
  559. TopestVersions.Add(Snapshot)
  560. End If
  561. Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}
  562. MyCard.StackInstall(PanInfo, 7)
  563. CardInfo.Children.Add(PanInfo)
  564. PanMinecraft.Children.Insert(0, CardInfo)
  565. '添加其他版本
  566. For Each Pair As KeyValuePair(Of String, List(Of JObject)) In Dict
  567. If Not Pair.Value.Any() Then Continue For
  568. '增加卡片
  569. Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 7}
  570. 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}
  571. NewCard.Children.Add(NewStack)
  572. NewCard.SwapControl = NewStack
  573. NewCard.IsSwaped = True
  574. PanMinecraft.Children.Add(NewCard)
  575. Next
  576. '自动选择版本
  577. If McVersionWaitingForSelect Is Nothing Then Exit Try
  578. Log("[Download] 自动选择 MC 版本:" & McVersionWaitingForSelect)
  579. For Each Version As JObject In Versions
  580. If Version("id").ToString <> McVersionWaitingForSelect Then Continue For
  581. Dim Item = McDownloadListItem(Version, Sub()
  582. End Sub, False)
  583. MinecraftSelected(Item, Nothing)
  584. Next
  585. Catch ex As Exception
  586. Log(ex, "可视化安装版本列表出错", LogLevel.Feedback)
  587. End Try
  588. End Sub
  589. ''' <summary>
  590. ''' 当 MC 版本列表加载完时,立即自动选择的版本。用于外部调用。
  591. ''' </summary>
  592. Public Shared McVersionWaitingForSelect As String = Nothing
  593. #End Region
  594. #Region "OptiFine 列表"
  595. ''' <summary>
  596. ''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
  597. ''' </summary>
  598. Private Function LoadOptiFineGetError() As String
  599. If LoadOptiFine Is Nothing OrElse LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  600. If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFine.State, Object).Error.Message
  601. '检查 Forge 1.13 - 1.14.3:全部不兼容
  602. If SelectedForge IsNot Nothing AndAlso
  603. VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then
  604. Return "与 Forge 不兼容"
  605. End If
  606. '检查最低 Forge 版本
  607. Dim MinimalForgeVersion As String = "9999.9999"
  608. Dim NotSuitForForge As Boolean = False
  609. For Each OptiFineVersion As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
  610. If Not OptiFineVersion.NameDisplay.StartsWith(SelectedMinecraftId & " ") Then Continue For '不是同一个大版本
  611. If SelectedForge Is Nothing Then Return Nothing '该版本可用
  612. If IsOptiFineSuitForForge(OptiFineVersion, SelectedForge) Then
  613. Return Nothing '该版本可用
  614. Else
  615. NotSuitForForge = True
  616. If OptiFineVersion.RequiredForgeVersion IsNot Nothing Then
  617. '设置用于显示的最低允许的 Forge 版本
  618. MinimalForgeVersion = If(VersionSortBoolean(MinimalForgeVersion, OptiFineVersion.RequiredForgeVersion),
  619. OptiFineVersion.RequiredForgeVersion, MinimalForgeVersion)
  620. End If
  621. End If
  622. Next
  623. If MinimalForgeVersion = "9999.9999" Then
  624. Return If(NotSuitForForge, "与 Forge 不兼容", "没有可用版本")
  625. Else
  626. Return "需要 Forge " & If(MinimalForgeVersion.Contains("."), "", "#") & MinimalForgeVersion & " 或更高版本"
  627. End If
  628. End Function
  629. '检查某个 OptiFine 是否与某个 Forge 兼容(最低 Forge 版本是否达到需求)
  630. Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
  631. If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
  632. If OptiFine.RequiredForgeVersion Is Nothing Then Return False '不兼容 Forge
  633. Return (OptiFine.RequiredForgeVersion.Contains(".") AndAlso 'XX.X.XXX
  634. VersionSortInteger(Forge.Version, OptiFine.RequiredForgeVersion) >= 0) OrElse
  635. (Not OptiFine.RequiredForgeVersion.Contains(".") AndAlso '#XXXX
  636. Forge.Version.After(".") >= OptiFine.RequiredForgeVersion)
  637. End Function
  638. '限制展开
  639. Private Sub CardOptiFine_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardOptiFine.PreviewSwap
  640. If LoadOptiFineGetError() IsNot Nothing Then e.Handled = True
  641. End Sub
  642. ''' <summary>
  643. ''' 尝试重新可视化 OptiFine 版本列表。
  644. ''' </summary>
  645. Private Sub OptiFine_Loaded() Handles LoadOptiFine.StateChanged
  646. Try
  647. If DlOptiFineListLoader.State <> LoadState.Finished Then Exit Sub
  648. '获取版本列表
  649. Dim Versions As New List(Of DlOptiFineListEntry)
  650. For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
  651. If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(Version, SelectedForge) Then Continue For
  652. If Version.NameDisplay.StartsWith(SelectedMinecraftId & " ") Then Versions.Add(Version)
  653. Next
  654. If Not Versions.Any() Then Exit Sub
  655. '排序
  656. Versions = Sort(Versions, Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
  657. If Not Left.IsPreview AndAlso Right.IsPreview Then Return True
  658. If Left.IsPreview AndAlso Not Right.IsPreview Then Return False
  659. Return VersionSortBoolean(Left.NameDisplay, Right.NameDisplay)
  660. End Function)
  661. '可视化
  662. PanOptiFine.Children.Clear()
  663. For Each Version In Versions
  664. PanOptiFine.Children.Add(OptiFineDownloadListItem(Version, AddressOf OptiFine_Selected, False))
  665. Next
  666. Catch ex As Exception
  667. Log(ex, "可视化 OptiFine 安装版本列表出错", LogLevel.Feedback)
  668. End Try
  669. End Sub
  670. '选择与清除
  671. Private Sub OptiFine_Selected(sender As MyListItem, e As EventArgs)
  672. SelectedOptiFine = sender.Tag
  673. If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedForge = Nothing
  674. OptiFabric_Loaded()
  675. Forge_Loaded()
  676. CardOptiFine.IsSwaped = True
  677. SelectReload()
  678. End Sub
  679. Private Sub OptiFine_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFineClear.MouseLeftButtonUp
  680. SelectedOptiFine = Nothing
  681. SelectedOptiFabric = Nothing
  682. CardOptiFine.IsSwaped = True
  683. e.Handled = True
  684. Forge_Loaded()
  685. SelectReload()
  686. End Sub
  687. #End Region
  688. #Region "LiteLoader 列表"
  689. ''' <summary>
  690. ''' 获取 LiteLoader 的加载异常信息。若正常则返回 Nothing。
  691. ''' </summary>
  692. Private Function LoadLiteLoaderGetError() As String
  693. If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) > 12 Then Return "没有可用版本"
  694. If LoadLiteLoader Is Nothing OrElse LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  695. If LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadLiteLoader.State, Object).Error.Message
  696. For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
  697. If Version.Inherit = SelectedMinecraftId Then Return Nothing
  698. Next
  699. Return "没有可用版本"
  700. End Function
  701. '限制展开
  702. Private Sub CardLiteLoader_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardLiteLoader.PreviewSwap
  703. If LoadLiteLoaderGetError() IsNot Nothing Then e.Handled = True
  704. End Sub
  705. ''' <summary>
  706. ''' 尝试重新可视化 LiteLoader 版本列表。
  707. ''' </summary>
  708. Private Sub LiteLoader_Loaded() Handles LoadLiteLoader.StateChanged
  709. Try
  710. If DlLiteLoaderListLoader.State <> LoadState.Finished Then Exit Sub
  711. '获取版本列表
  712. Dim Versions As New List(Of DlLiteLoaderListEntry)
  713. For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
  714. If Version.Inherit = SelectedMinecraftId Then Versions.Add(Version)
  715. Next
  716. If Not Versions.Any() Then Exit Sub
  717. '可视化
  718. PanLiteLoader.Children.Clear()
  719. For Each Version In Versions
  720. PanLiteLoader.Children.Add(LiteLoaderDownloadListItem(Version, AddressOf LiteLoader_Selected, False))
  721. Next
  722. Catch ex As Exception
  723. Log(ex, "可视化 LiteLoader 安装版本列表出错", LogLevel.Feedback)
  724. End Try
  725. End Sub
  726. '选择与清除
  727. Private Sub LiteLoader_Selected(sender As MyListItem, e As EventArgs)
  728. SelectedLiteLoader = sender.Tag
  729. CardLiteLoader.IsSwaped = True
  730. SelectReload()
  731. End Sub
  732. Private Sub LiteLoader_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnLiteLoaderClear.MouseLeftButtonUp
  733. SelectedLiteLoader = Nothing
  734. CardLiteLoader.IsSwaped = True
  735. e.Handled = True
  736. SelectReload()
  737. End Sub
  738. #End Region
  739. #Region "Forge 列表"
  740. ''' <summary>
  741. ''' 获取 Forge 的加载异常信息。若正常则返回 Nothing。
  742. ''' </summary>
  743. Private Function LoadForgeGetError() As String
  744. If Not SelectedMinecraftId.StartsWith("1.") Then Return "没有可用版本"
  745. If Not LoadForge.State.IsLoader Then Return "正在获取版本列表……"
  746. Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
  747. If SelectedMinecraftId <> Loader.Input Then Return "正在获取版本列表……"
  748. If Loader.State = LoadState.Loading Then Return "正在获取版本列表……"
  749. If Loader.State = LoadState.Failed Then
  750. Dim ErrorMessage As String = Loader.Error.Message
  751. If ErrorMessage.Contains("没有可用版本") Then
  752. Return "没有可用版本"
  753. Else
  754. Return "获取版本列表失败:" & ErrorMessage
  755. End If
  756. End If
  757. If Loader.State <> LoadState.Finished Then Return "获取版本列表失败:未知错误,状态为 " & GetStringFromEnum(Loader.State)
  758. Dim NotSuitForOptiFine As Boolean = False
  759. For Each Version In Loader.Output
  760. If Version.Category = "universal" OrElse Version.Category = "client" Then Continue For '跳过无法自动安装的版本
  761. If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
  762. If SelectedOptiFine IsNot Nothing AndAlso
  763. VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then
  764. Return "与 OptiFine 不兼容" '1.13 ~ 1.14.3 OptiFine 检查
  765. End If
  766. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, Version) Then
  767. NotSuitForOptiFine = True '与 OptiFine 不兼容
  768. Continue For
  769. End If
  770. Return Nothing
  771. Next
  772. Return If(NotSuitForOptiFine, "与 OptiFine 不兼容", "该版本不支持自动安装")
  773. End Function
  774. '限制展开
  775. Private Sub CardForge_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardForge.PreviewSwap
  776. If LoadForgeGetError() IsNot Nothing Then e.Handled = True
  777. End Sub
  778. ''' <summary>
  779. ''' 尝试重新可视化 Forge 版本列表。
  780. ''' </summary>
  781. Private Sub Forge_Loaded() Handles LoadForge.StateChanged
  782. Try
  783. If Not LoadForge.State.IsLoader Then Exit Sub
  784. Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
  785. If SelectedMinecraftId <> Loader.Input Then Exit Sub
  786. If Loader.State <> LoadState.Finished Then Exit Sub
  787. '获取要显示的版本
  788. Dim Versions As New List(Of DlForgeVersionEntry)
  789. Versions.AddRange(Loader.Output) '复制数组,以免 Output 在实例化后变空
  790. If Not Loader.Output.Any() Then Exit Sub
  791. PanForge.Children.Clear()
  792. Versions = Sort(Versions, Function(a, b) New Version(a.Version) > New Version(b.Version)).
  793. Where(Function(v)
  794. If v.Category = "universal" OrElse v.Category = "client" Then Return False '跳过无法自动安装的版本
  795. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, v) Then Return False
  796. Return True
  797. End Function).ToList
  798. ForgeDownloadListItemPreload(PanForge, Versions, AddressOf Forge_Selected, False)
  799. For Each Version In Versions
  800. PanForge.Children.Add(ForgeDownloadListItem(Version, AddressOf Forge_Selected, False))
  801. Next
  802. Catch ex As Exception
  803. Log(ex, "可视化 Forge 安装版本列表出错", LogLevel.Feedback)
  804. End Try
  805. End Sub
  806. '选择与清除
  807. Private Sub Forge_Selected(sender As MyListItem, e As EventArgs)
  808. SelectedForge = sender.Tag
  809. CardForge.IsSwaped = True
  810. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedOptiFine = Nothing
  811. OptiFine_Loaded()
  812. SelectReload()
  813. End Sub
  814. Private Sub Forge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnForgeClear.MouseLeftButtonUp
  815. SelectedForge = Nothing
  816. CardForge.IsSwaped = True
  817. e.Handled = True
  818. OptiFine_Loaded()
  819. SelectReload()
  820. End Sub
  821. #End Region
  822. #Region "Fabric 列表"
  823. ''' <summary>
  824. ''' 获取 Fabric 的加载异常信息。若正常则返回 Nothing。
  825. ''' </summary>
  826. Private Function LoadFabricGetError() As String
  827. If LoadFabric Is Nothing OrElse LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  828. If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabric.State, Object).Error.Message
  829. For Each Version As JObject In DlFabricListLoader.Output.Value("game")
  830. If Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") Then
  831. If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
  832. 'If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
  833. Return Nothing
  834. End If
  835. Next
  836. Return "没有可用版本"
  837. End Function
  838. '限制展开
  839. Private Sub CardFabric_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardFabric.PreviewSwap
  840. If LoadFabricGetError() IsNot Nothing Then e.Handled = True
  841. End Sub
  842. ''' <summary>
  843. ''' 尝试重新可视化 Fabric 版本列表。
  844. ''' </summary>
  845. Private Sub Fabric_Loaded() Handles LoadFabric.StateChanged
  846. Try
  847. If DlFabricListLoader.State <> LoadState.Finished Then Exit Sub
  848. '获取版本列表
  849. Dim Versions As JArray = DlFabricListLoader.Output.Value("loader")
  850. If Not Versions.Any() Then Exit Sub
  851. '可视化
  852. PanFabric.Children.Clear()
  853. PanFabric.Tag = Versions
  854. CardFabric.SwapControl = PanFabric
  855. CardFabric.SwapType = 12
  856. Catch ex As Exception
  857. Log(ex, "可视化 Fabric 安装版本列表出错", LogLevel.Feedback)
  858. End Try
  859. End Sub
  860. '选择与清除
  861. Public Sub Fabric_Selected(sender As MyListItem, e As EventArgs)
  862. SelectedFabric = sender.Tag("version").ToString
  863. FabricApi_Loaded()
  864. OptiFabric_Loaded()
  865. CardFabric.IsSwaped = True
  866. SelectReload()
  867. End Sub
  868. Private Sub Fabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricClear.MouseLeftButtonUp
  869. SelectedFabric = Nothing
  870. SelectedFabricApi = Nothing
  871. SelectedOptiFabric = Nothing
  872. CardFabric.IsSwaped = True
  873. e.Handled = True
  874. SelectReload()
  875. End Sub
  876. #End Region
  877. #Region "Fabric API 列表"
  878. ''' <summary>
  879. ''' 从显示名判断该 API 是否与某版本适配。
  880. ''' </summary>
  881. Public Shared Function IsSuitableFabricApi(DisplayName As String, MinecraftVersion As String) As Boolean
  882. Try
  883. If DisplayName Is Nothing OrElse MinecraftVersion Is Nothing Then Return False
  884. DisplayName = DisplayName.ToLower : MinecraftVersion = MinecraftVersion.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").ToLower
  885. If DisplayName.StartsWith("[" & MinecraftVersion & "]") Then Return True
  886. If Not DisplayName.Contains("/") OrElse Not DisplayName.Contains("]") Then Return False
  887. '直接的判断(例如 1.18.1/22w03a)
  888. For Each Part As String In DisplayName.Before("]").TrimStart("[").Split("/")
  889. If Part = MinecraftVersion Then Return True
  890. Next
  891. '将版本名分割语素(例如 1.16.4/5)
  892. Dim Lefts = RegexSearch(DisplayName.Before("]"), "[a-z/]+|[0-9/]+")
  893. Dim Rights = RegexSearch(MinecraftVersion.Before("]"), "[a-z/]+|[0-9/]+")
  894. '对每段进行判断
  895. Dim i As Integer = 0
  896. While True
  897. '两边均缺失,感觉是一个东西
  898. If Lefts.Count - 1 < i AndAlso Rights.Count - 1 < i Then Return True
  899. '确定两边是否一致
  900. Dim LeftValue As String = If(Lefts.Count - 1 < i, "-1", Lefts(i))
  901. Dim RightValue As String = If(Rights.Count - 1 < i, "-1", Rights(i))
  902. If Not LeftValue.Contains("/") Then
  903. If LeftValue <> RightValue Then Return False
  904. Else
  905. '左边存在斜杠
  906. If Not LeftValue.Contains(RightValue) Then Return False
  907. End If
  908. i += 1
  909. End While
  910. Return True
  911. Catch ex As Exception
  912. Log(ex, "判断 Fabric API 版本适配性出错(" & DisplayName & ", " & MinecraftVersion & ")")
  913. Return False
  914. End Try
  915. End Function
  916. ''' <summary>
  917. ''' 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
  918. ''' </summary>
  919. Private Function LoadFabricApiGetError() As String
  920. If LoadFabricApi Is Nothing OrElse LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  921. If LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabricApi.State, Object).Error.Message
  922. If DlFabricApiLoader.Output Is Nothing Then
  923. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  924. Return "正在获取版本列表……"
  925. End If
  926. For Each Version In DlFabricApiLoader.Output
  927. If Not IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Continue For
  928. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  929. Return Nothing
  930. Next
  931. Return "没有可用版本"
  932. End Function
  933. '限制展开
  934. Private Sub CardFabricApi_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardFabricApi.PreviewSwap
  935. If LoadFabricApiGetError() IsNot Nothing Then e.Handled = True
  936. End Sub
  937. Private AutoSelectedFabricApi As Boolean = False
  938. ''' <summary>
  939. ''' 尝试重新可视化 FabricApi 版本列表。
  940. ''' </summary>
  941. Private Sub FabricApi_Loaded() Handles LoadFabricApi.StateChanged
  942. Try
  943. If DlFabricApiLoader.State <> LoadState.Finished Then Exit Sub
  944. If SelectedMinecraftId Is Nothing OrElse SelectedFabric Is Nothing Then Exit Sub
  945. '获取版本列表
  946. Dim Versions As New List(Of CompFile)
  947. For Each Version In DlFabricApiLoader.Output
  948. If IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then
  949. If Not Version.DisplayName.StartsWith("[") Then
  950. Log("[Download] 已特判修改 Fabric API 显示名:" & Version.DisplayName, LogLevel.Debug)
  951. Version.DisplayName = "[" & SelectedMinecraftId & "] " & Version.DisplayName
  952. End If
  953. Versions.Add(Version)
  954. End If
  955. Next
  956. If Not Versions.Any() Then Exit Sub
  957. Versions = Sort(Versions, Function(a, b) a.ReleaseDate > b.ReleaseDate)
  958. '可视化
  959. PanFabricApi.Children.Clear()
  960. For Each Version In Versions
  961. If Not IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Continue For
  962. PanFabricApi.Children.Add(FabricApiDownloadListItem(Version, AddressOf FabricApi_Selected))
  963. Next
  964. '自动选择 Fabric API
  965. If Not AutoSelectedFabricApi Then
  966. AutoSelectedFabricApi = True
  967. Log($"[Download] 已自动选择 Fabric API:{CType(PanFabricApi.Children(0), MyListItem).Title}")
  968. FabricApi_Selected(PanFabricApi.Children(0), Nothing)
  969. End If
  970. Catch ex As Exception
  971. Log(ex, "可视化 Fabric API 安装版本列表出错", LogLevel.Feedback)
  972. End Try
  973. End Sub
  974. '选择与清除
  975. Private Sub FabricApi_Selected(sender As MyListItem, e As EventArgs)
  976. SelectedFabricApi = sender.Tag
  977. CardFabricApi.IsSwaped = True
  978. SelectReload()
  979. End Sub
  980. Private Sub FabricApi_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricApiClear.MouseLeftButtonUp
  981. SelectedFabricApi = Nothing
  982. CardFabricApi.IsSwaped = True
  983. e.Handled = True
  984. SelectReload()
  985. End Sub
  986. #End Region
  987. #Region "OptiFabric 列表"
  988. ''' <summary>
  989. ''' 从显示名判断该 Mod 是否与某版本适配。
  990. ''' </summary>
  991. Private Function IsSuitableOptiFabric(ModFile As CompFile, MinecraftVersion As String) As Boolean
  992. Try
  993. If MinecraftVersion Is Nothing Then Return False
  994. Return ModFile.GameVersions.Contains(MinecraftVersion)
  995. Catch ex As Exception
  996. Log(ex, "判断 OptiFabric 版本适配性出错(" & MinecraftVersion & ")")
  997. Return False
  998. End Try
  999. End Function
  1000. Private AutoSelectedOptiFabric As Boolean = False
  1001. ''' <summary>
  1002. ''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
  1003. ''' </summary>
  1004. Private Function LoadOptiFabricGetError() As String
  1005. If LoadOptiFabric Is Nothing OrElse LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  1006. If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFabric.State, Object).Error.Message
  1007. If DlOptiFabricLoader.Output Is Nothing Then
  1008. If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
  1009. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  1010. If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
  1011. Return "正在获取版本列表……"
  1012. End If
  1013. For Each Version In DlOptiFabricLoader.Output
  1014. If Not IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Continue For '2135#
  1015. If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
  1016. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  1017. If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
  1018. Return Nothing '通过检查
  1019. Next
  1020. Return "没有可用版本"
  1021. End Function
  1022. '限制展开
  1023. Private Sub CardOptiFabric_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardOptiFabric.PreviewSwap
  1024. If LoadOptiFabricGetError() IsNot Nothing Then e.Handled = True
  1025. End Sub
  1026. ''' <summary>
  1027. ''' 尝试重新可视化 OptiFabric 版本列表。
  1028. ''' </summary>
  1029. Private Sub OptiFabric_Loaded() Handles LoadOptiFabric.StateChanged
  1030. Try
  1031. If DlOptiFabricLoader.State <> LoadState.Finished Then Exit Sub
  1032. If SelectedMinecraftId Is Nothing OrElse SelectedFabric Is Nothing OrElse SelectedOptiFine Is Nothing Then Exit Sub
  1033. '获取版本列表
  1034. Dim Versions As New List(Of CompFile)
  1035. For Each Version In DlOptiFabricLoader.Output
  1036. If IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Versions.Add(Version)
  1037. Next
  1038. If Not Versions.Any() Then Exit Sub
  1039. '排序
  1040. Versions = Sort(Versions, Function(a, b) a.ReleaseDate > b.ReleaseDate)
  1041. '可视化
  1042. PanOptiFabric.Children.Clear()
  1043. For Each Version In Versions
  1044. If Not IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Continue For
  1045. PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
  1046. Next
  1047. '自动选择 OptiFabric
  1048. If Not AutoSelectedOptiFabric Then
  1049. AutoSelectedOptiFabric = True
  1050. Log($"[Download] 已自动选择 OptiFabric:{CType(PanOptiFabric.Children(0), MyListItem).Title}")
  1051. OptiFabric_Selected(PanOptiFabric.Children(0), Nothing)
  1052. End If
  1053. Catch ex As Exception
  1054. Log(ex, "可视化 OptiFabric 安装版本列表出错", LogLevel.Feedback)
  1055. End Try
  1056. End Sub
  1057. '选择与清除
  1058. Private Sub OptiFabric_Selected(sender As MyListItem, e As EventArgs)
  1059. SelectedOptiFabric = sender.Tag
  1060. CardOptiFabric.IsSwaped = True
  1061. SelectReload()
  1062. End Sub
  1063. Private Sub OptiFabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFabricClear.MouseLeftButtonUp
  1064. SelectedOptiFabric = Nothing
  1065. CardOptiFabric.IsSwaped = True
  1066. e.Handled = True
  1067. SelectReload()
  1068. End Sub
  1069. #End Region
  1070. #Region "安装"
  1071. Private Sub TextSelectName_KeyDown(sender As Object, e As KeyEventArgs) Handles TextSelectName.KeyDown
  1072. If e.Key = Key.Enter AndAlso BtnSelectStart.IsEnabled Then BtnSelectStart_Click()
  1073. End Sub
  1074. Private Sub BtnSelectStart_Click() Handles BtnSelectStart.Click
  1075. '确认版本隔离
  1076. If (SelectedForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
  1077. (Setup.Get("LaunchArgumentIndie") = 0 OrElse Setup.Get("LaunchArgumentIndie") = 2) Then
  1078. If MyMsgBox("你尚未开启版本隔离,这会导致多个 MC 共用同一个 Mod 文件夹。" & vbCrLf &
  1079. "因此在切换 MC 版本时,MC 会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
  1080. "PCL 推荐你在开始下载前,在 设置 → 版本隔离 中开启版本隔离选项!", "版本隔离提示", "取消下载", "继续") = 1 Then
  1081. Exit Sub
  1082. End If
  1083. End If
  1084. '提交安装申请
  1085. Dim Request As New McInstallRequest With {
  1086. .TargetVersionName = TextSelectName.Text,
  1087. .TargetVersionFolder = $"{PathMcFolder}versions\{TextSelectName.Text}\",
  1088. .MinecraftJson = SelectedMinecraftJsonUrl,
  1089. .MinecraftName = SelectedMinecraftId,
  1090. .OptiFineEntry = SelectedOptiFine,
  1091. .ForgeEntry = SelectedForge,
  1092. .FabricVersion = SelectedFabric,
  1093. .FabricApi = SelectedFabricApi,
  1094. .OptiFabric = SelectedOptiFabric,
  1095. .LiteLoaderEntry = SelectedLiteLoader
  1096. }
  1097. If Not McInstall(Request) Then Exit Sub
  1098. '返回,这样在再次进入安装页面时这个版本就会显示文件夹已重复
  1099. ExitSelectPage()
  1100. End Sub
  1101. #End Region
  1102. End Class