PageDownloadInstall.xaml.vb 55 KB

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