PageDownloadInstall.xaml.vb 54 KB

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