PageDownloadCompDetail.xaml.vb 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. Public Class PageDownloadCompDetail
  2. Private CompItem As MyCompItem = Nothing
  3. #Region "加载器"
  4. Private CompFileLoader As New LoaderTask(Of Integer, List(Of CompFile))(
  5. "Comp File",
  6. Sub(Task)
  7. LoadTargetFromAdditional()
  8. Dim Result = CompFilesGet(Project.Id, Project.FromCurseForge)
  9. If Task.IsInterrupted Then Return
  10. Task.Output = Result
  11. End Sub)
  12. '初始化加载器信息
  13. Private Sub PageDownloadCompDetail_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
  14. LoadTargetFromAdditional()
  15. PageLoaderInit(Load, PanLoad, PanMain, CardIntro, CompFileLoader, AddressOf Load_OnFinish)
  16. End Sub
  17. Public Sub LoadTargetFromAdditional() Handles Me.Loaded
  18. Project = FrmMain.PageCurrent.Additional(0)
  19. TargetInstance = FrmMain.PageCurrent.Additional(2)
  20. TargetLoader = FrmMain.PageCurrent.Additional(3)
  21. TargetType = FrmMain.PageCurrent.Additional(4)
  22. End Sub
  23. Private Project As CompProject
  24. Private TargetInstance As String, TargetLoader As CompModLoaderType
  25. ''' <summary>
  26. ''' 当前页面应展示的内容类别。
  27. ''' 若当前页面是在查看前置时进入,则也可能为 Any。
  28. ''' </summary>
  29. Private TargetType As CompType
  30. '自动重试
  31. Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
  32. Select Case CompFileLoader.State
  33. Case LoadState.Failed
  34. Dim ErrorMessage As String = ""
  35. If CompFileLoader.Error IsNot Nothing Then ErrorMessage = CompFileLoader.Error.Message
  36. If ErrorMessage.Contains("不是有效的 json 文件") Then
  37. Log("[Comp] 下载的文件 json 列表损坏,已自动重试", LogLevel.Debug)
  38. PageLoaderRestart()
  39. End If
  40. End Select
  41. End Sub
  42. '结果 UI 化
  43. Private Class CardSorter
  44. Implements IComparer(Of String)
  45. Public Topmost As String = ""
  46. Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
  47. '相同
  48. If x = y Then Return 0
  49. '置顶
  50. If x = Topmost Then Return -1
  51. If y = Topmost Then Return 1
  52. '特殊版本
  53. Dim IsXSpecial As Boolean = Not x.Contains(".")
  54. Dim IsYSpecial As Boolean = Not y.Contains(".")
  55. If IsXSpecial AndAlso IsYSpecial Then Return x.CompareTo(y)
  56. If IsXSpecial Then Return 1
  57. If IsYSpecial Then Return -1
  58. '比较版本号
  59. Dim VersionCodeSort = -CompareVersion(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", ""))
  60. If VersionCodeSort <> 0 Then Return VersionCodeSort
  61. '比较全部
  62. Return -CompareVersion(x, y)
  63. End Function
  64. Public Sub New(Optional Topmost As String = "")
  65. Me.Topmost = If(Topmost, "")
  66. End Sub
  67. End Class
  68. Private VersionFilter As String
  69. Private GroupedDrop As Boolean '是否按 Drop 筛选(1.21 / 1.20 / 1.19 / ...)而非小版本号(1.21.1 / 1.21 / 1.20.4 / ...)
  70. Private GroupedOld As Boolean '是否折叠远古版本为一个选项
  71. '筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表)
  72. Private Function GetResults() As List(Of CompFile)
  73. Dim Results As List(Of CompFile) = CompFileLoader.Output
  74. Select Case TargetType
  75. Case CompType.Any
  76. Results = Results.Where(Function(r) r.Type <> CompType.Plugin).ToList
  77. Case CompType.Shader, CompType.ResourcePack
  78. '不筛选光影和资源包,否则原版光影会因为是资源包格式而被过滤(#6473)
  79. Case Else
  80. Results = Results.Where(Function(r) r.Type = TargetType).ToList
  81. End Select
  82. Return Results
  83. End Function
  84. Private Sub Load_OnFinish()
  85. Dim Results = GetResults()
  86. '初始化筛选器
  87. Dim Filters As List(Of String) = Nothing
  88. Dim UpdateFilters =
  89. Sub()
  90. Filters = Results.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, GroupedDrop, GroupedOld)).
  91. Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
  92. End Sub
  93. '确定分组方式
  94. GroupedDrop = False : GroupedOld = False
  95. UpdateFilters()
  96. If Filters.Count < 9 Then GoTo GroupDone
  97. GroupedDrop = True : GroupedOld = False
  98. UpdateFilters()
  99. If Filters.Count < 9 Then GoTo GroupDone
  100. GroupedDrop = False : GroupedOld = True
  101. UpdateFilters()
  102. If Filters.Count < 9 Then GoTo GroupDone
  103. GroupedDrop = True : GroupedOld = True
  104. UpdateFilters()
  105. GroupDone:
  106. 'UI 化筛选器
  107. PanFilter.Children.Clear()
  108. If Filters.Count < 2 Then
  109. CardFilter.Visibility = Visibility.Collapsed
  110. VersionFilter = Nothing
  111. Else
  112. CardFilter.Visibility = Visibility.Visible
  113. Filters.Insert(0, "全部")
  114. '转化为按钮
  115. For Each Version As String In Filters
  116. Dim NewButton As New MyRadioButton With {
  117. .Text = Version, .Margin = New Thickness(2, 0, 2, 0), .ColorType = MyRadioButton.ColorState.Highlight}
  118. NewButton.LabText.Margin = New Thickness(-2, 0, 10, 0)
  119. AddHandler NewButton.Check,
  120. Sub(sender As MyRadioButton, raiseByMouse As Boolean)
  121. VersionFilter = If(sender.Text = "全部", Nothing, sender.Text)
  122. UpdateFilterResult()
  123. End Sub
  124. PanFilter.Children.Add(NewButton)
  125. Next
  126. '自动选择
  127. Dim ToCheck As MyRadioButton = Nothing
  128. If TargetInstance <> "" Then
  129. Dim TargetFile = Results.FirstOrDefault(Function(v) v.GameVersions.Contains(TargetInstance))
  130. If TargetFile IsNot Nothing Then
  131. Dim TargetGroup = GetGroupedVersionName(TargetInstance, GroupedDrop, GroupedOld)
  132. For Each Button As MyRadioButton In PanFilter.Children
  133. If Button.Text <> TargetGroup Then Continue For
  134. ToCheck = Button
  135. Exit For
  136. Next
  137. End If
  138. End If
  139. If ToCheck Is Nothing Then ToCheck = PanFilter.Children(0)
  140. ToCheck.Checked = True
  141. End If
  142. '更新筛选结果(文件列表 UI 化)
  143. UpdateFilterResult()
  144. End Sub
  145. Private Sub UpdateFilterResult()
  146. Dim Results = GetResults()
  147. Dim TargetCardName As String = If(TargetInstance <> "" OrElse TargetLoader <> CompModLoaderType.Any,
  148. $"{If(TargetLoader <> CompModLoaderType.Any, TargetLoader.ToString & " ", "")}{TargetInstance}(所选版本)", "")
  149. '归类到卡片下
  150. Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New CardSorter(TargetCardName))
  151. Dict.Add("其他", New List(Of CompFile))
  152. Dim SupportedLoaders As New List(Of Integer)([Enum].GetValues(GetType(CompModLoaderType)))
  153. For Each Version As CompFile In Results
  154. For Each GameVersion In Version.GameVersions
  155. '检查是否符合版本筛选器
  156. If VersionFilter IsNot Nothing AndAlso
  157. GetGroupedVersionName(GameVersion, GroupedDrop, GroupedOld) <> VersionFilter Then Continue For
  158. '决定添加到哪个卡片
  159. Dim VerName As String = GetGroupedVersionName(GameVersion, False, False)
  160. '遍历加入的加载器列表
  161. Dim Loaders As New List(Of String)
  162. If Project.ModLoaders.Count > 1 AndAlso '工程至少有两个加载器
  163. Version.Type = CompType.Mod AndAlso '是 Mod
  164. McVersion.IsFormatFit(VerName) Then '不是 “快照版本” 之类的
  165. For Each Loader In Version.ModLoaders
  166. If Loader = CompModLoaderType.Quilt AndAlso Settings.Get("ToolDownloadIgnoreQuilt") Then Continue For
  167. If SupportedLoaders.Contains(Loader) Then Loaders.Add(Loader.ToString & " ")
  168. Next
  169. End If
  170. If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
  171. '实际添加
  172. For Each Loader In Loaders
  173. Dim TargetCard As String = Loader & VerName
  174. If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile))
  175. If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
  176. Next
  177. Next
  178. Next
  179. '添加筛选的版本的卡片
  180. If TargetCardName <> "" AndAlso (VersionFilter Is Nothing OrElse GetGroupedVersionName(TargetInstance, GroupedDrop, GroupedOld).StartsWithF(VersionFilter)) Then
  181. Dict.Add(TargetCardName, New List(Of CompFile))
  182. For Each Version As CompFile In Results
  183. If Version.GameVersions.Contains(TargetInstance) AndAlso
  184. (TargetLoader = CompModLoaderType.Any OrElse Version.ModLoaders.Contains(TargetLoader)) Then
  185. '检查是否符合版本筛选器
  186. If VersionFilter IsNot Nothing AndAlso
  187. Not Version.GameVersions.Any(Function(v) GetGroupedVersionName(v, GroupedDrop, GroupedOld) = VersionFilter) Then Continue For
  188. If Not Dict(TargetCardName).Contains(Version) Then Dict(TargetCardName).Add(Version)
  189. End If
  190. Next
  191. End If
  192. '转化为 UI
  193. Try
  194. PanResults.Children.Clear()
  195. For Each Pair As KeyValuePair(Of String, List(Of CompFile)) In Dict
  196. If Not Pair.Value.Any() Then Continue For
  197. If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For
  198. '增加卡片
  199. Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(TargetType = CompType.ModPack, 9, 8)} '9 是安装,8 是另存为
  200. 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}
  201. NewCard.Children.Add(NewStack)
  202. NewCard.SwapControl = NewStack
  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. MyCard.StackInstall(NewStack, If(TargetType = CompType.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为
  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 = CompType.ModOrDataPack AndAlso (TargetType = CompType.Mod OrElse TargetType = CompType.DataPack) Then
  223. HintAlternative.Visibility = Visibility.Visible
  224. HintAlternative.Text = If(TargetType = CompType.Mod,
  225. "以下是该项目的 Mod 版本。点击这里查看其数据包版本。", "以下是该项目的数据包版本。点击这里查看其 Mod 版本。")
  226. Else
  227. HintAlternative.Visibility = Visibility.Collapsed
  228. End If
  229. Catch ex As Exception
  230. Log(ex, "可视化工程下载列表出错", LogLevel.Feedback)
  231. End Try
  232. End Sub
  233. Private Function GetGroupedVersionName(Name As String, GroupedByDrop As Boolean, FoldOld As Boolean) As String
  234. If Name Is Nothing Then
  235. Return "其他"
  236. ElseIf Name.Contains("w") Then
  237. Return "快照版"
  238. ElseIf Not McVersion.IsFormatFit(Name) OrElse (FoldOld AndAlso McVersion.VersionToDrop(Name, True) < 120) Then
  239. Return "远古版"
  240. ElseIf GroupedByDrop Then
  241. Return McVersion.DropToVersion(McVersion.VersionToDrop(Name, True))
  242. Else
  243. Return Name
  244. End If
  245. End Function
  246. #End Region
  247. Private IsFirstInit As Boolean = True
  248. Public Sub Init() Handles Me.PageEnter
  249. AniControlEnabled += 1
  250. Project = FrmMain.PageCurrent.Additional(0)
  251. PanBack.ScrollToHome()
  252. '重启加载器
  253. If IsFirstInit Then
  254. '在 Me.Initialized 已经初始化了加载器,不再重复初始化
  255. IsFirstInit = False
  256. Else
  257. PageLoaderRestart(IsForceRestart:=True)
  258. End If
  259. '放置当前工程
  260. If CompItem IsNot Nothing Then PanIntro.Children.Remove(CompItem)
  261. CompItem = Project.ToCompItem(True, True).Init()
  262. CompItem.CanInteraction = False
  263. CompItem.Margin = New Thickness(-7, -7, 0, 8)
  264. PanIntro.Children.Insert(0, CompItem)
  265. '决定按钮显示
  266. BtnIntroWeb.Text = If(Project.FromCurseForge, "转到 CurseForge", "转到 Modrinth")
  267. BtnIntroWiki.Visibility = If(Project.WikiId = 0, Visibility.Collapsed, Visibility.Visible)
  268. AniControlEnabled -= 1
  269. End Sub
  270. '整合包安装
  271. Public Sub Install_Click(sender As MyListItem, e As EventArgs)
  272. Try
  273. '获取基本信息
  274. Dim File As CompFile = sender.Tag
  275. Dim LoaderName As String = $"{If(Project.FromCurseForge, "CurseForge", "Modrinth")} 整合包下载:{Project.TranslatedName} "
  276. '获取版本名
  277. Dim PackName As String = Project.TranslatedName.Replace(".zip", "").Replace(".rar", "").Replace(".mrpack", "").Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
  278. Dim Validate As New ValidateFolderName(McFolderSelected & "versions")
  279. If Validate.Validate(PackName) <> "" Then PackName = ""
  280. Dim InstanceName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
  281. If String.IsNullOrEmpty(InstanceName) Then Return
  282. '构造步骤加载器
  283. Dim Loaders As New List(Of LoaderBase)
  284. Dim Target As String = $"{McFolderSelected}versions\{InstanceName}\原始整合包.{If(Project.FromCurseForge, "zip", "mrpack")}"
  285. Dim LogoFileAddress As String = CompItem.PathLogo.ActualSource
  286. Loaders.Add(New LoaderDownload("下载整合包文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 10, .Block = True})
  287. Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包",
  288. Sub() ModpackInstall(Target, InstanceName, If(IO.File.Exists(LogoFileAddress), LogoFileAddress, Nothing))) With {.ProgressWeight = 0.1})
  289. '启动
  290. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged =
  291. Sub(MyLoader)
  292. Select Case MyLoader.State
  293. Case LoadState.Failed
  294. Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetBrief(), HintType.Red)
  295. Case LoadState.Interrupted
  296. Hint(MyLoader.Name & "已取消!", HintType.Blue)
  297. Case LoadState.Loading
  298. Return '不重新加载版本列表
  299. End Select
  300. McInstallFailedClearFolder(MyLoader)
  301. End Sub}
  302. Loader.Start(McFolderSelected & "versions\" & InstanceName & "\")
  303. LoaderTaskbarAdd(Loader)
  304. FrmMain.BtnExtraDownload.ShowRefresh()
  305. FrmMain.BtnExtraDownload.Ribble()
  306. Catch ex As Exception
  307. Log(ex, "下载资源整合包失败", LogLevel.Feedback)
  308. End Try
  309. End Sub
  310. '资源下载;整合包另存为
  311. Public Shared CachedFolder As New Dictionary(Of CompType, String) '仅在本次缓存的下载文件夹
  312. Public Sub Save_Click(sender As Object, e As EventArgs)
  313. Dim File As CompFile = If(TypeOf sender Is MyListItem, sender, sender.Parent).Tag
  314. RunInNewThread(
  315. Sub()
  316. Try
  317. Dim Desc As String = Nothing
  318. Select Case File.Type
  319. Case CompType.ModPack : Desc = "整合包"
  320. Case CompType.Mod : Desc = "Mod "
  321. Case CompType.ResourcePack : Desc = "资源包"
  322. Case CompType.Shader : Desc = "光影包"
  323. Case CompType.DataPack : Desc = "数据包"
  324. End Select
  325. '确认默认保存位置
  326. Dim DefaultFolder As String = Nothing
  327. If File.Type <> CompType.ModPack Then
  328. Dim SubFolder As String = Nothing
  329. Select Case File.Type
  330. Case CompType.Mod : SubFolder = "mods\"
  331. Case CompType.ResourcePack : SubFolder = "resourcepacks\"
  332. Case CompType.Shader : SubFolder = "shaderpacks\"
  333. Case CompType.DataPack : SubFolder = "" '导航到版本根目录
  334. End Select
  335. Dim IsInstanceSuitable As Func(Of McInstance, Boolean) = Nothing
  336. '获取资源所需的加载器
  337. Dim AllowedLoaders As New List(Of CompModLoaderType)
  338. If File.ModLoaders.Any Then
  339. AllowedLoaders = File.ModLoaders
  340. ElseIf Project.ModLoaders.Any Then
  341. AllowedLoaders = Project.ModLoaders
  342. End If
  343. Log($"[Comp] {Desc}要求的加载器种类:" & If(AllowedLoaders.Any(), AllowedLoaders.Join(" / "), "无要求"))
  344. '判断某个版本是否符合资源要求
  345. IsInstanceSuitable =
  346. Function(Instance As McInstance)
  347. If Not Instance.IsLoaded Then Instance.Load()
  348. '只对 Mod 和数据包进行版本检测
  349. If File.Type = CompType.Mod OrElse File.Type = CompType.DataPack Then
  350. If Not File.GameVersions.Any( '判断是否有任何一个版本匹配
  351. Function(FileVersion)
  352. Dim FileIsSnapshot As Boolean = FileVersion.Contains("预览版") OrElse Not FileVersion.Contains(".")
  353. Dim InstanceIsSnapshot As Boolean = Instance.Version.VanillaName.Contains("snapshot") OrElse Not Instance.Version.VanillaName.Contains(".")
  354. If FileIsSnapshot <> InstanceIsSnapshot Then
  355. '只有一种是预览版
  356. Return False
  357. ElseIf Not FileIsSnapshot AndAlso Not InstanceIsSnapshot Then
  358. '都不是预览版
  359. Return FileVersion = Instance.Version.VanillaName
  360. Else
  361. '都是预览版
  362. Dim FileIsNewFormat As Boolean = FileVersion.Contains(".") AndAlso Val(FileVersion.BeforeFirst(".")) > 1
  363. Dim InstanceIsNewFormat As Boolean = Instance.Version.Drop > 250
  364. If FileIsNewFormat <> InstanceIsNewFormat Then
  365. '只有一种是新格式快照
  366. Return False
  367. ElseIf FileIsNewFormat AndAlso InstanceIsNewFormat Then
  368. '都是新格式快照
  369. Return FileVersion.BeforeFirst(" ") = Instance.Version.VanillaName.BeforeFirst("-")
  370. Else
  371. '都是旧格式快照
  372. If FileVersion.Contains("w") AndAlso Instance.Version.VanillaName.Contains("w") Then
  373. '都是 w 快照
  374. Return FileVersion = Instance.Version.VanillaName
  375. Else
  376. '不全是 w 快照
  377. Return True '只能假定相同,无法判断
  378. End If
  379. End If
  380. End If
  381. End Function) Then Return False
  382. End If
  383. '加载器
  384. If Not AllowedLoaders.Any() Then Return True '无要求
  385. If AllowedLoaders.Contains(CompModLoaderType.Forge) AndAlso Instance.Version.HasForge Then Return True
  386. If AllowedLoaders.Contains(CompModLoaderType.Fabric) AndAlso Instance.Version.HasFabric Then Return True
  387. If AllowedLoaders.Contains(CompModLoaderType.NeoForge) AndAlso Instance.Version.HasNeoForge Then Return True
  388. If AllowedLoaders.Contains(CompModLoaderType.LiteLoader) AndAlso Instance.Version.HasLiteLoader Then Return True
  389. Return False
  390. End Function
  391. '获取常规资源默认下载位置
  392. If CachedFolder.ContainsKey(File.Type) Then
  393. DefaultFolder = CachedFolder(File.Type)
  394. Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}")
  395. ElseIf McInstanceSelected IsNot Nothing AndAlso IsInstanceSuitable(McInstanceSelected) Then
  396. DefaultFolder = $"{McInstanceSelected.PathIndie}{SubFolder}"
  397. Directory.CreateDirectory(DefaultFolder)
  398. Log($"[Comp] 使用当前版本作为默认下载位置:{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) New DirectoryInfo($"{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 = SelectedInstance.FullName
  414. Directory.CreateDirectory(DefaultFolder)
  415. Log($"[Comp] 使用适合的游戏版本作为默认下载位置:{DefaultFolder}")
  416. Else
  417. DefaultFolder = McFolderSelected
  418. If NeedLoad Then
  419. Hint($"当前 MC 文件夹中没有找到合适的版本!")
  420. Else
  421. Log("[Comp] 由于当前版本不兼容,使用当前的 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("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.Type = CompType.Mod Then FileName = FileName.Replace("~", "-") '~ 会导致 Mixin 加载失败
  447. RunInUi(
  448. Sub()
  449. '弹窗要求选择保存位置
  450. Dim Target As String
  451. Target = SelectSaveFile("选择保存位置", FileName,
  452. Desc & "文件|" &
  453. If(File.Type = CompType.Mod,
  454. If(File.FileName.EndsWithF(".litemod"), "*.litemod", "*.jar"),
  455. If(File.FileName.EndsWithF(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
  456. If Not Target.Contains("\") Then Return
  457. '构造步骤加载器
  458. Dim LoaderName As String = Desc & "下载:" & IO.Path.GetFileNameWithoutExtension(Target) & " "
  459. If Target <> DefaultFolder Then CachedFolder(File.Type) = GetPathFromFullPath(Target)
  460. Dim Loaders As New List(Of LoaderBase)
  461. Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True})
  462. '启动
  463. Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged = AddressOf LoaderStateChangedHintOnly}
  464. Loader.Start(1)
  465. LoaderTaskbarAdd(Loader)
  466. FrmMain.BtnExtraDownload.ShowRefresh()
  467. FrmMain.BtnExtraDownload.Ribble()
  468. End Sub)
  469. Catch ex As Exception
  470. Log(ex, "保存资源文件失败", LogLevel.Feedback)
  471. End Try
  472. End Sub, "Download CompDetail Save")
  473. End Sub
  474. Private Sub BtnIntroWeb_Click(sender As Object, e As EventArgs) Handles BtnIntroWeb.Click
  475. OpenWebsite(Project.Website)
  476. End Sub
  477. Private Sub BtnIntroWiki_Click(sender As Object, e As EventArgs) Handles BtnIntroWiki.Click
  478. OpenWebsite("https://www.mcmod.cn/class/" & Project.WikiId & ".html")
  479. End Sub
  480. Private Sub BtnIntroCopy_Click(sender As Object, e As EventArgs) Handles BtnIntroCopy.Click
  481. ClipboardSet(CompItem.LabTitle.Text & CompItem.LabTitleRaw.Text)
  482. End Sub
  483. 'Mod / 数据包 互相跳转
  484. Private Sub HintAlternative_Click() Handles HintAlternative.Click
  485. TargetType = If(TargetType = CompType.Mod, CompType.DataPack, CompType.Mod)
  486. FrmMain.PageCurrent.Additional(4) = TargetType '加载器会从这里重新拿数据
  487. PageLoaderRestart(IsForceRestart:=True)
  488. End Sub
  489. End Class