PageDownloadInstall.xaml.vb 52 KB

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