PageDownloadCompDetail.xaml.vb 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. Public Class PageDownloadCompDetail
  2. Private CompItem As MyCompItem = Nothing
  3. Private Project As CompProject
  4. #Region "加载器"
  5. Private CompFileLoader As New LoaderTask(Of Integer, List(Of CompFile))(
  6. "Comp File", Sub(Task As LoaderTask(Of Integer, List(Of CompFile))) Task.Output = CompFilesGet(Project.Id, Project.FromCurseForge))
  7. '初始化加载器信息
  8. Private Sub PageDownloadCompDetail_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
  9. Project = FrmMain.PageCurrent.Additional
  10. PageLoaderInit(Load, PanLoad, PanMain, CardIntro, CompFileLoader, AddressOf Load_OnFinish)
  11. End Sub
  12. '自动重试
  13. Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
  14. Select Case CompFileLoader.State
  15. Case LoadState.Failed
  16. Dim ErrorMessage As String = ""
  17. If CompFileLoader.Error IsNot Nothing Then ErrorMessage = CompFileLoader.Error.Message
  18. If ErrorMessage.Contains("不是有效的 json 文件") Then
  19. Log("[Comp] 下载的文件 json 列表损坏,已自动重试", LogLevel.Debug)
  20. PageLoaderRestart()
  21. End If
  22. End Select
  23. End Sub
  24. '结果 UI 化
  25. Private Class VersionSorterWithSelect
  26. Implements IComparer(Of String)
  27. Public Top As String = ""
  28. Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
  29. If x = y Then Return 0
  30. If x = Top Then Return -1
  31. If y = Top Then Return 1
  32. Return -VersionSortInteger(x, y)
  33. End Function
  34. Public Sub New(Optional Top As String = "")
  35. Me.Top = If(Top, "")
  36. End Sub
  37. End Class
  38. Private Sub Load_OnFinish()
  39. '获取目标版本与 Mod 加载器
  40. Dim TargetVersion As String = ""
  41. Select Case Project.Type
  42. Case CompType.Mod
  43. TargetVersion = If(PageDownloadMod.Loader.Input.GameVersion, "")
  44. Case CompType.ModPack
  45. TargetVersion = If(PageDownloadPack.Loader.Input.GameVersion, "")
  46. Case Else 'CompType.ResourcePack
  47. 'FUTURE: Res
  48. TargetVersion = "" 'If(PageDownloadResource.Loader.Input.GameVersion, "")
  49. End Select
  50. Dim TargetLoader = CompModLoaderType.Any
  51. If Project.Type = CompType.Mod AndAlso PageDownloadMod.Loader.Input.ModLoader <> CompModLoaderType.Any Then
  52. TargetLoader = PageDownloadMod.Loader.Input.ModLoader
  53. End If
  54. Dim TargetCardName As String = If(TargetVersion <> "" OrElse TargetLoader <> CompModLoaderType.Any,
  55. $"目标版本:{TargetVersion} {If(TargetLoader <> CompModLoaderType.Any, TargetLoader, "")}", "")
  56. '初始化字典
  57. Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New VersionSorterWithSelect(TargetCardName))
  58. Dict.Add("未知版本", New List(Of CompFile))
  59. For Each Version As CompFile In CompFileLoader.Output
  60. For Each GameVersion In Version.GameVersions
  61. '决定添加到哪个版本
  62. Dim TargetCard As String
  63. If GameVersion Is Nothing Then
  64. TargetCard = "未知版本"
  65. ElseIf GameVersion.Contains("w") OrElse GameVersion.Contains("pre") OrElse GameVersion.Contains("rc") Then
  66. TargetCard = "快照版本"
  67. ElseIf GameVersion.Split(".").Count >= 2 Then
  68. TargetCard = GameVersion
  69. Else
  70. TargetCard = "未知版本"
  71. End If
  72. '实际进行添加
  73. If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile))
  74. If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
  75. Next
  76. Next
  77. '添加筛选的版本的卡片
  78. If TargetCardName <> "" Then
  79. Dict.Add(TargetCardName, New List(Of CompFile))
  80. For Each Version As CompFile In CompFileLoader.Output
  81. If Version.GameVersions.Contains(TargetVersion) AndAlso
  82. (TargetLoader = CompModLoaderType.Any OrElse Version.ModLoaders.Contains(TargetLoader)) Then
  83. If Not Dict(TargetCardName).Contains(Version) Then Dict(TargetCardName).Add(Version)
  84. End If
  85. Next
  86. End If
  87. #Region "转化为 UI"
  88. Try
  89. '清空当前
  90. PanMain.Children.Clear()
  91. '转化为 UI
  92. For Each Pair As KeyValuePair(Of String, List(Of CompFile)) In Dict
  93. If Pair.Value.Count = 0 Then Continue For
  94. '增加卡片
  95. Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(Project.Type = CompType.ModPack, 9, 8)} 'FUTURE: Res
  96. 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}
  97. NewCard.Children.Add(NewStack)
  98. NewCard.SwapControl = NewStack
  99. PanMain.Children.Add(NewCard)
  100. '确定卡片是否展开
  101. If Pair.Key = TargetCardName Then
  102. MyCard.StackInstall(NewStack, If(Project.Type = CompType.ModPack, 9, 8), Pair.Key) 'FUTURE: Res
  103. Else
  104. NewCard.IsSwaped = True
  105. End If
  106. '增加提示
  107. If Pair.Key = "未知版本" Then
  108. NewStack.Children.Add(New MyHint With {.Text = "由于 API 的版本信息更新缓慢,可能无法识别刚更新不久的 MC 版本,只需等待几天即可自动恢复正常。", .IsWarn = False, .Margin = New Thickness(0, 0, 0, 7)})
  109. End If
  110. Next
  111. '如果只有一张卡片,展开第一张卡片
  112. If PanMain.Children.Count = 1 Then
  113. CType(PanMain.Children(0), MyCard).IsSwaped = False
  114. End If
  115. Catch ex As Exception
  116. Log(ex, "可视化工程下载列表出错", LogLevel.Feedback)
  117. End Try
  118. #End Region
  119. End Sub
  120. #End Region
  121. Private IsFirstInit As Boolean = True
  122. Public Sub Init() Handles Me.PageEnter
  123. AniControlEnabled += 1
  124. Project = FrmMain.PageCurrent.Additional
  125. PanBack.ScrollToHome()
  126. '重启加载器
  127. If IsFirstInit Then
  128. '在 Me.Initialized 已经初始化了加载器,不再重复初始化
  129. IsFirstInit = False
  130. Else
  131. PageLoaderRestart(IsForceRestart:=True)
  132. End If
  133. '放置当前工程
  134. If CompItem IsNot Nothing Then PanIntro.Children.Remove(CompItem)
  135. CompItem = Project.ToCompItem(True, True)
  136. CompItem.Margin = New Thickness(-7, -7, 0, 8)
  137. PanIntro.Children.Insert(0, CompItem)
  138. '决定按钮显示
  139. BtnIntroWeb.Text = If(Project.FromCurseForge, "转到 CurseForge", "转到 Modrinth")
  140. BtnIntroWiki.Visibility = If(Project.WikiId = 0, Visibility.Collapsed, Visibility.Visible)
  141. BtnIntroMCBBS.Visibility = If(Project.MCBBS = 0, Visibility.Collapsed, Visibility.Visible)
  142. AniControlEnabled -= 1
  143. End Sub
  144. '整合包下载(安装)
  145. Public Sub Install_Click(sender As MyListItem, e As EventArgs)
  146. Try
  147. '获取基本信息
  148. Dim File As CompFile = sender.Tag
  149. Dim LoaderName As String = $"{If(Project.FromCurseForge, "CurseForge", "Modrinth")} 整合包下载:{Project.TranslatedName} "
  150. '获取版本名
  151. Dim PackName As String = Project.TranslatedName.Replace(".zip", "").Replace(".rar", "").Replace(".mrpack", "").Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
  152. Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
  153. If Validate.Validate(PackName) <> "" Then PackName = ""
  154. Dim VersionName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
  155. If String.IsNullOrEmpty(VersionName) Then Exit Sub
  156. '构造步骤加载器
  157. Dim Loaders As New List(Of LoaderBase)
  158. Dim Target As String = $"{PathMcFolder}versions\{VersionName}\原始整合包.{If(Project.FromCurseForge, "zip", "mrpack")}"
  159. Dim LogoFileAddress As String = PathTemp & "CompLogo\" & GetHash(CompItem.Logo) & ".png"
  160. Loaders.Add(New LoaderDownload("下载整合包文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 10, .Block = True})
  161. Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包",
  162. Sub()
  163. If Not ModpackInstall(Target, VersionName, Logo:=If(IO.File.Exists(LogoFileAddress), LogoFileAddress, Nothing)) Then
  164. Throw New Exception("整合包安装出现异常!")
  165. End If
  166. End Sub) With {.ProgressWeight = 0.1})
  167. '启动
  168. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = Sub(MyLoader)
  169. Select Case MyLoader.State
  170. Case LoadState.Failed
  171. Hint(MyLoader.Name & "失败:" & GetExceptionSummary(MyLoader.Error), HintType.Critical)
  172. Case LoadState.Aborted
  173. Hint(MyLoader.Name & "已取消!", HintType.Info)
  174. Case LoadState.Loading
  175. Exit Sub '不重新加载版本列表
  176. End Select
  177. McInstallFailedClearFolder(MyLoader)
  178. End Sub}
  179. Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
  180. LoaderTaskbarAdd(Loader)
  181. FrmMain.BtnExtraDownload.ShowRefresh()
  182. FrmMain.BtnExtraDownload.Ribble()
  183. Catch ex As Exception
  184. Log(ex, "下载资源整合包失败", LogLevel.Feedback)
  185. End Try
  186. End Sub
  187. 'Mod 下载;整合包另存为
  188. Public Shared CachedFolder As String = Nothing '仅在本次缓存的下载文件夹
  189. Public Sub Save_Click(sender As Object, e As EventArgs)
  190. Dim File As CompFile = If(TypeOf sender Is MyListItem, sender, sender.Parent).Tag
  191. RunInNewThread(
  192. Sub()
  193. Try
  194. Dim Desc As String = If(Project.Type = CompType.ModPack, "整合包", If(Project.Type = CompType.Mod, "Mod ", "资源包"))
  195. '确认默认保存位置
  196. Dim DefaultFolder As String = Nothing
  197. If Project.Type = CompType.Mod Then
  198. '获取 Mod 所需的加载器种类
  199. Dim AllowForge As Boolean? = Nothing, AllowFabric As Boolean? = Nothing
  200. If File.ModLoaders.Count > 0 Then '从文件中获取
  201. AllowForge = File.ModLoaders.Contains(CompModLoaderType.Forge)
  202. AllowFabric = File.ModLoaders.Contains(CompModLoaderType.Fabric)
  203. ElseIf Project.ModLoaders.Count > 0 Then '从工程中获取
  204. AllowForge = Project.ModLoaders.Contains(CompModLoaderType.Forge)
  205. AllowFabric = Project.ModLoaders.Contains(CompModLoaderType.Fabric)
  206. End If
  207. If AllowForge IsNot Nothing AndAlso Not AllowForge AndAlso
  208. AllowFabric IsNot Nothing AndAlso Not AllowFabric Then
  209. AllowForge = Nothing : AllowFabric = Nothing
  210. End If
  211. Log("[Comp] 允许 Forge:" & If(AllowForge, "未知") & ",允许 Fabric:" & If(AllowFabric, "未知"))
  212. '判断某个版本是否符合要求
  213. Dim IsVersionSuitable As Func(Of McVersion, Boolean) =
  214. Function(Version)
  215. If Not Version.IsLoaded Then Version.Load()
  216. If Not Version.Modable Then Return False
  217. If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso
  218. Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v.Split(".")(1) = Version.Version.McCodeMain.ToString) Then Return False
  219. If AllowForge Is Nothing OrElse AllowFabric Is Nothing Then Return True
  220. If AllowForge AndAlso Version.Version.HasForge Then Return True
  221. If AllowFabric AndAlso Version.Version.HasFabric Then Return True
  222. Return False
  223. End Function
  224. '获取 Mod 默认下载位置
  225. If CachedFolder IsNot Nothing Then
  226. DefaultFolder = CachedFolder
  227. Log("[Comp] 使用上次下载时的文件夹作为默认下载位置")
  228. ElseIf McVersionCurrent IsNot Nothing AndAlso IsVersionSuitable(McVersionCurrent) Then
  229. DefaultFolder = McVersionCurrent.PathIndie & "mods\"
  230. Directory.CreateDirectory(DefaultFolder)
  231. Log("[Comp] 使用当前版本的 mods 文件夹作为默认下载位置(" & McVersionCurrent.Name & ")")
  232. Else
  233. Dim NeedLoad As Boolean = McVersionListLoader.State <> LoadState.Finished
  234. If NeedLoad Then
  235. Hint("正在查找适合的游戏版本……")
  236. LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
  237. End If
  238. Dim SuitableVersions As New List(Of McVersion)
  239. For Each Version As McVersion In McVersionList.Values.SelectMany(Function(l) l)
  240. If IsVersionSuitable(Version) Then SuitableVersions.Add(Version)
  241. Next
  242. If SuitableVersions.Count = 0 Then
  243. DefaultFolder = PathMcFolder
  244. If NeedLoad Then
  245. Hint("当前 MC 文件夹中没有找到适合这个 Mod 的版本!")
  246. Else
  247. Log("[Comp] 由于当前版本不兼容,使用当前的 MC 文件夹作为默认下载位置")
  248. End If
  249. Else '选择 Mod 数量最多的版本
  250. Dim SelectedVersion = SuitableVersions.OrderBy(Function(v)
  251. Dim Info As New DirectoryInfo(v.PathIndie & "mods\")
  252. Return If(Info.Exists, Info.GetFiles().Length, -1)
  253. End Function).LastOrDefault()
  254. DefaultFolder = SelectedVersion.PathIndie & "mods\"
  255. Directory.CreateDirectory(DefaultFolder)
  256. Log("[Comp] 使用适合的游戏版本作为默认下载位置(" & SelectedVersion.Name & ")")
  257. End If
  258. End If
  259. End If
  260. '获取基本信息
  261. Dim FileName As String
  262. If Project.TranslatedName = Project.RawName Then
  263. FileName = File.FileName
  264. Else
  265. Dim ChineseName As String = Project.TranslatedName.Split(" (").First.Split(" - ").First.
  266. Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
  267. Select Case Setup.Get("ToolDownloadTranslate")
  268. Case 0
  269. FileName = $"[{ChineseName}] {File.FileName}"
  270. Case 1
  271. FileName = $"{ChineseName}-{File.FileName}"
  272. Case 2
  273. FileName = $"{File.FileName}-{ChineseName}"
  274. Case Else
  275. FileName = File.FileName
  276. End Select
  277. End If
  278. RunInUi(
  279. Sub()
  280. '弹窗要求选择保存位置
  281. Dim Target As String
  282. Target = SelectAs("选择保存位置", FileName,
  283. Desc & "文件|" &
  284. If(Project.Type = CompType.Mod,
  285. If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"),
  286. If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
  287. If Not Target.Contains("\") Then Exit Sub
  288. '构造步骤加载器
  289. Dim LoaderName As String = Desc & "下载:" & File.DisplayName & " "
  290. If Target <> DefaultFolder AndAlso Project.Type = CompType.Mod Then CachedFolder = GetPathFromFullPath(Target)
  291. Dim Loaders As New List(Of LoaderBase)
  292. Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True})
  293. '启动
  294. Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
  295. Loader.Start(1)
  296. LoaderTaskbarAdd(Loader)
  297. FrmMain.BtnExtraDownload.ShowRefresh()
  298. FrmMain.BtnExtraDownload.Ribble()
  299. End Sub)
  300. Catch ex As Exception
  301. Log(ex, "保存资源文件失败", LogLevel.Feedback)
  302. End Try
  303. End Sub, "Download CompDetail Save")
  304. End Sub
  305. Private Sub BtnIntroWeb_Click(sender As Object, e As EventArgs) Handles BtnIntroWeb.Click
  306. OpenWebsite(Project.Website)
  307. End Sub
  308. Private Sub BtnIntroWiki_Click(sender As Object, e As EventArgs) Handles BtnIntroWiki.Click
  309. OpenWebsite("https://www.mcmod.cn/class/" & Project.WikiId & ".html")
  310. End Sub
  311. Private Sub BtnIntroMCBBS_Click(sender As Object, e As EventArgs) Handles BtnIntroMCBBS.Click
  312. OpenWebsite("https://www.mcbbs.net/thread-" & Project.MCBBS & "-1-1.html")
  313. End Sub
  314. Private Sub BtnIntroCopy_Click(sender As Object, e As EventArgs) Handles BtnIntroCopy.Click
  315. ClipboardSet(CompItem.LabTitle.Text)
  316. End Sub
  317. End Class