345 lines
23 KiB
VB.net
345 lines
23 KiB
VB.net
Public Module ResourceFileLoader
|
|
Private Const ResourceFileCacheVersion As Integer = 16
|
|
|
|
'加载 Mod 列表
|
|
Public McModLoader As New LoaderTask(Of String, List(Of ResourceFile))("Mod List Loader", AddressOf McModLoad)
|
|
Private Sub McModLoad(Loader As LoaderTask(Of String, List(Of ResourceFile)))
|
|
Try
|
|
RunInUiWait(Sub() If FrmInstanceMod IsNot Nothing Then FrmInstanceMod.Load.ShowProgress = False)
|
|
|
|
'等待 Mod 更新完成
|
|
If PageInstanceMod.UpdatingInstanceModFolders.Contains(Loader.Input) Then
|
|
Log($"[Mod] 等待 Mod 更新完成后才能继续加载 Mod 列表:" & Loader.Input)
|
|
Try
|
|
RunInUiWait(Sub() If FrmInstanceMod IsNot Nothing Then FrmInstanceMod.Load.Text = "正在更新 Mod")
|
|
Do Until Not PageInstanceMod.UpdatingInstanceModFolders.Contains(Loader.Input)
|
|
If Loader.IsInterrupted Then Return
|
|
Thread.Sleep(100)
|
|
Loop
|
|
Finally
|
|
RunInUiWait(Sub() If FrmInstanceMod IsNot Nothing Then FrmInstanceMod.Load.Text = "正在加载 Mod 列表")
|
|
End Try
|
|
FrmInstanceMod.LoaderRun(LoaderFolderRunType.UpdateOnly)
|
|
End If
|
|
|
|
'获取 Mod 文件夹下的可用文件列表
|
|
Dim ModFileList As New List(Of FileInfo)
|
|
If Directory.Exists(Loader.Input) Then
|
|
Dim RawName As String = Loader.Input.Lower
|
|
For Each File As FileInfo In EnumerateFiles(Loader.Input)
|
|
If File.DirectoryName.Lower & "\" <> RawName Then
|
|
'仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod
|
|
If Not (PageInstanceLeft.Instance IsNot Nothing AndAlso PageInstanceLeft.Instance.Version.HasForge AndAlso
|
|
PageInstanceLeft.Instance.Version.Vanilla.Major < 13 AndAlso
|
|
File.Directory.Name = $"1.{PageInstanceLeft.Instance.Version.Vanilla.Major}.{PageInstanceLeft.Instance.Version.Vanilla.Build}") Then
|
|
Continue For
|
|
End If
|
|
End If
|
|
Static IsModFile As Func(Of String, Boolean) =
|
|
Function(FullName As String)
|
|
If FullName Is Nothing OrElse Not FullName.Contains(".") Then Return False
|
|
FullName = FullName.Lower
|
|
If FullName.EndsWithF(".jar", True) OrElse FullName.EndsWithF(".zip", True) OrElse FullName.EndsWithF(".litemod", True) OrElse
|
|
FullName.EndsWithF(".jar.disabled", True) OrElse FullName.EndsWithF(".zip.disabled", True) OrElse FullName.EndsWithF(".litemod.disabled", True) OrElse
|
|
FullName.EndsWithF(".jar.old", True) OrElse FullName.EndsWithF(".zip.old", True) OrElse FullName.EndsWithF(".litemod.old", True) Then Return True
|
|
Return False
|
|
End Function
|
|
If IsModFile(File.FullName) Then ModFileList.Add(File)
|
|
Next
|
|
End If
|
|
|
|
'获取本地文件缓存
|
|
Dim CachePath As String = PathTemp & "Cache\LocalMod.json"
|
|
Dim Cache As New JObject
|
|
Try
|
|
Dim CacheContent As String = ReadFile(CachePath)
|
|
If Not String.IsNullOrWhiteSpace(CacheContent) Then
|
|
Cache = GetJson(CacheContent)
|
|
If Not Cache.ContainsKey("version") OrElse Cache("version").ToObject(Of Integer) <> ResourceFileCacheVersion Then
|
|
Log($"[Mod] 本地 Mod 信息缓存版本已过期,将弃用这些缓存信息", NotifyLevel.DebugModeOnly)
|
|
Cache = New JObject
|
|
End If
|
|
End If
|
|
Catch ex As Exception
|
|
Log(ex, "读取本地 Mod 信息缓存失败,已重置")
|
|
Cache = New JObject
|
|
End Try
|
|
Cache("version") = ResourceFileCacheVersion
|
|
|
|
'加载 Mod 列表
|
|
Dim ModList As New List(Of ResourceFile)
|
|
For Each ModFile As FileInfo In ModFileList
|
|
If Loader.IsInterrupted Then Return
|
|
Dim ModEntry As New ResourceFile(ModFile)
|
|
Dim DumpMod As ResourceFile = ModList.FirstOrDefault(Function(m) m.EnabledName = ModEntry.EnabledName) '存在两个文件,名称相同,但一个启用一个禁用
|
|
If DumpMod IsNot Nothing Then
|
|
Dim DisabledMod As ResourceFile = If(DumpMod.IsEnabled, ModEntry, DumpMod)
|
|
Log($"[Mod] 重复的 Mod 文件:{DumpMod.File.Name} 与 {ModEntry.File.Name},已忽略 {DisabledMod.File.Name}", NotifyLevel.DebugModeOnly)
|
|
If DisabledMod Is ModEntry Then
|
|
Continue For
|
|
Else
|
|
ModList.Remove(DisabledMod)
|
|
End If
|
|
End If
|
|
ModList.Add(ModEntry)
|
|
Next
|
|
Log($"[Mod] 共发现 {ModList.Count} 个 Mod")
|
|
|
|
'排序
|
|
ModList = ModList.OrderBy(Function(m) m.File.Name).ToList
|
|
|
|
'回设
|
|
If Loader.IsInterrupted Then Return
|
|
Loader.Output = ModList
|
|
|
|
'开始联网加载
|
|
'TODO: 添加信息获取中提示
|
|
McModDetailLoader.Start(New KeyValuePair(Of List(Of ResourceFile), JObject)(ModList, Cache), IsForceRestart:=True)
|
|
|
|
Catch ex As Exception
|
|
Log(ex, "Mod 列表加载失败", NotifyLevel.DebugModeOnly)
|
|
Throw
|
|
End Try
|
|
End Sub
|
|
|
|
'联网加载 Mod 详情
|
|
Public McModDetailLoader As New LoaderTask(Of KeyValuePair(Of List(Of ResourceFile), JObject), Integer)("Mod List Detail Loader", AddressOf McModDetailLoad)
|
|
Private Sub McModDetailLoad(Loader As LoaderTask(Of KeyValuePair(Of List(Of ResourceFile), JObject), Integer))
|
|
Dim Mods As New List(Of ResourceFile)
|
|
Dim Cache As JObject = Loader.Input.Value
|
|
Static GetTargetModLoaders As Func(Of List(Of ModLoaderTypes)) =
|
|
Function() As List(Of ModLoaderTypes)
|
|
Dim Loaders As New List(Of ModLoaderTypes)
|
|
If PageInstanceLeft.Instance.Version.HasForge Then Loaders.Add(ModLoaderTypes.Forge)
|
|
If PageInstanceLeft.Instance.Version.HasNeoForge Then Loaders.Add(ModLoaderTypes.NeoForge)
|
|
If PageInstanceLeft.Instance.Version.HasFabric Then Loaders.Add(ModLoaderTypes.Fabric)
|
|
If PageInstanceLeft.Instance.Version.HasLiteLoader Then Loaders.Add(ModLoaderTypes.LiteLoader)
|
|
If Not Loaders.Any() Then Loaders.AddRange({ModLoaderTypes.Forge, ModLoaderTypes.NeoForge, ModLoaderTypes.Fabric, ModLoaderTypes.LiteLoader, ModLoaderTypes.Quilt})
|
|
Return Loaders
|
|
End Function
|
|
'读取缓存,获取需要更新的 Mod 列表
|
|
For Each ModEntry As ResourceFile In Loader.Input.Key
|
|
If Loader.IsInterrupted Then Return
|
|
Dim CacheKey = ModEntry.ModrinthHash & PageInstanceLeft.Instance.Version.VanillaName & GetTargetModLoaders().Join("")
|
|
If Cache.ContainsKey(CacheKey) Then
|
|
ModEntry.FromJson(Cache(CacheKey))
|
|
'如果缓存中的信息在 6 小时以内更新过,则无需重新获取
|
|
If ModEntry.OnlineDataLoaded AndAlso Date.Now - Cache(CacheKey)("Project")("CacheTime").ToObject(Of Date) < New TimeSpan(6, 0, 0) Then Continue For
|
|
End If
|
|
Mods.Add(ModEntry)
|
|
Next
|
|
Log($"[Mod] 有 {Mods.Where(Function(m) m.Project Is Nothing).Count} 个 Mod 需要联网获取信息,{Mods.Where(Function(m) m.Project IsNot Nothing).Count} 个 Mod 需要更新信息")
|
|
If Not Mods.Any Then
|
|
Loader.Input.Key.Where(Function(m) m.Version Is Nothing).ForAll(Sub(m) m.LoadMetadataFromJar()) '从 JAR 中获取缺失的版本信息(下面有另一个分支)
|
|
Return
|
|
End If
|
|
'获取作为检查目标的加载器和版本
|
|
'此处不应向下扩展检查的 MC 小版本,例如 Mod 在更新 1.16.5 后,对早期的 1.16.2 版本发布了修补补丁,这会导致 PCL 将 1.16.5 版本的 Mod 降级到 1.16.2
|
|
Dim TargetMcVersion As McVersion = PageInstanceLeft.Instance.Version
|
|
Dim ModLoaders = GetTargetModLoaders()
|
|
Dim VanillaVersion = TargetMcVersion.VanillaName
|
|
'开始网络获取
|
|
Log($"[Mod] 目标加载器:{ModLoaders.Join("/")},版本:{VanillaVersion}")
|
|
Dim EndedThreadCount As Integer = 0, IsFailed As Boolean = False
|
|
Dim CurrentTaskThread As Thread = Thread.CurrentThread
|
|
'从 Modrinth 获取信息
|
|
RunInNewThread(
|
|
Sub()
|
|
Try
|
|
'步骤 1:获取 Hash 与对应的工程 ID
|
|
Dim ModrinthHashes = Mods.Select(Function(m) m.ModrinthHash).ToList()
|
|
Dim ModrinthVersion As JObject = DlModRequest("https://api.modrinth.com/v2/version_files", HttpMethod.Post,
|
|
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")
|
|
Log($"[Mod] 从 Modrinth 获取到 {ModrinthVersion.Count} 个本地 Mod 的对应信息")
|
|
'步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系
|
|
If ModrinthVersion.Count = 0 Then Return
|
|
Dim ModrinthMapping As New Dictionary(Of String, List(Of ResourceFile))
|
|
For Each Entry In Mods
|
|
If Not ModrinthVersion.ContainsKey(Entry.ModrinthHash) Then Continue For
|
|
If ModrinthVersion(Entry.ModrinthHash)("files")(0)("hashes")("sha1") <> Entry.ModrinthHash Then Continue For
|
|
Dim ProjectId = ModrinthVersion(Entry.ModrinthHash)("project_id").ToString
|
|
If ResourceProject.Cache.ContainsKey(ProjectId) AndAlso Entry.Project Is Nothing Then Entry.Project = ResourceProject.Cache(ProjectId) '读取已加载的缓存,加快结果出现速度
|
|
If Not ModrinthMapping.ContainsKey(ProjectId) Then ModrinthMapping(ProjectId) = New List(Of ResourceFile)
|
|
ModrinthMapping(ProjectId).Add(Entry)
|
|
'记录对应的 ProjectVersion
|
|
Dim File = ResourceVersion.FromPlatformJson(ModrinthVersion(Entry.ModrinthHash), ResourceTypes.Mod)
|
|
If Entry.ProjectVersion Is Nothing OrElse Entry.ProjectVersion.ReleaseDate < File.ReleaseDate Then
|
|
Entry.ProjectVersion = File
|
|
Else
|
|
Entry.ProjectVersion.Version = File.Version '使用来自 Modrinth 的版本号
|
|
End If
|
|
Next
|
|
If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return
|
|
Log($"[Mod] 需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息")
|
|
'步骤 3:获取工程信息
|
|
If Not ModrinthMapping.Any() Then Return
|
|
Dim ModrinthProject As JArray = DlModRequest(
|
|
$"https://api.modrinth.com/v2/projects?ids=[""{ModrinthMapping.Keys.Join(""",""")}""]")
|
|
For Each ProjectJson In ModrinthProject
|
|
Dim Project As New ResourceProject(ProjectJson)
|
|
For Each Entry In ModrinthMapping(Project.Id)
|
|
Entry.Project = Project
|
|
Next
|
|
Next
|
|
Log($"[Mod] 已从 Modrinth 获取本地 Mod 信息,继续获取更新信息")
|
|
'步骤 4:获取更新信息
|
|
Dim ModrinthUpdate As JObject = DlModRequest("https://api.modrinth.com/v2/version_files/update", HttpMethod.Post,
|
|
$"{{""hashes"": [""{ModrinthMapping.SelectMany(Function(l) l.Value.Select(Function(m) m.ModrinthHash)).Join(""",""")}""], ""algorithm"": ""sha1"",
|
|
""loaders"": [""{ModLoaders.Join(""",""").Lower}""],""game_versions"": [""{VanillaVersion}""]}}", "application/json")
|
|
For Each Entry In Mods
|
|
If Not ModrinthUpdate.ContainsKey(Entry.ModrinthHash) OrElse Entry.ProjectVersion Is Nothing Then Continue For
|
|
Dim UpdateFile = ResourceVersion.FromPlatformJson(ModrinthUpdate(Entry.ModrinthHash), ResourceTypes.Mod)
|
|
If Not UpdateFile.DownloadAvailable Then Continue For
|
|
If ModeDebug Then Log($"[Mod] 本地文件 {Entry.ProjectVersion.FileName} 在 Modrinth 上的最新版为 {UpdateFile.FileName}")
|
|
If Entry.ProjectVersion.ReleaseDate >= UpdateFile.ReleaseDate OrElse Entry.ProjectVersion.Hash = UpdateFile.Hash Then Continue For
|
|
'设置更新日志与更新文件
|
|
If Entry.UpdateFile IsNot Nothing AndAlso UpdateFile.Hash = Entry.UpdateFile.Hash Then '合并
|
|
Entry.ChangelogUrls.Add($"https://modrinth.com/mod/{ModrinthUpdate(Entry.ModrinthHash)("project_id")}/changelog?g={VanillaVersion}")
|
|
UpdateFile.DownloadUrls.AddRange(Entry.UpdateFile.DownloadUrls) '合并下载源
|
|
Entry.UpdateFile = UpdateFile '优先使用 Modrinth 的文件
|
|
ElseIf Entry.UpdateFile Is Nothing OrElse UpdateFile.ReleaseDate >= Entry.UpdateFile.ReleaseDate Then '替换
|
|
Entry.ChangelogUrls = New List(Of String) From {$"https://modrinth.com/mod/{ModrinthUpdate(Entry.ModrinthHash)("project_id")}/changelog?g={VanillaVersion}"}
|
|
Entry.UpdateFile = UpdateFile
|
|
End If
|
|
Next
|
|
Log($"[Mod] 从 Modrinth 获取本地 Mod 信息结束")
|
|
Catch ex As Exception
|
|
Log(ex, "从 Modrinth 获取本地 Mod 信息失败")
|
|
IsFailed = True
|
|
Finally
|
|
EndedThreadCount += 1
|
|
End Try
|
|
End Sub, "Mod List Detail Loader Modrinth")
|
|
'从 CurseForge 获取信息
|
|
RunInNewThread(
|
|
Sub()
|
|
Try
|
|
'步骤 1:获取 Hash 与对应的工程 ID
|
|
Dim CurseForgeHashes As New List(Of UInteger)
|
|
For Each Entry In Mods
|
|
CurseForgeHashes.Add(Entry.CurseForgeHash)
|
|
If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return
|
|
Next
|
|
Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432", HttpMethod.Post,
|
|
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches")
|
|
Log($"[Mod] 从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地 Mod 的对应信息")
|
|
'步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系
|
|
If Not CurseForgeRaw.Any() Then Return
|
|
Dim CurseForgeMapping As New Dictionary(Of Integer, List(Of ResourceFile))
|
|
For Each Project In CurseForgeRaw
|
|
Dim ProjectId = Project("id").ToString
|
|
Dim Hash As UInteger = Project("file")("fileFingerprint")
|
|
For Each Entry In Mods
|
|
If Entry.CurseForgeHash <> Hash Then Continue For
|
|
If ResourceProject.Cache.ContainsKey(ProjectId) AndAlso Entry.Project Is Nothing Then Entry.Project = ResourceProject.Cache(ProjectId) '读取已加载的缓存,加快结果出现速度
|
|
If Not CurseForgeMapping.ContainsKey(ProjectId) Then CurseForgeMapping(ProjectId) = New List(Of ResourceFile)
|
|
CurseForgeMapping(ProjectId).Add(Entry)
|
|
'记录对应的 ProjectVersion
|
|
Dim File = ResourceVersion.FromPlatformJson(Project("file"), ResourceTypes.Mod)
|
|
If Entry.ProjectVersion Is Nothing OrElse Entry.ProjectVersion.ReleaseDate < File.ReleaseDate Then Entry.ProjectVersion = File
|
|
Next
|
|
Next
|
|
If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return
|
|
Log($"[Mod] 需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息")
|
|
'步骤 3:获取工程信息
|
|
If Not CurseForgeMapping.Any() Then Return
|
|
Dim CurseForgeProject = DlModRequest("https://api.curseforge.com/v1/mods", HttpMethod.Post,
|
|
$"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")("data")
|
|
Dim UpdateFileIds As New Dictionary(Of Integer, List(Of ResourceFile)) 'FileId -> 本地 Mod 文件列表
|
|
Dim FileIdToProjectSlug As New Dictionary(Of Integer, String)
|
|
For Each ProjectJson In CurseForgeProject
|
|
If ProjectJson("isAvailable") IsNot Nothing AndAlso Not ProjectJson("isAvailable").ToObject(Of Boolean) Then Continue For
|
|
'设置 Entry 中的工程信息
|
|
Dim Project As New ResourceProject(ProjectJson)
|
|
For Each Entry In CurseForgeMapping(Project.Id) '倒查防止 CurseForge 返回的内容有漏
|
|
If Entry.Project IsNot Nothing AndAlso Entry.Project.Platform = ResourcePlatforms.Modrinth Then
|
|
Entry.Project = Entry.Project '再次触发修改事件
|
|
Continue For
|
|
End If
|
|
Entry.Project = Project
|
|
Next
|
|
'查找或许版本更新的文件列表
|
|
If ModLoaders.IsSingle Then
|
|
Dim NewestVersion As String = Nothing
|
|
Dim NewestFileIds As New List(Of Integer)
|
|
For Each IndexEntry In ProjectJson("latestFilesIndexes")
|
|
If IndexEntry("modLoader") Is Nothing OrElse ModLoaders.Single <> IndexEntry("modLoader").ToObject(Of Integer) Then Continue For 'ModLoader 唯一且匹配
|
|
Dim IndexVersion As String = IndexEntry("gameVersion")
|
|
If IndexVersion <> VanillaVersion Then Continue For 'MC 版本匹配
|
|
'由于 latestFilesIndexes 是按时间从新到老排序的,所以只需取第一个;如果需要检查多个 releaseType 下的文件,将 > -1 改为 = 1,但这应当并不会获取到更新的文件
|
|
If NewestVersion IsNot Nothing AndAlso CompareVersion(NewestVersion, IndexVersion) > -1 Then Continue For '只保留最新 MC 版本
|
|
If NewestVersion <> IndexVersion Then
|
|
NewestVersion = IndexVersion
|
|
NewestFileIds.Clear()
|
|
End If
|
|
NewestFileIds.Add(IndexEntry("fileId").ToObject(Of Integer))
|
|
Next
|
|
For Each FileId In NewestFileIds
|
|
If Not UpdateFileIds.ContainsKey(FileId) Then UpdateFileIds(FileId) = New List(Of ResourceFile)
|
|
UpdateFileIds(FileId).AddRange(CurseForgeMapping(Project.Id))
|
|
FileIdToProjectSlug(FileId) = Project.Slug
|
|
Next
|
|
End If
|
|
Next
|
|
Log($"[Mod] 已从 CurseForge 获取本地 Mod 信息,需要获取 {UpdateFileIds.Count} 个用于检查更新的文件信息")
|
|
'步骤 4:获取更新文件信息
|
|
If Not UpdateFileIds.Any() Then Return
|
|
Dim CurseForgeFiles = DlModRequest("https://api.curseforge.com/v1/mods/files", HttpMethod.Post,
|
|
$"{{""fileIds"": [{UpdateFileIds.Keys.Join(",")}]}}", "application/json")("data")
|
|
Dim UpdateFiles As New Dictionary(Of ResourceFile, ResourceVersion)
|
|
For Each FileJson In CurseForgeFiles
|
|
Dim File = ResourceVersion.FromPlatformJson(FileJson, ResourceTypes.Mod)
|
|
If Not File.DownloadAvailable Then Continue For
|
|
For Each Entry As ResourceFile In UpdateFileIds(File.Id)
|
|
If UpdateFiles.ContainsKey(Entry) AndAlso UpdateFiles(Entry).ReleaseDate >= File.ReleaseDate Then Continue For
|
|
UpdateFiles(Entry) = File
|
|
Next
|
|
Next
|
|
For Each Pair In UpdateFiles
|
|
Dim Entry As ResourceFile = Pair.Key
|
|
Dim UpdateFile As ResourceVersion = Pair.Value
|
|
If ModeDebug Then Log($"[Mod] 本地文件 {Entry.ProjectVersion.FileName} 在 CurseForge 上的最新版为 {UpdateFile.FileName}")
|
|
If Entry.ProjectVersion.ReleaseDate >= UpdateFile.ReleaseDate OrElse Entry.ProjectVersion.Hash = UpdateFile.Hash Then Continue For
|
|
'设置更新日志与更新文件
|
|
If Entry.UpdateFile IsNot Nothing AndAlso UpdateFile.Hash = Entry.UpdateFile.Hash Then '合并
|
|
Entry.ChangelogUrls.Add($"https://www.curseforge.com/minecraft/mc-mods/{FileIdToProjectSlug(UpdateFile.Id)}/files/{UpdateFile.Id}")
|
|
Entry.UpdateFile.DownloadUrls.AddRange(UpdateFile.DownloadUrls) '合并下载源
|
|
ElseIf Entry.UpdateFile Is Nothing OrElse UpdateFile.ReleaseDate > Entry.UpdateFile.ReleaseDate Then '替换
|
|
Entry.ChangelogUrls = New List(Of String) From {$"https://www.curseforge.com/minecraft/mc-mods/{FileIdToProjectSlug(UpdateFile.Id)}/files/{UpdateFile.Id}"}
|
|
Entry.UpdateFile = UpdateFile
|
|
End If
|
|
Next
|
|
Log($"[Mod] 从 CurseForge 获取 Mod 更新信息结束")
|
|
Catch ex As Exception
|
|
Log(ex, "从 CurseForge 获取本地 Mod 信息失败")
|
|
IsFailed = True
|
|
Finally
|
|
EndedThreadCount += 1
|
|
End Try
|
|
End Sub, "Mod List Detail Loader CurseForge")
|
|
'从 JAR 中获取缺失的版本信息(上面有另一个分支)
|
|
Loader.Input.Key.Where(Function(m) m.Version Is Nothing).ForAll(Sub(m) m.LoadMetadataFromJar())
|
|
'等待线程结束
|
|
Do Until EndedThreadCount = 2
|
|
Thread.Sleep(10)
|
|
If Loader.IsInterrupted Then Return
|
|
Loop
|
|
'保存缓存
|
|
Mods = Mods.Where(Function(m) m.Project IsNot Nothing).ToList()
|
|
Log($"[Mod] 联网获取本地 Mod 信息完成,为 {Mods.Count} 个 Mod 更新缓存")
|
|
If Not Mods.Any() Then Return
|
|
For Each Entry In Mods
|
|
Entry.OnlineDataLoaded = Not IsFailed
|
|
Cache(Entry.ModrinthHash & VanillaVersion & ModLoaders.Join("")) = Entry.ToJson()
|
|
Next
|
|
FileUtils.Write(PathTemp & "Cache\LocalMod.json", Cache.ToString(If(ModeDebug, Newtonsoft.Json.Formatting.Indented, Newtonsoft.Json.Formatting.None)))
|
|
'刷新边栏
|
|
If Loader.IsInterrupted Then Return
|
|
If FrmInstanceMod?.Filter = PageInstanceMod.FilterType.CanUpdate Then
|
|
RunInUi(Sub() FrmInstanceMod?.RefreshUI()) '同步 “可更新” 列表 (#4677)
|
|
Else
|
|
RunInUi(Sub() FrmInstanceMod?.RefreshBars())
|
|
End If
|
|
End Sub
|
|
|
|
End Module |