ModModpack.vb 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. Imports System.IO.Compression
  2. Public Module ModModpack
  3. '触发整合包安装的外部接口
  4. ''' <summary>
  5. ''' 弹窗要求选择一个整合包文件并进行安装。
  6. ''' </summary>
  7. Public Sub ModpackInstall()
  8. Dim File As String = SelectFile("整合包文件(*.rar;*.zip;*.mrpack)|*.rar;*.zip;*.mrpack", "选择整合包压缩文件") '选择整合包文件
  9. If String.IsNullOrEmpty(File) Then Exit Sub
  10. RunInThread(Sub() ModpackInstall(File))
  11. End Sub
  12. ''' <summary>
  13. ''' 安装一个给定的整合包文件,返回启动的安装加载器,如果未成功启动则返回 Nothing。
  14. ''' 必须在工作线程执行。
  15. ''' </summary>
  16. Public Function ModpackInstall(File As String, Optional VersionName As String = Nothing, Optional ShowHint As Boolean = True, Optional Logo As String = Nothing) As LoaderCombo(Of String)
  17. Log("[ModPack] 整合包安装请求:" & If(File, "null"))
  18. Dim Archive As ZipArchive = Nothing
  19. Dim ArchiveBaseFolder As String = ""
  20. Try
  21. '获取整合包种类与关键 Json
  22. Dim PackType As Integer = -1
  23. Try
  24. Archive = New ZipArchive(New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
  25. '从根目录判断整合包类型
  26. If Archive.GetEntry("mcbbs.packmeta") IsNot Nothing Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断)
  27. If Archive.GetEntry("mmc-pack.json") IsNot Nothing Then PackType = 2 : Exit Try 'MMC 整合包(优先于 manifest.json 判断,#4194)
  28. If Archive.GetEntry("modrinth.index.json") IsNot Nothing Then PackType = 4 : Exit Try 'Modrinth 整合包
  29. If Archive.GetEntry("manifest.json") IsNot Nothing Then
  30. Dim Json As JObject = GetJson(ReadFile(Archive.GetEntry("manifest.json").Open, Encoding.UTF8))
  31. If Json("addons") Is Nothing Then
  32. PackType = 0 : Exit Try 'CurseForge 整合包
  33. Else
  34. PackType = 3 : Exit Try 'MCBBS 整合包
  35. End If
  36. End If
  37. If Archive.GetEntry("modpack.json") IsNot Nothing Then PackType = 1 : Exit Try 'HMCL 整合包
  38. '从一级目录判断整合包类型
  39. For Each Entry In Archive.Entries
  40. Dim FullNames As String() = Entry.FullName.Split("/")
  41. ArchiveBaseFolder = FullNames(0) & "/"
  42. If Entry.FullName.EndsWithF("/versions/") AndAlso FullNames.Count = 3 Then PackType = 9 : Exit Try '压缩包
  43. '确定为一级目录下
  44. If FullNames.Count <> 2 Then Continue For
  45. '判断是否为关键文件
  46. If FullNames(1) = "mcbbs.packmeta" Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断)
  47. If FullNames(1) = "mmc-pack.json" Then PackType = 2 : Exit Try 'MMC 整合包(优先于 manifest.json 判断,#4194)
  48. If FullNames(1) = "modrinth.index.json" Then PackType = 4 : Exit Try 'Modrinth 整合包
  49. If FullNames(1) = "manifest.json" Then
  50. Dim Json As JObject = GetJson(ReadFile(Entry.Open, Encoding.UTF8))
  51. If Json("addons") Is Nothing Then
  52. PackType = 0 : Exit Try 'CurseForge 整合包
  53. Else
  54. PackType = 3 : ArchiveBaseFolder = "overrides/" : Exit Try 'MCBBS 整合包
  55. End If
  56. End If
  57. If FullNames(1) = "modpack.json" Then PackType = 1 : Exit Try 'HMCL 整合包
  58. Next
  59. Catch ex As Exception
  60. If GetExceptionDetail(ex, True).Contains("Error.WinIOError") Then
  61. Log(ex, "打开整合包文件失败", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
  62. Return Nothing
  63. ElseIf File.EndsWithF(".rar", True) Then
  64. Log(ex, "PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
  65. Return Nothing
  66. Else
  67. Log(ex, "打开整合包文件失败,文件可能损坏或为不支持的压缩包格式", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
  68. Return Nothing
  69. End If
  70. End Try
  71. '执行对应的安装方法
  72. Select Case PackType
  73. Case 0
  74. Log("[ModPack] 整合包种类:CurseForge")
  75. Return InstallPackCurseForge(File, Archive, ArchiveBaseFolder, VersionName, Logo)
  76. Case 1
  77. Log("[ModPack] 整合包种类:HMCL")
  78. Return InstallPackHMCL(File, Archive, ArchiveBaseFolder)
  79. Case 2
  80. Log("[ModPack] 整合包种类:MMC")
  81. Return InstallPackMMC(File, Archive, ArchiveBaseFolder)
  82. Case 3
  83. Log("[ModPack] 整合包种类:MCBBS")
  84. Return InstallPackMCBBS(File, Archive, ArchiveBaseFolder, VersionName)
  85. Case 4
  86. Log("[ModPack] 整合包种类:Modrinth")
  87. Return InstallPackModrinth(File, Archive, ArchiveBaseFolder, VersionName, Logo)
  88. Case 9
  89. Log("[ModPack] 整合包种类:压缩包")
  90. Archive.Dispose()
  91. Archive = Nothing
  92. Return InstallPackCompress(File, ArchiveBaseFolder)
  93. Case Else
  94. If ShowHint Then
  95. Hint("未能识别该整合包的种类,无法安装!", HintType.Critical)
  96. Else
  97. Log("[ModPack] 未能识别该整合包的种类,无法安装!")
  98. End If
  99. Return Nothing
  100. End Select
  101. Catch ex As Exception
  102. Log(ex, "准备安装整合包失败", LogLevel.Feedback)
  103. Return Nothing
  104. Finally
  105. If Archive IsNot Nothing Then Archive.Dispose()
  106. End Try
  107. End Function
  108. '整合包缓存清理
  109. Private IsInstallCacheCleared As Boolean = False
  110. Private IsInstallCacheClearing As Boolean = False
  111. Private Sub UnpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase)
  112. '清理缓存文件夹
  113. If Not IsInstallCacheCleared Then
  114. IsInstallCacheCleared = True
  115. IsInstallCacheClearing = True
  116. Try
  117. Log("[ModPack] 开始清理整合包安装缓存")
  118. DeleteDirectory(PathTemp & "PackInstall\")
  119. Log("[ModPack] 已清理整合包安装缓存")
  120. Catch ex As Exception
  121. Log(ex, "清理整合包安装缓存失败")
  122. Finally
  123. IsInstallCacheClearing = False
  124. End Try
  125. ElseIf IsInstallCacheClearing Then
  126. '等待另一个整合包安装的清理步骤完成
  127. Do While IsInstallCacheClearing
  128. Thread.Sleep(1)
  129. Loop
  130. End If
  131. '解压文件
  132. Dim RetryCount As Integer = 1
  133. Dim Encode = Encoding.GetEncoding("GB18030")
  134. Try
  135. Retry:
  136. '完全不知道为啥会出现文件正在被另一进程使用的问题,总之多试试
  137. DeleteDirectory(InstallTemp)
  138. ExtractFile(FileAddress, InstallTemp, Encode)
  139. Catch ex As Exception
  140. Log(ex, "第 " & RetryCount & " 次解压尝试失败")
  141. If TypeOf ex Is ArgumentException Then
  142. Encode = Encoding.UTF8
  143. Log("[ModPack] 已切换压缩包解压编码为 UTF8")
  144. End If
  145. If RetryCount < 5 Then
  146. Thread.Sleep(RetryCount * 2000)
  147. If Loader IsNot Nothing AndAlso Loader.LoadingState <> MyLoading.MyLoadingState.Run Then Exit Sub
  148. RetryCount += 1
  149. GoTo Retry
  150. Else
  151. Throw
  152. End If
  153. End Try
  154. End Sub
  155. #Region "不同类型整合包的安装方法"
  156. 'CurseForge
  157. Private Function InstallPackCurseForge(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String,
  158. Optional VersionName As String = Nothing, Optional Logo As String = Nothing) As LoaderCombo(Of String)
  159. '读取 Json 文件
  160. Dim Json As JObject
  161. Try
  162. Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "manifest.json").Open))
  163. If Json("minecraft") Is Nothing OrElse Json("minecraft")("version") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息")
  164. Catch ex As Exception
  165. Log(ex, "CurseForge 整合包安装信息存在问题", LogLevel.Hint)
  166. Return Nothing
  167. End Try
  168. '获取版本名
  169. Dim ShowRibble As Boolean = VersionName Is Nothing
  170. If VersionName Is Nothing Then
  171. VersionName = If(Json("name"), "")
  172. Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
  173. If Validate.Validate(VersionName) <> "" Then VersionName = ""
  174. If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
  175. If String.IsNullOrEmpty(VersionName) Then Return Nothing
  176. End If
  177. '获取 Mod API 版本信息
  178. Dim ForgeVersion As String = Nothing
  179. Dim NeoForgeVersion As String = Nothing
  180. Dim FabricVersion As String = Nothing
  181. For Each Entry In If(Json("minecraft")("modLoaders"), {})
  182. Dim Id As String = If(Entry("id"), "").ToString.ToLower
  183. If Id.StartsWithF("forge-") Then
  184. 'Forge 指定
  185. If Id.Contains("recommended") Then
  186. Log("[ModPack] 该整合包版本过老,已不支持进行安装!", LogLevel.Hint)
  187. Return Nothing
  188. End If
  189. Try
  190. Log("[ModPack] 整合包 Forge 版本:" & Id)
  191. ForgeVersion = Id.Replace("forge-", "")
  192. Exit For
  193. Catch ex As Exception
  194. Log(ex, "读取整合包 Forge 版本失败:" & Id)
  195. End Try
  196. ElseIf Id.StartsWithF("neoforge-") Then
  197. 'NeoForge 指定
  198. Try
  199. Log("[ModPack] 整合包 NeoForge 版本:" & Id)
  200. NeoForgeVersion = Id.Replace("neoforge-", "")
  201. Exit For
  202. Catch ex As Exception
  203. Log(ex, "读取整合包 NeoForge 版本失败:" & Id)
  204. End Try
  205. ElseIf Id.StartsWithF("fabric-") Then
  206. 'Fabric 指定
  207. Try
  208. Log("[ModPack] 整合包 Fabric 版本:" & Id)
  209. FabricVersion = Id.Replace("fabric-", "")
  210. Exit For
  211. Catch ex As Exception
  212. Log(ex, "读取整合包 Fabric 版本失败:" & Id)
  213. End Try
  214. End If
  215. Next
  216. '解压与配置文件
  217. Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
  218. Dim InstallLoaders As New List(Of LoaderBase)
  219. Dim OverrideHome As String = If(Json("overrides"), "")
  220. If OverrideHome <> "" Then
  221. InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
  222. Sub(Task As LoaderTask(Of String, Integer))
  223. UnpackFiles(InstallTemp, FileAddress, Task)
  224. Task.Progress = 0.5
  225. Dim OverridePath As String = InstallTemp & ArchiveBaseFolder & OverrideHome
  226. '复制结果
  227. If Directory.Exists(OverridePath) Then
  228. CopyDirectory(OverridePath, PathMcFolder & "versions\" & VersionName)
  229. Log($"[ModPack] 整合包 override 复制:{OverridePath} -> {PathMcFolder & "versions\" & VersionName}")
  230. Else
  231. Log($"[ModPack] 整合包中未找到 override 文件夹:{OverridePath}")
  232. End If
  233. Task.Progress = 0.9
  234. '开启版本隔离
  235. WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
  236. End Sub) With {
  237. .ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
  238. End If
  239. '获取 Mod 列表
  240. Dim ModList As New List(Of Integer)
  241. Dim ModOptionalList As New List(Of Integer)
  242. For Each ModEntry In If(Json("files"), {})
  243. If ModEntry("projectID") Is Nothing OrElse ModEntry("fileID") Is Nothing Then
  244. Hint("某项 Mod 缺少必要信息,已跳过:" & ModEntry.ToString)
  245. Continue For
  246. End If
  247. ModList.Add(ModEntry("fileID"))
  248. If ModEntry("required") IsNot Nothing AndAlso Not ModEntry("required").ToObject(Of Boolean) Then ModOptionalList.Add(ModEntry("fileID"))
  249. Next
  250. If ModList.Any Then
  251. Dim ModDownloadLoaders As New List(Of LoaderBase)
  252. '获取 Mod 下载信息
  253. ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
  254. Sub(Task As LoaderTask(Of Integer, JArray))
  255. Task.Output = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json"))("data")
  256. '如果文件已被删除,则 API 会跳过那一项
  257. If ModList.Count > Task.Output.Count Then Throw New Exception("整合包所需要的部分 Mod 版本已被 Mod 作者删除,因此无法完成整合包安装,请联系整合包作者更新整合包中的 Mod 版本")
  258. End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s
  259. '构造 NetFile
  260. ModDownloadLoaders.Add(New LoaderTask(Of JArray, List(Of NetFile))("构造 Mod 下载信息",
  261. Sub(Task As LoaderTask(Of JArray, List(Of NetFile)))
  262. Dim FileList As New Dictionary(Of Integer, NetFile)
  263. For Each ModJson In Task.Input
  264. Dim Id As Integer = ModJson("id").ToObject(Of Integer)
  265. '跳过重复的 Mod(疑似 CurseForge Bug)
  266. If FileList.ContainsKey(Id) Then Continue For
  267. '可选 Mod 提示
  268. If ModOptionalList.Contains(Id) Then
  269. If MyMsgBox("是否要下载整合包中的可选文件 " & ModJson("displayName").ToString & "?",
  270. "下载可选文件", "是", "否") = 2 Then
  271. Continue For
  272. End If
  273. End If
  274. '建立 CompFile
  275. Dim File As New CompFile(ModJson, CompType.Mod)
  276. If Not File.Available Then Continue For
  277. '根据 modules 和文件名后缀判断资源类型
  278. Dim TargetFolder As String
  279. If ModJson("modules").Any Then 'modules 可能返回 null(#1006)
  280. Dim ModuleNames = CType(ModJson("modules"), JArray).Select(Function(l) l("name").ToString).ToList
  281. If ModuleNames.Contains("META-INF") OrElse ModuleNames.Contains("mcmod.info") OrElse
  282. File.FileName.EndsWithF(".jar", True) Then
  283. TargetFolder = "mods"
  284. ElseIf ModuleNames.Contains("pack.mcmeta") Then
  285. TargetFolder = "resourcepacks"
  286. Else
  287. TargetFolder = "shaderpacks"
  288. End If
  289. Else
  290. TargetFolder = "mods"
  291. End If
  292. '实际的添加
  293. FileList.Add(Id, File.ToNetFile($"{PathMcFolder}versions\{VersionName}\{TargetFolder}\"))
  294. Task.Progress += 1 / (1 + ModList.Count)
  295. Next
  296. Task.Output = FileList.Values.ToList
  297. End Sub) With {.ProgressWeight = ModList.Count / 200, .Show = False}) '每 200 Mod 需要 1s
  298. '下载 Mod 文件
  299. ModDownloadLoaders.Add(New LoaderDownload("下载 Mod", New List(Of NetFile)) With {.ProgressWeight = ModList.Count * 1.5}) '每个 Mod 需要 1.5s
  300. '构造加载器
  301. InstallLoaders.Add(New LoaderCombo(Of Integer)("下载 Mod(主加载器)", ModDownloadLoaders) With
  302. {.Show = False, .ProgressWeight = ModDownloadLoaders.Sum(Function(l) l.ProgressWeight)})
  303. End If
  304. '构造加载器
  305. Dim Request As New McInstallRequest With {
  306. .TargetVersionName = VersionName,
  307. .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
  308. .MinecraftName = Json("minecraft")("version").ToString,
  309. .ForgeVersion = ForgeVersion,
  310. .NeoForgeVersion = NeoForgeVersion,
  311. .FabricVersion = FabricVersion
  312. }
  313. Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
  314. If MergeLoaders Is Nothing Then Return Nothing
  315. '构造 Libraries 加载器
  316. Dim LoadersLib As New List(Of LoaderBase)
  317. LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
  318. LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
  319. '构造总加载器
  320. Dim Loaders As New List(Of LoaderBase)
  321. Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
  322. Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
  323. Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
  324. Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
  325. Sub(Task As LoaderTask(Of String, String))
  326. '设置图标
  327. Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
  328. If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
  329. File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
  330. WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
  331. WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
  332. Log("[ModPack] 已设置整合包 Logo:" & Logo)
  333. End If
  334. '删除原始整合包文件
  335. For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
  336. If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
  337. Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target)
  338. File.Delete(Target)
  339. End If
  340. Next
  341. End Sub) With {.ProgressWeight = 0.1, .Show = False})
  342. '重复任务检查
  343. Dim LoaderName As String = "CurseForge 整合包安装:" & VersionName & " "
  344. If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
  345. Hint("该整合包正在安装中!", HintType.Critical)
  346. Return Nothing
  347. End If
  348. '启动
  349. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
  350. Loader.Start(Request.TargetVersionFolder)
  351. LoaderTaskbarAdd(Loader)
  352. FrmMain.BtnExtraDownload.ShowRefresh()
  353. If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
  354. Return Loader
  355. End Function
  356. 'Modrinth
  357. Private Function InstallPackModrinth(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String, Optional VersionName As String = Nothing, Optional Logo As String = Nothing) As LoaderCombo(Of String)
  358. '读取 Json 文件
  359. Dim Json As JObject
  360. Try
  361. Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modrinth.index.json").Open))
  362. If Json("dependencies") Is Nothing OrElse Json("dependencies")("minecraft") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息")
  363. Catch ex As Exception
  364. Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
  365. Return Nothing
  366. End Try
  367. '获取 Mod API 版本信息
  368. Dim MinecraftVersion As String = Nothing
  369. Dim ForgeVersion As String = Nothing
  370. Dim NeoForgeVersion As String = Nothing
  371. Dim FabricVersion As String = Nothing
  372. For Each Entry As JProperty In If(Json("dependencies"), {})
  373. Select Case Entry.Name.ToLower
  374. Case "minecraft"
  375. MinecraftVersion = Entry.Value.ToString
  376. Case "forge" 'eg. 14.23.5.2859 / 1.19-41.1.0
  377. ForgeVersion = Entry.Value.ToString
  378. Log("[ModPack] 整合包 Forge 版本:" & ForgeVersion)
  379. Case "neoforge", "neo-forge" 'eg. 20.6.98-beta
  380. NeoForgeVersion = Entry.Value.ToString
  381. Log("[ModPack] 整合包 NeoForge 版本:" & NeoForgeVersion)
  382. Case "fabric-loader" 'eg. 0.14.14
  383. FabricVersion = Entry.Value.ToString
  384. Log("[ModPack] 整合包 Fabric 版本:" & FabricVersion)
  385. Case "quilt-loader" 'eg. 1.0.0
  386. Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
  387. Return Nothing
  388. Case Else
  389. Hint($"无法安装整合包,其中出现了未知的 Mod 加载器 {Entry.Value}!", HintType.Critical)
  390. Return Nothing
  391. End Select
  392. Next
  393. '获取版本名
  394. Dim ShowRibble As Boolean = VersionName Is Nothing
  395. If VersionName Is Nothing Then
  396. VersionName = If(Json("name"), "")
  397. Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
  398. If Validate.Validate(VersionName) <> "" Then VersionName = ""
  399. If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
  400. If String.IsNullOrEmpty(VersionName) Then Return Nothing
  401. End If
  402. '解压和配置文件
  403. Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
  404. Dim InstallLoaders As New List(Of LoaderBase)
  405. InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
  406. Sub(Task As LoaderTask(Of String, Integer))
  407. UnpackFiles(InstallTemp, FileAddress, Task)
  408. Task.Progress = 0.5
  409. '复制 overrides 文件夹和 client-overrides 文件夹
  410. If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then
  411. CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName)
  412. Else
  413. Log("[ModPack] 整合包中未找到 override 目录,已跳过")
  414. End If
  415. Task.Progress = 0.8
  416. If Directory.Exists(InstallTemp & ArchiveBaseFolder & "client-overrides") Then
  417. CopyDirectory(InstallTemp & ArchiveBaseFolder & "client-overrides", PathMcFolder & "versions\" & VersionName)
  418. End If
  419. Task.Progress = 0.9
  420. '开启版本隔离
  421. WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
  422. End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
  423. '获取下载文件列表
  424. Dim FileList As New List(Of NetFile)
  425. For Each File In If(Json("files"), {})
  426. '检查是否需要该文件
  427. If File("env") IsNot Nothing Then
  428. Select Case File("env")("client").ToString
  429. Case "optional"
  430. If MyMsgBox("是否要下载整合包中的可选文件 " & GetFileNameFromPath(File("path").ToString) & "?",
  431. "下载可选文件", "是", "否") = 2 Then
  432. Continue For
  433. End If
  434. Case "unsupported"
  435. Continue For
  436. End Select
  437. End If
  438. '添加下载文件
  439. Dim Urls = File("downloads").Select(Function(t) t.ToString.Replace("://edge.forgecdn", "://media.forgecdn")).ToList
  440. Urls.AddRange(Urls.Select(Function(u) DlSourceModGet(u)).ToList)
  441. Urls = Urls.Distinct.ToList()
  442. FileList.Add(New NetFile(Urls, PathMcFolder & "versions\" & VersionName & "\" & File("path").ToString,
  443. New FileChecker(ActualSize:=File("fileSize").ToObject(Of Long), Hash:=File("hashes")("sha1").ToString), True))
  444. Next
  445. If FileList.Any Then
  446. InstallLoaders.Add(New LoaderDownload("下载额外文件", FileList) With {.ProgressWeight = FileList.Count * 1.5}) '每个 Mod 需要 1.5s
  447. End If
  448. '构造加载器
  449. Dim Request As New McInstallRequest With {
  450. .TargetVersionName = VersionName,
  451. .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
  452. .MinecraftName = MinecraftVersion,
  453. .ForgeVersion = ForgeVersion,
  454. .NeoForgeVersion = NeoForgeVersion,
  455. .FabricVersion = FabricVersion
  456. }
  457. Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
  458. If MergeLoaders Is Nothing Then Return Nothing
  459. '构造 Libraries 加载器
  460. Dim LoadersLib As New List(Of LoaderBase)
  461. LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
  462. LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
  463. '构造总加载器
  464. Dim Loaders As New List(Of LoaderBase)
  465. Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
  466. Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
  467. Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
  468. Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
  469. Sub(Task As LoaderTask(Of String, String))
  470. '设置图标
  471. Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
  472. If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
  473. File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
  474. WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
  475. WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
  476. Log("[ModPack] 已设置整合包 Logo:" & Logo)
  477. End If
  478. '删除原始整合包文件
  479. For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
  480. If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
  481. Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target)
  482. File.Delete(Target)
  483. End If
  484. Next
  485. End Sub) With {.ProgressWeight = 0.1, .Show = False})
  486. '重复任务检查
  487. Dim LoaderName As String = "Modrinth 整合包安装:" & VersionName & " "
  488. If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
  489. Hint("该整合包正在安装中!", HintType.Critical)
  490. Return Nothing
  491. End If
  492. '启动
  493. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
  494. Loader.Start(Request.TargetVersionFolder)
  495. LoaderTaskbarAdd(Loader)
  496. FrmMain.BtnExtraDownload.ShowRefresh()
  497. If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
  498. Return Loader
  499. End Function
  500. 'HMCL
  501. Private Function InstallPackHMCL(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String) As LoaderCombo(Of String)
  502. '读取 Json 文件
  503. Dim Json As JObject
  504. Try
  505. Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modpack.json").Open, Encoding.UTF8))
  506. Catch ex As Exception
  507. Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
  508. Return Nothing
  509. End Try
  510. '获取版本名
  511. Dim VersionName As String = If(Json("name"), "")
  512. Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
  513. If Validate.Validate(VersionName) <> "" Then VersionName = ""
  514. If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
  515. If String.IsNullOrEmpty(VersionName) Then Return Nothing
  516. '解压与配置文件
  517. Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
  518. Dim InstallLoaders As New List(Of LoaderBase)
  519. InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
  520. Sub(Task As LoaderTask(Of String, Integer))
  521. UnpackFiles(InstallTemp, FileAddress, Task)
  522. Task.Progress = 0.5
  523. '复制结果
  524. If Directory.Exists(InstallTemp & ArchiveBaseFolder & "minecraft") Then
  525. CopyDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", PathMcFolder & "versions\" & VersionName)
  526. Else
  527. Log("[ModPack] 整合包中未找到 minecraft override 目录,已跳过")
  528. End If
  529. Task.Progress = 0.9
  530. '开启版本隔离
  531. WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
  532. End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
  533. '构造加载器
  534. If Json("gameVersion") Is Nothing Then
  535. Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
  536. Return Nothing
  537. End If
  538. Dim Request As New McInstallRequest With {
  539. .TargetVersionName = VersionName,
  540. .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
  541. .MinecraftName = Json("gameVersion").ToString
  542. }
  543. Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
  544. If MergeLoaders Is Nothing Then Return Nothing
  545. '构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
  546. Dim LoadersLib As New List(Of LoaderBase)
  547. LoadersLib.Add(New LoaderTask(Of String, String)("重命名版本 Json(副加载器)",
  548. Sub()
  549. Dim RealFileName As String = PathMcFolder & "versions\" & VersionName & "\" & VersionName & ".json"
  550. Dim OldFileName As String = PathMcFolder & "versions\" & VersionName & "\pack.json"
  551. If File.Exists(OldFileName) Then
  552. '修改 id
  553. Dim FileJson = GetJson(ReadFile(OldFileName))
  554. FileJson("id") = VersionName
  555. '替换文件
  556. File.Delete(OldFileName)
  557. WriteFile(RealFileName, FileJson.ToString)
  558. Log("[ModPack] 已重命名版本 Json:" & RealFileName)
  559. End If
  560. End Sub) With {.ProgressWeight = 0.1, .Show = False})
  561. LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
  562. LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
  563. '构造总加载器
  564. Dim Loaders As New List(Of LoaderBase) From {
  565. New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)},
  566. New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)},
  567. New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8}
  568. }
  569. '重复任务检查
  570. Dim LoaderName As String = "HMCL 整合包安装:" & VersionName & " "
  571. If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
  572. Hint("该整合包正在安装中!", HintType.Critical)
  573. Return Nothing
  574. End If
  575. '启动
  576. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
  577. 'If Archive IsNot Nothing Then Archive.Dispose() '解除占用,以免在加载器中触发 “正由另一进程使用,因此该进程无法访问此文件”
  578. Loader.Start(Request.TargetVersionFolder)
  579. LoaderTaskbarAdd(Loader)
  580. FrmMain.BtnExtraDownload.ShowRefresh()
  581. FrmMain.BtnExtraDownload.Ribble()
  582. Return Loader
  583. End Function
  584. 'MMC
  585. Private Function InstallPackMMC(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String) As LoaderCombo(Of String)
  586. '读取 Json 文件
  587. Dim PackJson As JObject, PackInstance As String
  588. Try
  589. PackJson = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "mmc-pack.json").Open, Encoding.UTF8))
  590. PackInstance = ReadFile(Archive.GetEntry(ArchiveBaseFolder & "instance.cfg").Open, Encoding.UTF8)
  591. Catch ex As Exception
  592. Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
  593. Return Nothing
  594. End Try
  595. '获取版本名
  596. Dim VersionName As String = If(RegexSeek(PackInstance, "(?<=\nname\=)[^\n]+"), "")
  597. Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
  598. If Validate.Validate(VersionName) <> "" Then VersionName = ""
  599. If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
  600. If String.IsNullOrEmpty(VersionName) Then Return Nothing
  601. '解压、配置设置文件
  602. Dim InstallTemp As String = $"{PathTemp}PackInstall\{RandomInteger(0, 100000)}\"
  603. Dim SetupFile As String = $"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini"
  604. Dim InstallLoaders As New List(Of LoaderBase)
  605. InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
  606. Sub(Task As LoaderTask(Of String, Integer))
  607. UnpackFiles(InstallTemp, FileAddress, Task)
  608. Task.Progress = 0.5
  609. '复制结果
  610. If Directory.Exists(InstallTemp & ArchiveBaseFolder & ".minecraft") Then
  611. CopyDirectory(InstallTemp & ArchiveBaseFolder & ".minecraft", PathMcFolder & "versions\" & VersionName)
  612. Else
  613. Log("[ModPack] 整合包中未找到 override .minecraft 目录,已跳过")
  614. End If
  615. Task.Progress = 0.9
  616. '开启版本隔离
  617. WriteIni(SetupFile, "VersionArgumentIndie", 1)
  618. '读取 MMC 设置文件(#2655)
  619. Try
  620. Dim MMCSetupFile As String = InstallTemp & ArchiveBaseFolder & "instance.cfg"
  621. If File.Exists(MMCSetupFile) Then
  622. '将其中的等号替换为冒号,以符合 ini 文件格式
  623. WriteFile(MMCSetupFile, ReadFile(MMCSetupFile).Replace("=", ":"))
  624. If ReadIni(MMCSetupFile, "OverrideCommands", False) Then
  625. Dim PreLaunchCommand As String = ReadIni(MMCSetupFile, "PreLaunchCommand")
  626. If PreLaunchCommand <> "" Then
  627. PreLaunchCommand = PreLaunchCommand.Replace("\""", """").
  628. Replace("$INST_JAVA", "{java}javaw.exe").
  629. Replace("$INST_MC_DIR\", "{minecraft}").Replace("$INST_MC_DIR", "{minecraft}").
  630. Replace("$INST_DIR\", "{verpath}").Replace("$INST_DIR", "{verpath}").
  631. Replace("$INST_ID", "{name}").Replace("$INST_NAME", "{name}")
  632. WriteIni(SetupFile, "VersionAdvanceRun", PreLaunchCommand)
  633. Log("[ModPack] 迁移 MultiMC 版本独立设置:启动前执行命令:" & PreLaunchCommand)
  634. End If
  635. End If
  636. If ReadIni(MMCSetupFile, "JoinServerOnLaunch", False) Then
  637. Dim ServerAddress As String = ReadIni(MMCSetupFile, "JoinServerOnLaunchAddress").Replace("\""", """")
  638. WriteIni(SetupFile, "VersionServerEnter", ServerAddress)
  639. Log("[ModPack] 迁移 MultiMC 版本独立设置:自动进入服务器:" & ServerAddress)
  640. End If
  641. If ReadIni(MMCSetupFile, "IgnoreJavaCompatibility", False) Then
  642. WriteIni(SetupFile, "VersionAdvanceJava", True)
  643. Log("[ModPack] 迁移 MultiMC 版本独立设置:忽略 Java 兼容性警告")
  644. End If
  645. Dim Logo As String = ReadIni(MMCSetupFile, "iconKey", "")
  646. If Logo <> "" AndAlso File.Exists($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png") Then
  647. WriteIni(SetupFile, "LogoCustom", True)
  648. WriteIni(SetupFile, "Logo", "PCL\Logo.png")
  649. CopyFile($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png", $"{PathMcFolder}versions\{VersionName}\PCL\Logo.png")
  650. Log($"[ModPack] 迁移 MultiMC 版本独立设置:版本图标({Logo}.png)")
  651. End If
  652. End If
  653. Catch ex As Exception
  654. Log(ex, $"读取 MMC 配置文件失败({InstallTemp}{ArchiveBaseFolder}instance.cfg)")
  655. End Try
  656. End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
  657. '构造版本安装请求
  658. If PackJson("components") Is Nothing Then
  659. Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
  660. Return Nothing
  661. End If
  662. Dim Request As New McInstallRequest With {.TargetVersionName = VersionName, .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\"}
  663. For Each Component In PackJson("components")
  664. Select Case If(Component("uid"), "").ToString
  665. Case "org.lwjgl"
  666. Log("[ModPack] 已跳过 LWJGL 项")
  667. Case "net.minecraft"
  668. Request.MinecraftName = Component("version")
  669. Case "net.minecraftforge"
  670. Request.ForgeVersion = Component("version")
  671. Case "net.neoforged"
  672. Request.NeoForgeVersion = Component("version")
  673. Case "net.fabricmc.fabric-loader"
  674. Request.FabricVersion = Component("version")
  675. Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
  676. Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
  677. Return Nothing
  678. End Select
  679. Next
  680. '构造加载器
  681. Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
  682. If MergeLoaders Is Nothing Then Return Nothing
  683. '构造 Libraries 加载器
  684. Dim LoadersLib As New List(Of LoaderBase)
  685. LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
  686. LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
  687. '构造总加载器
  688. Dim Loaders As New List(Of LoaderBase)
  689. Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
  690. Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
  691. Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
  692. '重复任务检查
  693. Dim LoaderName As String = "MMC 整合包安装:" & VersionName & " "
  694. If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
  695. Hint("该整合包正在安装中!", HintType.Critical)
  696. Return Nothing
  697. End If
  698. '启动
  699. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
  700. Loader.Start(Request.TargetVersionFolder)
  701. LoaderTaskbarAdd(Loader)
  702. FrmMain.BtnExtraDownload.ShowRefresh()
  703. FrmMain.BtnExtraDownload.Ribble()
  704. Return Loader
  705. End Function
  706. 'MCBBS
  707. Private Function InstallPackMCBBS(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String,
  708. Optional VersionName As String = Nothing) As LoaderCombo(Of String)
  709. '读取 Json 文件
  710. Dim Json As JObject
  711. Try
  712. Dim Entry = If(Archive.GetEntry(ArchiveBaseFolder & "mcbbs.packmeta"), Archive.GetEntry(ArchiveBaseFolder & "manifest.json"))
  713. Json = GetJson(ReadFile(Entry.Open, Encoding.UTF8))
  714. Catch ex As Exception
  715. Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
  716. Return Nothing
  717. End Try
  718. '获取版本名
  719. Dim ShowRibble As Boolean = VersionName Is Nothing
  720. If VersionName Is Nothing Then
  721. VersionName = If(Json("name"), "")
  722. Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
  723. If Validate.Validate(VersionName) <> "" Then VersionName = ""
  724. If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
  725. If String.IsNullOrEmpty(VersionName) Then Return Nothing
  726. End If
  727. '解压与配置文件
  728. Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
  729. Dim InstallLoaders As New List(Of LoaderBase)
  730. InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
  731. Sub(Task As LoaderTask(Of String, Integer))
  732. UnpackFiles(InstallTemp, FileAddress, Task)
  733. Task.Progress = 0.5
  734. '复制结果
  735. If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then
  736. CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName)
  737. Else
  738. Log("[ModPack] 整合包中未找到 overrides 目录,已跳过")
  739. End If
  740. Task.Progress = 0.9
  741. '开启版本隔离
  742. WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
  743. End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
  744. '构造加载器
  745. If Json("addons") Is Nothing Then
  746. Hint("该整合包未提供游戏版本附加信息,无法安装!", HintType.Critical)
  747. Return Nothing
  748. End If
  749. Dim Addons As New Dictionary(Of String, String)
  750. For Each Entry In Json("addons")
  751. Addons.Add(Entry("id"), Entry("version"))
  752. Next
  753. If Not Addons.ContainsKey("game") Then
  754. Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
  755. Return Nothing
  756. End If
  757. If Addons.ContainsKey("quilt") Then
  758. Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
  759. Return Nothing
  760. End If
  761. Dim Request As New McInstallRequest With {
  762. .TargetVersionName = VersionName,
  763. .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
  764. .MinecraftName = Addons("game"),
  765. .OptiFineVersion = If(Addons.ContainsKey("optifine"), Addons("optifine"), Nothing),
  766. .ForgeVersion = If(Addons.ContainsKey("forge"), Addons("forge"), Nothing),
  767. .NeoForgeVersion = If(Addons.ContainsKey("neoforge"), Addons("neoforge"), Nothing),
  768. .FabricVersion = If(Addons.ContainsKey("fabric"), Addons("fabric"), Nothing)
  769. }
  770. Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
  771. If MergeLoaders Is Nothing Then Return Nothing
  772. '构造 Libraries 加载器
  773. Dim LoadersLib As New List(Of LoaderBase)
  774. LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
  775. LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
  776. '构造总加载器
  777. Dim Loaders As New List(Of LoaderBase)
  778. Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
  779. Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
  780. Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
  781. '重复任务检查
  782. Dim LoaderName As String = "MCBBS 整合包安装:" & VersionName & " "
  783. If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
  784. Hint("该整合包正在安装中!", HintType.Critical)
  785. Return Nothing
  786. End If
  787. '启动
  788. Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
  789. 'If Archive IsNot Nothing Then Archive.Dispose() '解除占用,以免在加载器中触发 “正由另一进程使用,因此该进程无法访问此文件”
  790. Loader.Start(Request.TargetVersionFolder)
  791. LoaderTaskbarAdd(Loader)
  792. FrmMain.BtnExtraDownload.ShowRefresh()
  793. If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
  794. Return Loader
  795. End Function
  796. '普通压缩包
  797. Private Function InstallPackCompress(FileAddress As String, ArchiveBaseFolder As String) As LoaderCombo(Of String)
  798. MyMsgBox("请在接下来打开的窗口中选择安装目标文件夹,它必须是一个空文件夹。", "安装提示", "继续", ForceWait:=True)
  799. '获取解压路径
  800. Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)")
  801. If String.IsNullOrEmpty(TargetFolder) Then Return Nothing
  802. If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Return Nothing
  803. If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Return Nothing
  804. '要求显示名称
  805. Dim NewName As String = MyMsgBoxInput("输入显示名称", "输入该文件夹在左边栏列表中显示的名称。", GetFolderNameFromPath(TargetFolder),
  806. New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})})
  807. If String.IsNullOrWhiteSpace(NewName) Then Return Nothing
  808. '解压
  809. Dim Loader As New LoaderCombo(Of String)("安装压缩包", {
  810. New LoaderTask(Of String, Integer)("安装压缩包",
  811. Sub()
  812. UnpackFiles(TargetFolder, FileAddress, Nothing)
  813. PageSelectLeft.AddFolder(TargetFolder, NewName, False) '加入文件夹列表
  814. End Sub)
  815. })
  816. Loader.Start()
  817. LoaderTaskbarAdd(Loader)
  818. FrmMain.BtnExtraDownload.ShowRefresh()
  819. FrmMain.BtnExtraDownload.Ribble()
  820. Return Loader
  821. End Function
  822. #End Region
  823. End Module