PageDownloadInstall.xaml.vb 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  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. HintOptiFabric.Visibility = If(SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso SelectedOptiFabric Is Nothing, Visibility.Visible, Visibility.Collapsed)
  358. End Sub
  359. ''' <summary>
  360. ''' 清空已选择的项目。
  361. ''' </summary>
  362. Private Sub SelectClear()
  363. SelectedMinecraftId = Nothing
  364. SelectedMinecraftJsonUrl = Nothing
  365. SelectedMinecraftIcon = Nothing
  366. SelectedOptiFine = Nothing
  367. SelectedLiteLoader = Nothing
  368. SelectedForge = Nothing
  369. SelectedFabric = Nothing
  370. SelectedFabricApi = Nothing
  371. SelectedOptiFabric = Nothing
  372. End Sub
  373. '显示信息获取
  374. ''' <summary>
  375. ''' 获取默认版本名。
  376. ''' </summary>
  377. Private Function GetSelectName() As String
  378. Dim Name As String = SelectedMinecraftId
  379. If SelectedFabric IsNot Nothing Then
  380. Name += "-Fabric " & SelectedFabric.Replace("+build", "")
  381. End If
  382. If SelectedForge IsNot Nothing Then
  383. Name += "-Forge_" & SelectedForge.Version
  384. End If
  385. If SelectedLiteLoader IsNot Nothing Then
  386. Name += "-LiteLoader"
  387. End If
  388. If SelectedOptiFine IsNot Nothing Then
  389. Name += "-OptiFine_" & SelectedOptiFine.NameDisplay.Replace(SelectedMinecraftId & " ", "").Replace(" ", "_")
  390. End If
  391. Return Name
  392. End Function
  393. ''' <summary>
  394. ''' 获取版本描述信息。
  395. ''' </summary>
  396. Private Function GetSelectInfo() As String
  397. Dim Info As String = ""
  398. If SelectedFabric IsNot Nothing Then
  399. Info += ", Fabric " & SelectedFabric.Replace("+build", "")
  400. End If
  401. If SelectedForge IsNot Nothing Then
  402. Info += ", Forge " & SelectedForge.Version
  403. End If
  404. If SelectedLiteLoader IsNot Nothing Then
  405. Info += ", LiteLoader"
  406. End If
  407. If SelectedOptiFine IsNot Nothing Then
  408. Info += ", OptiFine " & SelectedOptiFine.NameDisplay.Replace(SelectedMinecraftId & " ", "")
  409. End If
  410. If Info = "" Then Info = ", 无附加安装"
  411. Return Info.TrimStart(", ".ToCharArray())
  412. End Function
  413. ''' <summary>
  414. ''' 获取版本图标。
  415. ''' </summary>
  416. Private Function GetSelectLogo() As String
  417. If SelectedFabric IsNot Nothing Then
  418. Return "pack://application:,,,/images/Blocks/Fabric.png"
  419. ElseIf SelectedForge IsNot Nothing Then
  420. Return "pack://application:,,,/images/Blocks/Anvil.png"
  421. ElseIf SelectedLiteLoader IsNot Nothing Then
  422. Return "pack://application:,,,/images/Blocks/Egg.png"
  423. ElseIf SelectedOptiFine IsNot Nothing Then
  424. Return "pack://application:,,,/images/Blocks/GrassPath.png"
  425. Else
  426. Return SelectedMinecraftIcon
  427. End If
  428. End Function
  429. '版本名处理
  430. Private IsSelectNameEdited As Boolean = False
  431. Private IsSelectNameChanging As Boolean = False
  432. Private Sub SelectNameUpdate()
  433. If IsSelectNameEdited OrElse IsSelectNameChanging Then Exit Sub
  434. IsSelectNameChanging = True
  435. TextSelectName.Text = GetSelectName()
  436. IsSelectNameChanging = False
  437. End Sub
  438. Private Sub TextSelectName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TextSelectName.TextChanged
  439. If IsSelectNameChanging Then Exit Sub
  440. IsSelectNameEdited = True
  441. SelectReload()
  442. End Sub
  443. Private Sub TextSelectName_ValidateChanged(sender As Object, e As EventArgs) Handles TextSelectName.ValidateChanged
  444. BtnSelectStart.IsEnabled = TextSelectName.ValidateResult = ""
  445. End Sub
  446. #End Region
  447. #Region "加载器"
  448. '结果数据化
  449. Private Sub LoadMinecraft_OnFinish()
  450. ExitSelectPage() '返回
  451. Try
  452. Dim Dict As New Dictionary(Of String, List(Of JObject)) From {
  453. {"正式版", New List(Of JObject)}, {"预览版", New List(Of JObject)}, {"远古版", New List(Of JObject)}, {"愚人节版", New List(Of JObject)}
  454. }
  455. Dim Versions As JArray = DlClientListLoader.Output.Value("versions")
  456. For Each Version As JObject In Versions
  457. '确定分类
  458. Dim Type As String = Version("type")
  459. Select Case Type
  460. Case "release"
  461. Type = "正式版"
  462. Case "snapshot"
  463. Type = "预览版"
  464. 'Mojang 误分类
  465. If Version("id").ToString.StartsWith("1.") AndAlso
  466. Not Version("id").ToString.ToLower.Contains("combat") AndAlso
  467. Not Version("id").ToString.ToLower.Contains("rc") AndAlso
  468. Not Version("id").ToString.ToLower.Contains("experimental") AndAlso
  469. Not Version("id").ToString.ToLower.Contains("pre") Then
  470. Type = "正式版"
  471. Version("type") = "release"
  472. End If
  473. '愚人节版本
  474. Select Case Version("id").ToString.ToLower
  475. Case "20w14infinite", "20w14∞"
  476. Type = "愚人节版"
  477. Version("id") = "20w14∞"
  478. Version("type") = "special"
  479. Version.Add("lore", GetMcFoolName(Version("id")))
  480. Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime"
  481. Type = "愚人节版"
  482. Version("type") = "special"
  483. Version.Add("lore", GetMcFoolName(Version("id")))
  484. End Select
  485. Case "special"
  486. '已被处理的愚人节版
  487. Type = "愚人节版"
  488. Case Else
  489. Type = "远古版"
  490. End Select
  491. '加入辞典
  492. Dict(Type).Add(Version)
  493. Next
  494. '排序
  495. For i = 0 To Dict.Keys.Count - 1
  496. Dict(Dict.Keys(i)) = Sort(Dict.Values(i), Function(Left As JObject, Right As JObject) As Boolean
  497. Return Left("releaseTime").Value(Of Date) > Right("releaseTime").Value(Of Date)
  498. End Function)
  499. Next
  500. '清空当前
  501. PanMinecraft.Children.Clear()
  502. '添加最新版本
  503. Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15), .SwapType = 2}
  504. Dim TopestVersions As New List(Of JObject)
  505. Dim Release As JObject = Dict("正式版")(0).DeepClone()
  506. Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
  507. TopestVersions.Add(Release)
  508. If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
  509. Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
  510. Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
  511. TopestVersions.Add(Snapshot)
  512. End If
  513. Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}
  514. MyCard.StackInstall(PanInfo, 7)
  515. CardInfo.Children.Add(PanInfo)
  516. PanMinecraft.Children.Insert(0, CardInfo)
  517. '添加其他版本
  518. For Each Pair As KeyValuePair(Of String, List(Of JObject)) In Dict
  519. If Pair.Value.Count = 0 Then Continue For
  520. '增加卡片
  521. Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 7}
  522. 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}
  523. NewCard.Children.Add(NewStack)
  524. NewCard.SwapControl = NewStack
  525. NewCard.IsSwaped = True
  526. PanMinecraft.Children.Add(NewCard)
  527. Next
  528. Catch ex As Exception
  529. Log(ex, "可视化安装版本列表出错", LogLevel.Feedback)
  530. End Try
  531. End Sub
  532. #End Region
  533. #Region "OptiFine 列表"
  534. ''' <summary>
  535. ''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
  536. ''' </summary>
  537. Private Function LoadOptiFineGetError() As String
  538. If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  539. If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFine.State, Object).Error.Message
  540. '检查 Forge 1.13 - 1.14.3:全部不兼容
  541. If SelectedForge IsNot Nothing AndAlso
  542. VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then
  543. Return "与 Forge 不兼容"
  544. End If
  545. '检查最低 Forge 版本
  546. Dim MinimalForgeVersion As String = "9999.9999"
  547. For Each OptiFineVersion As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
  548. If Not OptiFineVersion.NameDisplay.StartsWith(SelectedMinecraftId & " ") Then Continue For '不是同一个大版本
  549. If SelectedForge Is Nothing OrElse IsOptiFineSuitForForge(OptiFineVersion, SelectedForge) Then
  550. Return Nothing
  551. Else
  552. '设置用于显示的最低 Forge 版本
  553. MinimalForgeVersion = If(VersionSortBoolean(MinimalForgeVersion, OptiFineVersion.RequiredForgeVersion),
  554. OptiFineVersion.RequiredForgeVersion, MinimalForgeVersion)
  555. End If
  556. Next
  557. If MinimalForgeVersion = "9999.9999" Then
  558. Return "没有可用版本"
  559. Else
  560. Return "需要 Forge " & If(MinimalForgeVersion.Contains("."), "", "#") & MinimalForgeVersion & " 或更高版本"
  561. End If
  562. End Function
  563. '检查某个 OptiFine 是否与某个 Forge 兼容(最低 Forge 版本是否达到需求)
  564. Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
  565. If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
  566. Return (OptiFine.RequiredForgeVersion.Contains(".") AndAlso 'XX.X.XXX
  567. VersionSortInteger(Forge.Version, OptiFine.RequiredForgeVersion) >= 0) OrElse
  568. (Not OptiFine.RequiredForgeVersion.Contains(".") AndAlso '#XXXX
  569. VersionSortInteger(Forge.Version.Split(".").Last, OptiFine.RequiredForgeVersion) >= 0)
  570. End Function
  571. '限制展开
  572. Private Sub CardOptiFine_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardOptiFine.PreviewSwap
  573. If LoadOptiFineGetError() IsNot Nothing Then e.Handled = True
  574. End Sub
  575. ''' <summary>
  576. ''' 尝试重新可视化 OptiFine 版本列表。
  577. ''' </summary>
  578. Private Sub OptiFine_Loaded() Handles LoadOptiFine.StateChanged
  579. Try
  580. If DlOptiFineListLoader.State <> LoadState.Finished Then Exit Sub
  581. '获取版本列表
  582. Dim Versions As New List(Of DlOptiFineListEntry)
  583. For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
  584. If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(Version, SelectedForge) Then Continue For
  585. If Version.NameDisplay.StartsWith(SelectedMinecraftId & " ") Then Versions.Add(Version)
  586. Next
  587. If Versions.Count = 0 Then Exit Sub
  588. '排序
  589. Versions = Sort(Versions, Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
  590. Return VersionSortBoolean(Left.NameDisplay, Right.NameDisplay)
  591. End Function)
  592. '可视化
  593. PanOptiFine.Children.Clear()
  594. For Each Version In Versions
  595. PanOptiFine.Children.Add(OptiFineDownloadListItem(Version, AddressOf OptiFine_Selected, False))
  596. Next
  597. Catch ex As Exception
  598. Log(ex, "可视化 OptiFine 安装版本列表出错", LogLevel.Feedback)
  599. End Try
  600. End Sub
  601. '选择与清除
  602. Private Sub OptiFine_Selected(sender As MyListItem, e As EventArgs)
  603. SelectedOptiFine = sender.Tag
  604. If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedForge = Nothing
  605. OptiFabric_Loaded()
  606. Forge_Loaded()
  607. CardOptiFine.IsSwaped = True
  608. SelectReload()
  609. End Sub
  610. Private Sub OptiFine_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFineClear.MouseLeftButtonUp
  611. SelectedOptiFine = Nothing
  612. SelectedOptiFabric = Nothing
  613. CardOptiFine.IsSwaped = True
  614. e.Handled = True
  615. Forge_Loaded()
  616. SelectReload()
  617. End Sub
  618. #End Region
  619. #Region "LiteLoader 列表"
  620. ''' <summary>
  621. ''' 获取 LiteLoader 的加载异常信息。若正常则返回 Nothing。
  622. ''' </summary>
  623. Private Function LoadLiteLoaderGetError() As String
  624. If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) > 12 Then Return "没有可用版本"
  625. If LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  626. If LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadLiteLoader.State, Object).Error.Message
  627. For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
  628. If Version.Inherit = SelectedMinecraftId Then Return Nothing
  629. Next
  630. Return "没有可用版本"
  631. End Function
  632. '限制展开
  633. Private Sub CardLiteLoader_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardLiteLoader.PreviewSwap
  634. If LoadLiteLoaderGetError() IsNot Nothing Then e.Handled = True
  635. End Sub
  636. ''' <summary>
  637. ''' 尝试重新可视化 LiteLoader 版本列表。
  638. ''' </summary>
  639. Private Sub LiteLoader_Loaded() Handles LoadLiteLoader.StateChanged
  640. Try
  641. If DlLiteLoaderListLoader.State <> LoadState.Finished Then Exit Sub
  642. '获取版本列表
  643. Dim Versions As New List(Of DlLiteLoaderListEntry)
  644. For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
  645. If Version.Inherit = SelectedMinecraftId Then Versions.Add(Version)
  646. Next
  647. If Versions.Count = 0 Then Exit Sub
  648. '可视化
  649. PanLiteLoader.Children.Clear()
  650. For Each Version In Versions
  651. PanLiteLoader.Children.Add(LiteLoaderDownloadListItem(Version, AddressOf LiteLoader_Selected, False))
  652. Next
  653. Catch ex As Exception
  654. Log(ex, "可视化 LiteLoader 安装版本列表出错", LogLevel.Feedback)
  655. End Try
  656. End Sub
  657. '选择与清除
  658. Private Sub LiteLoader_Selected(sender As MyListItem, e As EventArgs)
  659. SelectedLiteLoader = sender.Tag
  660. CardLiteLoader.IsSwaped = True
  661. SelectReload()
  662. End Sub
  663. Private Sub LiteLoader_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnLiteLoaderClear.MouseLeftButtonUp
  664. SelectedLiteLoader = Nothing
  665. CardLiteLoader.IsSwaped = True
  666. e.Handled = True
  667. SelectReload()
  668. End Sub
  669. #End Region
  670. #Region "Forge 列表"
  671. ''' <summary>
  672. ''' 获取 Forge 的加载异常信息。若正常则返回 Nothing。
  673. ''' </summary>
  674. Private Function LoadForgeGetError() As String
  675. If Not SelectedMinecraftId.StartsWith("1.") Then Return "没有可用版本"
  676. If Not LoadForge.State.IsLoader Then Return "正在获取版本列表……"
  677. Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
  678. If SelectedMinecraftId <> Loader.Input Then Return "正在获取版本列表……"
  679. If Loader.State = LoadState.Loading Then Return "正在获取版本列表……"
  680. If Loader.State = LoadState.Failed Then
  681. Dim ErrorMessage As String = Loader.Error.Message
  682. If ErrorMessage.Contains("没有可用版本") Then
  683. Return "没有可用版本"
  684. Else
  685. Return "获取版本列表失败:" & ErrorMessage
  686. End If
  687. End If
  688. If Loader.State <> LoadState.Finished Then Return "获取版本列表失败:未知错误,状态为 " & GetStringFromEnum(Loader.State)
  689. For Each Version In Loader.Output
  690. If Version.Category = "universal" OrElse Version.Category = "client" Then Continue For '跳过无法自动安装的版本
  691. If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
  692. If SelectedOptiFine IsNot Nothing AndAlso VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then Return "与 OptiFine 不兼容"
  693. Return Nothing
  694. Next
  695. Return "该版本不支持自动安装"
  696. End Function
  697. '限制展开
  698. Private Sub CardForge_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardForge.PreviewSwap
  699. If LoadForgeGetError() IsNot Nothing Then e.Handled = True
  700. End Sub
  701. ''' <summary>
  702. ''' 尝试重新可视化 Forge 版本列表。
  703. ''' </summary>
  704. Private Sub Forge_Loaded() Handles LoadForge.StateChanged
  705. Try
  706. If Not LoadForge.State.IsLoader Then Exit Sub
  707. Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
  708. If SelectedMinecraftId <> Loader.Input Then Exit Sub
  709. If Loader.State <> LoadState.Finished Then Exit Sub
  710. '可视化
  711. Dim Versions As New List(Of DlForgeVersionEntry)
  712. Versions.AddRange(Loader.Output) '复制数组,以免 Output 在实例化后变空
  713. If Loader.Output.Count = 0 Then Exit Sub
  714. PanForge.Children.Clear()
  715. Versions = Sort(Versions, Function(Left As DlForgeVersionEntry, Right As DlForgeVersionEntry) As Boolean
  716. Return New Version(Left.Version) > New Version(Right.Version)
  717. End Function)
  718. ForgeDownloadListItemPreload(PanForge, Versions, AddressOf Forge_Selected, False)
  719. For Each Version In Versions
  720. If Version.Category = "universal" OrElse Version.Category = "client" Then Continue For '跳过无法自动安装的版本
  721. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, Version) Then Continue For
  722. PanForge.Children.Add(ForgeDownloadListItem(Version, AddressOf Forge_Selected, False))
  723. Next
  724. Catch ex As Exception
  725. Log(ex, "可视化 Forge 安装版本列表出错", LogLevel.Feedback)
  726. End Try
  727. End Sub
  728. '选择与清除
  729. Private Sub Forge_Selected(sender As MyListItem, e As EventArgs)
  730. SelectedForge = sender.Tag
  731. CardForge.IsSwaped = True
  732. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedOptiFine = Nothing
  733. OptiFine_Loaded()
  734. SelectReload()
  735. End Sub
  736. Private Sub Forge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnForgeClear.MouseLeftButtonUp
  737. SelectedForge = Nothing
  738. CardForge.IsSwaped = True
  739. e.Handled = True
  740. OptiFine_Loaded()
  741. SelectReload()
  742. End Sub
  743. #End Region
  744. #Region "Fabric 列表"
  745. ''' <summary>
  746. ''' 获取 Fabric 的加载异常信息。若正常则返回 Nothing。
  747. ''' </summary>
  748. Private Function LoadFabricGetError() As String
  749. If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  750. If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabric.State, Object).Error.Message
  751. For Each Version As JObject In DlFabricListLoader.Output.Value("game")
  752. If Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite") Then
  753. If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
  754. 'If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
  755. Return Nothing
  756. End If
  757. Next
  758. Return "没有可用版本"
  759. End Function
  760. '限制展开
  761. Private Sub CardFabric_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardFabric.PreviewSwap
  762. If LoadFabricGetError() IsNot Nothing Then e.Handled = True
  763. End Sub
  764. ''' <summary>
  765. ''' 尝试重新可视化 Fabric 版本列表。
  766. ''' </summary>
  767. Private Sub Fabric_Loaded() Handles LoadFabric.StateChanged
  768. Try
  769. If DlFabricListLoader.State <> LoadState.Finished Then Exit Sub
  770. '获取版本列表
  771. Dim Versions As JArray = DlFabricListLoader.Output.Value("loader")
  772. If Versions.Count = 0 Then Exit Sub
  773. '可视化
  774. PanFabric.Children.Clear()
  775. For Each Version In Versions
  776. PanFabric.Children.Add(FabricDownloadListItem(Version, AddressOf Fabric_Selected))
  777. Next
  778. Catch ex As Exception
  779. Log(ex, "可视化 Fabric 安装版本列表出错", LogLevel.Feedback)
  780. End Try
  781. End Sub
  782. '选择与清除
  783. Private Sub Fabric_Selected(sender As MyListItem, e As EventArgs)
  784. SelectedFabric = sender.Tag("version").ToString
  785. FabricApi_Loaded()
  786. OptiFabric_Loaded()
  787. CardFabric.IsSwaped = True
  788. SelectReload()
  789. If Not Setup.Get("HintInstallFabricApi") Then
  790. Setup.Set("HintInstallFabricApi", True)
  791. Hint("安装 Fabric 时通常还需要安装 Fabric API,在选择 Fabric 后就会显示其安装选项!")
  792. End If
  793. End Sub
  794. Private Sub Fabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricClear.MouseLeftButtonUp
  795. SelectedFabric = Nothing
  796. SelectedFabricApi = Nothing
  797. SelectedOptiFabric = Nothing
  798. CardFabric.IsSwaped = True
  799. e.Handled = True
  800. SelectReload()
  801. End Sub
  802. #End Region
  803. #Region "Fabric API 列表"
  804. ''' <summary>
  805. ''' 从显示名判断该 API 是否与某版本适配。
  806. ''' </summary>
  807. Public Shared Function IsSuitableFabricApi(DisplayName As String, MinecraftVersion As String) As Boolean
  808. Try
  809. If DisplayName Is Nothing OrElse MinecraftVersion Is Nothing Then Return False
  810. DisplayName = DisplayName.ToLower : MinecraftVersion = MinecraftVersion.ToLower
  811. If DisplayName.StartsWith("[" & MinecraftVersion & "]") Then Return True
  812. If Not DisplayName.Contains("/") OrElse Not DisplayName.Contains("]") Then Return False
  813. '直接的判断(例如 1.18.1/22w03a)
  814. For Each Part As String In DisplayName.Split("]")(0).TrimStart("[").Split("/")
  815. If Part = MinecraftVersion Then Return True
  816. Next
  817. '将版本名分割语素(例如 1.16.4/5)
  818. Dim Lefts = RegexSearch(DisplayName.Split("]")(0), "[a-z/]+|[0-9/]+")
  819. Dim Rights = RegexSearch(MinecraftVersion.Split("]")(0), "[a-z/]+|[0-9/]+")
  820. '对每段进行判断
  821. Dim i As Integer = 0
  822. While True
  823. '两边均缺失,感觉是一个东西
  824. If Lefts.Count - 1 < i AndAlso Rights.Count - 1 < i Then Return True
  825. '确定两边是否一致
  826. Dim LeftValue As String = If(Lefts.Count - 1 < i, "-1", Lefts(i))
  827. Dim RightValue As String = If(Rights.Count - 1 < i, "-1", Rights(i))
  828. If Not LeftValue.Contains("/") Then
  829. If LeftValue <> RightValue Then Return False
  830. Else
  831. '左边存在斜杠
  832. If Not LeftValue.Contains(RightValue) Then Return False
  833. End If
  834. i += 1
  835. End While
  836. Return True
  837. Catch ex As Exception
  838. Log(ex, "判断 Fabric API 版本适配性出错(" & DisplayName & ", " & MinecraftVersion & ")")
  839. Return False
  840. End Try
  841. End Function
  842. ''' <summary>
  843. ''' 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
  844. ''' </summary>
  845. Private Function LoadFabricApiGetError() As String
  846. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  847. If LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  848. If LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabricApi.State, Object).Error.Message
  849. For Each Version In DlFabricApiLoader.Output
  850. If IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Return Nothing
  851. Next
  852. Return "没有可用版本"
  853. End Function
  854. '限制展开
  855. Private Sub CardFabricApi_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardFabricApi.PreviewSwap
  856. If LoadFabricApiGetError() IsNot Nothing Then e.Handled = True
  857. End Sub
  858. ''' <summary>
  859. ''' 尝试重新可视化 FabricApi 版本列表。
  860. ''' </summary>
  861. Private Sub FabricApi_Loaded() Handles LoadFabricApi.StateChanged
  862. Try
  863. If DlFabricApiLoader.State <> LoadState.Finished Then Exit Sub
  864. If SelectedMinecraftId Is Nothing OrElse SelectedFabric Is Nothing Then Exit Sub
  865. '获取版本列表
  866. Dim Versions As New List(Of DlCfFile)
  867. For Each Version In DlFabricApiLoader.Output
  868. If IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then
  869. If Not Version.DisplayName.StartsWith("[") Then
  870. Log("[Download] 已特判修改 Fabric API 显示名:" & Version.DisplayName, LogLevel.Debug)
  871. Version.DisplayName = "[" & SelectedMinecraftId & "] " & Version.DisplayName
  872. End If
  873. Versions.Add(Version)
  874. End If
  875. Next
  876. If Versions.Count = 0 Then Exit Sub
  877. '排序
  878. Versions = Sort(Versions, Function(Left As DlCfFile, Right As DlCfFile) As Boolean
  879. Return Left.Date > Right.Date
  880. End Function)
  881. '可视化
  882. PanFabricApi.Children.Clear()
  883. For Each Version In Versions
  884. If Not IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Continue For
  885. PanFabricApi.Children.Add(FabricApiDownloadListItem(Version, AddressOf FabricApi_Selected))
  886. Next
  887. Catch ex As Exception
  888. Log(ex, "可视化 Fabric API 安装版本列表出错", LogLevel.Feedback)
  889. End Try
  890. End Sub
  891. '选择与清除
  892. Private Sub FabricApi_Selected(sender As MyListItem, e As EventArgs)
  893. SelectedFabricApi = sender.Tag
  894. CardFabricApi.IsSwaped = True
  895. SelectReload()
  896. End Sub
  897. Private Sub FabricApi_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricApiClear.MouseLeftButtonUp
  898. SelectedFabricApi = Nothing
  899. CardFabricApi.IsSwaped = True
  900. e.Handled = True
  901. SelectReload()
  902. End Sub
  903. #End Region
  904. #Region "OptiFabric 列表"
  905. ''' <summary>
  906. ''' 从显示名判断该 Mod 是否与某版本适配。
  907. ''' </summary>
  908. Private Function IsSuitableOptiFabric(ModFile As DlCfFile, MinecraftVersion As String) As Boolean
  909. Try
  910. If MinecraftVersion Is Nothing Then Return False
  911. Return ModFile.GameVersion.Contains(MinecraftVersion)
  912. Catch ex As Exception
  913. Log(ex, "判断 OptiFabric 版本适配性出错(" & MinecraftVersion & ")")
  914. Return False
  915. End Try
  916. End Function
  917. ''' <summary>
  918. ''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
  919. ''' </summary>
  920. Private Function LoadOptiFabricGetError() As String
  921. If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
  922. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  923. If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
  924. If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
  925. If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFabric.State, Object).Error.Message
  926. For Each Version In DlOptiFabricLoader.Output
  927. If IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Return Nothing
  928. Next
  929. Return "没有可用版本"
  930. End Function
  931. '限制展开
  932. Private Sub CardOptiFabric_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardOptiFabric.PreviewSwap
  933. If LoadOptiFabricGetError() IsNot Nothing Then e.Handled = True
  934. End Sub
  935. ''' <summary>
  936. ''' 尝试重新可视化 OptiFabric 版本列表。
  937. ''' </summary>
  938. Private Sub OptiFabric_Loaded() Handles LoadOptiFabric.StateChanged
  939. Try
  940. If DlOptiFabricLoader.State <> LoadState.Finished Then Exit Sub
  941. If SelectedMinecraftId Is Nothing OrElse SelectedFabric Is Nothing OrElse SelectedOptiFine Is Nothing Then Exit Sub
  942. '获取版本列表
  943. Dim Versions As New List(Of DlCfFile)
  944. For Each Version In DlOptiFabricLoader.Output
  945. If IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Versions.Add(Version)
  946. Next
  947. If Versions.Count = 0 Then Exit Sub
  948. '排序
  949. Versions = Sort(Versions, Function(Left As DlCfFile, Right As DlCfFile) As Boolean
  950. Return Left.Date > Right.Date
  951. End Function)
  952. '可视化
  953. PanOptiFabric.Children.Clear()
  954. For Each Version In Versions
  955. If Not IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Continue For
  956. PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
  957. Next
  958. Catch ex As Exception
  959. Log(ex, "可视化 Fabric API 安装版本列表出错", LogLevel.Feedback)
  960. End Try
  961. End Sub
  962. '选择与清除
  963. Private Sub OptiFabric_Selected(sender As MyListItem, e As EventArgs)
  964. SelectedOptiFabric = sender.Tag
  965. CardOptiFabric.IsSwaped = True
  966. SelectReload()
  967. End Sub
  968. Private Sub OptiFabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFabricClear.MouseLeftButtonUp
  969. SelectedOptiFabric = Nothing
  970. CardOptiFabric.IsSwaped = True
  971. e.Handled = True
  972. SelectReload()
  973. End Sub
  974. #End Region
  975. #Region "安装"
  976. Private Sub BtnSelectStart_Click(sender As Object, e As EventArgs) Handles BtnSelectStart.Click
  977. '确认版本隔离
  978. If (SelectedForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
  979. (Setup.Get("LaunchArgumentIndie") = 0 OrElse Setup.Get("LaunchArgumentIndie") = 2) Then
  980. If MyMsgBox("你尚未开启版本隔离,这会导致多个 MC 共用同一个 Mod 文件夹。" & vbCrLf &
  981. "因此在切换 MC 版本时,MC 会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
  982. "PCL2 推荐你在开始下载前,在 设置 → 版本隔离 中开启版本隔离选项!", "版本隔离提示", "取消下载", "继续") = 1 Then
  983. Exit Sub
  984. End If
  985. End If
  986. '提交安装申请
  987. Dim Request As New McInstallRequest With {
  988. .TargetVersionName = TextSelectName.Text,
  989. .MinecraftJson = SelectedMinecraftJsonUrl,
  990. .MinecraftName = SelectedMinecraftId,
  991. .OptiFineEntry = SelectedOptiFine,
  992. .ForgeEntry = SelectedForge,
  993. .FabricVersion = SelectedFabric,
  994. .FabricApi = SelectedFabricApi,
  995. .OptiFabric = SelectedOptiFabric,
  996. .LiteLoaderEntry = SelectedLiteLoader
  997. }
  998. If Not McInstall(Request) Then Exit Sub
  999. '返回,这样在再次进入安装页面时这个版本就会显示文件夹已重复
  1000. ExitSelectPage()
  1001. End Sub
  1002. #End Region
  1003. End Class