PageDownloadInstall.xaml.vb 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  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 ResourceVersion = Nothing
  153. Private SelectedOptiFabric As ResourceVersion = 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.Display.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.Display.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. VersionWaitingSelect = Nothing
  507. Return
  508. Next
  509. Catch ex As Exception
  510. Log(ex, "可视化安装版本列表出错", NotifyLevel.MsgBoxAndFeedback)
  511. End Try
  512. End Sub
  513. ''' <summary>
  514. ''' 当 MC 版本列表加载完时,立即自动选择的版本。用于外部调用。
  515. ''' </summary>
  516. Public Shared VersionWaitingSelect As String = Nothing
  517. #End Region
  518. #Region "OptiFine 列表"
  519. ''' <summary>
  520. ''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
  521. ''' </summary>
  522. Private Function LoadOptiFineGetError() As String
  523. If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
  524. '检查 Forge 1.13 - 1.14.3:全部不兼容
  525. If SelectedForge IsNot Nothing AndAlso
  526. CompareVersion(VanillaName, "1.13") >= 0 AndAlso CompareVersion("1.14.3", VanillaName) >= 0 Then
  527. Return "与 Forge 不兼容"
  528. End If
  529. '检查 Fabric 1.20.5+:全部不兼容
  530. If SelectedFabric IsNot Nothing AndAlso
  531. CompareVersion(VanillaName, "1.20.4") > 0 Then
  532. Return "与 Fabric 不兼容"
  533. End If
  534. '检查 Loader
  535. If GetLoaderError(LoadOptiFine) IsNot Nothing Then Return GetLoaderError(LoadOptiFine)
  536. '检查 Forge 版本
  537. Dim HasAny As Boolean = False
  538. Dim HasRequiredVersion As Boolean = False
  539. For Each OptiFineVersion As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
  540. If Not OptiFineVersion.DisplayName.StartsWithF(VanillaName & " ") Then Continue For '不是同一个大版本
  541. HasAny = True
  542. If SelectedForge Is Nothing Then Return Nothing '未选择 Forge
  543. If IsOptiFineSuitForForge(OptiFineVersion, SelectedForge) Then Return Nothing '该版本可用
  544. If OptiFineVersion.RequiredForgeVersion IsNot Nothing Then HasRequiredVersion = True
  545. Next
  546. If Not HasAny Then
  547. Return "无"
  548. ElseIf HasRequiredVersion Then
  549. Return "仅兼容特定版本的 Forge"
  550. Else
  551. Return "与 Forge 不兼容"
  552. End If
  553. End Function
  554. '检查某个 OptiFine 是否与某个 Forge 兼容
  555. Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
  556. If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
  557. If OptiFine.RequiredForgeVersion Is Nothing Then Return False '不兼容 Forge
  558. If String.IsNullOrWhiteSpace(OptiFine.RequiredForgeVersion) Then Return True '#4183
  559. If OptiFine.RequiredForgeVersion.Contains(".") Then 'XX.X.XXX
  560. Return CompareVersion(Forge.Version.ToString, OptiFine.RequiredForgeVersion) = 0
  561. Else 'XXXX
  562. Return Forge.Version.Revision = OptiFine.RequiredForgeVersion
  563. End If
  564. End Function
  565. '限制展开
  566. Private Sub CardOptiFine_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardOptiFine.PreviewSwap
  567. If LoadOptiFineGetError() IsNot Nothing Then e.Handled = True
  568. End Sub
  569. ''' <summary>
  570. ''' 尝试重新可视化 OptiFine 版本列表。
  571. ''' </summary>
  572. Private Sub OptiFine_Loaded() Handles LoadOptiFine.StateChanged
  573. Try
  574. If DlOptiFineListLoader.State <> LoadState.Finished Then Return
  575. '获取版本列表
  576. Dim Versions As New List(Of DlOptiFineListEntry)
  577. For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
  578. If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(Version, SelectedForge) Then Continue For
  579. If Version.DisplayName.StartsWithF(VanillaName & " ") Then Versions.Add(Version)
  580. Next
  581. If Not Versions.Any() Then Return
  582. '排序
  583. Versions = Versions.SortByComparison(
  584. Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
  585. If Not Left.IsPreview AndAlso Right.IsPreview Then Return True
  586. If Left.IsPreview AndAlso Not Right.IsPreview Then Return False
  587. Return CompareVersionGE(Left.DisplayName, Right.DisplayName)
  588. End Function)
  589. '可视化
  590. PanOptiFine.Children.Clear()
  591. For Each Version In Versions
  592. PanOptiFine.Children.Add(OptiFineDownloadListItem(Version, AddressOf OptiFine_Selected, False))
  593. Next
  594. Catch ex As Exception
  595. Log(ex, "可视化 OptiFine 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback)
  596. End Try
  597. End Sub
  598. '选择与清除
  599. Private Sub OptiFine_Selected(sender As MyListItem, e As EventArgs)
  600. SelectedOptiFine = sender.Tag
  601. If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedForge = Nothing
  602. OptiFabric_Loaded()
  603. Forge_Loaded()
  604. NeoForge_Loaded()
  605. CardOptiFine.IsSwapped = True
  606. ReloadSelected()
  607. End Sub
  608. Private Sub OptiFine_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFineClear.MouseLeftButtonUp
  609. SelectedOptiFine = Nothing
  610. SelectedOptiFabric = Nothing
  611. AutoSelectedOptiFabric = False
  612. CardOptiFine.IsSwapped = True
  613. e.Handled = True
  614. Forge_Loaded()
  615. NeoForge_Loaded()
  616. ReloadSelected()
  617. End Sub
  618. #End Region
  619. #Region "LiteLoader 列表"
  620. ''' <summary>
  621. ''' 获取 LiteLoader 的加载异常信息。若正常则返回 Nothing。
  622. ''' </summary>
  623. Private Function LoadLiteLoaderGetError() As String
  624. '检查 Loader
  625. If GetLoaderError(LoadLiteLoader) IsNot Nothing Then Return GetLoaderError(LoadLiteLoader)
  626. '检查版本
  627. Return If(DlLiteLoaderListLoader.Output.Value.Any(Function(v) v.Inherit = VanillaName), Nothing, "无")
  628. End Function
  629. '限制展开
  630. Private Sub CardLiteLoader_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardLiteLoader.PreviewSwap
  631. If LoadLiteLoaderGetError() IsNot Nothing Then e.Handled = True
  632. End Sub
  633. ''' <summary>
  634. ''' 尝试重新可视化 LiteLoader 版本列表。
  635. ''' </summary>
  636. Private Sub LiteLoader_Loaded() Handles LoadLiteLoader.StateChanged
  637. Try
  638. If DlLiteLoaderListLoader.State <> LoadState.Finished Then Return
  639. '获取版本列表
  640. Dim Versions As New List(Of DlLiteLoaderListEntry)
  641. For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
  642. If Version.Inherit = VanillaName Then Versions.Add(Version)
  643. Next
  644. If Not Versions.Any() Then Return
  645. '可视化
  646. PanLiteLoader.Children.Clear()
  647. For Each Version In Versions
  648. PanLiteLoader.Children.Add(LiteLoaderDownloadListItem(Version, AddressOf LiteLoader_Selected, False))
  649. Next
  650. Catch ex As Exception
  651. Log(ex, "可视化 LiteLoader 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback)
  652. End Try
  653. End Sub
  654. '选择与清除
  655. Private Sub LiteLoader_Selected(sender As MyListItem, e As EventArgs)
  656. SelectedLiteLoader = sender.Tag
  657. CardLiteLoader.IsSwapped = True
  658. ReloadSelected()
  659. End Sub
  660. Private Sub LiteLoader_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnLiteLoaderClear.MouseLeftButtonUp
  661. SelectedLiteLoader = Nothing
  662. CardLiteLoader.IsSwapped = True
  663. e.Handled = True
  664. ReloadSelected()
  665. End Sub
  666. #End Region
  667. #Region "Forge 列表"
  668. ''' <summary>
  669. ''' 获取 Forge 的加载异常信息。若正常则返回 Nothing。
  670. ''' </summary>
  671. Private Function LoadForgeGetError() As String
  672. If CompareVersionGE("1.5.1", VanillaName) AndAlso CompareVersionGE(VanillaName, "1.1") Then Return "无"
  673. '检查 Loader
  674. If GetLoaderError(LoadForge) IsNot Nothing Then Return GetLoaderError(LoadForge)
  675. Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
  676. If VanillaName <> Loader.Input Then Return "获取中……"
  677. '检查版本
  678. For Each Version In Loader.Output
  679. If Version.Category = "universal" OrElse Version.Category = "client" Then Continue For '跳过无法自动安装的版本
  680. If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
  681. If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
  682. If SelectedOptiFine IsNot Nothing AndAlso
  683. CompareVersionGE(VanillaName, "1.13") AndAlso CompareVersionGE("1.14.3", VanillaName) Then
  684. Return "与 OptiFine 不兼容" '1.13 ~ 1.14.3 OptiFine 检查
  685. End If
  686. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, Version) Then Continue For
  687. Return Nothing
  688. Next
  689. Return "与 OptiFine 不兼容"
  690. End Function
  691. '限制展开
  692. Private Sub CardForge_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardForge.PreviewSwap
  693. If LoadForgeGetError() IsNot Nothing Then e.Handled = True
  694. End Sub
  695. ''' <summary>
  696. ''' 尝试重新可视化 Forge 版本列表。
  697. ''' </summary>
  698. Private Sub Forge_Loaded() Handles LoadForge.StateChanged
  699. Try
  700. If Not LoadForge.State.IsLoader Then Return
  701. Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
  702. If VanillaName <> Loader.Input Then Return
  703. If Loader.State <> LoadState.Finished Then Return
  704. '获取要显示的版本
  705. Dim Versions = Loader.Output.ToList '复制数组,以免 Output 在实例化后变空
  706. If Not Loader.Output.Any() Then Return
  707. PanForge.Children.Clear()
  708. Versions = Versions.Where(
  709. Function(v)
  710. If v.Category = "universal" OrElse v.Category = "client" Then Return False '跳过无法自动安装的版本
  711. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, v) Then Return False
  712. Return True
  713. End Function).OrderByDescending(Function(v) v).ToList()
  714. ForgeDownloadListItemPreload(PanForge, Versions, AddressOf Forge_Selected, False)
  715. For Each Version In Versions
  716. PanForge.Children.Add(ForgeDownloadListItem(Version, AddressOf Forge_Selected, False))
  717. Next
  718. Catch ex As Exception
  719. Log(ex, "可视化 Forge 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback)
  720. End Try
  721. End Sub
  722. '选择与清除
  723. Private Sub Forge_Selected(sender As MyListItem, e As EventArgs)
  724. SelectedForge = sender.Tag
  725. CardForge.IsSwapped = True
  726. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedOptiFine = Nothing
  727. OptiFine_Loaded()
  728. ReloadSelected()
  729. End Sub
  730. Private Sub Forge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnForgeClear.MouseLeftButtonUp
  731. SelectedForge = Nothing
  732. CardForge.IsSwapped = True
  733. e.Handled = True
  734. OptiFine_Loaded()
  735. ReloadSelected()
  736. End Sub
  737. #End Region
  738. #Region "NeoForge 列表"
  739. ''' <summary>
  740. ''' 获取 NeoForge 的加载异常信息。若正常则返回 Nothing。
  741. ''' </summary>
  742. Private Function LoadNeoForgeGetError() As String
  743. If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
  744. If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
  745. If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
  746. '检查 Loader
  747. If GetLoaderError(LoadNeoForge) IsNot Nothing Then Return GetLoaderError(LoadNeoForge)
  748. '检查版本
  749. Return If(DlNeoForgeListLoader.Output.Value.Any(Function(v) v.Inherit = VanillaName), Nothing, "无")
  750. End Function
  751. '限制展开
  752. Private Sub CardNeoForge_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardNeoForge.PreviewSwap
  753. If LoadNeoForgeGetError() IsNot Nothing Then e.Handled = True
  754. End Sub
  755. ''' <summary>
  756. ''' 尝试重新可视化 NeoForge 版本列表。
  757. ''' </summary>
  758. Private Sub NeoForge_Loaded() Handles LoadNeoForge.StateChanged
  759. Try
  760. '获取版本列表
  761. If DlNeoForgeListLoader.State <> LoadState.Finished Then Return
  762. Dim Versions = DlNeoForgeListLoader.Output.Value.Where(Function(v) v.Inherit = VanillaName).ToList
  763. If Not Versions.Any() Then Return
  764. '可视化
  765. PanNeoForge.Children.Clear()
  766. NeoForgeDownloadListItemPreload(PanNeoForge, Versions, AddressOf NeoForge_Selected, False)
  767. For Each Version In Versions
  768. PanNeoForge.Children.Add(NeoForgeDownloadListItem(Version, AddressOf NeoForge_Selected, False))
  769. Next
  770. Catch ex As Exception
  771. Log(ex, "可视化 NeoForge 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback)
  772. End Try
  773. End Sub
  774. '选择与清除
  775. Private Sub NeoForge_Selected(sender As MyListItem, e As EventArgs)
  776. SelectedNeoForge = sender.Tag
  777. CardNeoForge.IsSwapped = True
  778. OptiFine_Loaded()
  779. ReloadSelected()
  780. End Sub
  781. Private Sub NeoForge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnNeoForgeClear.MouseLeftButtonUp
  782. SelectedNeoForge = Nothing
  783. CardNeoForge.IsSwapped = True
  784. e.Handled = True
  785. OptiFine_Loaded()
  786. ReloadSelected()
  787. End Sub
  788. #End Region
  789. #Region "Fabric 列表"
  790. ''' <summary>
  791. ''' 获取 Fabric 的加载异常信息。若正常则返回 Nothing。
  792. ''' </summary>
  793. Private Function LoadFabricGetError() As String
  794. '检查 OptiFine 1.20.5+:没有 OptiFabric 故全部不兼容
  795. If SelectedOptiFine IsNot Nothing AndAlso CompareVersionGE(VanillaName, "1.20.5") Then Return "与 OptiFine 不兼容"
  796. '检查 Loader
  797. If GetLoaderError(LoadFabric) IsNot Nothing Then Return GetLoaderError(LoadFabric)
  798. '检查版本
  799. For Each Version As JObject In DlFabricListLoader.Output.Value("game")
  800. If Version("version").ToString = VanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") Then
  801. If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
  802. If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
  803. Return Nothing
  804. End If
  805. Next
  806. Return "无"
  807. End Function
  808. '限制展开
  809. Private Sub CardFabric_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardFabric.PreviewSwap
  810. If LoadFabricGetError() IsNot Nothing Then e.Handled = True
  811. End Sub
  812. ''' <summary>
  813. ''' 尝试重新可视化 Fabric 版本列表。
  814. ''' </summary>
  815. Private Sub Fabric_Loaded() Handles LoadFabric.StateChanged
  816. Try
  817. If DlFabricListLoader.State <> LoadState.Finished Then Return
  818. '获取版本列表
  819. Dim Versions As JArray = DlFabricListLoader.Output.Value("loader")
  820. If Not Versions.Any() Then Return
  821. '可视化
  822. PanFabric.Children.Clear()
  823. PanFabric.Tag = Versions
  824. CardFabric.SwapControl = PanFabric
  825. CardFabric.SwapType = 12
  826. Catch ex As Exception
  827. Log(ex, "可视化 Fabric 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback)
  828. End Try
  829. End Sub
  830. '选择与清除
  831. Public Sub Fabric_Selected(sender As MyListItem, e As EventArgs)
  832. SelectedFabric = sender.Tag("version").ToString
  833. FabricApi_Loaded()
  834. OptiFabric_Loaded()
  835. CardFabric.IsSwapped = True
  836. ReloadSelected()
  837. End Sub
  838. Private Sub Fabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricClear.MouseLeftButtonUp
  839. SelectedFabric = Nothing
  840. SelectedFabricApi = Nothing
  841. AutoSelectedFabricApi = False
  842. SelectedOptiFabric = Nothing
  843. AutoSelectedOptiFabric = False
  844. CardFabric.IsSwapped = True
  845. e.Handled = True
  846. ReloadSelected()
  847. End Sub
  848. #End Region
  849. #Region "Fabric API 列表"
  850. ''' <summary>
  851. ''' 判断某 Fabric API 是否适配当前选择的原版版本。
  852. ''' </summary>
  853. Public Function IsFabricApiCompatible(FabricApi As ResourceVersion) As Boolean
  854. Dim FabricApiName = FabricApi.Display
  855. Try
  856. If FabricApiName Is Nothing OrElse VanillaName Is Nothing Then Return False
  857. FabricApiName = FabricApiName.Lower
  858. Dim TargetName = VanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").Lower
  859. If FabricApiName.StartsWithF("[" & TargetName & "]") Then Return True
  860. If Not FabricApiName.Contains("/") OrElse Not FabricApiName.Contains("]") Then Return False
  861. '直接的判断(例如 1.18.1/22w03a)
  862. For Each Part As String In FabricApiName.BeforeFirst("]").TrimStart("[").Split("/")
  863. If Part = TargetName Then Return True
  864. Next
  865. '将版本名分割语素(例如 1.16.4/5)
  866. Dim Lefts = RegexSearch(FabricApiName.BeforeFirst("]"), "[a-z/]+|[0-9/]+")
  867. Dim Rights = RegexSearch(TargetName.BeforeFirst("]"), "[a-z/]+|[0-9/]+")
  868. '对每段进行判断
  869. Dim i As Integer = 0
  870. While True
  871. '两边均缺失,感觉是一个东西
  872. If Lefts.Count - 1 < i AndAlso Rights.Count - 1 < i Then Return True
  873. '确定两边是否一致
  874. Dim LeftValue As String = If(Lefts.Count - 1 < i, "-1", Lefts(i))
  875. Dim RightValue As String = If(Rights.Count - 1 < i, "-1", Rights(i))
  876. If Not LeftValue.Contains("/") Then
  877. If LeftValue <> RightValue Then Return False
  878. Else
  879. '左边存在斜杠
  880. If Not LeftValue.Contains(RightValue) Then Return False
  881. End If
  882. i += 1
  883. End While
  884. Return True
  885. Catch ex As Exception
  886. Log(ex, "判断 Fabric API 版本适配性出错(" & FabricApiName & ", " & VanillaName & ")")
  887. Return False
  888. End Try
  889. End Function
  890. ''' <summary>
  891. ''' 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
  892. ''' </summary>
  893. Private Function LoadFabricApiGetError() As String
  894. '检查 Loader
  895. If GetLoaderError(LoadFabricApi) IsNot Nothing Then Return GetLoaderError(LoadFabricApi)
  896. If DlFabricApiLoader.Output Is Nothing Then Return If(SelectedFabric Is Nothing, "需要安装 Fabric", "获取中……")
  897. '检查版本
  898. If DlFabricApiLoader.Output.Any(Function(f) IsFabricApiCompatible(f)) Then
  899. Return If(SelectedFabric Is Nothing, "需要安装 Fabric", Nothing)
  900. Else
  901. Return "无"
  902. End If
  903. End Function
  904. '限制展开
  905. Private Sub CardFabricApi_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardFabricApi.PreviewSwap
  906. If LoadFabricApiGetError() IsNot Nothing Then e.Handled = True
  907. End Sub
  908. Private AutoSelectedFabricApi As Boolean = False
  909. ''' <summary>
  910. ''' 尝试重新可视化 FabricApi 版本列表。
  911. ''' </summary>
  912. Private Sub FabricApi_Loaded() Handles LoadFabricApi.StateChanged
  913. Try
  914. If DlFabricApiLoader.State <> LoadState.Finished Then Return
  915. If VanillaName Is Nothing OrElse SelectedFabric Is Nothing Then Return
  916. '获取版本列表
  917. Dim Versions As New List(Of ResourceVersion)
  918. For Each Version In DlFabricApiLoader.Output
  919. If IsFabricApiCompatible(Version) Then
  920. If Not Version.Display.StartsWithF("[") Then
  921. Log("[Download] 已特判修改 Fabric API 显示名:" & Version.Display, NotifyLevel.DebugModeOnly)
  922. Version.Display = "[" & VanillaName & "] " & Version.Display
  923. End If
  924. Versions.Add(Version)
  925. End If
  926. Next
  927. If Not Versions.Any() Then Return
  928. Versions = Versions.OrderByDescending(Function(v) v.ReleaseDate).ToList
  929. '可视化
  930. PanFabricApi.Children.Clear()
  931. For Each Version In Versions
  932. If Not IsFabricApiCompatible(Version) Then Continue For
  933. PanFabricApi.Children.Add(FabricApiDownloadListItem(Version, AddressOf FabricApi_Selected))
  934. Next
  935. '自动选择 Fabric API
  936. If Not AutoSelectedFabricApi Then
  937. AutoSelectedFabricApi = True
  938. Dim Item As MyListItem = MyVirtualizingElement.TryInit(PanFabricApi.Children(0))
  939. Log($"[Download] 已自动选择 Fabric API:{Item.Title}")
  940. FabricApi_Selected(Item, Nothing)
  941. End If
  942. Catch ex As Exception
  943. Log(ex, "可视化 Fabric API 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback)
  944. End Try
  945. End Sub
  946. '选择与清除
  947. Private Sub FabricApi_Selected(sender As MyListItem, e As EventArgs)
  948. SelectedFabricApi = sender.Tag
  949. CardFabricApi.IsSwapped = True
  950. ReloadSelected()
  951. End Sub
  952. Private Sub FabricApi_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricApiClear.MouseLeftButtonUp
  953. SelectedFabricApi = Nothing
  954. CardFabricApi.IsSwapped = True
  955. e.Handled = True
  956. ReloadSelected()
  957. End Sub
  958. #End Region
  959. #Region "OptiFabric 列表"
  960. ''' <summary>
  961. ''' 判断某 OptiFabric 是否适配当前选择的原版版本。
  962. ''' </summary>
  963. Private Function IsOptiFabricCompatible(ModFile As ResourceVersion) As Boolean
  964. Try
  965. If VanillaName Is Nothing Then Return False
  966. Return ModFile.GameVersions.Contains(VanillaName)
  967. Catch ex As Exception
  968. Log(ex, "判断 OptiFabric 版本适配性出错(" & VanillaName & ")")
  969. Return False
  970. End Try
  971. End Function
  972. Private AutoSelectedOptiFabric As Boolean = False
  973. ''' <summary>
  974. ''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
  975. ''' </summary>
  976. Private Function LoadOptiFabricGetError() As String
  977. If VanillaDrop >= 140 AndAlso VanillaDrop <= 150 Then Return "不兼容老版本 Fabric,请手动下载 OptiFabric Origins"
  978. '检查 Loader
  979. If GetLoaderError(LoadOptiFabric) IsNot Nothing Then Return GetLoaderError(LoadOptiFabric)
  980. '检查版本
  981. If DlOptiFabricLoader.Output Is Nothing Then
  982. If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
  983. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  984. If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
  985. Return "获取中……"
  986. End If
  987. For Each Version In DlOptiFabricLoader.Output
  988. If Not IsOptiFabricCompatible(Version) Then Continue For '2135#
  989. If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
  990. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  991. If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
  992. Return Nothing '通过检查
  993. Next
  994. Return "无"
  995. End Function
  996. '限制展开
  997. Private Sub CardOptiFabric_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardOptiFabric.PreviewSwap
  998. If LoadOptiFabricGetError() IsNot Nothing Then e.Handled = True
  999. End Sub
  1000. ''' <summary>
  1001. ''' 尝试重新可视化 OptiFabric 版本列表。
  1002. ''' </summary>
  1003. Private Sub OptiFabric_Loaded() Handles LoadOptiFabric.StateChanged
  1004. Try
  1005. If DlOptiFabricLoader.State <> LoadState.Finished Then Return
  1006. If VanillaName Is Nothing OrElse SelectedFabric Is Nothing OrElse SelectedOptiFine Is Nothing Then Return
  1007. '获取版本列表
  1008. Dim Versions As New List(Of ResourceVersion)
  1009. For Each Version In DlOptiFabricLoader.Output
  1010. If IsOptiFabricCompatible(Version) Then Versions.Add(Version)
  1011. Next
  1012. If Not Versions.Any() Then Return
  1013. '排序
  1014. Versions = Versions.OrderByDescending(Function(v) v.ReleaseDate).ToList
  1015. '可视化
  1016. PanOptiFabric.Children.Clear()
  1017. For Each Version In Versions
  1018. If Not IsOptiFabricCompatible(Version) Then Continue For
  1019. PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
  1020. Next
  1021. '自动选择 OptiFabric
  1022. If AutoSelectedOptiFabric OrElse VanillaDrop >= 140 AndAlso VanillaDrop <= 150 Then Return '1.14~15 不自动选择
  1023. AutoSelectedOptiFabric = True
  1024. Dim Item As MyListItem = MyVirtualizingElement.TryInit(PanOptiFabric.Children(0))
  1025. Log($"[Download] 已自动选择 OptiFabric:{Item.Title}")
  1026. OptiFabric_Selected(Item, Nothing)
  1027. Catch ex As Exception
  1028. Log(ex, "可视化 OptiFabric 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback)
  1029. End Try
  1030. End Sub
  1031. '选择与清除
  1032. Private Sub OptiFabric_Selected(sender As MyListItem, e As EventArgs)
  1033. SelectedOptiFabric = sender.Tag
  1034. CardOptiFabric.IsSwapped = True
  1035. ReloadSelected()
  1036. End Sub
  1037. Private Sub OptiFabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFabricClear.MouseLeftButtonUp
  1038. SelectedOptiFabric = Nothing
  1039. CardOptiFabric.IsSwapped = True
  1040. e.Handled = True
  1041. ReloadSelected()
  1042. End Sub
  1043. #End Region
  1044. #Region "安装"
  1045. Private Sub TextSelectName_KeyDown(sender As Object, e As KeyEventArgs) Handles TextSelectName.KeyDown
  1046. If e.Key = Key.Enter AndAlso BtnStart.IsEnabled Then BtnStart_Click()
  1047. End Sub
  1048. Private Sub BtnStart_Click() Handles BtnStart.Click
  1049. '确认版本隔离
  1050. If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
  1051. (Settings.Get("LaunchArgumentIndieV2") = 0 OrElse Settings.Get("LaunchArgumentIndieV2") = 2) Then
  1052. If MyMsgBox("你尚未开启版本隔离,多个 MC 版本会共用同一个 Mod 文件夹。" & vbCrLf &
  1053. "因此,游戏可能会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
  1054. "推荐先在 设置 → 启动选项 → 默认版本隔离 中开启版本隔离!", "版本隔离提示", "取消下载", "继续") = 1 Then
  1055. Return
  1056. End If
  1057. End If
  1058. '提交安装申请
  1059. Dim InstanceName As String = TextSelectName.Text
  1060. Dim Request As New McInstallRequest With {
  1061. .NewInstanceName = InstanceName,
  1062. .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\",
  1063. .MinecraftJson = VanillaData("url").ToString,
  1064. .MinecraftName = VanillaName,
  1065. .OptiFineEntry = SelectedOptiFine,
  1066. .ForgeEntry = SelectedForge,
  1067. .NeoForgeEntry = SelectedNeoForge,
  1068. .FabricVersion = SelectedFabric,
  1069. .FabricApi = SelectedFabricApi,
  1070. .OptiFabric = SelectedOptiFabric,
  1071. .LiteLoaderEntry = SelectedLiteLoader
  1072. }
  1073. If Not McInstall(Request) Then Return
  1074. '返回,这样在再次进入安装页面时这个版本就会显示文件夹已重复
  1075. ExitSelectPage()
  1076. End Sub
  1077. #End Region
  1078. Private Function GetLoaderError(Loader As MyLoading) As String
  1079. If Loader Is Nothing Then Return "获取中……"
  1080. If Not Loader.State.IsLoader Then Return "获取中……"
  1081. Select Case Loader.State.LoadingState
  1082. Case MyLoading.MyLoadingState.Run
  1083. Return "获取中……"
  1084. Case MyLoading.MyLoadingState.Error
  1085. Dim Message As String = CType(Loader.State, LoaderBase).Error.Message
  1086. Return If(Message = "无", "无", "获取失败:" & Message)
  1087. Case MyLoading.MyLoadingState.Unloaded
  1088. Return "未知错误,状态为 Unloaded"
  1089. Case Else
  1090. Return Nothing
  1091. End Select
  1092. End Function
  1093. End Class