2.7.0
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
'https://docs.curseforge.com/?http#tocS_ModLoaderType
|
||||
Any = 0
|
||||
Forge = 1
|
||||
LiteLoader = 3
|
||||
Fabric = 4
|
||||
Quilt = 5
|
||||
NeoForge = 6
|
||||
@@ -43,10 +44,10 @@
|
||||
For Each EntryData As String In Line.Split("¨")
|
||||
Dim Entry = New CompDatabaseEntry
|
||||
Dim SplitedLine = EntryData.Split("|")
|
||||
If SplitedLine(0).StartsWith("@") Then
|
||||
If SplitedLine(0).StartsWithF("@") Then
|
||||
Entry.CurseForgeSlug = Nothing
|
||||
Entry.ModrinthSlug = SplitedLine(0).Replace("@", "")
|
||||
ElseIf SplitedLine(0).EndsWith("@") Then
|
||||
ElseIf SplitedLine(0).EndsWithF("@") Then
|
||||
Entry.CurseForgeSlug = SplitedLine(0).TrimEnd("@")
|
||||
Entry.ModrinthSlug = Entry.CurseForgeSlug
|
||||
ElseIf SplitedLine(0).Contains("@") Then
|
||||
@@ -247,12 +248,26 @@
|
||||
LastUpdate = Data("dateReleased") '#1194
|
||||
DownloadCount = Data("downloadCount")
|
||||
If Data("logo").Count > 0 Then LogoUrl = Data("logo")("thumbnailUrl")
|
||||
'FileIndexes / GameVersions
|
||||
Dim Files = If(CType(Data("latestFilesIndexes"), JArray), New JArray).
|
||||
Where(Function(i) i("gameVersion").ToString.Contains("1."))
|
||||
CurseForgeFileIds = Files.Select(Of Integer)(Function(v) v("fileId")).Distinct.ToList
|
||||
GameVersions = Files.Select(Of Integer)(Function(v) Val(v("gameVersion").ToString.Split(".")(1).Split("-").First)).Where(Function(v) v > 0).
|
||||
Distinct.OrderByDescending(Function(v) v).ToList
|
||||
'FileIndexes / GameVersions / ModLoaders
|
||||
ModLoaders = New List(Of CompModLoaderType)
|
||||
Dim Files As New List(Of KeyValuePair(Of Integer, List(Of String))) 'FileId, GameVersions
|
||||
For Each File In If(Data("latestFiles"), New JArray)
|
||||
Dim NewFile As New CompFile(File, Type)
|
||||
If Not NewFile.Available Then Continue For
|
||||
ModLoaders.AddRange(NewFile.ModLoaders)
|
||||
Dim GameVersions = File("gameVersions").ToObject(Of List(Of String))
|
||||
If Not GameVersions.Any(Function(v) v.StartsWithF("1.")) Then Continue For
|
||||
Files.Add(New KeyValuePair(Of Integer, List(Of String))(File("id"), GameVersions))
|
||||
Next
|
||||
For Each File In If(Data("latestFilesIndexes"), New JArray) '这俩玩意儿包含的文件不一样,见 #3599
|
||||
If Not File("gameVersion").ToString.StartsWithF("1.") Then Continue For
|
||||
Files.Add(New KeyValuePair(Of Integer, List(Of String))(File("fileId"), {File("gameVersion").ToString}.ToList))
|
||||
Next
|
||||
CurseForgeFileIds = Files.Select(Function(f) f.Key).Distinct.ToList
|
||||
GameVersions = Files.SelectMany(Function(f) f.Value).Where(Function(v) v.StartsWithF("1.")).
|
||||
Select(Function(v) CInt(Val(v.Split(".")(1).Split("-").First))).Where(Function(v) v > 0).
|
||||
Distinct.OrderByDescending(Function(v) v).ToList
|
||||
ModLoaders = ModLoaders.Distinct.OrderBy(Of Integer)(Function(t) t).ToList
|
||||
'Type
|
||||
If Website.Contains("/mc-mods/") OrElse Website.Contains("/mod/") Then
|
||||
Type = CompType.Mod
|
||||
@@ -309,15 +324,7 @@
|
||||
'FUTURE: Res
|
||||
End Select
|
||||
Next
|
||||
If Tags.Count = 0 Then Tags.Add("杂项")
|
||||
'ModLoaders
|
||||
ModLoaders = New List(Of CompModLoaderType)
|
||||
For Each File In If(Data("latestFiles"), {})
|
||||
Dim NewFile As New CompFile(File, Type)
|
||||
If Not NewFile.Available Then Continue For
|
||||
ModLoaders.AddRange(NewFile.ModLoaders)
|
||||
Next
|
||||
ModLoaders = ModLoaders.Distinct.OrderBy(Of Integer)(Function(t) t).ToList
|
||||
If Not Tags.Any() Then Tags.Add("杂项")
|
||||
#End Region
|
||||
Else
|
||||
#Region "Modrinth"
|
||||
@@ -334,7 +341,7 @@
|
||||
'GameVersions
|
||||
'搜索结果的键为 versions,获取特定工程的键为 game_versions
|
||||
GameVersions = If(CType(If(Data("game_versions"), Data("versions")), JArray), New JArray).
|
||||
Select(Function(v) v.ToString).Where(Function(v) v.StartsWith("1.")).
|
||||
Select(Function(v) v.ToString).Where(Function(v) v.StartsWithF("1.")).
|
||||
Select(Of Integer)(Function(v) Val(v.Split(".")(1).Split("-").First)).Where(Function(v) v > 0).
|
||||
Distinct.OrderByDescending(Function(v) v).ToList
|
||||
'Type
|
||||
@@ -383,7 +390,7 @@
|
||||
'FUTURE: Res
|
||||
End Select
|
||||
Next
|
||||
If Tags.Count = 0 Then Tags.Add("杂项")
|
||||
If Not Tags.Any() Then Tags.Add("杂项")
|
||||
Tags.Sort()
|
||||
ModLoaders.Sort()
|
||||
#End Region
|
||||
@@ -562,7 +569,7 @@
|
||||
End If
|
||||
Next
|
||||
'根据分类后的结果处理
|
||||
If NormalNameList.Count = 0 OrElse SubtitleList.Count = 0 Then GoTo NoSubtitle
|
||||
If Not NormalNameList.Any() OrElse Not SubtitleList.Any() Then GoTo NoSubtitle
|
||||
'同时包含 NormalName 和 Subtitle
|
||||
Title = NormalNameList.Join(" - ")
|
||||
Else
|
||||
@@ -683,8 +690,8 @@ NoSubtitle:
|
||||
''' </summary>
|
||||
Public ReadOnly Property CanContinue As Boolean
|
||||
Get
|
||||
If Tag.StartsWith("/") OrElse Not Source.HasFlag(CompSourceType.CurseForge) Then Storage.CurseForgeTotal = 0
|
||||
If Tag.EndsWith("/") OrElse Not Source.HasFlag(CompSourceType.Modrinth) Then Storage.ModrinthTotal = 0
|
||||
If Tag.StartsWithF("/") OrElse Not Source.HasFlag(CompSourceType.CurseForge) Then Storage.CurseForgeTotal = 0
|
||||
If Tag.EndsWithF("/") OrElse Not Source.HasFlag(CompSourceType.Modrinth) Then Storage.ModrinthTotal = 0
|
||||
If Storage.CurseForgeTotal = -1 OrElse Storage.ModrinthTotal = -1 Then Return True
|
||||
Return Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal
|
||||
End Get
|
||||
@@ -732,7 +739,7 @@ NoSubtitle:
|
||||
''' </summary>
|
||||
Public Function GetCurseForgeAddress() As String
|
||||
If Not Source.HasFlag(CompSourceType.CurseForge) Then Return Nothing
|
||||
If Tag.StartsWith("/") Then Storage.CurseForgeTotal = 0
|
||||
If Tag.StartsWithF("/") Then Storage.CurseForgeTotal = 0
|
||||
If Storage.CurseForgeTotal > -1 AndAlso Storage.CurseForgeTotal <= Storage.CurseForgeOffset Then Return Nothing
|
||||
'应用筛选参数
|
||||
Dim Address As String = $"https://api.curseforge.com/v1/mods/search?gameId=432&sortField=2&sortOrder=desc&pageSize={CompPageSize}"
|
||||
@@ -756,7 +763,7 @@ NoSubtitle:
|
||||
''' </summary>
|
||||
Public Function GetModrinthAddress() As String
|
||||
If Not Source.HasFlag(CompSourceType.Modrinth) Then Return Nothing
|
||||
If Tag.EndsWith("/") Then Storage.ModrinthTotal = 0
|
||||
If Tag.EndsWithF("/") Then Storage.ModrinthTotal = 0
|
||||
If Storage.ModrinthTotal > -1 AndAlso Storage.ModrinthTotal <= Storage.ModrinthOffset Then Return Nothing
|
||||
'应用筛选参数
|
||||
Dim Address As String = $"https://api.modrinth.com/v2/search?limit={CompPageSize}&index=relevance"
|
||||
@@ -828,7 +835,7 @@ NoSubtitle:
|
||||
Log($"[Comp] 已有 {Task.Input.Storage.Results.Count} 个结果,多于所需的 {Task.Input.TargetResultCount} 个结果,结束处理")
|
||||
Exit Sub
|
||||
ElseIf Not Task.Input.CanContinue Then
|
||||
If Task.Input.Storage.Results.Count = 0 Then
|
||||
If Not Task.Input.Storage.Results.Any() Then
|
||||
Throw New Exception("没有符合条件的结果")
|
||||
Else
|
||||
Log($"[Comp] 已有 {Task.Input.Storage.Results.Count} 个结果,少于所需的 {Task.Input.TargetResultCount} 个结果,但无法继续获取,结束处理")
|
||||
@@ -867,7 +874,7 @@ NoSubtitle:
|
||||
Next
|
||||
'获取搜索结果
|
||||
Dim SearchResults = Search(SearchEntries, Task.Input.SearchText, 3)
|
||||
If SearchResults.Count = 0 Then Throw New Exception("无搜索结果,请尝试搜索英文名称")
|
||||
If Not SearchResults.Any() Then Throw New Exception("无搜索结果,请尝试搜索英文名称")
|
||||
Dim SearchResult As String = ""
|
||||
For i = 0 To Math.Min(4, SearchResults.Count - 1) '就算全是准确的,也最多只要 5 个
|
||||
If Not SearchResults(i).AbsoluteRight AndAlso i >= Math.Min(2, SearchResults.Count - 1) Then Exit For '把 3 个结果拼合以提高准确度
|
||||
@@ -880,7 +887,7 @@ NoSubtitle:
|
||||
'去除常见连接词
|
||||
Dim RealFilter As String = ""
|
||||
For Each Word In SearchResult.Split(" ")
|
||||
If {"the", "of", "a", "mod", "and"}.Contains(Word.ToLower) OrElse Val(Word) > 0 Then Continue For
|
||||
If {"the", "of", "a", "mod", "and"}.Contains(Word.ToLowerInvariant) OrElse Val(Word) > 0 Then Continue For
|
||||
If SearchResult.Split(" ").Count > 3 AndAlso {"ftb"}.Contains(Word.ToLower) Then Continue For
|
||||
RealFilter += Word.TrimStart("{[(").TrimEnd("}])") & " "
|
||||
Next
|
||||
@@ -904,15 +911,15 @@ NoSubtitle:
|
||||
End If
|
||||
RightKeywords.Add(Keyword)
|
||||
Next
|
||||
If RawFilter.Length > 0 AndAlso RightKeywords.Count = 0 Then
|
||||
If RawFilter.Length > 0 AndAlso Not RightKeywords.Any() Then
|
||||
Task.Input.SearchText = RawFilter '全都被过滤掉了
|
||||
Else
|
||||
Task.Input.SearchText = Join(RightKeywords.Distinct.ToList, " ").ToLower
|
||||
End If
|
||||
|
||||
'例外项:OptiForge、OptiFabric(拆词后因为包含 Forge/Fabric 导致无法搜到实际的 Mod)
|
||||
If RawFilter.Replace(" ", "").ToLower.Contains("optiforge") Then Task.Input.SearchText = "optiforge"
|
||||
If RawFilter.Replace(" ", "").ToLower.Contains("optifabric") Then Task.Input.SearchText = "optifabric"
|
||||
If RawFilter.Replace(" ", "").ContainsF("optiforge", True) Then Task.Input.SearchText = "optiforge"
|
||||
If RawFilter.Replace(" ", "").ContainsF("optifabric", True) Then Task.Input.SearchText = "optifabric"
|
||||
Log("[Comp] 工程列表搜索最终文本:" & Task.Input.SearchText, LogLevel.Debug)
|
||||
Task.Progress = 0.1
|
||||
|
||||
@@ -1003,15 +1010,15 @@ Retry:
|
||||
|
||||
'确保存在结果
|
||||
Storage.ErrorMessage = Nothing
|
||||
If RawResults.Count = 0 Then
|
||||
If Not RawResults.Any() Then
|
||||
If [Error] IsNot Nothing Then
|
||||
Throw [Error]
|
||||
Else
|
||||
If IsChineseSearch AndAlso Task.Input.Type <> CompType.Mod Then
|
||||
Throw New Exception($"{If(Task.Input.Type = CompType.ModPack, "整合包", "资源包")}搜索仅支持英文")
|
||||
ElseIf Task.Input.Source = CompSourceType.CurseForge AndAlso Task.Input.Tag.StartsWith("/") Then
|
||||
ElseIf Task.Input.Source = CompSourceType.CurseForge AndAlso Task.Input.Tag.StartsWithF("/") Then
|
||||
Throw New Exception("CurseForge 不兼容所选的类型")
|
||||
ElseIf Task.Input.Source = CompSourceType.Modrinth AndAlso Task.Input.Tag.EndsWith("/") Then
|
||||
ElseIf Task.Input.Source = CompSourceType.Modrinth AndAlso Task.Input.Tag.EndsWithF("/") Then
|
||||
Throw New Exception("Modrinth 不兼容所选的类型")
|
||||
Else
|
||||
Throw New Exception("没有符合条件的结果")
|
||||
@@ -1171,7 +1178,7 @@ Retry:
|
||||
''' </summary>
|
||||
Public ReadOnly Property Available As Boolean
|
||||
Get
|
||||
Return FileName IsNot Nothing
|
||||
Return FileName IsNot Nothing AndAlso DownloadUrls IsNot Nothing
|
||||
End Get
|
||||
End Property
|
||||
''' <summary>
|
||||
@@ -1181,7 +1188,11 @@ Retry:
|
||||
''' <summary>
|
||||
''' 文件所有可能的下载源。
|
||||
''' </summary>
|
||||
Private ReadOnly DownloadAddress As String()
|
||||
Public DownloadUrls As List(Of String)
|
||||
''' <summary>
|
||||
''' 文件的 SHA1 或 MD5。
|
||||
''' </summary>
|
||||
Public ReadOnly Hash As String = Nothing
|
||||
''' <summary>
|
||||
''' 该文件的所有依赖工程的原始 ID。
|
||||
''' 这些 ID 可能没有加载,在加载后会添加到 Dependencies 中(主要是因为 Modrinth 返回的是字符串 ID 而非 Slug,导致 Project.Id 查询不到)。
|
||||
@@ -1196,7 +1207,7 @@ Retry:
|
||||
''' </summary>
|
||||
''' <param name="LocalAddress">目标本地文件夹,或完整的文件路径。会自动判断类型。</param>
|
||||
Public Function ToNetFile(LocalAddress As String) As NetFile
|
||||
Return New NetFile(DownloadAddress, LocalAddress & If(LocalAddress.EndsWith("\"), FileName, ""), UseBrowserUserAgent:=True)
|
||||
Return New NetFile(DownloadUrls, LocalAddress & If(LocalAddress.EndsWithF("\"), FileName, ""), New FileChecker(Hash:=Hash), UseBrowserUserAgent:=True)
|
||||
End Function
|
||||
|
||||
'实例化
|
||||
@@ -1206,94 +1217,136 @@ Retry:
|
||||
''' </summary>
|
||||
Public Sub New(Data As JObject, Type As CompType)
|
||||
Me.Type = Type
|
||||
FromCurseForge = Data.ContainsKey("gameId")
|
||||
If FromCurseForge Then
|
||||
#Region "CurseForge"
|
||||
'简单信息
|
||||
Id = Data("id")
|
||||
DisplayName = Data("displayName").ToString.Replace(" ", "").Trim(" ")
|
||||
ReleaseDate = Data("fileDate")
|
||||
Status = CType(Data("releaseType").ToObject(Of Integer), CompFileStatus)
|
||||
DownloadCount = Data("downloadCount")
|
||||
FileName = Data("fileName")
|
||||
'DownloadAddress
|
||||
Dim Url = Data("downloadUrl").ToString
|
||||
If Url = "" Then Url = $"https://media.forgecdn.net/files/{CInt(Id.ToString.Substring(0, 4))}/{CInt(Id.ToString.Substring(4))}/{FileName}"
|
||||
Url = Url.Replace(FileName, Net.WebUtility.UrlEncode(FileName)) '对文件名进行编码
|
||||
DownloadAddress = {Url.Replace("-service.overwolf.wtf", ".forgecdn.net").Replace("://edge", "://media"),
|
||||
Url.Replace("-service.overwolf.wtf", ".forgecdn.net"),
|
||||
Url.Replace("://edge", "://media"),
|
||||
Url}.Distinct.ToArray
|
||||
'Dependencies
|
||||
If Type = CompType.Mod Then
|
||||
RawDependencies = Data("dependencies").
|
||||
Where(Function(d) d("relationType").ToObject(Of Integer) = 3 AndAlso '种类为依赖
|
||||
d("modId").ToObject(Of Integer) <> 306612 AndAlso d("modId").ToObject(Of Integer) <> 634179). '排除 Fabric API 和 Quilt API
|
||||
Select(Function(d) d("modId").ToString).ToList
|
||||
End If
|
||||
'GameVersions
|
||||
Dim RawVersions As List(Of String) = Data("gameVersions").Select(Function(t) t.ToString.Trim.ToLower).ToList
|
||||
GameVersions = RawVersions.Where(Function(v) v.StartsWith("1.")).Select(Function(v) v.Replace("-snapshot", " 快照")).ToList
|
||||
If GameVersions.Count > 1 Then
|
||||
GameVersions = Sort(GameVersions, AddressOf VersionSortBoolean).ToList
|
||||
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)}
|
||||
ElseIf GameVersions.Count = 1 Then
|
||||
GameVersions = GameVersions.ToList
|
||||
Else
|
||||
GameVersions = New List(Of String) From {"未知版本"}
|
||||
End If
|
||||
'ModLoaders
|
||||
ModLoaders = New List(Of CompModLoaderType)
|
||||
If RawVersions.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge)
|
||||
If RawVersions.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric)
|
||||
If RawVersions.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
|
||||
If RawVersions.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge)
|
||||
If Data.ContainsKey("FromCurseForge") Then
|
||||
#Region "CompJson"
|
||||
FromCurseForge = Data("FromCurseForge").ToObject(Of Boolean)
|
||||
Id = Data("Id").ToString
|
||||
DisplayName = Data("DisplayName").ToString
|
||||
ReleaseDate = Data("ReleaseDate").ToObject(Of Date)
|
||||
DownloadCount = Data("DownloadCount").ToObject(Of Integer)
|
||||
Status = CType(Data("Status").ToObject(Of Integer), CompFileStatus)
|
||||
If Data.ContainsKey("FileName") Then FileName = Data("FileName").ToString
|
||||
If Data.ContainsKey("DownloadUrls") Then DownloadUrls = Data("DownloadUrls").ToObject(Of List(Of String))
|
||||
If Data.ContainsKey("ModLoaders") Then ModLoaders = Data("ModLoaders").ToObject(Of List(Of CompModLoaderType))
|
||||
If Data.ContainsKey("Hash") Then Hash = Data("Hash").ToString
|
||||
If Data.ContainsKey("GameVersions") Then GameVersions = Data("GameVersions").ToObject(Of List(Of String))
|
||||
If Data.ContainsKey("RawDependencies") Then RawDependencies = Data("RawDependencies").ToObject(Of List(Of String))
|
||||
If Data.ContainsKey("Dependencies") Then Dependencies = Data("Dependencies").ToObject(Of List(Of String))
|
||||
#End Region
|
||||
Else
|
||||
#Region "Modrinth"
|
||||
'简单信息
|
||||
Id = Data("id")
|
||||
DisplayName = Data("name").ToString.Replace(" ", "").Trim(" ")
|
||||
ReleaseDate = Data("date_published")
|
||||
Status = If(Data("version_type").ToString = "release", CompFileStatus.Release, If(Data("version_type").ToString = "beta", CompFileStatus.Beta, CompFileStatus.Alpha))
|
||||
DownloadCount = Data("downloads")
|
||||
'可能为空
|
||||
If CType(Data("files"), JArray).Count > 0 Then
|
||||
FileName = Data("files")(0)("filename")
|
||||
DownloadAddress = {Data("files")(0)("url").ToString.Replace(FileName, FileName)}
|
||||
End If
|
||||
'Dependencies
|
||||
If Type = CompType.Mod Then
|
||||
RawDependencies = Data("dependencies").
|
||||
Where(Function(d) d("dependency_type") = "required" AndAlso '种类为依赖
|
||||
d("project_id") <> "P7dR8mSH" AndAlso d("project_id") <> "qvIfYCYJ" AndAlso '排除 Fabric API 和 Quilt API
|
||||
d("project_id").ToString.Length > 0). '有时候真的会空……
|
||||
Select(Function(d) d("project_id").ToString).ToList
|
||||
End If
|
||||
'GameVersions
|
||||
Dim RawVersions As List(Of String) = Data("game_versions").Select(Function(t) t.ToString.Trim.ToLower).ToList
|
||||
GameVersions = RawVersions.Where(Function(v) v.StartsWith("1.") OrElse v.StartsWith("b1.")).
|
||||
Select(Function(v) If(v.Contains("-"), v.Split("-").First & " 快照", If(v.StartsWith("b1."), "远古版本", v))).ToList
|
||||
If GameVersions.Count > 1 Then
|
||||
GameVersions = Sort(GameVersions, AddressOf VersionSortBoolean).ToList
|
||||
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)}
|
||||
ElseIf GameVersions.Count = 1 Then
|
||||
'无需处理
|
||||
ElseIf RawVersions.Any(Function(v) RegexCheck(v, "[0-9]{2}w[0-9]{2}[a-z]{1}")) Then
|
||||
GameVersions = RawVersions.Where(Function(v) RegexCheck(v, "[0-9]{2}w[0-9]{2}[a-z]{1}")).ToList
|
||||
Else
|
||||
GameVersions = New List(Of String) From {"未知版本"}
|
||||
End If
|
||||
'ModLoaders
|
||||
Dim RawLoaders As List(Of String) = Data("loaders").Select(Function(v) v.ToString).ToList
|
||||
ModLoaders = New List(Of CompModLoaderType)
|
||||
If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge)
|
||||
If RawLoaders.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric)
|
||||
If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
|
||||
FromCurseForge = Data.ContainsKey("gameId")
|
||||
If FromCurseForge Then
|
||||
#Region "CurseForge"
|
||||
'简单信息
|
||||
Id = Data("id")
|
||||
DisplayName = Data("displayName").ToString.Replace(" ", "").Trim(" ")
|
||||
ReleaseDate = Data("fileDate")
|
||||
Status = CType(Data("releaseType").ToObject(Of Integer), CompFileStatus)
|
||||
DownloadCount = Data("downloadCount")
|
||||
FileName = Data("fileName")
|
||||
Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 1)?("value")
|
||||
If Hash Is Nothing Then Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 2)?("value")
|
||||
'DownloadAddress
|
||||
Dim Url = Data("downloadUrl").ToString
|
||||
If Url = "" Then Url = $"https://media.forgecdn.net/files/{CInt(Id.ToString.Substring(0, 4))}/{CInt(Id.ToString.Substring(4))}/{FileName}"
|
||||
Url = Url.Replace(FileName, Net.WebUtility.UrlEncode(FileName)) '对文件名进行编码
|
||||
DownloadUrls = (New List(Of String) From {Url.Replace("-service.overwolf.wtf", ".forgecdn.net").Replace("://edge", "://media"),
|
||||
Url.Replace("-service.overwolf.wtf", ".forgecdn.net"),
|
||||
Url.Replace("://edge", "://media"),
|
||||
Url}).Distinct().ToList()
|
||||
'Dependencies
|
||||
If Type = CompType.Mod Then
|
||||
RawDependencies = Data("dependencies").
|
||||
Where(Function(d) d("relationType").ToObject(Of Integer) = 3 AndAlso '种类为依赖
|
||||
d("modId").ToObject(Of Integer) <> 306612 AndAlso d("modId").ToObject(Of Integer) <> 634179). '排除 Fabric API 和 Quilt API
|
||||
Select(Function(d) d("modId").ToString).ToList
|
||||
End If
|
||||
'GameVersions
|
||||
Dim RawVersions As List(Of String) = Data("gameVersions").Select(Function(t) t.ToString.Trim.ToLower).ToList
|
||||
GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.")).Select(Function(v) v.Replace("-snapshot", " 快照")).ToList
|
||||
If GameVersions.Count > 1 Then
|
||||
GameVersions = Sort(GameVersions, AddressOf VersionSortBoolean).ToList
|
||||
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)}
|
||||
ElseIf GameVersions.Count = 1 Then
|
||||
GameVersions = GameVersions.ToList
|
||||
Else
|
||||
GameVersions = New List(Of String) From {"未知版本"}
|
||||
End If
|
||||
'ModLoaders
|
||||
ModLoaders = New List(Of CompModLoaderType)
|
||||
If RawVersions.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge)
|
||||
If RawVersions.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric)
|
||||
If RawVersions.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
|
||||
If RawVersions.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge)
|
||||
#End Region
|
||||
Else
|
||||
#Region "Modrinth"
|
||||
'简单信息
|
||||
Id = Data("id")
|
||||
DisplayName = Data("name").ToString.Replace(" ", "").Trim(" ")
|
||||
ReleaseDate = Data("date_published")
|
||||
Status = If(Data("version_type").ToString = "release", CompFileStatus.Release, If(Data("version_type").ToString = "beta", CompFileStatus.Beta, CompFileStatus.Alpha))
|
||||
DownloadCount = Data("downloads")
|
||||
'可能为空
|
||||
If CType(Data("files"), JArray).Any() Then
|
||||
Dim File As JToken = Data("files")(0)
|
||||
FileName = File("filename")
|
||||
DownloadUrls = New List(Of String) From {File("url")}
|
||||
Hash = File("hashes")("sha1")
|
||||
End If
|
||||
'Dependencies
|
||||
If Type = CompType.Mod Then
|
||||
RawDependencies = Data("dependencies").
|
||||
Where(Function(d) d("dependency_type") = "required" AndAlso '种类为依赖
|
||||
d("project_id") <> "P7dR8mSH" AndAlso d("project_id") <> "qvIfYCYJ" AndAlso '排除 Fabric API 和 Quilt API
|
||||
d("project_id").ToString.Length > 0). '有时候真的会空……
|
||||
Select(Function(d) d("project_id").ToString).ToList
|
||||
End If
|
||||
'GameVersions
|
||||
Dim RawVersions As List(Of String) = Data("game_versions").Select(Function(t) t.ToString.Trim.ToLower).ToList
|
||||
GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.") OrElse v.StartsWithF("b1.")).
|
||||
Select(Function(v) If(v.Contains("-"), v.Split("-").First & " 快照", If(v.StartsWithF("b1."), "远古版本", v))).ToList
|
||||
If GameVersions.Count > 1 Then
|
||||
GameVersions = Sort(GameVersions, AddressOf VersionSortBoolean).ToList
|
||||
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)}
|
||||
ElseIf GameVersions.Count = 1 Then
|
||||
'无需处理
|
||||
ElseIf RawVersions.Any(Function(v) RegexCheck(v, "[0-9]{2}w[0-9]{2}[a-z]{1}")) Then
|
||||
GameVersions = RawVersions.Where(Function(v) RegexCheck(v, "[0-9]{2}w[0-9]{2}[a-z]{1}")).ToList
|
||||
Else
|
||||
GameVersions = New List(Of String) From {"未知版本"}
|
||||
End If
|
||||
'ModLoaders
|
||||
Dim RawLoaders As List(Of String) = Data("loaders").Select(Function(v) v.ToString).ToList
|
||||
ModLoaders = New List(Of CompModLoaderType)
|
||||
If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge)
|
||||
If RawLoaders.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric)
|
||||
If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
|
||||
#End Region
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 将当前实例转为可用于保存缓存的 Json。
|
||||
''' </summary>
|
||||
Public Function ToJson() As JObject
|
||||
Dim Json As New JObject
|
||||
Json.Add("FromCurseForge", FromCurseForge)
|
||||
Json.Add("Id", Id)
|
||||
Json.Add("DisplayName", DisplayName)
|
||||
Json.Add("ReleaseDate", ReleaseDate)
|
||||
Json.Add("DownloadCount", DownloadCount)
|
||||
Json.Add("ModLoaders", New JArray(ModLoaders.Select(Function(m) CInt(m))))
|
||||
Json.Add("GameVersions", New JArray(GameVersions))
|
||||
Json.Add("Status", CInt(Status))
|
||||
If FileName IsNot Nothing Then Json.Add("FileName", FileName)
|
||||
If DownloadUrls IsNot Nothing Then Json.Add("DownloadUrls", New JArray(DownloadUrls))
|
||||
If Hash IsNot Nothing Then Json.Add("Hash", Hash)
|
||||
Json.Add("RawDependencies", New JArray(RawDependencies))
|
||||
Json.Add("Dependencies", New JArray(Dependencies))
|
||||
Return Json
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 将当前文件信息实例化为控件。
|
||||
''' </summary>
|
||||
Public Function ToListItem(OnClick As MyListItem.ClickEventHandler, Optional OnSaveClick As MyIconButton.ClickEventHandler = Nothing,
|
||||
@@ -1434,7 +1487,7 @@ Retry:
|
||||
'如果为整合包就不会有 Dependencies 信息,所以不用管
|
||||
Dim Deps As List(Of String) = Files.SelectMany(Function(f) f.Dependencies).Distinct.ToList()
|
||||
Deps.Sort()
|
||||
If Deps.Count = 0 Then Exit Sub
|
||||
If Not Deps.Any() Then Exit Sub
|
||||
Deps = Deps.Where(Function(dep)
|
||||
If Not CompProjectCache.ContainsKey(dep) Then Log($"[Comp] 未找到 ID {dep} 的前置 Mod 信息", LogLevel.Debug)
|
||||
Return CompProjectCache.ContainsKey(dep)
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
Log(ex, "确认崩溃日志时间失败(" & LogFile & ")")
|
||||
End Try
|
||||
Next
|
||||
If RightLogs.Count = 0 Then Log("[Crash] 未发现可能可用的日志文件")
|
||||
If Not RightLogs.Any() Then Log("[Crash] 未发现可能可用的日志文件")
|
||||
|
||||
'将可能可用的日志文件导出
|
||||
For Each FilePath In RightLogs
|
||||
@@ -114,7 +114,7 @@
|
||||
Try
|
||||
Dim Info As New FileInfo(FilePath)
|
||||
If Not Info.Exists OrElse Info.Length = 0 Then Exit Try
|
||||
If Not FilePath.ToLower.EndsWith(".jar") AndAlso ExtractFile(FilePath, TempFolder & "Temp\") Then
|
||||
If Not FilePath.EndsWithF(".jar", True) AndAlso ExtractFile(FilePath, TempFolder & "Temp\") Then
|
||||
'解压成功
|
||||
Log("[Crash] 已解压导入的日志文件:" & FilePath)
|
||||
Else
|
||||
@@ -132,7 +132,7 @@
|
||||
If Not TargetFile.Exists OrElse TargetFile.Length = 0 Then Continue For
|
||||
Dim Ext As String = TargetFile.Extension.ToLower
|
||||
If Ext = ".log" OrElse Ext = ".txt" Then
|
||||
If TargetFile.Name.StartsWith("crash-") Then
|
||||
If TargetFile.Name.StartsWithF("crash-") Then
|
||||
AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(TargetFile.FullName, ReadFile(TargetFile.FullName).Split(vbCrLf.ToCharArray)))
|
||||
Else
|
||||
AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(TargetFile.FullName, ReadFile(TargetFile.FullName, Encoding.UTF8).Split(vbCrLf.ToCharArray)))
|
||||
@@ -169,10 +169,10 @@
|
||||
For Each LogFile In AnalyzeRawFiles
|
||||
Dim MatchName As String = GetFileNameFromPath(LogFile.Key).ToLower
|
||||
Dim TargetType As AnalyzeFileType
|
||||
If MatchName.StartsWith("hs_err") Then
|
||||
If MatchName.StartsWithF("hs_err") Then
|
||||
TargetType = AnalyzeFileType.HsErr
|
||||
DirectFile = LogFile
|
||||
ElseIf MatchName.StartsWith("crash-") Then
|
||||
ElseIf MatchName.StartsWithF("crash-") Then
|
||||
TargetType = AnalyzeFileType.CrashReport
|
||||
DirectFile = LogFile
|
||||
ElseIf MatchName = "latest.log" OrElse MatchName = "latest log.txt" OrElse
|
||||
@@ -187,13 +187,13 @@
|
||||
Else
|
||||
TargetType = AnalyzeFileType.ExtraLog
|
||||
End If
|
||||
ElseIf MatchName.EndsWith(".log") OrElse MatchName.EndsWith(".txt") Then
|
||||
ElseIf MatchName.EndsWithF(".log", True) OrElse MatchName.EndsWithF(".txt", True) Then
|
||||
TargetType = AnalyzeFileType.ExtraLog
|
||||
Else
|
||||
Log("[Crash] " & MatchName & " 分类为 Ignore")
|
||||
Continue For
|
||||
End If
|
||||
If LogFile.Value.Count = 0 Then
|
||||
If Not LogFile.Value.Any() Then
|
||||
Log("[Crash] " & MatchName & " 由于内容为空跳过")
|
||||
Else
|
||||
TotalFiles.Add(New KeyValuePair(Of AnalyzeFileType, KeyValuePair(Of String, String()))(TargetType, LogFile))
|
||||
@@ -208,7 +208,7 @@
|
||||
For Each File In TotalFiles
|
||||
If SelectType = File.Key Then SelectedFiles.Add(File.Value)
|
||||
Next
|
||||
If SelectedFiles.Count = 0 Then Continue For
|
||||
If Not SelectedFiles.Any() Then Continue For
|
||||
Try
|
||||
'根据文件类别判断
|
||||
Select Case SelectType
|
||||
@@ -437,7 +437,7 @@
|
||||
|
||||
'输出到日志
|
||||
Done:
|
||||
If CrashReasons.Count = 0 Then
|
||||
If Not CrashReasons.Any() Then
|
||||
Log("[Crash] 步骤 3:分析崩溃原因完成,未找到可能的原因")
|
||||
Else
|
||||
Log("[Crash] 步骤 3:分析崩溃原因完成,找到 " & CrashReasons.Count & " 条可能的原因")
|
||||
@@ -645,14 +645,14 @@ Done:
|
||||
"org.lwjgl", "com.sun", "net.minecraftforge", "paulscode.sound", "com.mojang", "net.minecraft", "cpw.mods", "com.google", "org.apache", "org.spongepowered", "net.fabricmc", "com.mumfrey",
|
||||
"com.electronwill.nightconfig", "it.unimi.dsi",
|
||||
"MojangTricksIntelDriversForPerformance_javaw"}
|
||||
If Stack.StartsWith(IgnoreStack) Then GoTo NextStack
|
||||
If Stack.StartsWithF(IgnoreStack) Then GoTo NextStack
|
||||
Next
|
||||
PossibleStacks.Add(Stack.Trim) '.Split("$").First)
|
||||
NextStack:
|
||||
Next
|
||||
PossibleStacks = PossibleStacks.Distinct.ToList
|
||||
Log("[Crash] 找到 " & PossibleStacks.Count & " 条可能的堆栈信息")
|
||||
If PossibleStacks.Count = 0 Then Return New List(Of String)
|
||||
If Not PossibleStacks.Any() Then Return New List(Of String)
|
||||
For Each Stack As String In PossibleStacks
|
||||
Log("[Crash] - " & Stack)
|
||||
Next
|
||||
@@ -663,7 +663,7 @@ NextStack:
|
||||
Dim Splited = Stack.Split(".")
|
||||
For i = 0 To Math.Min(3, Splited.Count - 1) '最多取前 4 节
|
||||
Dim Word As String = Splited(i)
|
||||
If Word.Length <= 2 OrElse Word.StartsWith("func_") Then Continue For
|
||||
If Word.Length <= 2 OrElse Word.StartsWithF("func_") Then Continue For
|
||||
If {"com", "org", "net", "asm", "fml", "mod", "jar", "sun", "lib", "map", "gui", "dev", "nio", "api", "dsi", "top",
|
||||
"core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base", "oshi",
|
||||
"forge", "setup", "block", "model", "mixin", "event", "unimi", "netty",
|
||||
@@ -716,8 +716,8 @@ NextStack:
|
||||
'[Fabric] 获取所有包含 Mod 信息的行
|
||||
Dim ModNameLines As New List(Of String)
|
||||
For Each Line In Details.Split(vbLf)
|
||||
If Line.ToLower.Contains(".jar") OrElse
|
||||
(IsFabricDetail AndAlso Line.StartsWith(vbTab & vbTab) AndAlso Not RegexCheck(Line, "\t\tfabric[\w-]*: Fabric")) Then ModNameLines.Add(Line)
|
||||
If Line.ContainsF(".jar", True) OrElse
|
||||
(IsFabricDetail AndAlso Line.StartsWithF(vbTab & vbTab) AndAlso Not RegexCheck(Line, "\t\tfabric[\w-]*: Fabric")) Then ModNameLines.Add(Line)
|
||||
Next
|
||||
Log("[Crash] 崩溃报告中找到 " & ModNameLines.Count & " 个可能的 Mod 项目行")
|
||||
|
||||
@@ -782,7 +782,7 @@ NextStack:
|
||||
|
||||
'输出
|
||||
ModFileNames = ModFileNames.Distinct.ToList
|
||||
If ModFileNames.Count = 0 Then
|
||||
If Not ModFileNames.Any() Then
|
||||
Return Nothing
|
||||
Else
|
||||
Log("[Crash] 找到 " & ModFileNames.Count & " 个可能的崩溃 Mod 文件名")
|
||||
@@ -866,7 +866,7 @@ NextStack:
|
||||
Private Function GetAnalyzeResult(IsHandAnalyze As Boolean) As String
|
||||
|
||||
'没有结果的处理
|
||||
If CrashReasons.Count = 0 Then
|
||||
If Not CrashReasons.Any() Then
|
||||
If IsHandAnalyze Then
|
||||
Return "很抱歉,PCL 无法确定错误原因。"
|
||||
Else
|
||||
@@ -1034,7 +1034,7 @@ NextStack:
|
||||
Replace("\e", If(IsHandAnalyze, "", vbCrLf & "你可以查看错误报告了解错误具体是如何发生的。")).
|
||||
Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, vbCrLf).
|
||||
Trim(vbCrLf.ToCharArray) &
|
||||
If(Not Results.Any(Function(r) r.EndsWith("\h")) OrElse IsHandAnalyze, "",
|
||||
If(Not Results.Any(Function(r) r.EndsWithF("\h")) OrElse IsHandAnalyze, "",
|
||||
vbCrLf & "如果要寻求帮助,请向他人发送错误报告文件,而不是发送这个窗口的截图。" &
|
||||
If(If(PageSetupSystem.IsLauncherNewest(), True), "",
|
||||
vbCrLf & vbCrLf & "此外,你正在使用老版本 PCL,更新到最新版可能会修复这个问题。" & vbCrLf & "你可以点击 设置 → 启动器 → 检查更新 来更新 PCL。"))
|
||||
|
||||
@@ -57,9 +57,9 @@
|
||||
|
||||
#Region "下载支持库文件"
|
||||
Dim LoadersLib As New List(Of LoaderBase) From {
|
||||
New LoaderTask(Of String, List(Of NetFile))("分析缺失支持库文件", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(Version)) With {.ProgressWeight = 1},
|
||||
New LoaderDownload("下载支持库文件", New List(Of NetFile)) With {.ProgressWeight = 15}
|
||||
}
|
||||
New LoaderTask(Of String, List(Of NetFile))("分析缺失支持库文件", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(Version)) With {.ProgressWeight = 1},
|
||||
New LoaderDownload("下载支持库文件", New List(Of NetFile)) With {.ProgressWeight = 15}
|
||||
}
|
||||
'构造加载器
|
||||
Loaders.Add(New LoaderCombo(Of String)("下载支持库文件(主加载器)", LoadersLib) With {.Block = False, .Show = False, .ProgressWeight = 16})
|
||||
#End Region
|
||||
@@ -71,19 +71,19 @@
|
||||
Dim LoadersAssets As New List(Of LoaderBase)
|
||||
'获取资源文件索引地址
|
||||
LoadersAssets.Add(New LoaderTask(Of String, List(Of NetFile))("分析资源文件索引地址",
|
||||
Sub(Task As LoaderTask(Of String, List(Of NetFile)))
|
||||
Try
|
||||
Dim IndexFile = DlClientAssetIndexGet(Version)
|
||||
Dim IndexFileInfo As New FileInfo(IndexFile.LocalPath)
|
||||
If AssetsIndexBehaviour <> AssetsIndexExistsBehaviour.AlwaysDownload AndAlso IndexFile.Check.Check(IndexFile.LocalPath) Is Nothing Then
|
||||
Task.Output = New List(Of NetFile)
|
||||
Else
|
||||
Task.Output = New List(Of NetFile) From {IndexFile}
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Throw New Exception("分析资源文件索引地址失败", ex)
|
||||
End Try
|
||||
End Sub) With {.ProgressWeight = 0.5, .Show = False})
|
||||
Sub(Task As LoaderTask(Of String, List(Of NetFile)))
|
||||
Try
|
||||
Dim IndexFile = DlClientAssetIndexGet(Version)
|
||||
Dim IndexFileInfo As New FileInfo(IndexFile.LocalPath)
|
||||
If AssetsIndexBehaviour <> AssetsIndexExistsBehaviour.AlwaysDownload AndAlso IndexFile.Check.Check(IndexFile.LocalPath) Is Nothing Then
|
||||
Task.Output = New List(Of NetFile)
|
||||
Else
|
||||
Task.Output = New List(Of NetFile) From {IndexFile}
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Throw New Exception("分析资源文件索引地址失败", ex)
|
||||
End Try
|
||||
End Sub) With {.ProgressWeight = 0.5, .Show = False})
|
||||
'下载资源文件索引
|
||||
LoadersAssets.Add(New LoaderDownload("下载资源文件索引", New List(Of NetFile)) With {.ProgressWeight = 2})
|
||||
'要求独立更新索引
|
||||
@@ -91,27 +91,29 @@
|
||||
Dim LoadersAssetsUpdate As New List(Of LoaderBase)
|
||||
Dim TempAddress As String = Nothing
|
||||
Dim RealAddress As String = Nothing
|
||||
LoadersAssetsUpdate.Add(New LoaderTask(Of String, List(Of NetFile))("后台分析资源文件索引地址", Sub(Task As LoaderTask(Of String, List(Of NetFile)))
|
||||
Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Version)
|
||||
RealAddress = BackAssetsFile.LocalPath
|
||||
TempAddress = PathTemp & "Cache\" & BackAssetsFile.LocalName
|
||||
BackAssetsFile.LocalPath = TempAddress
|
||||
Task.Output = New List(Of NetFile) From {BackAssetsFile}
|
||||
End Sub))
|
||||
LoadersAssetsUpdate.Add(New LoaderTask(Of String, List(Of NetFile))("后台分析资源文件索引地址",
|
||||
Sub(Task As LoaderTask(Of String, List(Of NetFile)))
|
||||
Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Version)
|
||||
RealAddress = BackAssetsFile.LocalPath
|
||||
TempAddress = PathTemp & "Cache\" & BackAssetsFile.LocalName
|
||||
BackAssetsFile.LocalPath = TempAddress
|
||||
Task.Output = New List(Of NetFile) From {BackAssetsFile}
|
||||
End Sub))
|
||||
LoadersAssetsUpdate.Add(New LoaderDownload("后台下载资源文件索引", New List(Of NetFile)))
|
||||
LoadersAssetsUpdate.Add(New LoaderTask(Of List(Of NetFile), String)("后台复制资源文件索引", Sub(Task As LoaderTask(Of List(Of NetFile), String))
|
||||
CopyFile(TempAddress, RealAddress)
|
||||
McLaunchLog("后台更新资源文件索引成功:" & TempAddress)
|
||||
End Sub))
|
||||
LoadersAssetsUpdate.Add(New LoaderTask(Of List(Of NetFile), String)("后台复制资源文件索引",
|
||||
Sub(Task As LoaderTask(Of List(Of NetFile), String))
|
||||
CopyFile(TempAddress, RealAddress)
|
||||
McLaunchLog("后台更新资源文件索引成功:" & TempAddress)
|
||||
End Sub))
|
||||
Dim Updater As New LoaderCombo(Of String)("后台更新资源文件索引", LoadersAssetsUpdate)
|
||||
Log("[Download] 开始后台更新资源文件索引")
|
||||
Updater.Start()
|
||||
End If
|
||||
'获取资源文件地址
|
||||
LoadersAssets.Add(New LoaderTask(Of String, List(Of NetFile))("分析缺失资源文件",
|
||||
Sub(Task As LoaderTask(Of String, List(Of NetFile)))
|
||||
Task.Output = McAssetsFixList(McAssetsGetIndexName(Version), CheckAssetsHash, Task)
|
||||
End Sub) With {.ProgressWeight = 3})
|
||||
Sub(Task As LoaderTask(Of String, List(Of NetFile)))
|
||||
Task.Output = McAssetsFixList(McAssetsGetIndexName(Version), CheckAssetsHash, Task)
|
||||
End Sub) With {.ProgressWeight = 3})
|
||||
'下载资源文件
|
||||
LoadersAssets.Add(New LoaderDownload("下载资源文件", New List(Of NetFile)) With {.ProgressWeight = 25})
|
||||
'构造加载器
|
||||
@@ -248,7 +250,7 @@
|
||||
End Select
|
||||
'确认版本格式标准
|
||||
Id = Id.Replace("_", "-") '1.7.10_pre4 在版本列表中显示为 1.7.10-pre4
|
||||
If Id <> "1.0" AndAlso Id.EndsWith(".0") Then Id = Left(Id, Id.Length - 2) 'OptiFine 1.8 的下载会触发此问题,显示版本为 1.8.0
|
||||
If Id <> "1.0" AndAlso Id.EndsWithF(".0") Then Id = Left(Id, Id.Length - 2) 'OptiFine 1.8 的下载会触发此问题,显示版本为 1.8.0
|
||||
'查找版本并开始
|
||||
For Each Version As JObject In DlClientListLoader.Output.Value("versions")
|
||||
If Version("id") = Id Then
|
||||
@@ -306,7 +308,7 @@
|
||||
Return _inherit
|
||||
End Get
|
||||
Set(value As String)
|
||||
If value.EndsWith(".0") Then value = Left(value, value.Length - 2)
|
||||
If value.EndsWithF(".0") Then value = Left(value, value.Length - 2)
|
||||
_inherit = value
|
||||
End Set
|
||||
End Property
|
||||
@@ -366,9 +368,9 @@
|
||||
Dim Entry As New DlOptiFineListEntry With {
|
||||
.NameDisplay = Name(i).Replace("HD U ", "").Replace(".0 ", " "),
|
||||
.ReleaseTime = Join({ReleaseTime(i).Split(".")(2), ReleaseTime(i).Split(".")(1), ReleaseTime(i).Split(".")(0)}, "/"),
|
||||
.IsPreview = Name(i).ToLower.Contains("pre"),
|
||||
.IsPreview = Name(i).ContainsF("pre", True),
|
||||
.Inherit = Name(i).ToString.Split(" ")(0),
|
||||
.NameFile = If(Name(i).ToLower.Contains("pre"), "preview_", "") & "OptiFine_" & Name(i).Replace(" ", "_") & ".jar",
|
||||
.NameFile = If(Name(i).ContainsF("pre", True), "preview_", "") & "OptiFine_" & Name(i).Replace(" ", "_") & ".jar",
|
||||
.RequiredForgeVersion = Forge(i).Replace("Forge ", "").Replace("#", "")}
|
||||
If Entry.RequiredForgeVersion.Contains("N/A") Then Entry.RequiredForgeVersion = Nothing
|
||||
Entry.NameVersion = Entry.Inherit & "-OptiFine_" & Name(i).ToString.Replace(" ", "_").Replace(Entry.Inherit & "_", "")
|
||||
@@ -389,7 +391,7 @@
|
||||
Dim Entry As New DlOptiFineListEntry With {
|
||||
.NameDisplay = (Token("mcversion").ToString & Token("type").ToString.Replace("HD_U", "").Replace("_", " ") & " " & Token("patch").ToString).Replace(".0 ", " "),
|
||||
.ReleaseTime = "",
|
||||
.IsPreview = Token("patch").ToString.ToLower.Contains("pre"),
|
||||
.IsPreview = Token("patch").ToString.ContainsF("pre", True),
|
||||
.Inherit = Token("mcversion").ToString,
|
||||
.NameFile = Token("filename").ToString,
|
||||
.RequiredForgeVersion = If(Token("forge"), "").ToString.Replace("Forge ", "").Replace("#", "")
|
||||
@@ -601,7 +603,7 @@
|
||||
Dim Versions As New List(Of DlForgeVersionEntry)
|
||||
Try
|
||||
'分割版本信息
|
||||
Dim VersionCodes = Mid(Result, 1, Result.LastIndexOf("</table>")).Split("<td class=""download-version")
|
||||
Dim VersionCodes = Mid(Result, 1, Result.LastIndexOfF("</table>")).Split("<td class=""download-version")
|
||||
'获取所有版本信息
|
||||
For i = 1 To VersionCodes.Count - 1
|
||||
Dim VersionCode = VersionCodes(i)
|
||||
@@ -626,17 +628,17 @@
|
||||
Dim MD5 As String, Category As String
|
||||
If VersionCode.Contains("classifier-installer""") Then
|
||||
'类型为 installer.jar,支持范围 ~753 (~ 1.6.1 部分), 738~684 (1.5.2 全部)
|
||||
VersionCode = VersionCode.Substring(VersionCode.IndexOf("installer.jar"))
|
||||
VersionCode = VersionCode.Substring(VersionCode.IndexOfF("installer.jar"))
|
||||
MD5 = RegexSeek(VersionCode, "(?<=MD5:</strong> )[^<]+")
|
||||
Category = "installer"
|
||||
ElseIf VersionCode.Contains("classifier-universal""") Then
|
||||
'类型为 universal.zip,支持范围 751~449 (1.6.1 部分), 682~183 (1.5.1 ~ 1.3.2 部分)
|
||||
VersionCode = VersionCode.Substring(VersionCode.IndexOf("universal.zip"))
|
||||
VersionCode = VersionCode.Substring(VersionCode.IndexOfF("universal.zip"))
|
||||
MD5 = RegexSeek(VersionCode, "(?<=MD5:</strong> )[^<]+")
|
||||
Category = "universal"
|
||||
ElseIf VersionCode.Contains("client.zip") Then
|
||||
'类型为 client.zip,支持范围 182~ (1.3.2 部分 ~)
|
||||
VersionCode = VersionCode.Substring(VersionCode.IndexOf("client.zip"))
|
||||
VersionCode = VersionCode.Substring(VersionCode.IndexOfF("client.zip"))
|
||||
MD5 = RegexSeek(VersionCode, "(?<=MD5:</strong> )[^<]+")
|
||||
Category = "client"
|
||||
Else
|
||||
@@ -652,7 +654,7 @@
|
||||
Catch ex As Exception
|
||||
Throw New Exception("版本列表解析失败(" & Result & ")", ex)
|
||||
End Try
|
||||
If Versions.Count = 0 Then Throw New Exception("没有可用版本")
|
||||
If Not Versions.Any() Then Throw New Exception("没有可用版本")
|
||||
Loader.Output = Versions
|
||||
End Sub
|
||||
|
||||
@@ -708,7 +710,7 @@
|
||||
Catch ex As Exception
|
||||
Throw New Exception("版本列表解析失败(" & Json.ToString & ")", ex)
|
||||
End Try
|
||||
If Versions.Count = 0 Then Throw New Exception("没有可用版本")
|
||||
If Not Versions.Any() Then Throw New Exception("没有可用版本")
|
||||
Loader.Output = Versions
|
||||
End Sub
|
||||
|
||||
@@ -799,7 +801,7 @@
|
||||
Dim Json As JObject = Result("versions")
|
||||
Dim Versions As New List(Of DlLiteLoaderListEntry)
|
||||
For Each Pair As KeyValuePair(Of String, JToken) In Json
|
||||
If Pair.Key.StartsWith("1.6") OrElse Pair.Key.StartsWith("1.5") Then Continue For
|
||||
If Pair.Key.StartsWithF("1.6") OrElse Pair.Key.StartsWithF("1.5") Then Continue For
|
||||
Dim RealEntry As JToken = If(Pair.Value("artefacts"), Pair.Value("snapshots"))("com.mumfrey:liteloader")("latest")
|
||||
Versions.Add(New DlLiteLoaderListEntry With {
|
||||
.Inherit = Pair.Key,
|
||||
@@ -827,7 +829,7 @@
|
||||
Dim Json As JObject = Result("versions")
|
||||
Dim Versions As New List(Of DlLiteLoaderListEntry)
|
||||
For Each Pair As KeyValuePair(Of String, JToken) In Json
|
||||
If Pair.Key.StartsWith("1.6") OrElse Pair.Key.StartsWith("1.5") Then Continue For
|
||||
If Pair.Key.StartsWithF("1.6") OrElse Pair.Key.StartsWithF("1.5") Then Continue For
|
||||
Dim RealEntry As JToken = If(Pair.Value("artefacts"), Pair.Value("snapshots"))("com.mumfrey:liteloader")("latest")
|
||||
Versions.Add(New DlLiteLoaderListEntry With {
|
||||
.Inherit = Pair.Key,
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
Public ReadOnly Property HasEnvironment As Boolean
|
||||
Get
|
||||
If PathFolder Is Nothing OrElse PathEnv Is Nothing Then Return False
|
||||
Return PathEnv.Replace("\", "").Replace("/", "").ToLower.Contains(PathFolder.Replace("\", "").ToLower)
|
||||
Return PathEnv.Replace("\", "").Replace("/", "").ContainsF(PathFolder.Replace("\", ""), True)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
''' </summary>
|
||||
Public Overrides Function ToString() As String
|
||||
Dim VersionString = Version.ToString
|
||||
If VersionString.StartsWith("1.") Then VersionString = Mid(VersionString, 3)
|
||||
If VersionString.StartsWithF("1.") Then VersionString = Mid(VersionString, 3)
|
||||
Return If(IsJre, "JRE ", "JDK ") & VersionCode & " (" & VersionString & ")," & If(Is64Bit, "64", "32") & " 位" & If(IsUserImport, ",手动导入", "") & ":" & PathFolder
|
||||
End Function
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
''' 输入 javaw.exe 文件所在文件夹的路径,不限制结尾。
|
||||
''' </summary>
|
||||
Public Sub New(Folder As String, IsUserImport As Boolean)
|
||||
If Not Folder.EndsWith("\") Then Folder += "\"
|
||||
If Not Folder.EndsWithF("\") Then Folder += "\"
|
||||
PathFolder = Folder.Replace("/", "\")
|
||||
Me.IsUserImport = IsUserImport
|
||||
End Sub
|
||||
@@ -116,8 +116,9 @@
|
||||
If Output.Contains("/lib/ext exists") Then Throw New ApplicationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试")
|
||||
'获取详细信息
|
||||
Dim VersionString = If(RegexSeek(Output, "(?<=version "")[^""]+"), If(RegexSeek(Output, "(?<=openjdk )[0-9]+"), "")).Replace("_", ".").Split("-").First
|
||||
If VersionString.Split(".").Count > 4 Then VersionString = VersionString.Replace(".0.", ".") '#3493,VersionString = "21.0.2.0.2"
|
||||
Do While VersionString.Split(".").Count < 4
|
||||
If VersionString.StartsWith("1.") Then
|
||||
If VersionString.StartsWithF("1.") Then
|
||||
VersionString = VersionString & ".0"
|
||||
Else
|
||||
VersionString = "1." & VersionString
|
||||
@@ -184,7 +185,7 @@
|
||||
JavaList.Add(JavaEntry.FromJson(JsonEntry))
|
||||
Next
|
||||
End If
|
||||
If JavaList.Count = 0 Then
|
||||
If Not JavaList.Any() Then
|
||||
Log("[Java] 初始化未找到可用的 Java,将自动触发搜索", LogLevel.Developer)
|
||||
JavaSearchLoader.Start(0)
|
||||
Else
|
||||
@@ -232,7 +233,7 @@
|
||||
Dim UserJava As JavaEntry = Nothing
|
||||
|
||||
'获取版本独立设置中指定的 Java
|
||||
If RelatedVersion IsNot Nothing AndAlso Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion).ToString.StartsWith("{") Then
|
||||
If RelatedVersion IsNot Nothing AndAlso Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion).ToString.StartsWithF("{") Then
|
||||
Try
|
||||
UserJava = JavaEntry.FromJson(GetJson(Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion)))
|
||||
UserJava.Check()
|
||||
@@ -291,7 +292,7 @@ RetryGet:
|
||||
Next
|
||||
|
||||
'若未找到适合的 Java,尝试触发搜索
|
||||
If AllowedJavaList.Count = 0 AndAlso JavaSearchLoader.State = LoadState.Waiting Then
|
||||
If Not AllowedJavaList.Any() AndAlso JavaSearchLoader.State = LoadState.Waiting Then
|
||||
Log("[Java] 未找到满足条件的 Java,尝试进行搜索")
|
||||
JavaSearchLoader.Start(IsForceRestart:=True)
|
||||
GoTo RetryGet
|
||||
@@ -352,7 +353,7 @@ ExitUserJavaCheck:
|
||||
#End Region
|
||||
|
||||
'若依然未找到适合的 Java,直接返回
|
||||
If AllowedJavaList.Count = 0 Then Return Nothing
|
||||
If Not AllowedJavaList.Any() Then Return Nothing
|
||||
|
||||
'优先使用特定目录下的 Java
|
||||
For Each Java In AllowedJavaList
|
||||
@@ -445,11 +446,11 @@ NoUserJava:
|
||||
Dim ProgramPathParent As String, MinecraftPathParent As String = ""
|
||||
ProgramPathParent = If(New DirectoryInfo(Path).Parent, New DirectoryInfo(Path)).FullName
|
||||
If PathMcFolder <> "" Then MinecraftPathParent = If(New DirectoryInfo(PathMcFolder).Parent, New DirectoryInfo(PathMcFolder)).FullName
|
||||
If Left.PathFolder.StartsWith(ProgramPathParent) AndAlso Not Right.PathFolder.StartsWith(ProgramPathParent) Then Return True
|
||||
If Not Left.PathFolder.StartsWith(ProgramPathParent) AndAlso Right.PathFolder.StartsWith(ProgramPathParent) Then Return False
|
||||
If Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Not Right.PathFolder.StartsWithF(ProgramPathParent) Then Return True
|
||||
If Not Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Right.PathFolder.StartsWithF(ProgramPathParent) Then Return False
|
||||
If PathMcFolder <> "" Then
|
||||
If Left.PathFolder.StartsWith(MinecraftPathParent) AndAlso Not Right.PathFolder.StartsWith(MinecraftPathParent) Then Return True
|
||||
If Not Left.PathFolder.StartsWith(MinecraftPathParent) AndAlso Right.PathFolder.StartsWith(MinecraftPathParent) Then Return False
|
||||
If Left.PathFolder.StartsWithF(MinecraftPathParent) AndAlso Not Right.PathFolder.StartsWithF(MinecraftPathParent) Then Return True
|
||||
If Not Left.PathFolder.StartsWithF(MinecraftPathParent) AndAlso Right.PathFolder.StartsWithF(MinecraftPathParent) Then Return False
|
||||
End If
|
||||
'2. 尽量使用 64 位
|
||||
If Left.Is64Bit AndAlso Not Right.Is64Bit Then Return True
|
||||
@@ -459,7 +460,7 @@ NoUserJava:
|
||||
If Not Left.IsJre AndAlso Right.IsJre Then Return False
|
||||
'4. Java 大版本
|
||||
If Left.VersionCode <> Right.VersionCode Then
|
||||
' Java 7 8 9 10 11 12 13 14 15 16 17 18 19 20...
|
||||
' Java 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21...
|
||||
Dim Weight = {0, 1, 2, 3, 4, 5, 6, 14, 30, 10, 12, 15, 13, 9, 8, 7, 11, 31, 29, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}
|
||||
Return Weight.ElementAtOrDefault(Left.VersionCode) >= Weight.ElementAtOrDefault(Right.VersionCode)
|
||||
End If
|
||||
@@ -500,7 +501,7 @@ NoUserJava:
|
||||
For Each PathInEnv As String In Split((PathEnv & ";" & PathJavaHome).Replace("\\", "\").Replace("/", "\"), ";")
|
||||
PathInEnv = PathInEnv.Trim(" """.ToCharArray())
|
||||
If PathInEnv = "" Then Continue For
|
||||
If Not PathInEnv.EndsWith("\") Then PathInEnv += "\"
|
||||
If Not PathInEnv.EndsWithF("\") Then PathInEnv += "\"
|
||||
'粗略检查有效性
|
||||
If File.Exists(PathInEnv & "javaw.exe") Then JavaPreList(PathInEnv) = False
|
||||
Next
|
||||
@@ -652,7 +653,7 @@ Wait:
|
||||
'确认目录存在
|
||||
If Not OriginalPath.Exists Then Exit Sub
|
||||
Dim Path As String = OriginalPath.FullName.Replace("\\", "\")
|
||||
If Not Path.EndsWith("\") Then Path += "\"
|
||||
If Not Path.EndsWithF("\") Then Path += "\"
|
||||
'若该目录有 Java,则加入结果
|
||||
If File.Exists(Path & "javaw.exe") Then Results(Path) = Source
|
||||
'查找其下的所有文件夹
|
||||
@@ -715,7 +716,7 @@ Wait:
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' 获取下载 Java 8/14/17 的加载器。需要开启 IsForceRestart 以正常刷新 Java 列表。
|
||||
''' 获取下载 Java 8/14/17/21 的加载器。需要开启 IsForceRestart 以正常刷新 Java 列表。
|
||||
''' </summary>
|
||||
Public Function JavaFixLoaders(Version As Integer) As LoaderCombo(Of Integer)
|
||||
Return New LoaderCombo(Of Integer)($"下载 Java {Version}", {
|
||||
@@ -734,7 +735,7 @@ Wait:
|
||||
Dim MainEntry As JObject = CType(GetJson(IndexFileStr), JObject)($"windows-x{If(Is32BitSystem, "86", "64")}")
|
||||
Dim Entries = MainEntry.Children.Reverse. '选择最靠后的一项(最新)
|
||||
SelectMany(Function(e As JProperty) CType(e.Value, JArray).Select(Function(v) New KeyValuePair(Of String, JObject)(e.Name, v)))
|
||||
Dim TargetEntry = Entries.First(Function(t) t.Value("version")("name").ToString.StartsWith(Loader.Input))
|
||||
Dim TargetEntry = Entries.First(Function(t) t.Value("version")("name").ToString.StartsWithF(Loader.Input))
|
||||
Dim Address As String = TargetEntry.Value("manifest")("url")
|
||||
Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}")
|
||||
'获取文件列表
|
||||
|
||||
@@ -143,7 +143,7 @@ Public Module ModLaunch
|
||||
Catch ex As Exception
|
||||
Dim CurrentEx = ex
|
||||
NextInner:
|
||||
If CurrentEx.Message.StartsWith("$") Then
|
||||
If CurrentEx.Message.StartsWithF("$") Then
|
||||
'若有以 $ 开头的错误信息,则以此为准显示提示
|
||||
'若错误信息为 $$,则不提示
|
||||
If Not CurrentEx.Message = "$$" Then MyMsgBox(CurrentEx.Message.TrimStart("$"), If(Loader.Input.SaveBatch Is Nothing, "启动失败", "导出启动脚本失败"))
|
||||
@@ -752,7 +752,7 @@ LoginFinish:
|
||||
End Select
|
||||
ElseIf AllMessage.Contains("超时") OrElse AllMessage.Contains("imeout") OrElse AllMessage.Contains("网络请求失败") Then
|
||||
Throw New Exception("$登录失败:连接登录服务器超时。" & vbCrLf & "请检查你的网络状况是否良好,或尝试使用 VPN!")
|
||||
ElseIf ex.Message.StartsWith("$") Then
|
||||
ElseIf ex.Message.StartsWithF("$") Then
|
||||
Throw
|
||||
Else
|
||||
Throw New Exception("登录失败:" & ex.Message, ex)
|
||||
@@ -990,13 +990,13 @@ SystemBrowser:
|
||||
Case 1
|
||||
'Steve
|
||||
Do Until McSkinSex(Uuid) = "Steve"
|
||||
If Uuid.EndsWith("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
|
||||
If Uuid.EndsWithF("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
|
||||
Uuid = Mid(Uuid, 1, 32 - 5) & (Long.Parse(Right(Uuid, 5), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X")
|
||||
Loop
|
||||
Case 2
|
||||
'Alex
|
||||
Do Until McSkinSex(Uuid) = "Alex"
|
||||
If Uuid.EndsWith("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
|
||||
If Uuid.EndsWithF("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
|
||||
Uuid = Mid(Uuid, 1, 32 - 5) & (Long.Parse(Right(Uuid, 5), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X")
|
||||
Loop
|
||||
Case 3
|
||||
@@ -1013,7 +1013,7 @@ SystemBrowser:
|
||||
Case 4
|
||||
'自定义
|
||||
Do Until McSkinSex(Uuid) = If(Setup.Get("LaunchSkinSlim"), "Alex", "Steve")
|
||||
If Uuid.EndsWith("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
|
||||
If Uuid.EndsWithF("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
|
||||
Uuid = Mid(Uuid, 1, 32 - 5) & (Long.Parse(Right(Uuid, 5), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X")
|
||||
Loop
|
||||
End Select
|
||||
@@ -1057,7 +1057,12 @@ SystemBrowser:
|
||||
Dim MinVer As New Version(0, 0, 0, 0), MaxVer As New Version(999, 999, 999, 999)
|
||||
|
||||
'MC 大版本检测
|
||||
If (McVersionCurrent.ReleaseTime >= New Date(2021, 11, 16) AndAlso McVersionCurrent.Version.McCodeMain = 99) OrElse
|
||||
If (McVersionCurrent.ReleaseTime >= New Date(2024, 4, 2) AndAlso McVersionCurrent.Version.McCodeMain = 99) OrElse
|
||||
(McVersionCurrent.Version.McCodeMain > 20 AndAlso McVersionCurrent.Version.McCodeMain <> 99) OrElse
|
||||
(McVersionCurrent.Version.McCodeMain = 20 AndAlso McVersionCurrent.Version.McCodeSub >= 5) Then
|
||||
'1.20.5+(24w14a+):至少 Java 21
|
||||
MinVer = New Version(1, 21, 0, 0)
|
||||
ElseIf (McVersionCurrent.ReleaseTime >= New Date(2021, 11, 16) AndAlso McVersionCurrent.Version.McCodeMain = 99) OrElse
|
||||
(McVersionCurrent.Version.McCodeMain >= 18 AndAlso McVersionCurrent.Version.McCodeMain <> 99) Then
|
||||
'1.18 pre2+:至少 Java 17
|
||||
MinVer = New Version(1, 17, 0, 0)
|
||||
@@ -1140,7 +1145,10 @@ SystemBrowser:
|
||||
If Task.IsAborted Then Exit Sub '中断加载会导致 JavaSelect 异常地返回空值,误判找不到 Java
|
||||
McLaunchLog("无合适的 Java,需要确认是否自动下载")
|
||||
Dim JavaCode As String
|
||||
If MinVer >= New Version(1, 9, 0, 0) Then
|
||||
If MinVer >= New Version(1, 21, 0, 0) Then
|
||||
JavaCode = 21
|
||||
If Not JavaDownloadConfirm("Java 21") Then Throw New Exception("$$")
|
||||
ElseIf MinVer >= New Version(1, 9, 0, 0) Then
|
||||
JavaCode = 17
|
||||
If Not JavaDownloadConfirm("Java 17") Then Throw New Exception("$$")
|
||||
ElseIf MaxVer < New Version(1, 8, 0, 0) Then
|
||||
@@ -1394,9 +1402,9 @@ NextVersion:
|
||||
Dim DeDuplicateDataList As New List(Of String)
|
||||
For i = 0 To DataList.Count - 1
|
||||
Dim CurrentEntry As String = DataList(i)
|
||||
If DataList(i).StartsWith("-") Then
|
||||
If DataList(i).StartsWithF("-") Then
|
||||
Do While i < DataList.Count - 1
|
||||
If DataList(i + 1).StartsWith("-") Then
|
||||
If DataList(i + 1).StartsWithF("-") Then
|
||||
Exit Do
|
||||
Else
|
||||
i += 1
|
||||
@@ -1487,9 +1495,9 @@ NextVersion:
|
||||
Dim DeDuplicateDataList As New List(Of String)
|
||||
For i = 0 To DataList.Count - 1
|
||||
Dim CurrentEntry As String = DataList(i)
|
||||
If DataList(i).StartsWith("-") Then
|
||||
If DataList(i).StartsWithF("-") Then
|
||||
Do While i < DataList.Count - 1
|
||||
If DataList(i + 1).StartsWith("-") Then
|
||||
If DataList(i + 1).StartsWithF("-") Then
|
||||
Exit Do
|
||||
Else
|
||||
i += 1
|
||||
@@ -1595,7 +1603,7 @@ NextVersion:
|
||||
End Try
|
||||
For Each Entry In Zip.Entries
|
||||
Dim FileName As String = Entry.FullName
|
||||
If FileName.EndsWith(".dll") Then
|
||||
If FileName.EndsWithF(".dll", True) Then
|
||||
'实际解压文件的步骤
|
||||
Dim FilePath As String = McVersionCurrent.Path & McVersionCurrent.Name & "-natives\" & FileName
|
||||
ExistFiles.Add(FilePath)
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
'格式:TMZ 12>C://xxx/xx/|Test>D://xxx/xx/|名称>路径
|
||||
For Each Folder As String In Setup.Get("LaunchFolders").Split("|")
|
||||
If Folder = "" Then Continue For
|
||||
If Not Folder.Contains(">") OrElse Not Folder.EndsWith("\") Then
|
||||
If Not Folder.Contains(">") OrElse Not Folder.EndsWithF("\") Then
|
||||
Hint("无效的 Minecraft 文件夹:" & Folder, HintType.Critical)
|
||||
Continue For
|
||||
End If
|
||||
@@ -92,13 +92,13 @@
|
||||
For Each Folder As McFolder In CacheMcFolderList
|
||||
If Not Folder.Type = McFolderType.Original Then NewSetup.Add(Folder.Name & ">" & Folder.Path)
|
||||
Next
|
||||
If NewSetup.Count = 0 Then NewSetup.Add("") '防止 0 元素 Join 返回 Nothing
|
||||
If Not NewSetup.Any() Then NewSetup.Add("") '防止 0 元素 Join 返回 Nothing
|
||||
Setup.Set("LaunchFolders", Join(NewSetup, "|"))
|
||||
|
||||
#End Region
|
||||
|
||||
'若没有可用文件夹,则创建 .minecraft
|
||||
If CacheMcFolderList.Count = 0 Then
|
||||
If Not CacheMcFolderList.Any() Then
|
||||
Directory.CreateDirectory(Path & ".minecraft\versions\")
|
||||
CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Path = Path & ".minecraft\", .Type = McFolderType.Original})
|
||||
End If
|
||||
@@ -149,7 +149,7 @@
|
||||
|
||||
#Region "版本处理"
|
||||
|
||||
Public Const McVersionCacheVersion As Integer = 26
|
||||
Public Const McVersionCacheVersion As Integer = 27
|
||||
|
||||
Private _McVersionCurrent As McVersion
|
||||
Private _McVersionLast = 0 '为 0 以保证与 Nothing 不相同,使得 UI 显示可以正常初始化
|
||||
@@ -418,7 +418,7 @@
|
||||
End Try
|
||||
VersionSearchFinish:
|
||||
'获取版本号
|
||||
If _Version.McName.StartsWith("1.") Then
|
||||
If _Version.McName.StartsWithF("1.") Then
|
||||
Dim SplitVersion = _Version.McName.Split(" "c, "_"c, "-"c, "."c)
|
||||
Dim SplitResult As String
|
||||
'分割获取信息
|
||||
@@ -546,8 +546,8 @@ Recheck:
|
||||
'处理 JumpLoader
|
||||
If Text.Contains("minecraftforge") AndAlso File.Exists(PathIndie & "config\jumploader.json") Then
|
||||
For Each ModFile In Directory.EnumerateFiles(PathIndie & "mods")
|
||||
Dim FileName As String = GetFileNameFromPath(ModFile).ToLower
|
||||
If FileName.EndsWith(".jar") AndAlso FileName.Contains("jumploader") Then
|
||||
Dim FileName As String = GetFileNameFromPath(ModFile)
|
||||
If FileName.EndsWithF(".jar", True) AndAlso FileName.ContainsF("jumploader", True) Then
|
||||
Log("[Minecraft] 发现 JumpLoader 分支项:" & FileName)
|
||||
HasJumpLoader = True
|
||||
Exit For
|
||||
@@ -612,7 +612,7 @@ Recheck:
|
||||
Public Sub New(Path As String)
|
||||
Me.Path = If(Path.Contains(":"), "", PathMcFolder & "versions\") & '补全完整路径
|
||||
Path &
|
||||
If(Path.EndsWith("\"), "", "\") '补全右划线
|
||||
If(Path.EndsWithF("\"), "", "\") '补全右划线
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
@@ -684,7 +684,7 @@ Recheck:
|
||||
'愚人节与快照版本
|
||||
If If(JsonObject("type"), "").ToString = "fool" OrElse GetMcFoolName(Version.McName) <> "" Then
|
||||
State = McVersionState.Fool
|
||||
ElseIf Version.McName.ToLower.Contains("w") OrElse Name.ToLower.Contains("combat") OrElse Version.McName.ToLower.Contains("rc") OrElse Version.McName.ToLower.Contains("pre") OrElse Version.McName.Contains("experimental") OrElse If(JsonObject("type"), "").ToString = "snapshot" OrElse If(JsonObject("type"), "").ToString = "pending" Then
|
||||
ElseIf Version.McName.ContainsF("w", True) OrElse Name.ContainsF("combat", True) OrElse Version.McName.ContainsF("rc", True) OrElse Version.McName.ContainsF("pre", True) OrElse Version.McName.ContainsF("experimental", True) OrElse If(JsonObject("type"), "").ToString = "snapshot" OrElse If(JsonObject("type"), "").ToString = "pending" Then
|
||||
State = McVersionState.Snapshot
|
||||
End If
|
||||
'OptiFine
|
||||
@@ -744,9 +744,9 @@ ExitDataLoad:
|
||||
If CustomInfo = "" Then
|
||||
Select Case State
|
||||
Case McVersionState.Snapshot
|
||||
If Version.McName.ToLower.Contains("pre") Then
|
||||
If Version.McName.ContainsF("pre", True) Then
|
||||
Info = "预发布版 " & Version.McName
|
||||
ElseIf Version.McName.ToLower.Contains("rc") Then
|
||||
ElseIf Version.McName.ContainsF("rc", True) Then
|
||||
Info = "发布候选 " & Version.McName
|
||||
ElseIf Version.McName.Contains("experimental") OrElse Version.McName = "pending" Then
|
||||
Info = "实验性快照"
|
||||
@@ -948,8 +948,8 @@ ExitDataLoad:
|
||||
(Asc(CType(Left(OptiFineVersion.ToUpper, 1), Char)) - Asc("A"c) + 1) * 10000 + '第二段:字母编号(2 位),如 G2 中的 G(7)
|
||||
Val(RegexSeek(Right(OptiFineVersion, OptiFineVersion.Length - 1), "[0-9]+")) * 100 '第三段:末尾数字(2 位),如 C5 beta4 中的 5
|
||||
'第三段:测试标记
|
||||
If OptiFineVersion.ToLower.Contains("pre") Then _SortCode += 50
|
||||
If OptiFineVersion.ToLower.Contains("pre") OrElse OptiFineVersion.ToLower.Contains("beta") Then
|
||||
If OptiFineVersion.ContainsF("pre", True) Then _SortCode += 50
|
||||
If OptiFineVersion.ContainsF("pre", True) OrElse OptiFineVersion.ContainsF("beta", True) Then
|
||||
If Val(Right(OptiFineVersion, 1)) = 0 AndAlso Right(OptiFineVersion, 1) <> "0" Then
|
||||
_SortCode += 1 '为 pre 或 beta 结尾,视作 1
|
||||
Else
|
||||
@@ -981,9 +981,9 @@ ExitDataLoad:
|
||||
''' </summary>
|
||||
Public Function GetMcFoolName(Name As String) As String
|
||||
Name = Name.ToLower
|
||||
If Name.StartsWith("2.0") Then
|
||||
If Name.StartsWithF("2.0") Then
|
||||
Return "这个秘密计划了两年的更新将游戏推向了一个新高度!"
|
||||
ElseIf Name.StartsWith("20w14inf") OrElse Name = "20w14∞" Then
|
||||
ElseIf Name.StartsWithF("20w14inf") OrElse Name = "20w14∞" Then
|
||||
Return "我们加入了 20 亿个新的维度,让无限的想象变成了现实!"
|
||||
ElseIf Name = "15w14a" Then
|
||||
Return "作为一款全年龄向的游戏,我们需要和平,需要爱与拥抱。"
|
||||
@@ -994,9 +994,9 @@ ExitDataLoad:
|
||||
ElseIf Name = "22w13oneblockatatime" Then
|
||||
Return "一次一个方块更新!迎接全新的挖掘、合成与骑乘玩法吧!"
|
||||
ElseIf Name = "23w13a_or_b" Then
|
||||
Return "研究表明玩家喜欢作出选择——越多越好!"
|
||||
Return "研究表明:玩家喜欢作出选择——越多越好!"
|
||||
ElseIf Name = "24w14potato" Then
|
||||
Return "我们的有毒块茎一直被忽视和低估,于是我们加强了毒马铃薯!"
|
||||
Return "毒马铃薯一直都被大家忽视和低估,于是我们超级加强了它!"
|
||||
Else
|
||||
Return ""
|
||||
End If
|
||||
@@ -1020,6 +1020,12 @@ ExitDataLoad:
|
||||
''' </summary>
|
||||
Public McVersionListLoader As New LoaderTask(Of String, Integer)("Minecraft Version List", AddressOf McVersionListLoad) With {.ReloadTimeout = 1}
|
||||
|
||||
''' <summary>
|
||||
''' 是否为本次打开 PCL 后第一次加载版本列表。
|
||||
''' 这会清理所有 .pclignore 文件,而非跳过这些对应版本。
|
||||
''' </summary>
|
||||
Private IsFirstMcVersionListLoad As Boolean = True
|
||||
|
||||
''' <summary>
|
||||
''' 开始加载当前 Minecraft 文件夹的版本列表。
|
||||
''' </summary>
|
||||
@@ -1042,7 +1048,7 @@ ExitDataLoad:
|
||||
End Try
|
||||
End If
|
||||
'没有可用版本
|
||||
If FolderList.Count = 0 Then
|
||||
If Not FolderList.Any() Then
|
||||
WriteIni(Path & "PCL.ini", "VersionCache", "") '清空缓存
|
||||
GoTo OnLoaded
|
||||
End If
|
||||
@@ -1064,6 +1070,7 @@ Reload:
|
||||
WriteIni(Path & "PCL.ini", "VersionCache", FolderListCheck)
|
||||
McVersionList = McVersionListLoadNoCache(Path)
|
||||
End If
|
||||
IsFirstMcVersionListLoad = False
|
||||
If Loader.IsAborted Then Exit Sub
|
||||
|
||||
'改变当前选择的版本
|
||||
@@ -1116,14 +1123,20 @@ OnLoaded:
|
||||
'循环读取版本
|
||||
For Each Folder As String In ReadIni(Path & "PCL.ini", "CardValue" & (i + 1), ":").Split(":")
|
||||
If Folder = "" Then Continue For
|
||||
If File.Exists(Path & "versions\" & Folder & "\.pclignore") Then
|
||||
Log("[Minecraft] 跳过要求忽略的项目:" & Path & "versions\" & Folder)
|
||||
Continue For
|
||||
Dim VersionFolder As String = $"{Path}versions\{Folder}\"
|
||||
If File.Exists(VersionFolder & ".pclignore") Then
|
||||
If IsFirstMcVersionListLoad Then
|
||||
Log("[Minecraft] 清理残留的忽略项目:" & VersionFolder) '#2781
|
||||
File.Delete(VersionFolder & ".pclignore")
|
||||
Else
|
||||
Log("[Minecraft] 跳过要求忽略的项目:" & VersionFolder)
|
||||
Continue For
|
||||
End If
|
||||
End If
|
||||
Try
|
||||
|
||||
'读取单个版本
|
||||
Dim Version As New McVersion(Path & "versions\" & Folder & "\")
|
||||
Dim Version As New McVersion(VersionFolder)
|
||||
VersionList.Add(Version)
|
||||
Version.Info = ReadIni(Version.Path & "PCL\Setup.ini", "CustomInfo", "")
|
||||
If Version.Info = "" Then Version.Info = ReadIni(Version.Path & "PCL\Setup.ini", "Info", Version.Info)
|
||||
@@ -1195,11 +1208,17 @@ OnLoaded:
|
||||
Log("[Minecraft] 跳过可能不是版本文件夹的项目:" & Folder.FullName)
|
||||
Continue For
|
||||
End If
|
||||
If File.Exists(Folder.FullName & "\.pclignore") Then
|
||||
Log("[Minecraft] 跳过要求忽略的项目:" & Folder.FullName)
|
||||
Continue For
|
||||
Dim VersionFolder As String = Folder.FullName & "\"
|
||||
If File.Exists(VersionFolder & ".pclignore") Then
|
||||
If IsFirstMcVersionListLoad Then
|
||||
Log("[Minecraft] 清理残留的忽略项目:" & VersionFolder) '#2781
|
||||
File.Delete(VersionFolder & ".pclignore")
|
||||
Else
|
||||
Log("[Minecraft] 跳过要求忽略的项目:" & VersionFolder)
|
||||
Continue For
|
||||
End If
|
||||
End If
|
||||
Dim Version As New McVersion(Folder.FullName & "\")
|
||||
Dim Version As New McVersion(VersionFolder)
|
||||
VersionList.Add(Version)
|
||||
Version.Load()
|
||||
Next
|
||||
@@ -1496,7 +1515,7 @@ NextVersion:
|
||||
''' </summary>
|
||||
Public Function McSkinGetAddress(Uuid As String, Type As String) As String
|
||||
If Uuid = "" Then Throw New Exception("Uuid 为空。")
|
||||
If Uuid.StartsWith("000000") Then Throw New Exception("离线 Uuid 无正版皮肤文件。")
|
||||
If Uuid.StartsWithF("000000") Then Throw New Exception("离线 Uuid 无正版皮肤文件。")
|
||||
'尝试读取缓存
|
||||
Dim CacheSkinAddress As String = ReadIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", Uuid)
|
||||
If Not CacheSkinAddress = "" Then Return CacheSkinAddress
|
||||
@@ -1962,7 +1981,7 @@ NextVersion:
|
||||
'获取 Url 的真实地址
|
||||
Urls.Add(Token.Url)
|
||||
If Token.Url.Contains("launcher.mojang.com/v1/objects") Then Urls = DlSourceLauncherOrMetaGet(Token.Url).ToList() 'Mappings
|
||||
If Token.Url.Contains("maven") Then Urls.Insert(0, Token.Url.Replace(Mid(Token.Url, 1, Token.Url.IndexOf("maven")), "https://bmclapi2.bangbang93.com/").Replace("maven.fabricmc.net", "maven").Replace("maven.minecraftforge.net", "maven"))
|
||||
If Token.Url.Contains("maven") Then Urls.Insert(0, Token.Url.Replace(Mid(Token.Url, 1, Token.Url.IndexOfF("maven")), "https://bmclapi2.bangbang93.com/").Replace("maven.fabricmc.net", "maven").Replace("maven.minecraftforge.net", "maven"))
|
||||
End If
|
||||
If Token.LocalPath.Contains("transformer-discovery-service") Then
|
||||
'Transformer 文件释放
|
||||
@@ -1992,10 +2011,6 @@ NextVersion:
|
||||
Public Function McLibGet(Original As String, Optional WithHead As Boolean = True, Optional IgnoreLiteLoader As Boolean = False, Optional CustomMcFolder As String = Nothing) As String
|
||||
CustomMcFolder = If(CustomMcFolder, PathMcFolder)
|
||||
Dim Splited = Original.Split(":")
|
||||
'If Original.ToLower.Contains("xray") OrElse Original.ToLower.Contains("rift") OrElse Original.ToLower.Contains("mixin") OrElse Original.Contains("net.minecraftforge:forge") OrElse Splited(2).Contains("beta") OrElse (IgnoreLiteLoader AndAlso Original.Contains("liteloader")) Then
|
||||
'ElseIf Splited(2).Contains("-") Then
|
||||
' Log("[Launch] 可能存在分段问题的支持库:" & Original)
|
||||
'End If
|
||||
McLibGet = If(WithHead, CustomMcFolder & "libraries\", "") &
|
||||
Splited(0).Replace(".", "\") & "\" & Splited(1) & "\" & Splited(2) & "\" & Splited(1) & "-" & Splited(2) & ".jar"
|
||||
'判断 OptiFine 是否应该使用 installer
|
||||
@@ -2252,8 +2267,10 @@ NextVersion:
|
||||
If Left = "未知版本" AndAlso Right = "未知版本" Then Return 0
|
||||
If Left <> "未知版本" AndAlso Right = "未知版本" Then Return -1
|
||||
End If
|
||||
Dim Lefts = RegexSearch(Left.ToLower.Replace("快照", "snapshot"), "[a-z]+|[0-9]+")
|
||||
Dim Rights = RegexSearch(Right.ToLower.Replace("快照", "snapshot"), "[a-z]+|[0-9]+")
|
||||
Left = Left.ToLowerInvariant
|
||||
Right = Right.ToLowerInvariant
|
||||
Dim Lefts = RegexSearch(Left.Replace("快照", "snapshot"), "[a-z]+|[0-9]+")
|
||||
Dim Rights = RegexSearch(Right.Replace("快照", "snapshot"), "[a-z]+|[0-9]+")
|
||||
Dim i As Integer = 0
|
||||
While True
|
||||
'两边均缺失,感觉是一个东西
|
||||
|
||||
@@ -48,7 +48,7 @@ Public Module ModMod
|
||||
Load()
|
||||
If Not IsFileAvailable Then
|
||||
Return McModState.Unavaliable
|
||||
ElseIf Path.EndsWith(".disabled") OrElse Path.EndsWith(".old") Then
|
||||
ElseIf Path.EndsWithF(".disabled", True) OrElse Path.EndsWithF(".old", True) Then
|
||||
Return McModState.Disabled
|
||||
Else
|
||||
Return McModState.Fine
|
||||
@@ -76,7 +76,7 @@ Public Module ModMod
|
||||
Return _Name
|
||||
End Get
|
||||
Set(value As String)
|
||||
If _Name Is Nothing AndAlso value IsNot Nothing AndAlso
|
||||
If _Name Is Nothing AndAlso value IsNot Nothing AndAlso Not value.Contains("modname") AndAlso
|
||||
value.ToLower <> "name" AndAlso value.Count > 1 AndAlso Val(value).ToString <> value Then
|
||||
_Name = value
|
||||
End If
|
||||
@@ -113,12 +113,12 @@ Public Module ModMod
|
||||
Return _Version
|
||||
End Get
|
||||
Set(value As String)
|
||||
If _Version IsNot Nothing AndAlso (_Version.Contains(".") OrElse _Version.Contains("-")) Then Exit Property
|
||||
If value IsNot Nothing AndAlso value.ToLower.Contains("version") Then value = "version" '需要修改的标识
|
||||
If _Version IsNot Nothing AndAlso RegexCheck(_Version, "[0-9.\-]+") Then Return
|
||||
If value?.ContainsF("version", True) Then value = "version" '需要修改的标识
|
||||
_Version = value
|
||||
End Set
|
||||
End Property
|
||||
Private _Version As String = Nothing
|
||||
Public _Version As String = Nothing
|
||||
|
||||
''' <summary>
|
||||
''' 用于依赖检查的 ModID。
|
||||
@@ -129,12 +129,12 @@ Public Module ModMod
|
||||
Return _ModId
|
||||
End Get
|
||||
Set(value As String)
|
||||
If value Is Nothing Then Exit Property
|
||||
value = RegexSeek(value.ToLower, "[0-9a-z_-]+")
|
||||
If value IsNot Nothing AndAlso value.ToLower <> "name" AndAlso value.Count > 1 AndAlso Val(value).ToString <> value Then
|
||||
If Not PossibleModId.Contains(value) Then PossibleModId.Add(value)
|
||||
If _ModId Is Nothing Then _ModId = value
|
||||
End If
|
||||
If value Is Nothing Then Return
|
||||
value = RegexSeek(value, "[0-9a-zA-Z_-]+")
|
||||
If value Is Nothing OrElse value.Count <= 1 OrElse Val(value).ToString = value Then Return
|
||||
If value.ContainsF("name", True) OrElse value.ContainsF("modid", True) Then Return
|
||||
If Not PossibleModId.Contains(value) Then PossibleModId.Add(value)
|
||||
If _ModId Is Nothing Then _ModId = value
|
||||
End Set
|
||||
End Property
|
||||
Private _ModId As String = Nothing
|
||||
@@ -152,7 +152,7 @@ Public Module ModMod
|
||||
Return _Url
|
||||
End Get
|
||||
Set(value As String)
|
||||
If _Url Is Nothing AndAlso value IsNot Nothing AndAlso value.StartsWith("http") Then
|
||||
If _Url Is Nothing AndAlso value IsNot Nothing AndAlso value.StartsWithF("http") Then
|
||||
_Url = value
|
||||
End If
|
||||
End Set
|
||||
@@ -193,7 +193,7 @@ Public Module ModMod
|
||||
If VersionRequirement Is Nothing OrElse ((Not VersionRequirement.Contains(".")) AndAlso (Not VersionRequirement.Contains("-"))) OrElse VersionRequirement.Contains("$") Then
|
||||
VersionRequirement = Nothing
|
||||
Else
|
||||
If (Not VersionRequirement.StartsWith("[")) AndAlso (Not VersionRequirement.StartsWith("(")) AndAlso (Not VersionRequirement.EndsWith("]")) AndAlso (Not VersionRequirement.EndsWith(")")) Then VersionRequirement = "[" & VersionRequirement & ",)"
|
||||
If (Not VersionRequirement.StartsWithF("[")) AndAlso (Not VersionRequirement.StartsWithF("(")) AndAlso (Not VersionRequirement.EndsWithF("]")) AndAlso (Not VersionRequirement.EndsWithF(")")) Then VersionRequirement = "[" & VersionRequirement & ",)"
|
||||
End If
|
||||
'向依赖项中添加
|
||||
If _Dependencies.ContainsKey(ModID) Then
|
||||
@@ -270,7 +270,6 @@ Public Module ModMod
|
||||
_Dependencies = New Dictionary(Of String, String)
|
||||
IsLoaded = False
|
||||
_FileUnavailableReason = Nothing
|
||||
IsInfoWithoutClassAvailable = False
|
||||
IsInfoWithClassLoaded = False
|
||||
IsInfoWithClassAvailable = False
|
||||
End Sub
|
||||
@@ -284,15 +283,12 @@ Public Module ModMod
|
||||
Init()
|
||||
Dim Jar As ZipArchive = Nothing
|
||||
Try
|
||||
'阶段 1:基础可用性检查、打开 Jar 文件
|
||||
'基础可用性检查、打开 Jar 文件
|
||||
If Path.Length < 2 Then Throw New FileNotFoundException("错误的 Mod 文件路径(" & If(Path, "null") & ")")
|
||||
If Not File.Exists(Path) Then Throw New FileNotFoundException("未找到 Mod 文件(" & Path & ")")
|
||||
Jar = New ZipArchive(New FileStream(Path, FileMode.Open))
|
||||
If Jar.Entries.Count = 0 Then Throw New FileFormatException("文件内容为空")
|
||||
'阶段 2:信息获取
|
||||
LoadWithoutClass(Jar)
|
||||
'阶段 3: Class 信息获取
|
||||
If Not IsInfoWithoutClassAvailable Then LoadWithClass(Jar)
|
||||
'信息获取
|
||||
LookupMetadata(Jar)
|
||||
Catch ex As UnauthorizedAccessException
|
||||
Log(ex, "Mod 文件由于无权限无法打开(" & Path & ")", LogLevel.Developer)
|
||||
_FileUnavailableReason = New UnauthorizedAccessException("没有读取此文件的权限,请尝试右键以管理员身份运行 PCL", ex)
|
||||
@@ -307,9 +303,9 @@ Public Module ModMod
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 进行不使用 .class 文件的信息获取。
|
||||
''' 从 jar 文件中获取 Mod 信息。
|
||||
''' </summary>
|
||||
Private Sub LoadWithoutClass(Jar As ZipArchive)
|
||||
Private Sub LookupMetadata(Jar As ZipArchive)
|
||||
|
||||
#Region "尝试使用 mcmod.info"
|
||||
Try
|
||||
@@ -347,7 +343,7 @@ Public Module ModMod
|
||||
If Reqs IsNot Nothing Then
|
||||
For Each Token As String In Reqs
|
||||
If Not String.IsNullOrEmpty(Token) Then
|
||||
Token = Token.Substring(Token.IndexOf(":") + 1)
|
||||
Token = Token.Substring(Token.IndexOfF(":") + 1)
|
||||
If Token.Contains("@") Then
|
||||
AddDependency(Token.Split("@")(0), Token.Split("@")(1))
|
||||
Else
|
||||
@@ -360,7 +356,7 @@ Public Module ModMod
|
||||
If Reqs IsNot Nothing Then
|
||||
For Each Token As String In Reqs
|
||||
If Not String.IsNullOrEmpty(Token) Then
|
||||
Token = Token.Substring(Token.IndexOf(":") + 1)
|
||||
Token = Token.Substring(Token.IndexOfF(":") + 1)
|
||||
If Token.Contains("@") Then
|
||||
AddDependency(Token.Split("@")(0), Token.Split("@")(1))
|
||||
Else
|
||||
@@ -407,8 +403,8 @@ GotFabric:
|
||||
' Dim Deps As String = If(If(FabricObject("dependencies") IsNot Nothing, FabricObject("dependencies")("value"), ""), "")
|
||||
' If Deps <> "" Then
|
||||
' For Each Dep In Deps.Split(";")
|
||||
' If Dep = "" OrElse Not Dep.StartsWith("required-") Then Continue For
|
||||
' Dep = Dep.Substring(Dep.IndexOf(":") + 1)
|
||||
' If Dep = "" OrElse Not Dep.StartsWithF("required-") Then Continue For
|
||||
' Dep = Dep.Substring(Dep.IndexOfF(":") + 1)
|
||||
' If Dep.Contains("@") Then
|
||||
' AddDependency(Dep.Split("@")(0), Dep.Split("@")(1))
|
||||
' Else
|
||||
@@ -436,10 +432,10 @@ GotFabric:
|
||||
'文件标准化:统一换行符为 vbLf,去除注释、头尾的空格、空行
|
||||
Dim Lines As New List(Of String)
|
||||
For Each Line In TomlText.Replace(vbCrLf, vbLf).Replace(vbCr, vbLf).Split(vbLf) '统一换行符
|
||||
If Line.StartsWith("#") Then '去除注释
|
||||
If Line.StartsWithF("#") Then '去除注释
|
||||
Continue For
|
||||
ElseIf Line.Contains("#") Then
|
||||
Line = Line.Substring(0, Line.IndexOf("#"))
|
||||
Line = Line.Substring(0, Line.IndexOfF("#"))
|
||||
End If
|
||||
Line = Line.Trim(New Char() {" "c, " "c, " "c}) '去除头尾的空格
|
||||
If Line.Count > 0 Then Lines.Add(Line) '去除空行
|
||||
@@ -448,28 +444,28 @@ GotFabric:
|
||||
Dim TomlData As New List(Of KeyValuePair(Of String, Dictionary(Of String, Object))) From {New KeyValuePair(Of String, Dictionary(Of String, Object))("", New Dictionary(Of String, Object))}
|
||||
For i = 0 To Lines.Count - 1
|
||||
Dim Line As String = Lines(i)
|
||||
If Line.StartsWith("[") AndAlso Line.EndsWith("]") Then
|
||||
If Line.StartsWithF("[") AndAlso Line.EndsWithF("]") Then
|
||||
'段落标记
|
||||
Dim Header = Line.Trim("[]".ToCharArray)
|
||||
TomlData.Add(New KeyValuePair(Of String, Dictionary(Of String, Object))(Header, New Dictionary(Of String, Object)))
|
||||
ElseIf Line.Contains("=") Then
|
||||
'字段标记
|
||||
Dim Key As String = Line.Substring(0, Line.IndexOf("=")).TrimEnd(New Char() {" "c, " "c, " "c})
|
||||
Dim RawValue As String = Line.Substring(Line.IndexOf("=") + 1).TrimStart(New Char() {" "c, " "c, " "c})
|
||||
Dim Key As String = Line.Substring(0, Line.IndexOfF("=")).TrimEnd(New Char() {" "c, " "c, " "c})
|
||||
Dim RawValue As String = Line.Substring(Line.IndexOfF("=") + 1).TrimStart(New Char() {" "c, " "c, " "c})
|
||||
Dim Value As Object
|
||||
If RawValue.StartsWith("""") AndAlso RawValue.EndsWith("""") Then
|
||||
If RawValue.StartsWithF("""") AndAlso RawValue.EndsWithF("""") Then
|
||||
'单行字符串
|
||||
Value = RawValue.Trim("""")
|
||||
ElseIf RawValue.StartsWith("'''") Then
|
||||
ElseIf RawValue.StartsWithF("'''") Then
|
||||
'多行字符串
|
||||
Dim ValueLines As New List(Of String) From {RawValue.TrimStart("'")}
|
||||
If ValueLines(0).EndsWith("'''") Then '把多行字符串按单行写法写的错误处理(#2732)
|
||||
If ValueLines(0).EndsWithF("'''") Then '把多行字符串按单行写法写的错误处理(#2732)
|
||||
ValueLines(0) = ValueLines(0).TrimEnd("'")
|
||||
Else
|
||||
Do Until i >= Lines.Count - 1
|
||||
i += 1
|
||||
Dim ValueLine As String = Lines(i)
|
||||
If ValueLine.EndsWith("'''") Then
|
||||
If ValueLine.EndsWithF("'''") Then
|
||||
ValueLines.Add(ValueLine.TrimEnd("'"))
|
||||
Exit Do
|
||||
Else
|
||||
@@ -575,8 +571,8 @@ Got:
|
||||
Dim Deps As String = If(If(FmlObject("dependencies") IsNot Nothing, FmlObject("dependencies")("value"), ""), "")
|
||||
If Deps <> "" Then
|
||||
For Each Dep In Deps.Split(";")
|
||||
If Dep = "" OrElse Not Dep.StartsWith("required-") Then Continue For
|
||||
Dep = Dep.Substring(Dep.IndexOf(":") + 1)
|
||||
If Dep = "" OrElse Not Dep.StartsWithF("required-") Then Continue For
|
||||
Dep = Dep.Substring(Dep.IndexOfF(":") + 1)
|
||||
If Dep.Contains("@") Then
|
||||
AddDependency(Dep.Split("@")(0), Dep.Split("@")(1))
|
||||
Else
|
||||
@@ -597,7 +593,7 @@ Finished:
|
||||
If MetaEntry IsNot Nothing Then
|
||||
Dim MetaString As String = ReadFile(MetaEntry.Open()).Replace(" :", ":").Replace(": ", ":")
|
||||
If MetaString.Contains("Implementation-Version:") Then
|
||||
MetaString = MetaString.Substring(MetaString.IndexOf("Implementation-Version:") + "Implementation-Version:".Count)
|
||||
MetaString = MetaString.Substring(MetaString.IndexOfF("Implementation-Version:") + "Implementation-Version:".Count)
|
||||
MetaString = MetaString.Substring(0, MetaString.IndexOfAny(vbCrLf.ToCharArray)).Trim
|
||||
Version = MetaString
|
||||
End If
|
||||
@@ -610,97 +606,17 @@ Finished:
|
||||
If _Version IsNot Nothing AndAlso Not (_Version.Contains(".") OrElse _Version.Contains("-")) Then Version = Nothing
|
||||
#End Region
|
||||
|
||||
IsInfoWithoutClassAvailable = _ModId IsNot Nothing AndAlso _Version IsNot Nothing
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 进行使用 .class 文件的信息获取。
|
||||
''' </summary>
|
||||
Private Sub LoadWithClass(Jar As ZipArchive)
|
||||
Try
|
||||
'查找入口点文件
|
||||
Dim ModClass As String = Nothing
|
||||
Dim ModClassNotBest As String = Nothing '非完美匹配
|
||||
For Each Entry In Jar.Entries
|
||||
If Entry.Name.EndsWith(".class") Then
|
||||
Dim Temp As String = ReadFile(Entry.Open()).ToLower
|
||||
If Temp.Contains("#lnet/minecraftforge/fml/common/mod;") Then
|
||||
ModClass = Temp
|
||||
Exit For
|
||||
ElseIf Temp.Contains("modid") Then
|
||||
ModClassNotBest = Temp
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
If ModClass Is Nothing Then ModClass = ModClassNotBest
|
||||
If ModClass Is Nothing Then Throw New FileNotFoundException("未找到 Mod 入口点")
|
||||
ModClass = ModClass.Replace("ljava/lang/string;", "")
|
||||
If ModClass.Count > 3000 Then ModClass = ModClass.Substring(0, 3000) '如果文件过大,截取前 3000 Byte
|
||||
Dim IndexHead As Integer, IndexTail As Integer, IncreaseCount As Integer
|
||||
'获取 ModID
|
||||
If _ModId Is Nothing Then
|
||||
IndexHead = ModClass.IndexOf("modid") + "modid".Length + 1
|
||||
IncreaseCount = 0
|
||||
Do While Convert.ToInt32(ModClass(IndexHead)) < 32
|
||||
IndexHead += 1
|
||||
IncreaseCount += 1
|
||||
If IncreaseCount > 10 Then Throw New Exception("ModID 头匹配失败")
|
||||
Loop
|
||||
IndexTail = IndexHead + 1
|
||||
IncreaseCount = 0
|
||||
Do Until Convert.ToInt32(ModClass(IndexTail)) < 32
|
||||
IndexTail += 1
|
||||
IncreaseCount += 1
|
||||
If IncreaseCount > 50 Then Throw New Exception("ModID 尾匹配失败")
|
||||
Loop
|
||||
ModId = ModClass.Substring(IndexHead, IndexTail - IndexHead)
|
||||
End If
|
||||
'获取 Version
|
||||
If _Version Is Nothing AndAlso ModClass.Contains("version") Then
|
||||
IndexHead = ModClass.IndexOf("version") + "version".Length + 1
|
||||
IncreaseCount = 0
|
||||
Do While Convert.ToInt32(ModClass(IndexHead)) < 32
|
||||
IndexHead += 1
|
||||
IncreaseCount += 1
|
||||
If IncreaseCount > 10 Then GoTo VersionFindFail
|
||||
Loop
|
||||
IndexTail = IndexHead + 1
|
||||
IncreaseCount = 0
|
||||
Do While ModClass(IndexTail) = "."c OrElse ModClass(IndexTail) = "-"c OrElse
|
||||
(ModClass(IndexTail) >= "0"c AndAlso ModClass(IndexTail) <= "9"c) OrElse
|
||||
(ModClass(IndexTail) >= "a"c AndAlso ModClass(IndexTail) <= "z"c)
|
||||
IndexTail += 1
|
||||
IncreaseCount += 1
|
||||
If IncreaseCount > 50 Then GoTo VersionFindFail
|
||||
Loop
|
||||
_Version = ModClass.Substring(IndexHead, IndexTail - IndexHead)
|
||||
End If
|
||||
VersionFindFail:
|
||||
'获取 Dependencies
|
||||
IndexHead = ModClass.IndexOf("dependencies")
|
||||
If IndexHead > 0 Then
|
||||
If ModClass.Count >= IndexHead + 300 Then ModClass = ModClass.Substring(IndexHead, 299)
|
||||
Dim Deps As List(Of String) = RegexSearch(ModClass, "(?<=required-((before|after|before-client|after-client)?):)[0-9a-z]+(@[\(\[]{1}[0-9.,]+[\)\]]{1})?")
|
||||
For Each Token As String In Deps
|
||||
If Not String.IsNullOrEmpty(Token) Then
|
||||
If Token.Contains("@") Then
|
||||
AddDependency(Token.Split("@")(0), Token.Split("@")(1))
|
||||
Else
|
||||
AddDependency(Token)
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "Mod Class 信息不可用(" & If(Path, "null") & ")", LogLevel.Normal)
|
||||
End Try
|
||||
IsInfoWithClassAvailable = _ModId IsNot Nothing AndAlso _Version IsNot Nothing
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "网络信息"
|
||||
|
||||
''' <summary>
|
||||
''' 当任何网络信息更新时触发。
|
||||
''' </summary>
|
||||
Public Event OnCompUpdate(sender As McMod)
|
||||
|
||||
''' <summary>
|
||||
''' 该 Mod 关联的网络项目。
|
||||
''' </summary>
|
||||
@@ -710,12 +626,70 @@ VersionFindFail:
|
||||
End Get
|
||||
Set(value As CompProject)
|
||||
_Comp = value
|
||||
RaiseEvent OnGetCompProject(Me)
|
||||
RaiseEvent OnCompUpdate(Me)
|
||||
End Set
|
||||
End Property
|
||||
Private _Comp As CompProject
|
||||
Public IsCompFromModrinth = False
|
||||
Public Event OnGetCompProject(sender As McMod)
|
||||
|
||||
''' <summary>
|
||||
''' 本地文件对应的联网文件信息。
|
||||
''' </summary>
|
||||
Public CompFile As CompFile
|
||||
|
||||
''' <summary>
|
||||
''' 该 Mod 对应的联网最新版本。
|
||||
''' </summary>
|
||||
Public Property UpdateFile As CompFile
|
||||
Get
|
||||
Return _UpdateFile
|
||||
End Get
|
||||
Set(value As CompFile)
|
||||
_UpdateFile = value
|
||||
RaiseEvent OnCompUpdate(Me)
|
||||
End Set
|
||||
End Property
|
||||
Private _UpdateFile As CompFile
|
||||
|
||||
''' <summary>
|
||||
''' 该 Mod 的更新日志网址。
|
||||
''' </summary>
|
||||
Public ChangelogUrls As New List(Of String)
|
||||
''' <summary>
|
||||
''' 所有网络信息是否已成功加载。
|
||||
''' </summary>
|
||||
Public CompLoaded As Boolean = False
|
||||
|
||||
''' <summary>
|
||||
''' 将网络信息保存为 Json。
|
||||
''' </summary>
|
||||
Public Function ToJson() As JObject
|
||||
Dim Json As New JObject
|
||||
If Comp IsNot Nothing Then Json.Add("Comp", Comp.ToJson())
|
||||
Json.Add("ChangelogUrls", New JArray(ChangelogUrls))
|
||||
Json.Add("CompLoaded", CompLoaded)
|
||||
If CompFile IsNot Nothing Then Json.Add("CompFile", CompFile.ToJson())
|
||||
If UpdateFile IsNot Nothing Then Json.Add("UpdateFile", UpdateFile.ToJson())
|
||||
Return Json
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 从 Json 中读取网络信息。
|
||||
''' </summary>
|
||||
Public Sub FromJson(Json As JObject)
|
||||
CompLoaded = Json("CompLoaded")
|
||||
If Json.ContainsKey("Comp") Then Comp = New CompProject(Json("Comp"))
|
||||
If Json.ContainsKey("ChangelogUrls") Then ChangelogUrls = Json("ChangelogUrls").ToObject(Of List(Of String))
|
||||
If Json.ContainsKey("CompFile") Then CompFile = New CompFile(Json("CompFile"), CompType.Mod)
|
||||
If Json.ContainsKey("UpdateFile") Then UpdateFile = New CompFile(Json("UpdateFile"), CompType.Mod)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 该文件是否可以更新。
|
||||
''' </summary>
|
||||
Public ReadOnly Property CanUpdate As Boolean
|
||||
Get
|
||||
Return ChangelogUrls.Any()
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <summary>
|
||||
''' 获取用于 CurseForge 信息获取的 Hash 值(MurmurHash2)。
|
||||
@@ -723,6 +697,14 @@ VersionFindFail:
|
||||
Public ReadOnly Property CurseForgeHash As UInteger
|
||||
Get
|
||||
If _CurseForgeHash Is Nothing Then
|
||||
'读取缓存
|
||||
Dim Info As New FileInfo(Path)
|
||||
Dim CacheKey As String = GetHash($"{RawPath}-{Info.LastWriteTime.ToLongTimeString}-{Info.Length}-C")
|
||||
Dim Cached As String = ReadIni(PathTemp & "Cache\ModHash.ini", CacheKey)
|
||||
If Cached <> "" Then
|
||||
_CurseForgeHash = Cached
|
||||
Return _CurseForgeHash
|
||||
End If
|
||||
'读取文件
|
||||
Dim data As New List(Of Byte)
|
||||
For Each b As Byte In File.ReadAllBytes(Path)
|
||||
@@ -757,6 +739,8 @@ VersionFindFail:
|
||||
h = (h * &H5BD1E995L) And &HFFFFFFFFL
|
||||
h = h Xor (h >> 15)
|
||||
_CurseForgeHash = h
|
||||
'写入缓存
|
||||
WriteIni(PathTemp & "Cache\ModHash.ini", CacheKey, h.ToString)
|
||||
End If
|
||||
Return _CurseForgeHash
|
||||
End Get
|
||||
@@ -769,7 +753,18 @@ VersionFindFail:
|
||||
Public ReadOnly Property ModrinthHash As String
|
||||
Get
|
||||
If _ModrinthHash Is Nothing Then
|
||||
'读取缓存
|
||||
Dim Info As New FileInfo(Path)
|
||||
Dim CacheKey As String = GetHash($"{RawPath}-{Info.LastWriteTime.ToLongTimeString}-{Info.Length}-M")
|
||||
Dim Cached As String = ReadIni(PathTemp & "Cache\ModHash.ini", CacheKey)
|
||||
If Cached <> "" Then
|
||||
_ModrinthHash = Cached
|
||||
Return _ModrinthHash
|
||||
End If
|
||||
'计算 SHA1
|
||||
_ModrinthHash = GetFileSHA1(Path)
|
||||
'写入缓存
|
||||
WriteIni(PathTemp & "Cache\ModHash.ini", CacheKey, _ModrinthHash)
|
||||
End If
|
||||
Return _ModrinthHash
|
||||
End Get
|
||||
@@ -794,7 +789,7 @@ VersionFindFail:
|
||||
''' 是否可能为前置 Mod。
|
||||
''' </summary>
|
||||
Public Function IsPresetMod() As Boolean
|
||||
Return Dependencies.Count = 0 AndAlso Name IsNot Nothing AndAlso (Name.ToLower.Contains("core") OrElse Name.ToLower.Contains("lib"))
|
||||
Return Not Dependencies.Any() AndAlso Name IsNot Nothing AndAlso (Name.ToLower.Contains("core") OrElse Name.ToLower.Contains("lib"))
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
@@ -803,9 +798,9 @@ VersionFindFail:
|
||||
Public Shared Function IsModFile(Path As String)
|
||||
If Path Is Nothing OrElse Not Path.Contains(".") Then Return False
|
||||
Path = Path.ToLower
|
||||
If Path.EndsWith(".jar") OrElse Path.EndsWith(".zip") OrElse Path.EndsWith(".litemod") OrElse
|
||||
Path.EndsWith(".jar.disabled") OrElse Path.EndsWith(".zip.disabled") OrElse Path.EndsWith(".litemod.disabled") OrElse
|
||||
Path.EndsWith(".jar.old") OrElse Path.EndsWith(".zip.old") OrElse Path.EndsWith(".litemod.old") Then Return True
|
||||
If Path.EndsWithF(".jar", True) OrElse Path.EndsWithF(".zip", True) OrElse Path.EndsWithF(".litemod", True) OrElse
|
||||
Path.EndsWithF(".jar.disabled", True) OrElse Path.EndsWithF(".zip.disabled", True) OrElse Path.EndsWithF(".litemod.disabled", True) OrElse
|
||||
Path.EndsWithF(".jar.old", True) OrElse Path.EndsWithF(".zip.old", True) OrElse Path.EndsWithF(".litemod.old", True) Then Return True
|
||||
Return False
|
||||
End Function
|
||||
|
||||
@@ -817,6 +812,20 @@ VersionFindFail:
|
||||
Try
|
||||
RunInUiWait(Sub() If FrmVersionMod IsNot Nothing Then FrmVersionMod.Load.ShowProgress = False)
|
||||
|
||||
'等待 Mod 更新完成
|
||||
If PageVersionMod.UpdatingVersions.Contains(Loader.Input) Then
|
||||
Log($"[Mod] 等待 Mod 更新完成后才能继续加载 Mod 列表")
|
||||
Try
|
||||
RunInUiWait(Sub() If FrmVersionMod IsNot Nothing Then FrmVersionMod.Load.Text = "正在更新 Mod")
|
||||
Do Until Not PageVersionMod.UpdatingVersions.Contains(Loader.Input)
|
||||
If Loader.IsAborted Then Exit Sub
|
||||
Thread.Sleep(100)
|
||||
Loop
|
||||
Finally
|
||||
RunInUiWait(Sub() If FrmVersionMod IsNot Nothing Then FrmVersionMod.Load.Text = "正在加载 Mod 列表")
|
||||
End Try
|
||||
End If
|
||||
|
||||
'获取 Mod 文件夹下的可用文件列表
|
||||
Dim ModFileList As New List(Of FileInfo)
|
||||
If Directory.Exists(Loader.Input) Then
|
||||
@@ -846,7 +855,7 @@ VersionFindFail:
|
||||
If CacheContent <> "" Then
|
||||
Cache = GetJson(CacheContent)
|
||||
If Not Cache.ContainsKey("version") OrElse Cache("version").ToObject(Of Integer) <> LocalModCacheVersion Then
|
||||
Log($"[Mod] 本地 Mod 信息缓存版本已过期,将弃用这些缓存信息")
|
||||
Log($"[Mod] 本地 Mod 信息缓存版本已过期,将弃用这些缓存信息", LogLevel.Debug)
|
||||
Cache = New JObject
|
||||
End If
|
||||
End If
|
||||
@@ -859,7 +868,7 @@ VersionFindFail:
|
||||
Dim ModList As New List(Of McMod)
|
||||
Dim ModUpdateList As New List(Of McMod)
|
||||
For Each ModFile As FileInfo In ModFileList
|
||||
Loader.Progress += 0.95 / ModFileList.Count
|
||||
Loader.Progress += 0.94 / ModFileList.Count
|
||||
If Loader.IsAborted Then Exit Sub
|
||||
'加载 McMod 对象
|
||||
Dim ModEntry As New McMod(ModFile.FullName)
|
||||
@@ -880,10 +889,9 @@ VersionFindFail:
|
||||
If ModEntry.State = McMod.McModState.Unavaliable Then Continue For
|
||||
Dim Hash = ModEntry.ModrinthHash
|
||||
If Cache.ContainsKey(Hash) Then
|
||||
ModEntry.Comp = New CompProject(Cache(Hash))
|
||||
ModEntry.IsCompFromModrinth = Not ModEntry.Comp.FromCurseForge
|
||||
ModEntry.FromJson(Cache(Hash))
|
||||
'如果缓存中的信息在 6 小时以内更新过,则无需重新获取
|
||||
If Date.Now - Cache(Hash)("CacheTime").ToObject(Of Date) < New TimeSpan(6, 0, 0) Then Continue For
|
||||
If ModEntry.CompLoaded AndAlso Date.Now - Cache(Hash)("Comp")("CacheTime").ToObject(Of Date) < New TimeSpan(6, 0, 0) Then Continue For
|
||||
End If
|
||||
ModUpdateList.Add(ModEntry)
|
||||
Next
|
||||
@@ -906,10 +914,10 @@ VersionFindFail:
|
||||
|
||||
'开始联网加载
|
||||
If ModUpdateList.Any() Then
|
||||
'TODO: 添加信息获取中提示
|
||||
McModDetailLoader.Start(New KeyValuePair(Of List(Of McMod), JObject)(ModUpdateList, Cache), IsForceRestart:=True)
|
||||
End If
|
||||
|
||||
Loader.Progress = 1
|
||||
Catch ex As Exception
|
||||
Log(ex, "Mod 列表加载失败", LogLevel.Debug)
|
||||
Throw
|
||||
@@ -917,29 +925,31 @@ VersionFindFail:
|
||||
End Sub
|
||||
|
||||
'联网加载 Mod 详情
|
||||
Private Const LocalModCacheVersion As Integer = 1
|
||||
Private Const LocalModCacheVersion As Integer = 2
|
||||
Public McModDetailLoader As New LoaderTask(Of KeyValuePair(Of List(Of McMod), JObject), Integer)("Mod List Detail Loader", AddressOf McModDetailLoad)
|
||||
Private Sub McModDetailLoad(Loader As LoaderTask(Of KeyValuePair(Of List(Of McMod), JObject), Integer))
|
||||
Dim Mods As List(Of McMod) = Loader.Input.Key
|
||||
Dim Cache As JObject = Loader.Input.Value
|
||||
'获取作为检查目标的加载器和版本
|
||||
Dim TargetMcVersion As McVersionInfo = PageVersionLeft.Version.Version
|
||||
Dim ModLoaders As New List(Of String)
|
||||
If TargetMcVersion.HasForge Then ModLoaders.Add("forge")
|
||||
If TargetMcVersion.HasFabric Then ModLoaders.Add("fabric")
|
||||
If TargetMcVersion.HasLiteLoader Then ModLoaders.Add("liteloader")
|
||||
If Not ModLoaders.Any() Then ModLoaders.AddRange({"forge", "fabric", "liteloader"})
|
||||
Dim ModLoaders As New List(Of CompModLoaderType)
|
||||
If TargetMcVersion.HasForge Then ModLoaders.Add(CompModLoaderType.Forge)
|
||||
If TargetMcVersion.HasFabric Then ModLoaders.Add(CompModLoaderType.Fabric)
|
||||
If TargetMcVersion.HasLiteLoader Then ModLoaders.Add(CompModLoaderType.LiteLoader)
|
||||
If Not ModLoaders.Any() Then ModLoaders.AddRange({CompModLoaderType.Forge, CompModLoaderType.Fabric, CompModLoaderType.LiteLoader, CompModLoaderType.Quilt})
|
||||
Dim McVersions As New List(Of String) From {TargetMcVersion.McName}
|
||||
If TargetMcVersion.McCodeMain > 0 AndAlso TargetMcVersion.McCodeMain < 99 Then
|
||||
McVersions.Add($"1.{TargetMcVersion.McCodeMain}")
|
||||
For i = 1 To TargetMcVersion.McCodeSub
|
||||
McVersions.Add($"1.{TargetMcVersion.McCodeMain}.{i}")
|
||||
Next
|
||||
End If
|
||||
McVersions = McVersions.Distinct().ToList()
|
||||
'暂不向下扩展检查的 MC 小版本
|
||||
'例如:Mod 在更新 1.16.5 后,对早期的 1.16.2 版本发布了修补补丁,这会导致 PCL 将 1.16.5 版本的 Mod 降级到 1.16.2
|
||||
'If TargetMcVersion.McCodeMain > 0 AndAlso TargetMcVersion.McCodeMain < 99 Then
|
||||
' McVersions.Add($"1.{TargetMcVersion.McCodeMain}")
|
||||
' For i = 1 To TargetMcVersion.McCodeSub
|
||||
' McVersions.Add($"1.{TargetMcVersion.McCodeMain}.{i}")
|
||||
' Next
|
||||
'End If
|
||||
'McVersions = McVersions.Distinct().ToList()
|
||||
'开始网络获取
|
||||
Log($"[Mod] 目标加载器:{ModLoaders.Join("/")},版本:{McVersions.Join("/")}")
|
||||
Dim CompletedThread As Integer = 0
|
||||
Dim EndedThreadCount As Integer = 0, SucceedThreadCount As Integer = 0
|
||||
Dim MainThread As Thread = Thread.CurrentThread
|
||||
'从 Modrinth 获取信息
|
||||
RunInNewThread(
|
||||
@@ -947,25 +957,24 @@ VersionFindFail:
|
||||
Try
|
||||
'步骤 1:获取 Hash 与对应的工程 ID
|
||||
Dim ModrinthHashes = Mods.Select(Function(m) m.ModrinthHash).ToList()
|
||||
Dim ModrinthUpdate = CType(GetJson(NetRequestRetry("https://api.modrinth.com/v2/version_files/update", "POST",
|
||||
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1"",
|
||||
""loaders"": [""{ModLoaders.Join(""",""")}""],""game_versions"": [""{McVersions.Join(""",""")}""]}}", "application/json")), JObject)
|
||||
Log($"[Mod] 从 Modrinth 获取到 {ModrinthUpdate.Count} 个本地 Mod 的对应信息")
|
||||
Dim ModrinthVersion = CType(GetJson(NetRequestRetry("https://api.modrinth.com/v2/version_files", "POST",
|
||||
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")), JObject)
|
||||
Log($"[Mod] 从 Modrinth 获取到 {ModrinthVersion.Count} 个本地 Mod 的对应信息")
|
||||
'步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系
|
||||
If ModrinthUpdate.Count = 0 Then Exit Sub
|
||||
If ModrinthVersion.Count = 0 Then Exit Sub
|
||||
Dim ModrinthMapping As New Dictionary(Of String, List(Of McMod))
|
||||
For Each ModEntity In Mods
|
||||
If Not ModrinthUpdate.ContainsKey(ModEntity.ModrinthHash) Then Continue For
|
||||
Dim ProjectId = ModrinthUpdate(ModEntity.ModrinthHash)("project_id").ToString
|
||||
If CompProjectCache.ContainsKey(ProjectId) Then
|
||||
ModEntity.Comp = CompProjectCache(ProjectId)
|
||||
Else
|
||||
If Not ModrinthMapping.ContainsKey(ProjectId) Then ModrinthMapping(ProjectId) = New List(Of McMod)
|
||||
ModrinthMapping(ProjectId).Add(ModEntity)
|
||||
End If
|
||||
For Each Entry In Mods
|
||||
If Not ModrinthVersion.ContainsKey(Entry.ModrinthHash) Then Continue For
|
||||
Dim ProjectId = ModrinthVersion(Entry.ModrinthHash)("project_id").ToString
|
||||
If CompProjectCache.ContainsKey(ProjectId) AndAlso Entry.Comp Is Nothing Then Entry.Comp = CompProjectCache(ProjectId) '读取已加载的缓存,加快结果出现速度
|
||||
If Not ModrinthMapping.ContainsKey(ProjectId) Then ModrinthMapping(ProjectId) = New List(Of McMod)
|
||||
ModrinthMapping(ProjectId).Add(Entry)
|
||||
'记录对应的 CompFile
|
||||
Dim File As New CompFile(ModrinthVersion(Entry.ModrinthHash), CompType.Mod)
|
||||
If Entry.CompFile Is Nothing OrElse Entry.CompFile.ReleaseDate < File.ReleaseDate Then Entry.CompFile = File
|
||||
Next
|
||||
If Loader.IsAbortedWithThread(MainThread) Then Exit Sub
|
||||
Log($"[Mod] 读取缓存后还需要从 Modrinth 获取 {ModrinthMapping.Count} 类本地 Mod 的工程信息")
|
||||
Log($"[Mod] 需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息")
|
||||
'步骤 3:获取工程信息
|
||||
If Not ModrinthMapping.Any() Then Exit Sub
|
||||
Dim ModrinthProject = CType(GetJson(NetRequestRetry(
|
||||
@@ -974,18 +983,37 @@ VersionFindFail:
|
||||
For Each ProjectJson In ModrinthProject
|
||||
Dim Project As New CompProject(ProjectJson)
|
||||
For Each Entry In ModrinthMapping(Project.Id)
|
||||
If Entry.Comp IsNot Nothing AndAlso Not Entry.IsCompFromModrinth Then
|
||||
Project.LogoUrl = Entry.Comp.LogoUrl 'Modrinth 的部分 Logo 加载不出来
|
||||
End If
|
||||
Entry.IsCompFromModrinth = True
|
||||
If Entry.Comp IsNot Nothing AndAlso Entry.Comp.FromCurseForge Then Project.LogoUrl = Entry.Comp.LogoUrl 'Modrinth 的部分 Logo 不是图片,如果可能,使用 CurseForge 的 Logo
|
||||
Entry.Comp = Project
|
||||
Next
|
||||
Next
|
||||
Log($"[Mod] 已从 Modrinth 获取本地 Mod 信息,继续获取更新信息")
|
||||
'步骤 4:获取更新信息
|
||||
Dim ModrinthUpdate = CType(GetJson(NetRequestRetry("https://api.modrinth.com/v2/version_files/update", "POST",
|
||||
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1"",
|
||||
""loaders"": [""{ModLoaders.Join(""",""").ToLower}""],""game_versions"": [""{McVersions.Join(""",""")}""]}}", "application/json")), JObject)
|
||||
For Each Entry In Mods
|
||||
If Not ModrinthUpdate.ContainsKey(Entry.ModrinthHash) OrElse Entry.CompFile Is Nothing Then Continue For
|
||||
Dim UpdateFile As New CompFile(ModrinthUpdate(Entry.ModrinthHash), CompType.Mod)
|
||||
If Not UpdateFile.Available Then Continue For
|
||||
If ModeDebug Then Log($"[Mod] 本地文件 {Entry.CompFile.FileName} 在 Modrinth 上的最新版为 {UpdateFile.FileName}")
|
||||
If Entry.CompFile.ReleaseDate >= UpdateFile.ReleaseDate OrElse Entry.CompFile.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?{McVersions.Select(Function(v) $"g={v}&").Join("")}")
|
||||
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?{McVersions.Select(Function(v) $"g={v}&").Join("")}"}
|
||||
Entry.UpdateFile = UpdateFile
|
||||
End If
|
||||
Next
|
||||
Log($"[Mod] 从 Modrinth 获取本地 Mod 信息结束")
|
||||
SucceedThreadCount += 1
|
||||
Catch ex As Exception
|
||||
Log(ex, "从 Modrinth 获取本地 Mod 信息失败")
|
||||
Finally
|
||||
CompletedThread += 1
|
||||
EndedThreadCount += 1
|
||||
End Try
|
||||
End Sub, "Mod List Detail Loader Modrinth")
|
||||
'从 CurseForge 获取信息
|
||||
@@ -994,57 +1022,110 @@ VersionFindFail:
|
||||
Try
|
||||
'步骤 1:获取 Hash 与对应的工程 ID
|
||||
Dim CurseForgeHashes As New List(Of UInteger)
|
||||
For Each ModEntity In Mods
|
||||
CurseForgeHashes.Add(ModEntity.CurseForgeHash)
|
||||
For Each Entry In Mods
|
||||
CurseForgeHashes.Add(Entry.CurseForgeHash)
|
||||
If Loader.IsAbortedWithThread(MainThread) Then Exit Sub
|
||||
Next
|
||||
Dim CurseForgeRaw = CType(CType(GetJson(NetRequestRetry("https://api.curseforge.com/v1/fingerprints/432/", "POST",
|
||||
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")), JObject)("data")("exactMatches"), JContainer)
|
||||
Log($"[Mod] 从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地 Mod 的对应信息")
|
||||
'步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系
|
||||
If CurseForgeRaw.Count = 0 Then Exit Sub
|
||||
If Not CurseForgeRaw.Any() Then Exit Sub
|
||||
Dim CurseForgeMapping As New Dictionary(Of Integer, List(Of McMod))
|
||||
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 CompProjectCache.ContainsKey(ProjectId) Then
|
||||
Entry.Comp = CompProjectCache(ProjectId)
|
||||
Else
|
||||
If Not CurseForgeMapping.ContainsKey(ProjectId) Then CurseForgeMapping(ProjectId) = New List(Of McMod)
|
||||
CurseForgeMapping(ProjectId).Add(Entry)
|
||||
End If
|
||||
If CompProjectCache.ContainsKey(ProjectId) AndAlso Entry.Comp Is Nothing Then Entry.Comp = CompProjectCache(ProjectId) '读取已加载的缓存,加快结果出现速度
|
||||
If Not CurseForgeMapping.ContainsKey(ProjectId) Then CurseForgeMapping(ProjectId) = New List(Of McMod)
|
||||
CurseForgeMapping(ProjectId).Add(Entry)
|
||||
'记录对应的 CompFile
|
||||
Dim File As New CompFile(Project("file"), CompType.Mod)
|
||||
If Entry.CompFile Is Nothing OrElse Entry.CompFile.ReleaseDate < File.ReleaseDate Then Entry.CompFile = File
|
||||
Next
|
||||
Next
|
||||
If Loader.IsAbortedWithThread(MainThread) Then Exit Sub
|
||||
Log($"[Mod] 读取缓存后还需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息")
|
||||
Log($"[Mod] 需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息")
|
||||
'步骤 3:获取工程信息
|
||||
If Not CurseForgeMapping.Any() Then Exit Sub
|
||||
Dim CurseForgeProject = CType(GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods", "POST",
|
||||
$"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")), JObject)("data")
|
||||
Dim UpdateFileIds As New Dictionary(Of Integer, List(Of McMod)) 'FileId -> 本地 Mod 文件列表
|
||||
Dim FileIdToProjectSlug As New Dictionary(Of Integer, String)
|
||||
For Each ProjectJson In CurseForgeProject
|
||||
If Not ProjectJson("isAvailable").ToObject(Of Boolean) Then Continue For
|
||||
'设置 Entry 中的工程信息
|
||||
Dim Project As New CompProject(ProjectJson)
|
||||
For Each Entry In CurseForgeMapping(Project.Id) '倒查防止 CurseForge 返回的内容有漏
|
||||
If Entry.Comp IsNot Nothing AndAlso Entry.IsCompFromModrinth Then
|
||||
If Entry.Comp IsNot Nothing AndAlso Not Entry.Comp.FromCurseForge Then
|
||||
Entry.Comp.LogoUrl = Project.LogoUrl 'Modrinth 部分 Logo 加载不出来
|
||||
Entry.Comp = Entry.Comp '再次触发修改事件
|
||||
Continue For
|
||||
End If
|
||||
Entry.IsCompFromModrinth = False
|
||||
Entry.Comp = Project
|
||||
Next
|
||||
'查找或许版本更新的文件列表
|
||||
If ModLoaders.Count = 1 Then 'TODO: 结果有多个 ModLoader 时提示无法检测更新
|
||||
Dim NewestVersion As String = Nothing
|
||||
Dim NewestFileIds As New List(Of Integer)
|
||||
For Each IndexEntry In ProjectJson("latestFilesIndexes")
|
||||
If ModLoaders.Single <> IndexEntry("modLoader")?.ToObject(Of Integer) Then Continue For 'ModLoader 唯一且匹配
|
||||
Dim IndexVersion As String = IndexEntry("gameVersion")
|
||||
If Not McVersions.Contains(IndexVersion) Then Continue For 'MC 版本匹配
|
||||
'由于 latestFilesIndexes 是按时间从新到老排序的,所以只需取第一个;如果需要检查多个 releaseType 下的文件,将 > -1 改为 = 1,但这应当并不会获取到更新的文件
|
||||
If NewestVersion IsNot Nothing AndAlso VersionSortInteger(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 McMod)
|
||||
UpdateFileIds(FileId).AddRange(CurseForgeMapping(Project.Id))
|
||||
FileIdToProjectSlug(FileId) = Project.Slug
|
||||
Next
|
||||
End If
|
||||
Next
|
||||
Log($"[Mod] 从 CurseForge 获取本地 Mod 信息结束")
|
||||
Log($"[Mod] 已从 CurseForge 获取本地 Mod 信息,需要获取 {UpdateFileIds.Count} 个用于检查更新的文件信息")
|
||||
'步骤 4:获取更新文件信息
|
||||
If Not UpdateFileIds.Any() Then Exit Sub
|
||||
Dim CurseForgeFiles = CType(GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods/files", "POST",
|
||||
$"{{""fileIds"": [{UpdateFileIds.Keys.Join(",")}]}}", "application/json")), JObject)("data")
|
||||
Dim UpdateFiles As New Dictionary(Of McMod, CompFile)
|
||||
For Each FileJson In CurseForgeFiles
|
||||
Dim File As New CompFile(FileJson, CompType.Mod)
|
||||
If Not File.Available Then Continue For
|
||||
For Each Entry As McMod 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 McMod = Pair.Key
|
||||
Dim UpdateFile As CompFile = Pair.Value
|
||||
If ModeDebug Then Log($"[Mod] 本地文件 {Entry.CompFile.FileName} 在 CurseForge 上的最新版为 {UpdateFile.FileName}")
|
||||
If Entry.CompFile.ReleaseDate >= UpdateFile.ReleaseDate OrElse Entry.CompFile.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 更新信息结束")
|
||||
SucceedThreadCount += 1
|
||||
Catch ex As Exception
|
||||
Log(ex, "从 CurseForge 获取本地 Mod 信息失败")
|
||||
Finally
|
||||
CompletedThread += 1
|
||||
EndedThreadCount += 1
|
||||
End Try
|
||||
End Sub, "Mod List Detail Loader CurseForge")
|
||||
'等待线程结束
|
||||
Do Until CompletedThread = 2
|
||||
Do Until EndedThreadCount = 2
|
||||
If Loader.IsAborted Then Exit Sub
|
||||
Thread.Sleep(10)
|
||||
Loop
|
||||
@@ -1052,8 +1133,9 @@ VersionFindFail:
|
||||
Mods = Mods.Where(Function(m) m.Comp IsNot Nothing).ToList()
|
||||
Log($"[Mod] 联网获取本地 Mod 信息完成,为 {Mods.Count} 个 Mod 更新缓存")
|
||||
If Not Mods.Any() Then Exit Sub
|
||||
For Each ModEntity In Mods
|
||||
Cache(ModEntity.ModrinthHash) = ModEntity.Comp.ToJson()
|
||||
For Each Entry In Mods 'TODO: Bookshelf 的 Logo 会在两个网站间横跳
|
||||
Entry.CompLoaded = SucceedThreadCount = 2
|
||||
Cache(Entry.ModrinthHash) = Entry.ToJson()
|
||||
Next
|
||||
WriteFile(PathTemp & "Cache\LocalMod.json", Cache.ToString(If(ModeDebug, Newtonsoft.Json.Formatting.Indented, Newtonsoft.Json.Formatting.None)))
|
||||
End Sub
|
||||
@@ -1083,12 +1165,12 @@ VersionFindFail:
|
||||
If CurrentDependencies.ContainsKey(PossibleModId) Then
|
||||
If CurrentDependencies(PossibleModId)(2) = 1 Then
|
||||
Result.Add("重复添加了相同的 Mod,请尝试删除其中一个(ModID:" & PossibleModId & ")。" & vbCrLf &
|
||||
" - " & ModEntity.FileName & vbCrLf &
|
||||
" - " & CurrentDependencies(PossibleModId)(1))
|
||||
" - " & ModEntity.FileName & vbCrLf &
|
||||
" - " & CurrentDependencies(PossibleModId)(1))
|
||||
Else
|
||||
Log("[Minecraft] 由于可能有多个 ModID,跳过疑似的重复项(ModID:" & PossibleModId & ")。" & vbCrLf &
|
||||
" - " & ModEntity.FileName & vbCrLf &
|
||||
" - " & CurrentDependencies(PossibleModId)(1), LogLevel.Developer)
|
||||
" - " & ModEntity.FileName & vbCrLf &
|
||||
" - " & CurrentDependencies(PossibleModId)(1), LogLevel.Developer)
|
||||
End If
|
||||
Else
|
||||
CurrentDependencies.Add(PossibleModId, {ModEntity.Version, ModEntity.FileName, ModEntity.PossibleModId.Count})
|
||||
@@ -1106,8 +1188,8 @@ VersionFindFail:
|
||||
If Dependency.Value IsNot Nothing Then
|
||||
'获取分段后的详细版本信息
|
||||
Dim ReqVersion As String = Dependency.Value
|
||||
Dim ReqVersionHeadCanEqual As Boolean = ReqVersion.StartsWith("[")
|
||||
Dim ReqVersionTailCanEqual As Boolean = ReqVersion.EndsWith("]")
|
||||
Dim ReqVersionHeadCanEqual As Boolean = ReqVersion.StartsWithF("[")
|
||||
Dim ReqVersionTailCanEqual As Boolean = ReqVersion.EndsWithF("]")
|
||||
Dim ReqVersionHead As String
|
||||
Dim ReqVersionTail As String
|
||||
If ReqVersion.Contains(",") Then
|
||||
@@ -1121,8 +1203,8 @@ VersionFindFail:
|
||||
ReqVersionTailCanEqual = False
|
||||
End If
|
||||
End If
|
||||
If ReqVersionHead.StartsWith("1.") AndAlso ReqVersionHead.Contains("-") Then ReqVersionHead = ReqVersionHead.Substring(ReqVersionHead.LastIndexOf("-") + 1)
|
||||
If ReqVersionTail.StartsWith("1.") AndAlso ReqVersionTail.Contains("-") Then ReqVersionTail = ReqVersionTail.Substring(ReqVersionTail.LastIndexOf("-") + 1)
|
||||
If ReqVersionHead.StartsWithF("1.") AndAlso ReqVersionHead.Contains("-") Then ReqVersionHead = ReqVersionHead.Substring(ReqVersionHead.LastIndexOfF("-") + 1)
|
||||
If ReqVersionTail.StartsWithF("1.") AndAlso ReqVersionTail.Contains("-") Then ReqVersionTail = ReqVersionTail.Substring(ReqVersionTail.LastIndexOfF("-") + 1)
|
||||
'获取报错描述文本
|
||||
Dim VersionRequire As String
|
||||
If ReqVersionHead = ReqVersionTail Then
|
||||
@@ -1150,7 +1232,7 @@ VersionFindFail:
|
||||
Continue For
|
||||
End If
|
||||
Dim CurrentVersion As String = If(CurrentDependencies(ReqId)(0), "0.0")
|
||||
If CurrentVersion.StartsWith("1.") AndAlso CurrentVersion.Contains("-") Then CurrentVersion = CurrentVersion.Substring(CurrentVersion.LastIndexOf("-") + 1)
|
||||
If CurrentVersion.StartsWithF("1.") AndAlso CurrentVersion.Contains("-") Then CurrentVersion = CurrentVersion.Substring(CurrentVersion.LastIndexOfF("-") + 1)
|
||||
'对比前置 Mod 头部版本
|
||||
If ReqVersionHead.Contains(".") Then
|
||||
If VersionSortInteger(ReqVersionHead, CurrentVersion) > If(ReqVersionHeadCanEqual, 0, -1) Then
|
||||
@@ -1179,7 +1261,7 @@ VersionFindFail:
|
||||
Log(ex, "检查 Mod 时出错")
|
||||
End Try
|
||||
Next
|
||||
If Result.Count = 0 Then
|
||||
If Not Result.Any() Then
|
||||
Log("[Minecraft] Mod 检查未发现异常")
|
||||
Else
|
||||
Log("[Minecraft] Mod 检查异常结果:" & vbCrLf & Join(Result, vbCrLf))
|
||||
|
||||
@@ -40,7 +40,7 @@ Public Module ModModpack
|
||||
For Each Entry In Archive.Entries
|
||||
Dim FullNames As String() = Entry.FullName.Split("/")
|
||||
ArchiveBaseFolder = FullNames(0) & "/"
|
||||
If Entry.FullName.EndsWith("/versions/") AndAlso FullNames.Count = 3 Then PackType = 9 : Exit Try '压缩包
|
||||
If Entry.FullName.EndsWithF("/versions/") AndAlso FullNames.Count = 3 Then PackType = 9 : Exit Try '压缩包
|
||||
'确定为一级目录下
|
||||
If FullNames.Count <> 2 Then Continue For
|
||||
'判断是否为关键文件
|
||||
@@ -61,7 +61,7 @@ Public Module ModModpack
|
||||
If GetExceptionDetail(ex, True).Contains("Error.WinIOError") Then
|
||||
Log(ex, "打开整合包文件失败", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
|
||||
Return False
|
||||
ElseIf File.ToLower.EndsWith(".rar") Then
|
||||
ElseIf File.EndsWithF(".rar", True) Then
|
||||
Log(ex, "PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
|
||||
Return False
|
||||
Else
|
||||
@@ -186,7 +186,7 @@ Retry:
|
||||
Dim FabricVersion As String = Nothing
|
||||
For Each Entry In If(Json("minecraft")("modLoaders"), {})
|
||||
Dim Id As String = If(Entry("id"), "").ToString.ToLower
|
||||
If Id.StartsWith("forge-") Then
|
||||
If Id.StartsWithF("forge-") Then
|
||||
'Forge 指定
|
||||
If Id.Contains("recommended") Then
|
||||
Log("[ModPack] 该整合包版本过老,已不支持进行安装!", LogLevel.Hint)
|
||||
@@ -199,7 +199,7 @@ Retry:
|
||||
Catch ex As Exception
|
||||
Log(ex, "读取整合包 Forge 版本失败:" & Id)
|
||||
End Try
|
||||
ElseIf Id.StartsWith("fabric-") Then
|
||||
ElseIf Id.StartsWithF("fabric-") Then
|
||||
'Fabric 指定
|
||||
Try
|
||||
Log("[ModPack] 整合包 Fabric 版本:" & Id)
|
||||
@@ -277,7 +277,7 @@ Retry:
|
||||
IsResourcePack =
|
||||
(Not ModuleNames.Contains("META-INF")) AndAlso (Not ModuleNames.Contains("mcmod.info")) AndAlso '不包含 META-INF 或 mcmod.info
|
||||
ModuleNames.Contains("pack.mcmeta") AndAlso '包含 pack.mcmeta
|
||||
(Not File.FileName.EndsWith(".jar")) '文件后缀不是 .jar
|
||||
(Not File.FileName.EndsWithF(".jar", True)) '文件后缀不是 .jar
|
||||
Else
|
||||
IsResourcePack = False
|
||||
End If
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
'输出文本
|
||||
Dim Copyed As New List(Of String)
|
||||
SyncLock WaitingLogLock
|
||||
If WaitingLog.Count = 0 Then Exit Sub
|
||||
If Not WaitingLog.Any() Then Exit Sub
|
||||
Copyed = WaitingLog
|
||||
WaitingLog = New List(Of String)(1000)
|
||||
End SyncLock
|
||||
@@ -192,7 +192,7 @@
|
||||
If LogProgress < 2 AndAlso Text.Contains("Setting user:") Then
|
||||
WatcherLog("日志 2/5:游戏用户已设置") '仅确保支持 Minecraft 1.7+
|
||||
LogProgress = 2
|
||||
ElseIf LogProgress < 3 AndAlso Text.ToLower.Contains("lwjgl version") Then
|
||||
ElseIf LogProgress < 3 AndAlso Text.ContainsF("lwjgl version", True) Then
|
||||
WatcherLog("日志 3/5:LWJGL 版本已确认")
|
||||
LogProgress = 3
|
||||
ElseIf LogProgress < 4 AndAlso (Text.Contains("OpenAL initialized") OrElse Text.Contains("Starting up SoundSystem")) Then
|
||||
@@ -269,7 +269,7 @@
|
||||
If MinecraftWindow Is Nothing Then Exit Sub
|
||||
Dim MinecraftWindowName = MinecraftWindow.Value.Value, MinecraftWindowHandle = MinecraftWindow.Value.Key
|
||||
'已找到窗口
|
||||
If Not MinecraftWindowName.StartsWith("FML") Then
|
||||
If Not MinecraftWindowName.StartsWithF("FML") Then
|
||||
'已找到 Minecraft 窗口
|
||||
WindowHandle = MinecraftWindowHandle
|
||||
WatcherLog($"Minecraft 窗口已加载:{MinecraftWindowName}({MinecraftWindowHandle.ToInt64})")
|
||||
@@ -317,7 +317,7 @@
|
||||
Dim WindowText As String = str.ToString
|
||||
'有的 Mod 可以修改窗口标题,所以不能检测是否为 Minecraft 打头,这并不准确
|
||||
'部分版本会搞个 GLFW message window 出来所以得反选
|
||||
If Not (WindowText.StartsWith("FML") OrElse (WindowText <> "PopupMessageWindow") AndAlso Not WindowText.StartsWith("GLFW")) Then Exit Sub
|
||||
If Not (WindowText.StartsWithF("FML") OrElse (WindowText <> "PopupMessageWindow") AndAlso Not WindowText.StartsWithF("GLFW")) Then Exit Sub
|
||||
'获取窗口关联的进程
|
||||
Dim ProcessId As Integer
|
||||
GetWindowThreadProcessId(hwnd, ProcessId)
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
_Logo = value
|
||||
Dim FileAddress = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png"
|
||||
Try
|
||||
If _Logo.ToLower.StartsWith("http") Then
|
||||
If _Logo.StartsWithF("http", True) Then
|
||||
'网络图片
|
||||
If File.Exists(FileAddress) Then
|
||||
PathLogo.Source = New MyBitmap(FileAddress)
|
||||
ElseIf _Logo.ToLower.EndsWith(".webp") Then 'Modrinth 林业 Mod 使用了不支持的 WebP 格式 Logo
|
||||
ElseIf _Logo.EndsWithF(".webp", True) Then 'Modrinth 林业 Mod 使用了不支持的 WebP 格式 Logo
|
||||
Log($"[Comp] 发现不支持的 WebP 格式图标,已更改为默认图标:{_Logo}")
|
||||
PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
|
||||
Else
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<Grid x:Class="MyLocalModItem"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Name="PanBack" Height="44"
|
||||
RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True">
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:PCL;assembly="
|
||||
x:Name="PanBack" Height="44"
|
||||
RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="6" />
|
||||
<ColumnDefinition Width="34" />
|
||||
@@ -19,7 +20,7 @@
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Logo -->
|
||||
<Border Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" IsHitTestVisible="False" SnapsToDevicePixels="True" UseLayoutRounding="True"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center" Width="34" Height="34">
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center" Width="34" Height="34">
|
||||
<Border.Clip>
|
||||
<RectangleGeometry Rect="0,0,34,34" RadiusX="6" RadiusY="6" />
|
||||
</Border.Clip>
|
||||
@@ -27,10 +28,26 @@
|
||||
</Border>
|
||||
<!-- 标题 -->
|
||||
<StackPanel Grid.Column="3" Grid.ColumnSpan="2" Grid.Row="1" VerticalAlignment="Bottom" Margin="0,1,0,0" Orientation="Horizontal"
|
||||
IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False">
|
||||
<TextBlock x:Name="LabTitle" TextTrimming="WordEllipsis" FontSize="14" />
|
||||
<TextBlock x:Name="LabTitleRaw" TextTrimming="WordEllipsis" FontSize="12" Foreground="{StaticResource ColorBrushGray1}" Opacity="0.4" VerticalAlignment="Bottom" Visibility="Collapsed" />
|
||||
SnapsToDevicePixels="False" UseLayoutRounding="False">
|
||||
<TextBlock x:Name="LabTitle" TextTrimming="WordEllipsis" FontSize="14" IsHitTestVisible="False" />
|
||||
<TextBlock x:Name="LabTitleRaw" TextTrimming="WordEllipsis" FontSize="12" IsHitTestVisible="False"
|
||||
Foreground="{StaticResource ColorBrushGray1}" Opacity="0.4" VerticalAlignment="Bottom" Visibility="Collapsed" />
|
||||
<!-- 更新按钮 -->
|
||||
<local:MyIconButton Width="21" Height="21" Margin="-2,-1.6,0,0" x:Name="BtnUpdate" Theme="Black" Opacity="0.4" Visibility="Collapsed"
|
||||
ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="100" ToolTipService.VerticalOffset="-9"
|
||||
Logo="M640 768H384l-32-32V509H213L190 454l298-298h45l298 298L810 509h-138v226z m-224-64h192V477l32-32h93L512 223 290 445H384l32 32zM352 831h320v64h-320z" />
|
||||
</StackPanel>
|
||||
<!--<Grid Grid.Column="3" Grid.ColumnSpan="2" Grid.Row="1" VerticalAlignment="Bottom" Margin="0,1,0,0" IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="LabTitle" TextTrimming="WordEllipsis" FontSize="14" Grid.Column="0" />
|
||||
<TextBlock x:Name="LabTitleRaw" TextTrimming="WordEllipsis" FontSize="12" Grid.Column="1"
|
||||
Foreground="{StaticResource ColorBrushGray1}" Opacity="0.4" VerticalAlignment="Bottom" Visibility="Collapsed" />
|
||||
<local:MyIconTextButton Grid.Column="2" Text="更新" />
|
||||
</Grid>-->
|
||||
<!-- Tag 与 详情 -->
|
||||
<StackPanel x:Name="PanTags" Grid.Row="2" Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Bottom" Margin="-1,0,1,0" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<!--<Border Background="{DynamicResource ColorBrush6}" Padding="3,1" CornerRadius="3" Margin="0,0,4,0" SnapsToDevicePixels="True" UseLayoutRounding="False">
|
||||
|
||||
@@ -16,11 +16,11 @@ Public Class MyLocalModItem
|
||||
_Logo = value
|
||||
Dim FileAddress = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png"
|
||||
Try
|
||||
If _Logo.ToLower.StartsWith("http") Then
|
||||
If _Logo.StartsWithF("http", True) Then
|
||||
'网络图片
|
||||
If File.Exists(FileAddress) Then
|
||||
PathLogo.Source = New MyBitmap(FileAddress)
|
||||
ElseIf _Logo.ToLower.EndsWith(".webp") Then 'Modrinth 林业 Mod 使用了不支持的 WebP 格式 Logo
|
||||
ElseIf _Logo.EndsWithF(".webp", True) Then 'Modrinth 林业 Mod 使用了不支持的 WebP 格式 Logo
|
||||
Log($"[LocalModItem] 发现不支持的 WebP 格式图标,已更改为默认图标:{_Logo}")
|
||||
PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
|
||||
Else
|
||||
@@ -190,6 +190,39 @@ RetryStart:
|
||||
If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = True
|
||||
End Sub
|
||||
|
||||
'滑动选中
|
||||
Private Shared SwipeStart As Integer, SwipeEnd As Integer
|
||||
Private Shared Swiping As Boolean = False
|
||||
Private Shared SwipToState As Boolean '被滑动到的目标应将 Checked 改为此值
|
||||
Private Sub Button_MouseSwipeStart(sender As Object, e As Object) Handles Me.MouseLeftButtonDown
|
||||
'开始滑动
|
||||
Dim Index = CType(Parent, StackPanel).Children.IndexOf(Me)
|
||||
SwipeStart = Index
|
||||
SwipeEnd = Index
|
||||
Swiping = True
|
||||
SwipToState = Not Checked
|
||||
FrmVersionMod.CardSelect.IsHitTestVisible = False '暂时禁用下边栏
|
||||
End Sub
|
||||
Private Sub Button_MouseSwipe(sender As Object, e As Object) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonUp
|
||||
'结束滑动
|
||||
If Mouse.LeftButton <> MouseButtonState.Pressed OrElse Not Swiping Then
|
||||
Swiping = False
|
||||
FrmVersionMod.CardSelect.IsHitTestVisible = True
|
||||
Exit Sub
|
||||
End If
|
||||
'计算滑动范围
|
||||
Dim Index = CType(Parent, StackPanel).Children.IndexOf(Me)
|
||||
SwipeStart = Math.Min(SwipeStart, Index)
|
||||
SwipeEnd = Math.Max(SwipeEnd, Index)
|
||||
'勾选所有范围中的项
|
||||
If SwipeStart = SwipeEnd Then Exit Sub
|
||||
For i = SwipeStart To SwipeEnd
|
||||
Dim Item As MyLocalModItem = CType(Parent, StackPanel).Children(i)
|
||||
Item.InitLate(Item, e)
|
||||
Item.Checked = SwipToState
|
||||
Next
|
||||
End Sub
|
||||
|
||||
'勾选状态
|
||||
Public Event Check(sender As Object, e As RouteEventArgs)
|
||||
Public Event Changed(sender As Object, e As RouteEventArgs)
|
||||
@@ -201,10 +234,10 @@ RetryStart:
|
||||
Set(value As Boolean)
|
||||
Try
|
||||
'触发属性值修改
|
||||
Dim ChangedEventArgs As New RouteEventArgs(False)
|
||||
Dim RawValue = _Checked
|
||||
If value = _Checked Then Exit Property
|
||||
_Checked = value
|
||||
Dim ChangedEventArgs As New RouteEventArgs(False)
|
||||
If IsInitialized Then
|
||||
RaiseEvent Changed(Me, ChangedEventArgs)
|
||||
If ChangedEventArgs.Handled Then
|
||||
@@ -310,7 +343,7 @@ RetryStart:
|
||||
Children.Remove(ButtonStack)
|
||||
ButtonStack = Nothing
|
||||
End If
|
||||
If value.Count = 0 Then Exit Property
|
||||
If Not value.Any() Then Exit Property
|
||||
'添加新 Stack
|
||||
ButtonStack = New StackPanel With {.Opacity = 0, .Margin = New Thickness(0, 0, 5, 0), .SnapsToDevicePixels = False, .Orientation = Orientation.Horizontal,
|
||||
.HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Center, .UseLayoutRounding = False}
|
||||
@@ -347,6 +380,30 @@ RetryStart:
|
||||
Public Sub Refresh()
|
||||
RunInUi(
|
||||
Sub()
|
||||
'更新
|
||||
If Entry.CanUpdate Then
|
||||
BtnUpdate.Visibility = Visibility.Visible
|
||||
Dim CurrentName = Entry.CompFile.FileName.Replace(".jar", "")
|
||||
Dim NewestName = Entry.UpdateFile.FileName.Replace(".jar", "")
|
||||
'简化名称对比
|
||||
Dim CurrentSegs = CurrentName.Split("-"c).ToList()
|
||||
Dim NewestSegs = NewestName.Split("-"c).ToList()
|
||||
Dim Shortened As Boolean = False
|
||||
For Each Seg In CurrentSegs.ToList()
|
||||
If Not NewestSegs.Contains(Seg) Then Continue For
|
||||
CurrentSegs.Remove(Seg)
|
||||
NewestSegs.Remove(Seg)
|
||||
Shortened = True
|
||||
Next
|
||||
If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then
|
||||
CurrentName = Join(CurrentSegs, "-")
|
||||
NewestName = Join(NewestSegs, "-")
|
||||
Entry._Version = CurrentName '使用网络信息作为显示的版本号
|
||||
End If
|
||||
BtnUpdate.ToolTip = $"当前版本:{CurrentName} ({Entry.CompFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}最新版本:{NewestName} ({Entry.UpdateFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}点击以更新,右键查看更新日志。"
|
||||
Else
|
||||
BtnUpdate.Visibility = Visibility.Collapsed
|
||||
End If
|
||||
'标题
|
||||
If Entry.Comp Is Nothing Then
|
||||
Title = Entry.Name
|
||||
@@ -390,9 +447,9 @@ RetryStart:
|
||||
Else
|
||||
If ImgState Is Nothing Then
|
||||
ImgState = New Image With {
|
||||
.Width = 20, .Height = 20, .Margin = New Thickness(0, 0, -5, -3), .IsHitTestVisible = False,
|
||||
.HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Bottom
|
||||
}
|
||||
.Width = 20, .Height = 20, .Margin = New Thickness(0, 0, -5, -3), .IsHitTestVisible = False,
|
||||
.HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Bottom
|
||||
}
|
||||
RenderOptions.SetBitmapScalingMode(ImgState, BitmapScalingMode.HighQuality)
|
||||
SetColumn(ImgState, 1) : SetRow(ImgState, 1) : SetRowSpan(ImgState, 2)
|
||||
Children.Add(ImgState)
|
||||
@@ -409,11 +466,7 @@ RetryStart:
|
||||
End Sub
|
||||
|
||||
Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp, Me.Changed
|
||||
'按钮虚拟化检测
|
||||
If ButtonHandler IsNot Nothing Then
|
||||
ButtonHandler(sender, e)
|
||||
ButtonHandler = Nothing
|
||||
End If
|
||||
InitLate(sender, e)
|
||||
'触发颜色动画
|
||||
Dim Time As Integer = If(IsMouseOver, 120, 180)
|
||||
Dim Ani As New List(Of AniData)
|
||||
@@ -422,19 +475,19 @@ RetryStart:
|
||||
If IsMouseOver Then
|
||||
Ani.Add(AaOpacity(ButtonStack, 1 - ButtonStack.Opacity, Time * 0.7, Time * 0.3))
|
||||
Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
|
||||
5 + Buttons.Count * 25 - ColumnPaddingRight.Width.Value, Time * 0.3, Time * 0.7))
|
||||
5 + Buttons.Count * 25 - ColumnPaddingRight.Width.Value, Time * 0.3, Time * 0.7))
|
||||
Else
|
||||
Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.4))
|
||||
Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
|
||||
4 - ColumnPaddingRight.Width.Value, Time * 0.4))
|
||||
4 - ColumnPaddingRight.Width.Value, Time * 0.4))
|
||||
End If
|
||||
End If
|
||||
'RectBack
|
||||
If IsMouseOver OrElse Checked Then
|
||||
Ani.AddRange({
|
||||
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
|
||||
AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
|
||||
})
|
||||
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
|
||||
AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
|
||||
})
|
||||
If IsMouseDown Then
|
||||
Ani.Add(AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
|
||||
Else
|
||||
@@ -442,12 +495,42 @@ RetryStart:
|
||||
End If
|
||||
Else
|
||||
Ani.AddRange({
|
||||
AaOpacity(RectBack, -RectBack.Opacity, Time),
|
||||
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
|
||||
AaScaleTransform(RectBack, -0.196, 1,,, True)
|
||||
})
|
||||
AaOpacity(RectBack, -RectBack.Opacity, Time),
|
||||
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
|
||||
AaScaleTransform(RectBack, -0.196, 1,,, True)
|
||||
})
|
||||
End If
|
||||
AniStart(Ani, "LocalModItem Color " & Uuid)
|
||||
End Sub
|
||||
|
||||
'触发虚拟化内容
|
||||
Private Sub InitLate(sender As Object, e As EventArgs)
|
||||
If ButtonHandler IsNot Nothing Then
|
||||
ButtonHandler(sender, e)
|
||||
ButtonHandler = Nothing
|
||||
End If
|
||||
End Sub
|
||||
|
||||
'显示更新日志
|
||||
Private Sub ShowUpdateLog(sender As Object, e As MouseButtonEventArgs) Handles BtnUpdate.PreviewMouseRightButtonUp
|
||||
e.Handled = True
|
||||
Dim CurseForgeUrl As String = Entry.ChangelogUrls.FirstOrDefault(Function(x) x.Contains("curseforge.com"))
|
||||
Dim ModrinthUrl As String = Entry.ChangelogUrls.FirstOrDefault(Function(x) x.Contains("modrinth.com"))
|
||||
If CurseForgeUrl Is Nothing OrElse ModrinthUrl Is Nothing Then
|
||||
OpenWebsite(Entry.ChangelogUrls.First)
|
||||
Else
|
||||
Select Case MyMsgBox("要在哪个网站上查看更新日志?", "查看更新日志", "Modrinth", "CurseForge", "取消")
|
||||
Case 1
|
||||
OpenWebsite(ModrinthUrl)
|
||||
Case 2
|
||||
OpenWebsite(CurseForgeUrl)
|
||||
End Select
|
||||
End If
|
||||
End Sub
|
||||
|
||||
'触发更新
|
||||
Private Sub BtnUpdate_Click(sender As Object, e As EventArgs) Handles BtnUpdate.Click
|
||||
FrmVersionMod.UpdateMods({Entry})
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
|
||||
Reference in New Issue
Block a user