PageDownloadCompDetail.xaml.vb 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. Imports System.Collections.ObjectModel
  2. Public Class PageDownloadResourceDetail
  3. Private ResourceItem As MyResourceItem = Nothing
  4. ''' <summary>
  5. ''' 当前页面应展示的内容类别。
  6. ''' 若当前页面是在查看前置时进入,则为 Any;这也能用于指示当前是否在查看前置。
  7. ''' </summary>
  8. Private TargetResourceType As ResourceTypes
  9. Private Project As ResourceProject
  10. Private TargetVersion As String
  11. Private TargetLoaders As ModLoaders
  12. Public Sub LoadPageArguments() Handles Me.Loaded
  13. Project = FrmMain.PageCurrent.Additional(0)
  14. TargetVersion = FrmMain.PageCurrent.Additional(2)
  15. TargetLoaders = CType(FrmMain.PageCurrent.Additional(3), ModLoaders)
  16. If TargetLoaders <> ModLoaders.None AndAlso Not TargetLoaders.Flags.IsSingle Then TargetLoaders = TargetLoaders.Flags.First() '强制取第一个
  17. TargetResourceType = FrmMain.PageCurrent.Additional(4)
  18. End Sub
  19. #Region "加载器"
  20. Private ResourceFileLoader As New LoaderTask(Of Integer, List(Of ResourceVersion))(
  21. "Resource File",
  22. Sub(Task)
  23. LoadPageArguments()
  24. Dim Result = ResourceVersion.FromProjectId(Project.Id, Project.Platform)
  25. If Task.IsCanceled Then Return
  26. Task.Output = Result
  27. End Sub)
  28. '初始化加载器信息
  29. Private Sub PageDownloadResourceDetail_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
  30. LoadPageArguments()
  31. PageLoaderInit(Load, PanLoad, PanMain, CardIntro, ResourceFileLoader, AddressOf Load_OnFinish)
  32. End Sub
  33. '自动重试
  34. Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
  35. Select Case ResourceFileLoader.State
  36. Case LoadState.Failed
  37. Dim ErrorMessage As String = ""
  38. If ResourceFileLoader.Error IsNot Nothing Then ErrorMessage = ResourceFileLoader.Error.Message
  39. If ErrorMessage.Contains("不是有效的 json 文件") Then
  40. Logger.Warn("下载的文件 json 列表损坏,已自动重试")
  41. PageLoaderRestart()
  42. End If
  43. End Select
  44. End Sub
  45. '结果 UI 化
  46. Private Class CardSorter
  47. Implements IComparer(Of String)
  48. Public Topmost As String = ""
  49. Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
  50. '相同
  51. If x = y Then Return 0
  52. '置顶
  53. If x = Topmost Then Return -1
  54. If y = Topmost Then Return 1
  55. '特殊版本
  56. Dim IsXSpecial As Boolean = Not x.Contains(".")
  57. Dim IsYSpecial As Boolean = Not y.Contains(".")
  58. If IsXSpecial AndAlso IsYSpecial Then Return x.CompareTo(y)
  59. If IsXSpecial Then Return 1
  60. If IsYSpecial Then Return -1
  61. '比较版本号
  62. Dim VersionCodeSort = -McUtils.CompareVersion(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", ""))
  63. If VersionCodeSort <> 0 Then Return VersionCodeSort
  64. '比较全部
  65. Return -McUtils.CompareVersion(x, y)
  66. End Function
  67. Public Sub New(Optional Topmost As String = "")
  68. Me.Topmost = If(Topmost, "")
  69. End Sub
  70. End Class
  71. Private VersionFilter As String
  72. Private GroupedDrop As Boolean '是否按 Drop 筛选(1.21 / 1.20 / 1.19 / ...)而非小版本号(1.21.1 / 1.21 / 1.20.4 / ...)
  73. Private GroupedOld As Boolean '是否折叠远古版本为一个选项
  74. '筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表)
  75. Private Function GetResults() As List(Of ResourceVersion)
  76. Dim Results As List(Of ResourceVersion) = ResourceFileLoader.Output
  77. Select Case TargetResourceType
  78. Case ResourceTypes.Any
  79. Results = Results.Where(Function(r) r.ResourceType <> ResourceTypes.Plugin).ToList
  80. Case ResourceTypes.Shader, ResourceTypes.ResourcePack
  81. '不筛选光影和资源包,否则原版光影会因为是资源包格式而被过滤(#6473)
  82. Case Else
  83. Results = Results.Where(Function(r) r.ResourceType = TargetResourceType).ToList
  84. End Select
  85. Return Results
  86. End Function
  87. Private Sub Load_OnFinish()
  88. Dim Results = GetResults()
  89. '初始化筛选器
  90. Dim Filters As List(Of String) = Nothing
  91. Dim UpdateFilters =
  92. Sub()
  93. Filters = Results.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, GroupedDrop, GroupedOld)).
  94. Distinct.OrderByDescending(Function(s) s, Comparer(Of String).Create(Function(x, y) McUtils.CompareVersion(x, y))).ToList
  95. End Sub
  96. '确定分组方式
  97. GroupedDrop = False : GroupedOld = False
  98. UpdateFilters()
  99. If Filters.Count < 9 Then GoTo GroupDone
  100. GroupedDrop = True : GroupedOld = False
  101. UpdateFilters()
  102. If Filters.Count < 9 Then GoTo GroupDone
  103. GroupedDrop = False : GroupedOld = True
  104. UpdateFilters()
  105. If Filters.Count < 9 Then GoTo GroupDone
  106. GroupedDrop = True : GroupedOld = True
  107. UpdateFilters()
  108. GroupDone:
  109. 'UI 化筛选器
  110. PanFilter.Children.Clear()
  111. If Filters.Count < 2 Then
  112. CardFilter.Visibility = Visibility.Collapsed
  113. VersionFilter = Nothing
  114. Else
  115. CardFilter.Visibility = Visibility.Visible
  116. Filters.Insert(0, "全部")
  117. '转化为按钮
  118. For Each Version As String In Filters
  119. Dim NewButton As New MyRadioButton With {
  120. .Text = Version, .Margin = New Thickness(2, 0, 2, 0), .ColorType = MyRadioButton.ColorState.Highlight}
  121. NewButton.LabText.Margin = New Thickness(-2, 0, 10, 0)
  122. AddHandler NewButton.Check,
  123. Sub(sender As MyRadioButton, raiseByMouse As Boolean)
  124. VersionFilter = If(sender.Text = "全部", Nothing, sender.Text)
  125. UpdateFilterResult()
  126. End Sub
  127. PanFilter.Children.Add(NewButton)
  128. Next
  129. '自动选择
  130. Dim ToCheck As MyRadioButton = Nothing
  131. If TargetVersion <> "" Then
  132. Dim TargetFile = Results.FirstOrDefault(Function(v) v.GameVersions.Contains(TargetVersion))
  133. If TargetFile IsNot Nothing Then
  134. Dim TargetGroup = GetGroupedVersionName(TargetVersion, GroupedDrop, GroupedOld)
  135. For Each Button As MyRadioButton In PanFilter.Children
  136. If Button.Text <> TargetGroup Then Continue For
  137. ToCheck = Button
  138. Exit For
  139. Next
  140. End If
  141. End If
  142. If ToCheck Is Nothing Then ToCheck = PanFilter.Children(0)
  143. ToCheck.Checked = True
  144. End If
  145. '更新筛选结果(文件列表 UI 化)
  146. UpdateFilterResult()
  147. End Sub
  148. Private Sub UpdateFilterResult()
  149. Dim Results = GetResults()
  150. Dim TargetCardName As String = If(TargetVersion <> "" OrElse TargetLoaders <> ModLoaders.None,
  151. $"{If(TargetLoaders <> ModLoaders.None, TargetLoaders.ToString + " ", "")}{TargetVersion}(所选版本)", "")
  152. '归类到卡片下
  153. Dim Dict As New SortedDictionary(Of String, List(Of ResourceVersion))(New CardSorter(TargetCardName))
  154. Dict.Add("其他", New List(Of ResourceVersion))
  155. For Each Version As ResourceVersion In Results
  156. For Each GameVersion In Version.GameVersions
  157. '检查是否符合版本筛选器
  158. If VersionFilter IsNot Nothing AndAlso
  159. GetGroupedVersionName(GameVersion, GroupedDrop, GroupedOld) <> VersionFilter Then Continue For
  160. '决定添加到哪个卡片
  161. Dim VerName As String = GetGroupedVersionName(GameVersion, False, False)
  162. '遍历加入的加载器列表
  163. Dim Loaders As New List(Of String)
  164. If Project.ModLoaders.Flags.Count > 1 AndAlso '工程至少有两个加载器
  165. Version.ResourceType = ResourceTypes.Mod AndAlso '是 Mod
  166. McVersion.IsStandardFormat(VerName) Then '不是 “快照版本” 之类的
  167. Loaders.AddRange(Version.ModLoaders.Flags.Select(Function(f) f.ToString & " "))
  168. End If
  169. If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
  170. '实际添加
  171. For Each Loader In Loaders
  172. Dim TargetCard As String = Loader & VerName
  173. If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of ResourceVersion))
  174. If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
  175. Next
  176. Next
  177. Next
  178. '添加筛选的版本的卡片
  179. If TargetCardName <> "" AndAlso (VersionFilter Is Nothing OrElse GetGroupedVersionName(TargetVersion, GroupedDrop, GroupedOld).StartsWithF(VersionFilter)) Then
  180. Dict.Add(TargetCardName, New List(Of ResourceVersion))
  181. For Each Version As ResourceVersion In Results
  182. If Version.GameVersions.Contains(TargetVersion) AndAlso
  183. (TargetLoaders = ModLoaders.None OrElse TargetLoaders.Flags.Intersect(Version.ModLoaders.Flags).Any) Then
  184. '检查是否符合版本筛选器
  185. If VersionFilter IsNot Nothing AndAlso
  186. Not Version.GameVersions.Any(Function(v) GetGroupedVersionName(v, GroupedDrop, GroupedOld) = VersionFilter) Then Continue For
  187. If Not Dict(TargetCardName).Contains(Version) Then Dict(TargetCardName).Add(Version)
  188. End If
  189. Next
  190. End If
  191. '转化为 UI
  192. Try
  193. PanResults.Children.Clear()
  194. For Each Pair As KeyValuePair(Of String, List(Of ResourceVersion)) In Dict
  195. If Not Pair.Value.Any() Then Continue For
  196. If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For
  197. '增加卡片
  198. Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15)}
  199. 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}
  200. NewCard.Children.Add(NewStack)
  201. NewCard.SwapControl = NewStack
  202. NewCard.SetContentBuilder(AddressOf InitializeStackResourceVersions)
  203. PanResults.Children.Add(NewCard)
  204. '确定卡片是否默认展开
  205. If Pair.Key = TargetCardName OrElse
  206. (FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
  207. CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then
  208. NewCard.BuildContent()
  209. Else
  210. NewCard.IsSwapped = True
  211. End If
  212. '增加提示
  213. If Pair.Key = "其他" Then
  214. NewStack.Children.Add(New MyHint With {.Text = "由于版本信息更新缓慢,可能无法识别刚更新的 MC 版本。几天后即可正常识别。", .Theme = MyHint.Themes.Yellow, .Margin = New Thickness(5, 0, 0, 8)})
  215. End If
  216. Next
  217. '如果只有一张卡片,展开第一张卡片
  218. If PanResults.Children.Count = 1 Then
  219. CType(PanResults.Children(0), MyCard).IsSwapped = False
  220. End If
  221. '替代提示
  222. If Project.Types = ResourceTypes.ModOrDataPack AndAlso (TargetResourceType = ResourceTypes.Mod OrElse TargetResourceType = ResourceTypes.DataPack) Then
  223. HintAlternative.Visibility = Visibility.Visible
  224. HintAlternative.Text = If(TargetResourceType = ResourceTypes.Mod,
  225. "以下是该项目的 Mod 版本。点击这里查看其数据包版本。", "以下是该项目的数据包版本。点击这里查看其 Mod 版本。")
  226. Else
  227. HintAlternative.Visibility = Visibility.Collapsed
  228. End If
  229. Catch ex As Exception
  230. Logger.Error(ex, "可视化工程下载列表出错")
  231. End Try
  232. End Sub
  233. ''' <summary>
  234. ''' 根据卡片中的 StackPanel.Tag 将资源版本列表数据实例化为 UI。
  235. ''' </summary>
  236. Private Sub InitializeStackResourceVersions(Stack As StackPanel)
  237. Dim Versions = CType(Stack.Tag, List(Of ResourceVersion)).SortByComparison(Function(a, b) a.ReleaseDate > b.ReleaseDate)
  238. Dim HasDuplicates = Versions.DistinctBy(Function(a) a.Display).Count <> Versions.Count
  239. Dim Dependences As List(Of String)
  240. '获取并添加前置信息
  241. If TargetResourceType = ResourceTypes.ModPack Then
  242. Dependences = New List(Of String) '整合包的前置信息会显示其中包含的一大堆 Mod,不是真正意义的前置
  243. Else
  244. Dependences = Versions.SelectMany(Function(f) f.Dependencies).Distinct.Ordered.ToList()
  245. End If
  246. If Dependences.Any() Then
  247. Dependences = Dependences.Where(
  248. Function(d)
  249. If Not ResourceProject.Cache.ContainsKey(d) Then Logger.Warn($"未找到 ID {d} 的前置信息")
  250. Return ResourceProject.Cache.ContainsKey(d)
  251. End Function).ToList
  252. '添加开头间隔
  253. Stack.Children.Add(New TextBlock With {.Text = "前置资源", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 2, 0, 5)})
  254. '添加前置列表
  255. For Each Dep In Dependences
  256. Dim Item = ResourceProject.Cache(Dep).ToResourceItem(False, False)
  257. Stack.Children.Add(Item)
  258. Next
  259. '添加结尾间隔
  260. Stack.Children.Add(New TextBlock With {.Text = "版本列表", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 12, 0, 5)})
  261. End If
  262. '实例化每个元素
  263. For Each Version In Versions
  264. If Not RestrictMcDownload AndAlso TargetResourceType = ResourceTypes.ModPack Then
  265. Stack.Children.Add(Version.ToListItem(AddressOf Install_Click, AddressOf Save_Click, IsBadDisplay:=HasDuplicates))
  266. Else
  267. Stack.Children.Add(Version.ToListItem(AddressOf Save_Click, IsBadDisplay:=HasDuplicates))
  268. End If
  269. Next
  270. Stack.Children.Add(New FrameworkElement With {.Height = 18})
  271. Stack.Tag = Nothing
  272. End Sub
  273. Private Function GetGroupedVersionName(Name As String, GroupedByDrop As Boolean, FoldOld As Boolean) As String
  274. Dim Drop = McVersion.VersionToDrop(Name)
  275. If Name Is Nothing Then
  276. Return "其他"
  277. ElseIf Name.Contains("w") OrElse Drop = 209 Then
  278. Return "快照版"
  279. ElseIf Not McVersion.IsStandardFormat(Name) OrElse (FoldOld AndAlso Drop < 120) Then
  280. Return "远古版"
  281. ElseIf GroupedByDrop Then
  282. Return McVersion.DropToVersion(Drop)
  283. Else
  284. Return Name
  285. End If
  286. End Function
  287. #End Region
  288. Private IsFirstInit As Boolean = True
  289. Public Sub Init() Handles Me.PageEnter
  290. AniControlEnabled += 1
  291. Project = FrmMain.PageCurrent.Additional(0)
  292. PanBack.ScrollToHome()
  293. '重启加载器
  294. If IsFirstInit Then
  295. '在 Me.Initialized 已经初始化了加载器,不再重复初始化
  296. IsFirstInit = False
  297. Else
  298. PageLoaderRestart(IsForceRestart:=True)
  299. End If
  300. '放置当前工程
  301. If ResourceItem IsNot Nothing Then PanIntro.Children.Remove(ResourceItem)
  302. ResourceItem = Project.ToResourceItem(True, True).Init()
  303. ResourceItem.CanInteraction = False
  304. ResourceItem.Margin = New Thickness(-7, -7, 0, 8)
  305. PanIntro.Children.Insert(0, ResourceItem)
  306. '决定按钮显示
  307. BtnIntroWeb.Text = $"转到 {Project.Platform}"
  308. BtnIntroWiki.Visibility = If(Project.WikiId = 0, Visibility.Collapsed, Visibility.Visible)
  309. AniControlEnabled -= 1
  310. End Sub
  311. '整合包安装
  312. Public Sub Install_Click(sender As MyListItem, e As EventArgs)
  313. Try
  314. '获取基本信息
  315. Dim File As ResourceVersion = sender.Tag
  316. Dim LoaderName As String = $"{Project.Platform} 整合包下载:{Project.TranslatedName} "
  317. '获取版本名
  318. Dim PackName As String = Project.TranslatedName.Replace(".zip", "").Replace(".rar", "").Replace(".mrpack", "").Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
  319. Dim Validate As New ValidateFolderName(McFolderSelected & "versions")
  320. If Validate.Validate(PackName) <> "" Then PackName = ""
  321. Dim InstanceName As String = MyMsgBoxInput("输入版本名称", "", PackName, New Collection(Of Validate) From {Validate})
  322. If String.IsNullOrEmpty(InstanceName) Then Return
  323. '构造步骤加载器
  324. Dim Loaders As New List(Of LoaderBase)
  325. Dim Target As String = $"{McFolderSelected}versions\{InstanceName}\原始整合包.{If(Project.Platform = ResourcePlatforms.CurseForge, "zip", "mrpack")}"
  326. Dim LogoFileAddress As String = ResourceItem.PathLogo.ActualSource
  327. Loaders.Add(New LoaderDownload("下载整合包文件", {
  328. File.ToNetFile(Target, ResourceVersion.DownloadReason.Standalone, File.GameVersions.FirstOrDefault, File.ModLoaders)
  329. }) With {.ProgressWeight = 10, .Block = True})
  330. Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包",
  331. Sub() ModpackInstall(Target, InstanceName, If(FileUtils.Exists(LogoFileAddress), LogoFileAddress, Nothing))) With {.ProgressWeight = 0.1})
  332. '启动
  333. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged =
  334. Sub(MyLoader)
  335. Select Case MyLoader.State
  336. Case LoadState.Failed
  337. Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetDisplay(False), HintType.Red)
  338. Case LoadState.Canceled
  339. Hint(MyLoader.Name & "已取消!", HintType.Blue)
  340. Case LoadState.Loading
  341. Return '不重新加载版本列表
  342. End Select
  343. McInstallFailedClearFolder(MyLoader)
  344. End Sub}
  345. Loader.Start(McFolderSelected & "versions\" & InstanceName & "\")
  346. LoaderTaskbarAdd(Loader)
  347. FrmMain.BtnExtraDownload.ShowRefresh()
  348. FrmMain.PageChange(FormMain.PageType.TaskManager)
  349. Catch ex As Exception
  350. Logger.Error(ex, "下载资源整合包失败")
  351. End Try
  352. End Sub
  353. '资源下载;整合包另存为
  354. Public Shared CachedFolder As New Dictionary(Of ResourceTypes, String) '仅在本次缓存的下载文件夹
  355. Public Sub Save_Click(sender As Object, e As EventArgs)
  356. Dim File As ResourceVersion = If(TypeOf sender Is MyListItem, sender, sender.Parent).Tag
  357. RunInNewThread(
  358. Sub()
  359. Try
  360. Dim Desc As String = Nothing
  361. Select Case File.ResourceType
  362. Case ResourceTypes.ModPack : Desc = "整合包"
  363. Case ResourceTypes.Mod : Desc = "Mod "
  364. Case ResourceTypes.ResourcePack : Desc = "资源包"
  365. Case ResourceTypes.Shader : Desc = "光影包"
  366. Case ResourceTypes.DataPack : Desc = "数据包"
  367. End Select
  368. '确认默认保存位置
  369. Dim DefaultFolder As String = Nothing
  370. If File.ResourceType <> ResourceTypes.ModPack Then
  371. Dim SubFolder As String = Nothing
  372. Select Case File.ResourceType
  373. Case ResourceTypes.Mod : SubFolder = "mods\"
  374. Case ResourceTypes.ResourcePack : SubFolder = "resourcepacks\"
  375. Case ResourceTypes.Shader : SubFolder = "shaderpacks\"
  376. Case ResourceTypes.DataPack : SubFolder = "" '导航到版本根目录
  377. End Select
  378. Dim IsInstanceSuitable As Func(Of McInstance, Boolean) = Nothing
  379. '获取资源所需的加载器
  380. Dim AllowedLoaders As ModLoaders = ModLoaders.None
  381. If File.ModLoaders <> ModLoaders.None Then
  382. AllowedLoaders = File.ModLoaders
  383. ElseIf Project.ModLoaders <> ModLoaders.None Then
  384. AllowedLoaders = Project.ModLoaders
  385. End If
  386. Logger.Info($"{Desc}要求的加载器种类:{AllowedLoaders}")
  387. '判断某个版本是否符合资源要求
  388. IsInstanceSuitable =
  389. Function(Instance As McInstance)
  390. If Not Instance.IsLoaded Then Instance.Load()
  391. '只对 Mod 和数据包进行版本检测
  392. If File.ResourceType = ResourceTypes.Mod OrElse File.ResourceType = ResourceTypes.DataPack Then
  393. If Not File.GameVersions.Any( '判断是否有任何一个版本匹配
  394. Function(FileVersion)
  395. Dim FileIsSnapshot As Boolean = FileVersion.Contains("预览版") OrElse Not FileVersion.Contains(".")
  396. Dim InstanceIsSnapshot As Boolean = Instance.Version.VanillaName.Contains("snapshot") OrElse Not Instance.Version.VanillaName.Contains(".")
  397. If FileIsSnapshot <> InstanceIsSnapshot Then
  398. '只有一种是预览版
  399. Return False
  400. ElseIf Not FileIsSnapshot AndAlso Not InstanceIsSnapshot Then
  401. '都不是预览版
  402. Return FileVersion = Instance.Version.VanillaName
  403. Else
  404. '都是预览版
  405. Dim FileIsNewFormat As Boolean = FileVersion.Contains(".") AndAlso Val(FileVersion.BeforeFirst(".")) > 1
  406. Dim InstanceIsNewFormat As Boolean = Instance.Version.Drop > 250
  407. If FileIsNewFormat <> InstanceIsNewFormat Then
  408. '只有一种是新格式快照
  409. Return False
  410. ElseIf FileIsNewFormat AndAlso InstanceIsNewFormat Then
  411. '都是新格式快照
  412. Return FileVersion.BeforeFirst(" ") = Instance.Version.VanillaName.BeforeFirst("-")
  413. Else
  414. '都是旧格式快照
  415. If FileVersion.Contains("w") AndAlso Instance.Version.VanillaName.Contains("w") Then
  416. '都是 w 快照
  417. Return FileVersion = Instance.Version.VanillaName
  418. Else
  419. '不全是 w 快照
  420. Return True '只能假定相同,无法判断
  421. End If
  422. End If
  423. End If
  424. End Function) Then Return False
  425. End If
  426. '加载器
  427. Return AllowedLoaders = ModLoaders.None OrElse AllowedLoaders.Flags.Intersect(Instance.Version.ModLoaders.Flags).Any
  428. End Function
  429. '获取常规资源默认下载位置
  430. If CachedFolder.ContainsKey(File.ResourceType) Then
  431. DefaultFolder = CachedFolder(File.ResourceType)
  432. Logger.Info($"使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}")
  433. ElseIf McInstanceSelected IsNot Nothing AndAlso IsInstanceSuitable(McInstanceSelected) Then
  434. DefaultFolder = $"{McInstanceSelected.PathIndie}{SubFolder}"
  435. DirectoryUtils.Create(DefaultFolder)
  436. Logger.Info($"使用当前版本作为默认下载位置:{DefaultFolder}")
  437. Else
  438. '查找所有可能的版本
  439. Dim NeedLoad As Boolean = McInstanceListLoader.State <> LoadState.Finished
  440. If NeedLoad Then
  441. Hint("正在查找适合的游戏版本……")
  442. LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
  443. End If
  444. Dim SuitableInstanceList = McInstanceList.Values.SelectMany(Function(l) l).Where(Function(v) IsInstanceSuitable(v)).
  445. Select(Function(v) DirectoryUtils.GetInfo($"{v.PathIndie}{SubFolder}"))
  446. If SuitableInstanceList.Any Then
  447. Dim SelectedInstance = SuitableInstanceList.
  448. OrderByDescending(Function(Dir) If(Dir.Exists, Dir.LastWriteTimeUtc, Date.MinValue)). '先按文件夹更改时间降序
  449. ThenByDescending(Function(Dir) If(Dir.Exists, Dir.GetFiles().Length, -1)). '再按文件夹中的文件数量降序
  450. First()
  451. DefaultFolder = PathUtils.RemoveExtendedPrefix(SelectedInstance.FullName)
  452. DirectoryUtils.Create(DefaultFolder)
  453. Logger.Info($"使用适合的游戏版本作为默认下载位置:{DefaultFolder}")
  454. Else
  455. DefaultFolder = McFolderSelected
  456. If NeedLoad Then
  457. Hint($"当前 MC 文件夹中没有找到合适的版本!")
  458. Else
  459. Logger.Info("由于当前版本不兼容,使用当前的 MC 文件夹作为默认下载位置")
  460. End If
  461. End If
  462. End If
  463. End If
  464. '获取基本信息
  465. Dim FileName As String
  466. If Project.TranslatedName = Project.RawName Then
  467. FileName = File.FileName
  468. Else
  469. Dim ChineseName As String = Project.TranslatedName.BeforeFirst(" (").BeforeFirst(" - ").
  470. Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
  471. Select Case Settings.Get(Of Integer)("ToolDownloadTranslateV2")
  472. Case 0
  473. FileName = $"【{ChineseName}】{File.FileName}"
  474. Case 1
  475. FileName = $"[{ChineseName}] {File.FileName}"
  476. Case 2
  477. FileName = $"{ChineseName}-{File.FileName}"
  478. Case 3
  479. FileName = $"{File.FileName}-{ChineseName}"
  480. Case Else
  481. FileName = File.FileName
  482. End Select
  483. End If
  484. If File.ResourceType = ResourceTypes.Mod Then FileName = FileName.Replace("~", "-") '~ 会导致 Mixin 加载失败
  485. RunInUi(
  486. Sub()
  487. '弹窗要求选择保存位置
  488. Dim Target As String
  489. Dim Ext As String = If(File.ResourceType = ResourceTypes.Mod,
  490. If(PathUtils.GetExtension(File.FileName) = "litemod", "litemod", "jar"),
  491. If(PathUtils.GetExtension(File.FileName) = "mrpack", "mrpack", "zip"))
  492. Target = Dialogs.SaveFile("选择保存位置", FileName, DefaultFolder, {(Ext, Desc & "文件")})
  493. If Target Is Nothing Then Return
  494. '构造步骤加载器
  495. Dim LoaderName As String = Desc & "下载:" & PathUtils.GetFileNameWithoutExtension(Target) & " "
  496. If Not PathUtils.IsSame(PathUtils.RemoveLastPart(Target), DefaultFolder) Then CachedFolder(File.ResourceType) = PathUtils.RemoveLastPart(Target)
  497. Dim Loaders As New List(Of LoaderBase)
  498. Loaders.Add(New LoaderDownload("下载文件", {
  499. File.ToNetFile(Target, If(TargetResourceType = ResourceTypes.Any, ResourceVersion.DownloadReason.Dependency, ResourceVersion.DownloadReason.Standalone))
  500. }) With {.ProgressWeight = 6, .Block = True})
  501. '启动
  502. Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged =
  503. Sub(MyLoader)
  504. LoaderStateChangedHintOnly(MyLoader)
  505. If MyLoader.State = LoadState.Finished AndAlso File.ResourceType = ResourceTypes.ModPack Then OpenExplorer(Target)
  506. End Sub}
  507. Loader.Start(1)
  508. LoaderTaskbarAdd(Loader)
  509. FrmMain.BtnExtraDownload.ShowRefresh()
  510. FrmMain.BtnExtraDownload.Ribble()
  511. End Sub)
  512. Catch ex As Exception
  513. Logger.Error(ex, "保存资源文件失败")
  514. End Try
  515. End Sub, "Download Resource Detail Save")
  516. End Sub
  517. Private Sub BtnIntroWeb_Click(sender As Object, e As EventArgs) Handles BtnIntroWeb.Click
  518. OpenWebsite(Project.Website)
  519. End Sub
  520. Private Sub BtnIntroWiki_Click(sender As Object, e As EventArgs) Handles BtnIntroWiki.Click
  521. OpenWebsite("https://www.mcmod.cn/class/" & Project.WikiId & ".html")
  522. End Sub
  523. Private Sub BtnIntroCopy_Click(sender As Object, e As EventArgs) Handles BtnIntroCopy.Click
  524. ClipboardSet(ResourceItem.LabTitle.Text & ResourceItem.LabTitleRaw.Text)
  525. End Sub
  526. 'Mod / 数据包 互相跳转
  527. Private Sub HintAlternative_Click() Handles HintAlternative.Click
  528. TargetResourceType = If(TargetResourceType = ResourceTypes.Mod, ResourceTypes.DataPack, ResourceTypes.Mod)
  529. FrmMain.PageCurrent.Additional(4) = TargetResourceType '加载器会从这里重新拿数据
  530. PageLoaderRestart(IsForceRestart:=True)
  531. End Sub
  532. End Class