PageDownloadInstall.xaml.vb 61 KB

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