PageDownloadInstall.xaml.vb 53 KB

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