PageDownloadInstall.xaml.vb 60 KB

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