1
0

PageDownloadInstall.xaml.vb 54 KB

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