PageDownloadCompDetail.xaml.vb 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  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 = -CompareVersion(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", ""))
  63. If VersionCodeSort <> 0 Then Return VersionCodeSort
  64. '比较全部
  65. Return -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, New VersionComparer).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.IsFormatFit(VerName) Then '不是 “快照版本” 之类的
  167. For Each Loader In Version.ModLoaders.Flags
  168. If Loader = ModLoaders.Quilt AndAlso Settings.Get(Of Boolean)("ToolDownloadIgnoreQuilt") Then Continue For
  169. Loaders.Add(Loader.ToString & " ")
  170. Next
  171. End If
  172. If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
  173. '实际添加
  174. For Each Loader In Loaders
  175. Dim TargetCard As String = Loader & VerName
  176. If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of ResourceVersion))
  177. If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
  178. Next
  179. Next
  180. Next
  181. '添加筛选的版本的卡片
  182. If TargetCardName <> "" AndAlso (VersionFilter Is Nothing OrElse GetGroupedVersionName(TargetVersion, GroupedDrop, GroupedOld).StartsWithF(VersionFilter)) Then
  183. Dict.Add(TargetCardName, New List(Of ResourceVersion))
  184. For Each Version As ResourceVersion In Results
  185. If Version.GameVersions.Contains(TargetVersion) AndAlso
  186. (TargetLoaders = ModLoaders.None OrElse TargetLoaders.Flags.Intersect(Version.ModLoaders.Flags).Any) Then
  187. '检查是否符合版本筛选器
  188. If VersionFilter IsNot Nothing AndAlso
  189. Not Version.GameVersions.Any(Function(v) GetGroupedVersionName(v, GroupedDrop, GroupedOld) = VersionFilter) Then Continue For
  190. If Not Dict(TargetCardName).Contains(Version) Then Dict(TargetCardName).Add(Version)
  191. End If
  192. Next
  193. End If
  194. '转化为 UI
  195. Try
  196. PanResults.Children.Clear()
  197. For Each Pair As KeyValuePair(Of String, List(Of ResourceVersion)) In Dict
  198. If Not Pair.Value.Any() Then Continue For
  199. If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For
  200. '增加卡片
  201. Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(TargetResourceType = ResourceTypes.ModPack, 9, 8)} '9 是安装,8 是另存为
  202. 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}
  203. NewCard.Children.Add(NewStack)
  204. NewCard.SwapControl = NewStack
  205. PanResults.Children.Add(NewCard)
  206. '确定卡片是否默认展开
  207. If Pair.Key = TargetCardName OrElse
  208. (FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
  209. CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then
  210. MyCard.StackInstall(NewStack, If(TargetResourceType = ResourceTypes.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为
  211. Else
  212. NewCard.IsSwapped = True
  213. End If
  214. '增加提示
  215. If Pair.Key = "其他" Then
  216. NewStack.Children.Add(New MyHint With {.Text = "由于版本信息更新缓慢,可能无法识别刚更新的 MC 版本。几天后即可正常识别。", .Theme = MyHint.Themes.Yellow, .Margin = New Thickness(5, 0, 0, 8)})
  217. End If
  218. Next
  219. '如果只有一张卡片,展开第一张卡片
  220. If PanResults.Children.Count = 1 Then
  221. CType(PanResults.Children(0), MyCard).IsSwapped = False
  222. End If
  223. '替代提示
  224. If Project.Types = ResourceTypes.ModOrDataPack AndAlso (TargetResourceType = ResourceTypes.Mod OrElse TargetResourceType = ResourceTypes.DataPack) Then
  225. HintAlternative.Visibility = Visibility.Visible
  226. HintAlternative.Text = If(TargetResourceType = ResourceTypes.Mod,
  227. "以下是该项目的 Mod 版本。点击这里查看其数据包版本。", "以下是该项目的数据包版本。点击这里查看其 Mod 版本。")
  228. Else
  229. HintAlternative.Visibility = Visibility.Collapsed
  230. End If
  231. Catch ex As Exception
  232. Logger.Error(ex, "可视化工程下载列表出错")
  233. End Try
  234. End Sub
  235. Private Function GetGroupedVersionName(Name As String, GroupedByDrop As Boolean, FoldOld As Boolean) As String
  236. Dim Drop = McVersion.VersionToDrop(Name)
  237. If Name Is Nothing Then
  238. Return "其他"
  239. ElseIf Name.Contains("w") OrElse Drop = 209 Then
  240. Return "快照版"
  241. ElseIf Not McVersion.IsFormatFit(Name) OrElse (FoldOld AndAlso Drop < 120) Then
  242. Return "远古版"
  243. ElseIf GroupedByDrop Then
  244. Return McVersion.DropToVersion(Drop)
  245. Else
  246. Return Name
  247. End If
  248. End Function
  249. #End Region
  250. Private IsFirstInit As Boolean = True
  251. Public Sub Init() Handles Me.PageEnter
  252. AniControlEnabled += 1
  253. Project = FrmMain.PageCurrent.Additional(0)
  254. PanBack.ScrollToHome()
  255. '重启加载器
  256. If IsFirstInit Then
  257. '在 Me.Initialized 已经初始化了加载器,不再重复初始化
  258. IsFirstInit = False
  259. Else
  260. PageLoaderRestart(IsForceRestart:=True)
  261. End If
  262. '放置当前工程
  263. If ResourceItem IsNot Nothing Then PanIntro.Children.Remove(ResourceItem)
  264. ResourceItem = Project.ToResourceItem(True, True).Init()
  265. ResourceItem.CanInteraction = False
  266. ResourceItem.Margin = New Thickness(-7, -7, 0, 8)
  267. PanIntro.Children.Insert(0, ResourceItem)
  268. '决定按钮显示
  269. BtnIntroWeb.Text = $"转到 {Project.Platform}"
  270. BtnIntroWiki.Visibility = If(Project.WikiId = 0, Visibility.Collapsed, Visibility.Visible)
  271. AniControlEnabled -= 1
  272. End Sub
  273. '整合包安装
  274. Public Sub Install_Click(sender As MyListItem, e As EventArgs)
  275. Try
  276. '获取基本信息
  277. Dim File As ResourceVersion = sender.Tag
  278. Dim LoaderName As String = $"{Project.Platform} 整合包下载:{Project.TranslatedName} "
  279. '获取版本名
  280. Dim PackName As String = Project.TranslatedName.Replace(".zip", "").Replace(".rar", "").Replace(".mrpack", "").Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
  281. Dim Validate As New ValidateFolderName(McFolderSelected & "versions")
  282. If Validate.Validate(PackName) <> "" Then PackName = ""
  283. Dim InstanceName As String = MyMsgBoxInput("输入版本名称", "", PackName, New Collection(Of Validate) From {Validate})
  284. If String.IsNullOrEmpty(InstanceName) Then Return
  285. '构造步骤加载器
  286. Dim Loaders As New List(Of LoaderBase)
  287. Dim Target As String = $"{McFolderSelected}versions\{InstanceName}\原始整合包.{If(Project.Platform = ResourcePlatforms.CurseForge, "zip", "mrpack")}"
  288. Dim LogoFileAddress As String = ResourceItem.PathLogo.ActualSource
  289. Loaders.Add(New LoaderDownload("下载整合包文件", {
  290. File.ToNetFile(Target, ResourceVersion.DownloadReason.Standalone, File.GameVersions.FirstOrDefault, File.ModLoaders)
  291. }) With {.ProgressWeight = 10, .Block = True})
  292. Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包",
  293. Sub() ModpackInstall(Target, InstanceName, If(FileUtils.Exists(LogoFileAddress), LogoFileAddress, Nothing))) With {.ProgressWeight = 0.1})
  294. '启动
  295. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged =
  296. Sub(MyLoader)
  297. Select Case MyLoader.State
  298. Case LoadState.Failed
  299. Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetDisplay(False), HintType.Red)
  300. Case LoadState.Canceled
  301. Hint(MyLoader.Name & "已取消!", HintType.Blue)
  302. Case LoadState.Loading
  303. Return '不重新加载版本列表
  304. End Select
  305. McInstallFailedClearFolder(MyLoader)
  306. End Sub}
  307. Loader.Start(McFolderSelected & "versions\" & InstanceName & "\")
  308. LoaderTaskbarAdd(Loader)
  309. FrmMain.BtnExtraDownload.ShowRefresh()
  310. FrmMain.BtnExtraDownload.Ribble()
  311. Catch ex As Exception
  312. Logger.Error(ex, "下载资源整合包失败")
  313. End Try
  314. End Sub
  315. '资源下载;整合包另存为
  316. Public Shared CachedFolder As New Dictionary(Of ResourceTypes, String) '仅在本次缓存的下载文件夹
  317. Public Sub Save_Click(sender As Object, e As EventArgs)
  318. Dim File As ResourceVersion = If(TypeOf sender Is MyListItem, sender, sender.Parent).Tag
  319. RunInNewThread(
  320. Sub()
  321. Try
  322. Dim Desc As String = Nothing
  323. Select Case File.ResourceType
  324. Case ResourceTypes.ModPack : Desc = "整合包"
  325. Case ResourceTypes.Mod : Desc = "Mod "
  326. Case ResourceTypes.ResourcePack : Desc = "资源包"
  327. Case ResourceTypes.Shader : Desc = "光影包"
  328. Case ResourceTypes.DataPack : Desc = "数据包"
  329. End Select
  330. '确认默认保存位置
  331. Dim DefaultFolder As String = Nothing
  332. If File.ResourceType <> ResourceTypes.ModPack Then
  333. Dim SubFolder As String = Nothing
  334. Select Case File.ResourceType
  335. Case ResourceTypes.Mod : SubFolder = "mods\"
  336. Case ResourceTypes.ResourcePack : SubFolder = "resourcepacks\"
  337. Case ResourceTypes.Shader : SubFolder = "shaderpacks\"
  338. Case ResourceTypes.DataPack : SubFolder = "" '导航到版本根目录
  339. End Select
  340. Dim IsInstanceSuitable As Func(Of McInstance, Boolean) = Nothing
  341. '获取资源所需的加载器
  342. Dim AllowedLoaders As ModLoaders = ModLoaders.None
  343. If File.ModLoaders <> ModLoaders.None Then
  344. AllowedLoaders = File.ModLoaders
  345. ElseIf Project.ModLoaders <> ModLoaders.None Then
  346. AllowedLoaders = Project.ModLoaders
  347. End If
  348. Logger.Info($"{Desc}要求的加载器种类:{AllowedLoaders}")
  349. '判断某个版本是否符合资源要求
  350. IsInstanceSuitable =
  351. Function(Instance As McInstance)
  352. If Not Instance.IsLoaded Then Instance.Load()
  353. '只对 Mod 和数据包进行版本检测
  354. If File.ResourceType = ResourceTypes.Mod OrElse File.ResourceType = ResourceTypes.DataPack Then
  355. If Not File.GameVersions.Any( '判断是否有任何一个版本匹配
  356. Function(FileVersion)
  357. Dim FileIsSnapshot As Boolean = FileVersion.Contains("预览版") OrElse Not FileVersion.Contains(".")
  358. Dim InstanceIsSnapshot As Boolean = Instance.Version.VanillaName.Contains("snapshot") OrElse Not Instance.Version.VanillaName.Contains(".")
  359. If FileIsSnapshot <> InstanceIsSnapshot Then
  360. '只有一种是预览版
  361. Return False
  362. ElseIf Not FileIsSnapshot AndAlso Not InstanceIsSnapshot Then
  363. '都不是预览版
  364. Return FileVersion = Instance.Version.VanillaName
  365. Else
  366. '都是预览版
  367. Dim FileIsNewFormat As Boolean = FileVersion.Contains(".") AndAlso Val(FileVersion.BeforeFirst(".")) > 1
  368. Dim InstanceIsNewFormat As Boolean = Instance.Version.Drop > 250
  369. If FileIsNewFormat <> InstanceIsNewFormat Then
  370. '只有一种是新格式快照
  371. Return False
  372. ElseIf FileIsNewFormat AndAlso InstanceIsNewFormat Then
  373. '都是新格式快照
  374. Return FileVersion.BeforeFirst(" ") = Instance.Version.VanillaName.BeforeFirst("-")
  375. Else
  376. '都是旧格式快照
  377. If FileVersion.Contains("w") AndAlso Instance.Version.VanillaName.Contains("w") Then
  378. '都是 w 快照
  379. Return FileVersion = Instance.Version.VanillaName
  380. Else
  381. '不全是 w 快照
  382. Return True '只能假定相同,无法判断
  383. End If
  384. End If
  385. End If
  386. End Function) Then Return False
  387. End If
  388. '加载器
  389. Return AllowedLoaders = ModLoaders.None OrElse AllowedLoaders.Flags.Intersect(Instance.Version.ModLoaders.Flags).Any
  390. End Function
  391. '获取常规资源默认下载位置
  392. If CachedFolder.ContainsKey(File.ResourceType) Then
  393. DefaultFolder = CachedFolder(File.ResourceType)
  394. Logger.Info($"使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}")
  395. ElseIf McInstanceSelected IsNot Nothing AndAlso IsInstanceSuitable(McInstanceSelected) Then
  396. DefaultFolder = $"{McInstanceSelected.PathIndie}{SubFolder}"
  397. DirectoryUtils.Create(DefaultFolder)
  398. Logger.Info($"使用当前版本作为默认下载位置:{DefaultFolder}")
  399. Else
  400. '查找所有可能的版本
  401. Dim NeedLoad As Boolean = McInstanceListLoader.State <> LoadState.Finished
  402. If NeedLoad Then
  403. Hint("正在查找适合的游戏版本……")
  404. LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
  405. End If
  406. Dim SuitableInstanceList = McInstanceList.Values.SelectMany(Function(l) l).Where(Function(v) IsInstanceSuitable(v)).
  407. Select(Function(v) DirectoryUtils.GetInfo($"{v.PathIndie}{SubFolder}"))
  408. If SuitableInstanceList.Any Then
  409. Dim SelectedInstance = SuitableInstanceList.
  410. OrderByDescending(Function(Dir) If(Dir.Exists, Dir.LastWriteTimeUtc, Date.MinValue)). '先按文件夹更改时间降序
  411. ThenByDescending(Function(Dir) If(Dir.Exists, Dir.GetFiles().Length, -1)). '再按文件夹中的文件数量降序
  412. First()
  413. DefaultFolder = PathUtils.RemoveExtendedPrefix(SelectedInstance.FullName)
  414. DirectoryUtils.Create(DefaultFolder)
  415. Logger.Info($"使用适合的游戏版本作为默认下载位置:{DefaultFolder}")
  416. Else
  417. DefaultFolder = McFolderSelected
  418. If NeedLoad Then
  419. Hint($"当前 MC 文件夹中没有找到合适的版本!")
  420. Else
  421. Logger.Info("由于当前版本不兼容,使用当前的 MC 文件夹作为默认下载位置")
  422. End If
  423. End If
  424. End If
  425. End If
  426. '获取基本信息
  427. Dim FileName As String
  428. If Project.TranslatedName = Project.RawName Then
  429. FileName = File.FileName
  430. Else
  431. Dim ChineseName As String = Project.TranslatedName.BeforeFirst(" (").BeforeFirst(" - ").
  432. Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
  433. Select Case Settings.Get(Of Integer)("ToolDownloadTranslateV2")
  434. Case 0
  435. FileName = $"【{ChineseName}】{File.FileName}"
  436. Case 1
  437. FileName = $"[{ChineseName}] {File.FileName}"
  438. Case 2
  439. FileName = $"{ChineseName}-{File.FileName}"
  440. Case 3
  441. FileName = $"{File.FileName}-{ChineseName}"
  442. Case Else
  443. FileName = File.FileName
  444. End Select
  445. End If
  446. If File.ResourceType = ResourceTypes.Mod Then FileName = FileName.Replace("~", "-") '~ 会导致 Mixin 加载失败
  447. RunInUi(
  448. Sub()
  449. '弹窗要求选择保存位置
  450. Dim Target As String
  451. Dim Ext As String = If(File.ResourceType = ResourceTypes.Mod,
  452. If(File.FileName.EndsWithF(".litemod"), "litemod", "jar"),
  453. If(File.FileName.EndsWithF(".mrpack"), "mrpack", "zip"))
  454. Target = Dialogs.SaveFile("选择保存位置", FileName, DefaultFolder, {(Ext, Desc & "文件")})
  455. If Target Is Nothing Then Return
  456. '构造步骤加载器
  457. Dim LoaderName As String = Desc & "下载:" & PathUtils.GetFileNameWithoutExtension(Target) & " "
  458. If Target <> DefaultFolder Then CachedFolder(File.ResourceType) = PathUtils.RemoveLastPart(Target)
  459. Dim Loaders As New List(Of LoaderBase)
  460. Loaders.Add(New LoaderDownload("下载文件", {
  461. File.ToNetFile(Target, If(TargetResourceType = ResourceTypes.Any, ResourceVersion.DownloadReason.Dependency, ResourceVersion.DownloadReason.Standalone))
  462. }) With {.ProgressWeight = 6, .Block = True})
  463. '启动
  464. Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged = AddressOf LoaderStateChangedHintOnly}
  465. Loader.Start(1)
  466. LoaderTaskbarAdd(Loader)
  467. FrmMain.BtnExtraDownload.ShowRefresh()
  468. FrmMain.BtnExtraDownload.Ribble()
  469. End Sub)
  470. Catch ex As Exception
  471. Logger.Error(ex, "保存资源文件失败")
  472. End Try
  473. End Sub, "Download Resource Detail Save")
  474. End Sub
  475. Private Sub BtnIntroWeb_Click(sender As Object, e As EventArgs) Handles BtnIntroWeb.Click
  476. OpenWebsite(Project.Website)
  477. End Sub
  478. Private Sub BtnIntroWiki_Click(sender As Object, e As EventArgs) Handles BtnIntroWiki.Click
  479. OpenWebsite("https://www.mcmod.cn/class/" & Project.WikiId & ".html")
  480. End Sub
  481. Private Sub BtnIntroCopy_Click(sender As Object, e As EventArgs) Handles BtnIntroCopy.Click
  482. ClipboardSet(ResourceItem.LabTitle.Text & ResourceItem.LabTitleRaw.Text)
  483. End Sub
  484. 'Mod / 数据包 互相跳转
  485. Private Sub HintAlternative_Click() Handles HintAlternative.Click
  486. TargetResourceType = If(TargetResourceType = ResourceTypes.Mod, ResourceTypes.DataPack, ResourceTypes.Mod)
  487. FrmMain.PageCurrent.Additional(4) = TargetResourceType '加载器会从这里重新拿数据
  488. PageLoaderRestart(IsForceRestart:=True)
  489. End Sub
  490. ''' <summary>
  491. ''' 预载包含大量 ProjectVersion 的卡片,添加必要的元素和前置列表。
  492. ''' </summary>
  493. Public Shared Sub ResourceFilesCardPreload(Stack As StackPanel, Files As List(Of ResourceVersion))
  494. '获取卡片对应的前置 ID
  495. '如果为整合包就不会有 Dependencies 信息,所以不用管
  496. Dim Deps As List(Of String) = Files.SelectMany(Function(f) f.Dependencies).Distinct.ToList()
  497. Deps.Sort()
  498. If Not Deps.Any() Then Return
  499. Deps = Deps.Where(
  500. Function(dep)
  501. If Not ResourceProject.Cache.ContainsKey(dep) Then Logger.Warn($"未找到 ID {dep} 的前置信息")
  502. Return ResourceProject.Cache.ContainsKey(dep)
  503. End Function).ToList
  504. '添加开头间隔
  505. Stack.Children.Add(New TextBlock With {.Text = "前置资源", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 2, 0, 5)})
  506. '添加前置列表
  507. For Each Dep In Deps
  508. Dim Item = ResourceProject.Cache(Dep).ToResourceItem(False, False)
  509. Stack.Children.Add(Item)
  510. Next
  511. '添加结尾间隔
  512. Stack.Children.Add(New TextBlock With {.Text = "版本列表", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 12, 0, 5)})
  513. End Sub
  514. End Class