PageDownloadCompDetail.xaml.vb 19 KB

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