2.12.3
This commit is contained in:
@@ -95,7 +95,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Canvas x:Name="ImgBack" IsHitTestVisible="False" Grid.Row="1" RenderOptions.BitmapScalingMode="LowQuality" />
|
<Canvas x:Name="ImgBack" IsHitTestVisible="False" Grid.Row="1" RenderOptions.BitmapScalingMode="LowQuality"
|
||||||
|
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
|
||||||
<Grid x:Name="PanTitle" Height="48">
|
<Grid x:Name="PanTitle" Height="48">
|
||||||
<Grid.Background>
|
<Grid.Background>
|
||||||
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
|
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ Public Class FormMain
|
|||||||
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
|
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
|
||||||
'统计更新日志条目
|
'统计更新日志条目
|
||||||
#If BETA Then
|
#If BETA Then
|
||||||
|
If LastVersion < 381 Then 'Release 2.12.2
|
||||||
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法搜索 CurseForge 上的社区资源"))
|
||||||
|
FeatureCount += 3
|
||||||
|
BugCount += 13
|
||||||
|
End If
|
||||||
If LastVersion < 379 Then 'Release 2.12.1
|
If LastVersion < 379 Then 'Release 2.12.1
|
||||||
If LastVersion >= 376 Then
|
If LastVersion >= 376 Then
|
||||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "删除:暂时隐藏联机入口……不过只是暂时关闭,它还会回来的!"))
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "删除:暂时隐藏联机入口……不过只是暂时关闭,它还会回来的!"))
|
||||||
@@ -128,8 +133,15 @@ Public Class FormMain
|
|||||||
'3:BUG+ IMP* FEAT-
|
'3:BUG+ IMP* FEAT-
|
||||||
'2:BUG* IMP-
|
'2:BUG* IMP-
|
||||||
'1:BUG-
|
'1:BUG-
|
||||||
|
If LastVersion < 382 Then 'Snapshot 2.12.3
|
||||||
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:部分关键词搜不到资源,特别是中文 Mod 搜索经常没有结果"))
|
||||||
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:下载可能完全卡住,或是下载进度反复回退"))
|
||||||
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:内存管理设置,可以选择 G1GC、ZGC 或分代 ZGC"))
|
||||||
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:来自 Modrinth 的文件下载速度"))
|
||||||
|
FeatureCount += 15
|
||||||
|
BugCount += 16
|
||||||
|
End If
|
||||||
If LastVersion < 380 Then 'Snapshot 2.12.2
|
If LastVersion < 380 Then 'Snapshot 2.12.2
|
||||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法搜索 CurseForge 上的社区资源"))
|
|
||||||
FeatureCount += 3
|
FeatureCount += 3
|
||||||
BugCount += 13
|
BugCount += 13
|
||||||
End If
|
End If
|
||||||
@@ -606,6 +618,12 @@ Public Class FormMain
|
|||||||
Setup.Set("ToolDownloadTranslateV2", Setup.Get("ToolDownloadTranslate") + 1)
|
Setup.Set("ToolDownloadTranslateV2", Setup.Get("ToolDownloadTranslate") + 1)
|
||||||
Log("[Start] 已从老版本迁移 Mod 命名设置")
|
Log("[Start] 已从老版本迁移 Mod 命名设置")
|
||||||
End If
|
End If
|
||||||
|
'重置 JVM 参数设置
|
||||||
|
If LastVersionCode <= 381 AndAlso Not Setup.IsUnset("LaunchAdvanceJvm") AndAlso
|
||||||
|
Setup.Get("LaunchAdvanceJvm").ToString.Replace("-XX:+UseG1GC ", "").Replace("-XX:-UseAdaptiveSizePolicy ", "").Trim = Setup.GetDefault("LaunchAdvanceJvm") Then
|
||||||
|
Setup.Reset("LaunchAdvanceJvm")
|
||||||
|
Log("[Start] 已重置 JVM 参数设置")
|
||||||
|
End If
|
||||||
'输出更新日志
|
'输出更新日志
|
||||||
If LastVersionCode <= 0 Then Return
|
If LastVersionCode <= 0 Then Return
|
||||||
If LowerVersionCode >= VersionCode Then Return
|
If LowerVersionCode >= VersionCode Then Return
|
||||||
@@ -819,12 +837,12 @@ Public Class FormMain
|
|||||||
Log(ex, "切回窗口时出错", LogLevel.Feedback)
|
Log(ex, "切回窗口时出错", LogLevel.Feedback)
|
||||||
End Try
|
End Try
|
||||||
'读取剪贴板,自动加入联机房间
|
'读取剪贴板,自动加入联机房间
|
||||||
|
Return 'UNDONE: 联机复活赛
|
||||||
If PageLinkMain.LinkState <> PageLinkMain.LinkStates.Waiting Then Return '已启动联机
|
If PageLinkMain.LinkState <> PageLinkMain.LinkStates.Waiting Then Return '已启动联机
|
||||||
If PageCurrent = PageType.Link Then Return '已在联机界面
|
If PageCurrent = PageType.Link Then Return '已在联机界面
|
||||||
Dim Code = ClipboardGetText() : If Code Is Nothing Then Return '剪贴板无文本
|
Dim Code = ClipboardGetText() : If Code Is Nothing Then Return '剪贴板无文本
|
||||||
If Setup.Get("LinkLastAutoJoinInviteCode") = Code Then Return
|
If Setup.Get("LinkLastAutoJoinInviteCode") = Code Then Return
|
||||||
' If PageLinkMain.ValidateCodeFormat(Code) IsNot Nothing Then Return '不是邀请码
|
If PageLinkMain.ValidateCodeFormat(Code) IsNot Nothing Then Return '不是邀请码
|
||||||
Return '联机关闭 直接return
|
|
||||||
Setup.Set("LinkLastAutoJoinInviteCode", Code)
|
Setup.Set("LinkLastAutoJoinInviteCode", Code)
|
||||||
RunInThread(
|
RunInThread(
|
||||||
Sub()
|
Sub()
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ Public Module ModBase
|
|||||||
#Region "声明"
|
#Region "声明"
|
||||||
|
|
||||||
'下列版本信息由更新器自动修改
|
'下列版本信息由更新器自动修改
|
||||||
Public Const VersionBaseName As String = "2.12.2" '不含分支前缀的显示用版本名
|
Public Const VersionBaseName As String = "2.12.3" '不含分支前缀的显示用版本名
|
||||||
Public Const VersionStandardCode As String = "2.12.2." & VersionBranchCode '标准格式的四段式版本号
|
Public Const VersionStandardCode As String = "2.12.3." & VersionBranchCode '标准格式的四段式版本号
|
||||||
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
|
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
|
||||||
#If BETA Then
|
#If BETA Then
|
||||||
Public Const VersionCode As Integer = 379 'Release
|
Public Const VersionCode As Integer = 381 'Release
|
||||||
#Else
|
#Else
|
||||||
Public Const VersionCode As Integer = 380 'Snapshot
|
Public Const VersionCode As Integer = 382 'Snapshot
|
||||||
#End If
|
#End If
|
||||||
'自动生成的版本信息
|
'自动生成的版本信息
|
||||||
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
||||||
@@ -1071,10 +1071,9 @@ Public Module ModBase
|
|||||||
''' 获取文件 MD5,若失败则返回空字符串。
|
''' 获取文件 MD5,若失败则返回空字符串。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Function GetFileMD5(FilePath As String) As String
|
Public Function GetFileMD5(FilePath As String) As String
|
||||||
Dim Retry As Boolean = False
|
Dim Retried As Boolean = False
|
||||||
Re:
|
Re:
|
||||||
Try
|
Try
|
||||||
'获取 MD5
|
|
||||||
Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||||
Using h = MD5Cng.Create()
|
Using h = MD5Cng.Create()
|
||||||
Dim Retval As Byte() = h.ComputeHash(File)
|
Dim Retval As Byte() = h.ComputeHash(File)
|
||||||
@@ -1082,16 +1081,15 @@ Re:
|
|||||||
For i = 0 To Retval.Length - 1
|
For i = 0 To Retval.Length - 1
|
||||||
Result.Append(Retval(i).ToString("x2"))
|
Result.Append(Retval(i).ToString("x2"))
|
||||||
Next
|
Next
|
||||||
|
|
||||||
Return Result.ToString
|
Return Result.ToString
|
||||||
End Using
|
End Using
|
||||||
End Using
|
End Using
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
If Retry OrElse TypeOf ex Is FileNotFoundException Then
|
If Retried OrElse TypeOf ex Is FileNotFoundException Then
|
||||||
Log(ex, "获取文件 MD5 失败:" & FilePath)
|
Log(ex, "获取文件 MD5 失败:" & FilePath)
|
||||||
Return ""
|
Return ""
|
||||||
Else
|
Else
|
||||||
Retry = True
|
Retried = True
|
||||||
Log(ex, "获取文件 MD5 可重试失败:" & FilePath, LogLevel.Normal)
|
Log(ex, "获取文件 MD5 可重试失败:" & FilePath, LogLevel.Normal)
|
||||||
Thread.Sleep(RandomInteger(200, 500))
|
Thread.Sleep(RandomInteger(200, 500))
|
||||||
GoTo Re
|
GoTo Re
|
||||||
@@ -1102,29 +1100,25 @@ Re:
|
|||||||
''' 获取文件 SHA512,若失败则返回空字符串。
|
''' 获取文件 SHA512,若失败则返回空字符串。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Function GetFileSHA512(FilePath As String) As String
|
Public Function GetFileSHA512(FilePath As String) As String
|
||||||
Dim Retry As Boolean = False
|
Dim Retried As Boolean = False
|
||||||
Re:
|
Re:
|
||||||
Try
|
Try
|
||||||
''检测该文件是否在下载中,若在下载则放弃检测
|
Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||||
'If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return ""
|
|
||||||
'获取 SHA512
|
|
||||||
Using file As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
|
||||||
Using h = SHA512Cng.Create()
|
Using h = SHA512Cng.Create()
|
||||||
Dim retval As Byte() = h.ComputeHash(file)
|
Dim retval As Byte() = h.ComputeHash(File)
|
||||||
Dim Result As New StringBuilder(retval.Length * 2)
|
Dim Result As New StringBuilder(retval.Length * 2)
|
||||||
For i As Integer = 0 To retval.Length - 1
|
For i As Integer = 0 To retval.Length - 1
|
||||||
Result.Append(retval(i).ToString("x2"))
|
Result.Append(retval(i).ToString("x2"))
|
||||||
Next
|
Next
|
||||||
|
|
||||||
Return Result.ToString
|
Return Result.ToString
|
||||||
End Using
|
End Using
|
||||||
End Using
|
End Using
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
If Retry OrElse TypeOf ex Is FileNotFoundException Then
|
If Retried OrElse TypeOf ex Is FileNotFoundException Then
|
||||||
Log(ex, "获取文件 SHA512 失败:" & FilePath)
|
Log(ex, "获取文件 SHA512 失败:" & FilePath)
|
||||||
Return ""
|
Return ""
|
||||||
Else
|
Else
|
||||||
Retry = True
|
Retried = True
|
||||||
Log(ex, "获取文件 SHA512 可重试失败:" & FilePath, LogLevel.Normal)
|
Log(ex, "获取文件 SHA512 可重试失败:" & FilePath, LogLevel.Normal)
|
||||||
Thread.Sleep(RandomInteger(200, 500))
|
Thread.Sleep(RandomInteger(200, 500))
|
||||||
GoTo Re
|
GoTo Re
|
||||||
@@ -1138,17 +1132,13 @@ Re:
|
|||||||
Dim Retry As Boolean = False
|
Dim Retry As Boolean = False
|
||||||
Re:
|
Re:
|
||||||
Try
|
Try
|
||||||
''检测该文件是否在下载中,若在下载则放弃检测
|
Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||||
'If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return ""
|
|
||||||
'获取 SHA256
|
|
||||||
Using file As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
|
||||||
Using h = SHA256Cng.Create()
|
Using h = SHA256Cng.Create()
|
||||||
Dim retval As Byte() = h.ComputeHash(file)
|
Dim retval As Byte() = h.ComputeHash(File)
|
||||||
Dim Result As New StringBuilder(retval.Length * 2)
|
Dim Result As New StringBuilder(retval.Length * 2)
|
||||||
For i As Integer = 0 To retval.Length - 1
|
For i As Integer = 0 To retval.Length - 1
|
||||||
Result.Append(retval(i).ToString("x2"))
|
Result.Append(retval(i).ToString("x2"))
|
||||||
Next
|
Next
|
||||||
|
|
||||||
Return Result.ToString()
|
Return Result.ToString()
|
||||||
End Using
|
End Using
|
||||||
End Using
|
End Using
|
||||||
@@ -1171,15 +1161,13 @@ Re:
|
|||||||
Dim Retry As Boolean = False
|
Dim Retry As Boolean = False
|
||||||
Re:
|
Re:
|
||||||
Try
|
Try
|
||||||
'获取 SHA1
|
Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||||
Using file As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
|
||||||
Using h = SHA1Cng.Create()
|
Using h = SHA1Cng.Create()
|
||||||
Dim retval As Byte() = h.ComputeHash(file)
|
Dim retval As Byte() = h.ComputeHash(File)
|
||||||
Dim Result As New StringBuilder(retval.Length * 2)
|
Dim Result As New StringBuilder(retval.Length * 2)
|
||||||
For i As Integer = 0 To retval.Length - 1
|
For i As Integer = 0 To retval.Length - 1
|
||||||
Result.Append(retval(i).ToString("x2"))
|
Result.Append(retval(i).ToString("x2"))
|
||||||
Next
|
Next
|
||||||
|
|
||||||
Return Result.ToString
|
Return Result.ToString
|
||||||
End Using
|
End Using
|
||||||
End Using
|
End Using
|
||||||
@@ -1327,7 +1315,7 @@ Re:
|
|||||||
End Using
|
End Using
|
||||||
End Sub
|
End Sub
|
||||||
Try
|
Try
|
||||||
TryExtractZip(Encoding.UTF8)
|
TryExtractZip(New UTF8Encoding(False, True))
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Log(ex, $"首次解压尝试失败,将更换编码并重试({CompressFilePath} → {DestDirectory})")
|
Log(ex, $"首次解压尝试失败,将更换编码并重试({CompressFilePath} → {DestDirectory})")
|
||||||
Try
|
Try
|
||||||
@@ -1896,50 +1884,53 @@ RetryDir:
|
|||||||
''' <param name="Source">被搜索的长内容。</param>
|
''' <param name="Source">被搜索的长内容。</param>
|
||||||
''' <param name="Query">用户输入的搜索文本。</param>
|
''' <param name="Query">用户输入的搜索文本。</param>
|
||||||
Private Function SearchSimilarity(Source As String, Query As String) As Double
|
Private Function SearchSimilarity(Source As String, Query As String) As Double
|
||||||
|
If String.IsNullOrEmpty(Source) OrElse String.IsNullOrEmpty(Query) Then Return 0
|
||||||
Dim qp As Integer = 0, lenSum As Double = 0
|
Dim qp As Integer = 0, lenSum As Double = 0
|
||||||
Source = Source.ToLower.Replace(" ", "")
|
Dim str As New StringBuilder(Source.Length)
|
||||||
Query = Query.ToLower.Replace(" ", "")
|
str.Append(Source.ToLower().Replace(" ", ""))
|
||||||
Dim sourceLength As Integer = Source.Length, queryLength As Integer = Query.Length '用于计算最后因数的长度缓存
|
Query = Query.ToLower().Replace(" ", "")
|
||||||
|
Dim sourceLength As Integer = str.Length, queryLength As Integer = Query.Length '用于计算最后因数的长度缓存
|
||||||
|
If queryLength = 0 Then Return 0
|
||||||
Do While qp < queryLength
|
Do While qp < queryLength
|
||||||
'对 qp 作为开始位置计算
|
'对 qp 作为开始位置计算
|
||||||
Dim sp As Integer = 0, lenMax As Integer = 0, spMax As Integer = 0
|
Dim sp As Integer = 0, lenMax As Integer = 0, spMax As Integer = 0
|
||||||
'查找以 qp 为头的最大子串
|
Dim currentSourceLength As Integer = str.Length
|
||||||
Do While sp < Source.Length
|
Do While sp < currentSourceLength
|
||||||
'对每个 sp 作为开始位置计算最大子串
|
|
||||||
Dim len As Integer = 0
|
Dim len As Integer = 0
|
||||||
Do While (qp + len) < queryLength AndAlso (sp + len) < Source.Length AndAlso Source(sp + len) = Query(qp + len)
|
While (qp + len) < queryLength AndAlso (sp + len) < currentSourceLength AndAlso str(sp + len) = Query(qp + len)
|
||||||
len += 1
|
len += 1
|
||||||
Loop
|
End While
|
||||||
'存储 len
|
'存储 len
|
||||||
If len > lenMax Then
|
If len > lenMax Then
|
||||||
lenMax = len
|
lenMax = len
|
||||||
spMax = sp
|
spMax = sp
|
||||||
End If
|
End If
|
||||||
'根据结果增加 sp
|
'根据结果增加 sp
|
||||||
sp += Math.Max(1, len)
|
sp += If(len > 0, len, 1)
|
||||||
Loop
|
Loop
|
||||||
If lenMax > 0 Then
|
If lenMax > 0 Then
|
||||||
Source = Source.Substring(0, spMax) & If(Source.Count > spMax + lenMax, Source.Substring(spMax + lenMax), String.Empty) '将源中的对应字段替换空
|
str.Remove(spMax, lenMax) '将源中的对应字段移除
|
||||||
'存储 lenSum
|
'存储 lenSum
|
||||||
Dim IncWeight = (Math.Pow(1.4, 3 + lenMax) - 3.6) '根据长度加成
|
Dim IncWeight = (Math.Pow(1.4, 3 + lenMax) - 3.6) '根据长度加成
|
||||||
IncWeight *= 1 + 0.3 * Math.Max(0, 3 - Math.Abs(qp - spMax)) '根据位置加成
|
IncWeight *= 1 + 0.3 * Math.Max(0, 3 - Math.Abs(qp - spMax)) '根据位置加成
|
||||||
lenSum += IncWeight
|
lenSum += IncWeight
|
||||||
End If
|
End If
|
||||||
'根据结果增加 qp
|
qp += If(lenMax > 0, lenMax, 1)
|
||||||
qp += Math.Max(1, lenMax)
|
|
||||||
Loop
|
Loop
|
||||||
'计算结果:重复字段量 × 源长度影响比例
|
'计算结果:重复字段量 × 源长度影响比例
|
||||||
Return (lenSum / queryLength) * (3 / Math.Pow(sourceLength + 15, 0.5)) * If(queryLength <= 2, 3 - queryLength, 1)
|
Return (lenSum / queryLength) * (3 / Math.Sqrt(sourceLength + 15)) * If(queryLength <= 2, 3 - queryLength, 1)
|
||||||
End Function
|
End Function
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 获取多段文本加权后的相似度。
|
''' 获取多段文本加权后的相似度。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Function SearchSimilarityWeighted(Source As List(Of KeyValuePair(Of String, Double)), Query As String) As Double
|
Private Function SearchSimilarityWeighted(Source As List(Of SearchSource), Query As String) As Double
|
||||||
Dim TotalWeight As Double = 0
|
Dim TotalWeight As Double = 0
|
||||||
Dim Sum As Double = 0
|
Dim Sum As Double = 0
|
||||||
For Each Pair In Source
|
For Each Pair In Source
|
||||||
Sum += SearchSimilarity(Pair.Key, Query) * Pair.Value
|
If Pair.Aliases.Any Then
|
||||||
TotalWeight += Pair.Value
|
Sum += Pair.Aliases.Max(Function(a) SearchSimilarity(a, Query)) * Pair.Weight
|
||||||
|
End If
|
||||||
|
TotalWeight += Pair.Weight
|
||||||
Next
|
Next
|
||||||
Return Sum / TotalWeight
|
Return Sum / TotalWeight
|
||||||
End Function
|
End Function
|
||||||
@@ -1952,9 +1943,10 @@ RetryDir:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public Item As T
|
Public Item As T
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 该项目用于搜索的源。
|
''' 该项目用于搜索的文本源。
|
||||||
|
''' 在搜索时,会对每个文本源单独加权,但单个文本源内的多个别名只取最高的一个的相似度。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public SearchSource As List(Of KeyValuePair(Of String, Double))
|
Public SearchSource As List(Of SearchSource)
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 相似度。
|
''' 相似度。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
@@ -1963,9 +1955,28 @@ RetryDir:
|
|||||||
''' 是否完全匹配。
|
''' 是否完全匹配。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public AbsoluteRight As Boolean
|
Public AbsoluteRight As Boolean
|
||||||
|
Public Overrides Function ToString() As String
|
||||||
|
Return Math.Round(Similarity, 3) & " - " & Item.ToString()
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
''' <summary>
|
||||||
|
''' 单个用于搜索的文本源。
|
||||||
|
''' </summary>
|
||||||
|
Public Class SearchSource
|
||||||
|
Public Aliases As String()
|
||||||
|
Public Weight As Double
|
||||||
|
Public Sub New(Aliases As String(), Optional Weight As Double = 1)
|
||||||
|
Me.Aliases = Aliases
|
||||||
|
Me.Weight = Weight
|
||||||
|
End Sub
|
||||||
|
Public Sub New(Text As String, Optional Weight As Double = 1)
|
||||||
|
Me.Aliases = {Text}
|
||||||
|
Me.Weight = Weight
|
||||||
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 进行多段文本加权搜索,获取相似度较高的数项结果。
|
''' 进行多段文本加权搜索,获取相似度较高的数项结果。
|
||||||
|
''' 在搜索时,会对每个文本源单独加权,但单个文本源内的多个别名只取最高的一个的相似度。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
''' <param name="MaxBlurCount">返回的最大模糊结果数。</param>
|
''' <param name="MaxBlurCount">返回的最大模糊结果数。</param>
|
||||||
''' <param name="MinBlurSimilarity">返回结果要求的最低相似度。</param>
|
''' <param name="MinBlurSimilarity">返回结果要求的最低相似度。</param>
|
||||||
@@ -1974,15 +1985,19 @@ RetryDir:
|
|||||||
Dim ResultList As New List(Of SearchEntry(Of T))
|
Dim ResultList As New List(Of SearchEntry(Of T))
|
||||||
If Not Entries.Any() Then Return ResultList
|
If Not Entries.Any() Then Return ResultList
|
||||||
'进行搜索,获取相似信息
|
'进行搜索,获取相似信息
|
||||||
|
Dim QueryParts = Query.Split({" "c}, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
Dim Candidates As New List(Of SearchEntry(Of T))
|
||||||
For Each Entry In Entries
|
For Each Entry In Entries
|
||||||
Entry.Similarity = SearchSimilarityWeighted(Entry.SearchSource, Query)
|
Entry.Similarity = SearchSimilarityWeighted(Entry.SearchSource, Query)
|
||||||
Entry.AbsoluteRight =
|
Entry.AbsoluteRight =
|
||||||
Query.Split(" ").All( '对于按空格分割的每一段
|
QueryParts.All( '对于按空格分割的每一段
|
||||||
Function(QueryPart) Entry.SearchSource.Any( '若与任意一个搜索源完全匹配,则标记为完全匹配项
|
Function(QueryPart) Entry.SearchSource.Any( '若与任意一个搜索源完全匹配,则标记为完全匹配项
|
||||||
Function(Source) Source.Key.Replace(" ", "").ContainsF(QueryPart, True)))
|
Function(Source) Source.Aliases.Any(
|
||||||
|
Function([Alias]) [Alias].Replace(" ", "").ContainsF(QueryPart, True))))
|
||||||
|
If Entry.AbsoluteRight OrElse Entry.Similarity >= MinBlurSimilarity Then Candidates.Add(Entry)
|
||||||
Next
|
Next
|
||||||
'按照相似度进行排序
|
'按照相似度进行排序
|
||||||
Entries = Entries.SortByComparison(
|
Candidates = Candidates.SortByComparison(
|
||||||
Function(Left, Right) As Boolean
|
Function(Left, Right) As Boolean
|
||||||
If Left.AbsoluteRight Xor Right.AbsoluteRight Then
|
If Left.AbsoluteRight Xor Right.AbsoluteRight Then
|
||||||
Return Left.AbsoluteRight
|
Return Left.AbsoluteRight
|
||||||
@@ -1992,11 +2007,11 @@ RetryDir:
|
|||||||
End Function)
|
End Function)
|
||||||
'返回结果
|
'返回结果
|
||||||
Dim BlurCount As Integer = 0
|
Dim BlurCount As Integer = 0
|
||||||
For Each Entry In Entries
|
For Each Entry In Candidates
|
||||||
If Entry.AbsoluteRight Then
|
If Entry.AbsoluteRight Then
|
||||||
ResultList.Add(Entry) '完全匹配,直接加入
|
ResultList.Add(Entry) '完全匹配,直接加入
|
||||||
Else
|
Else
|
||||||
If Entry.Similarity < MinBlurSimilarity OrElse BlurCount = MaxBlurCount Then Exit For '模糊结果边界条件
|
If BlurCount = MaxBlurCount Then Exit For
|
||||||
ResultList.Add(Entry)
|
ResultList.Add(Entry)
|
||||||
BlurCount += 1 '模糊结果计数
|
BlurCount += 1 '模糊结果计数
|
||||||
End If
|
End If
|
||||||
@@ -2175,7 +2190,7 @@ RetryDir:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
<Extension> Public Function GetResultWithTimeout(Of T)(TargetTask As Task(Of T), TokenSource As CancellationTokenSource, TimeoutMs As Integer) As T
|
<Extension> Public Function GetResultWithTimeout(Of T)(TargetTask As Task(Of T), TokenSource As CancellationTokenSource, TimeoutMs As Integer) As T
|
||||||
Dim DelayTask = Task.Delay(TimeoutMs)
|
Dim DelayTask = Task.Delay(TimeoutMs)
|
||||||
If Task.WhenAny(TargetTask, DelayTask).GetAwaiter().GetResult() Is DelayTask Then
|
If Task.WhenAny(TargetTask, DelayTask).ConfigureAwait(False).GetAwaiter().GetResult() Is DelayTask Then
|
||||||
TokenSource.Cancel()
|
TokenSource.Cancel()
|
||||||
Throw New TimeoutException($"任务超时({TimeoutMs} ms)")
|
Throw New TimeoutException($"任务超时({TimeoutMs} ms)")
|
||||||
End If
|
End If
|
||||||
@@ -2186,7 +2201,7 @@ RetryDir:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
<Extension> Public Sub GetResultWithTimeout(TargetTask As Task, TokenSource As CancellationTokenSource, TimeoutMs As Integer)
|
<Extension> Public Sub GetResultWithTimeout(TargetTask As Task, TokenSource As CancellationTokenSource, TimeoutMs As Integer)
|
||||||
Dim DelayTask = Task.Delay(TimeoutMs)
|
Dim DelayTask = Task.Delay(TimeoutMs)
|
||||||
If Task.WhenAny(TargetTask, DelayTask).GetAwaiter().GetResult() Is DelayTask Then
|
If Task.WhenAny(TargetTask, DelayTask).ConfigureAwait(False).GetAwaiter().GetResult() Is DelayTask Then
|
||||||
TokenSource.Cancel()
|
TokenSource.Cancel()
|
||||||
Throw New TimeoutException($"任务超时({TimeoutMs} ms)")
|
Throw New TimeoutException($"任务超时({TimeoutMs} ms)")
|
||||||
End If
|
End If
|
||||||
@@ -2537,7 +2552,7 @@ NextElement:
|
|||||||
''' 选择最大值对应的对象。
|
''' 选择最大值对应的对象。
|
||||||
''' 若没有元素则返回 Nothing。
|
''' 若没有元素则返回 Nothing。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
<Extension> Public Function MaxOf(Of T, C As IComparable(Of C))(Source As IEnumerable(Of T), Selector As Func(Of T, C)) As T
|
<Extension> Public Function MaxBy(Of T, C As IComparable(Of C))(Source As IEnumerable(Of T), Selector As Func(Of T, C)) As T
|
||||||
Using Enumerator = Source.GetEnumerator()
|
Using Enumerator = Source.GetEnumerator()
|
||||||
If Not Enumerator.MoveNext() Then Return Nothing
|
If Not Enumerator.MoveNext() Then Return Nothing
|
||||||
Dim MaxItem As T = Enumerator.Current
|
Dim MaxItem As T = Enumerator.Current
|
||||||
@@ -2555,7 +2570,7 @@ NextElement:
|
|||||||
''' 选择最小值对应的对象。
|
''' 选择最小值对应的对象。
|
||||||
''' 若没有元素则返回 Nothing。
|
''' 若没有元素则返回 Nothing。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
<Extension> Public Function MinOf(Of T, C As IComparable(Of C))(List As IEnumerable(Of T), Selector As Func(Of T, C)) As T
|
<Extension> Public Function MinBy(Of T, C As IComparable(Of C))(List As IEnumerable(Of T), Selector As Func(Of T, C)) As T
|
||||||
Using Enumerator = List.GetEnumerator()
|
Using Enumerator = List.GetEnumerator()
|
||||||
If Not Enumerator.MoveNext() Then Return Nothing
|
If Not Enumerator.MoveNext() Then Return Nothing
|
||||||
Dim MinItem As T = Enumerator.Current
|
Dim MinItem As T = Enumerator.Current
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
Imports System.Net.Http.Headers
|
Imports System.Net.Sockets
|
||||||
Imports System.Net.Sockets
|
|
||||||
Imports System.Runtime.CompilerServices
|
Imports System.Runtime.CompilerServices
|
||||||
Imports System.Threading.Tasks
|
Imports System.Threading.Tasks
|
||||||
|
|
||||||
@@ -248,7 +247,7 @@ RequestFinished:
|
|||||||
SecretHeadersSign(Url, Request, SimulateBrowserHeaders)
|
SecretHeadersSign(Url, Request, SimulateBrowserHeaders)
|
||||||
'DNS 解析
|
'DNS 解析
|
||||||
CancelToken = New CancellationTokenSource(Timeout)
|
CancelToken = New CancellationTokenSource(Timeout)
|
||||||
HostIp = DNSLookup(Request, CancelToken)
|
HostIp = DNSLookup(Request, CancelToken.Token)
|
||||||
If HostIp IsNot Nothing AndAlso Not IPReliability.ContainsKey(HostIp) Then
|
If HostIp IsNot Nothing AndAlso Not IPReliability.ContainsKey(HostIp) Then
|
||||||
IPReliability(HostIp) = -0.01 '预先降低一点,这样快速的重复请求会使用不同的 IP 以提高成功率
|
IPReliability(HostIp) = -0.01 '预先降低一点,这样快速的重复请求会使用不同的 IP 以提高成功率
|
||||||
End If
|
End If
|
||||||
@@ -263,12 +262,13 @@ RequestFinished:
|
|||||||
End If
|
End If
|
||||||
End SyncLock
|
End SyncLock
|
||||||
Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
|
Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
|
||||||
Dim ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
|
|
||||||
Dim ResponseBytes As Byte()
|
Dim ResponseBytes As Byte()
|
||||||
|
Using ResponseStream = Response.Content.ReadAsStreamAsync().GetResultWithTimeout(CancelToken, Timeout)
|
||||||
Using Stream As New MemoryStream
|
Using Stream As New MemoryStream
|
||||||
ResponseStream.CopyToAsync(Stream, 81920, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
|
ResponseStream.CopyToAsync(Stream, 81920, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
|
||||||
ResponseBytes = Stream.ToArray()
|
ResponseBytes = Stream.ToArray()
|
||||||
End Using
|
End Using
|
||||||
|
End Using
|
||||||
'输出
|
'输出
|
||||||
If Response.IsSuccessStatusCode Then
|
If Response.IsSuccessStatusCode Then
|
||||||
RecordIPReliability(HostIp, 0.5)
|
RecordIPReliability(HostIp, 0.5)
|
||||||
@@ -304,10 +304,9 @@ RequestFinished:
|
|||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 进行 DNS 解析。它仅在选择的 IP 与系统默认的不一致时才对 URL 中的 Host 进行替换。
|
''' 进行 DNS 解析。它仅在选择的 IP 与系统默认的不一致时才对 URL 中的 Host 进行替换。
|
||||||
''' 返回请求时应使用的 IP;若为 IPv6,则加上了方括号。
|
''' 返回请求时应使用的 IP。若解析失败,则返回 Nothing。
|
||||||
''' 若解析失败,则返回 Nothing。
|
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Function DNSLookup(Request As HttpRequestMessage, CancelToken As CancellationTokenSource) As String
|
Private Function DNSLookup(Request As HttpRequestMessage, CancelToken As CancellationToken) As String
|
||||||
'若一分钟内已失败过,则不再重复尝试解析,以减少断网时的 Exception 数量
|
'若一分钟内已失败过,则不再重复尝试解析,以减少断网时的 Exception 数量
|
||||||
Dim Host = Request.RequestUri.Host
|
Dim Host = Request.RequestUri.Host
|
||||||
SyncLock DNSFailureRecord.SyncRoot
|
SyncLock DNSFailureRecord.SyncRoot
|
||||||
@@ -320,43 +319,36 @@ RequestFinished:
|
|||||||
End If
|
End If
|
||||||
End SyncLock
|
End SyncLock
|
||||||
'初步 DNS 解析
|
'初步 DNS 解析
|
||||||
Dim DnsTask As Task(Of IPAddress()) = Nothing
|
Dim Candidates As IPAddress()
|
||||||
Try
|
Try
|
||||||
DnsTask = Dns.GetHostAddressesAsync(Host)
|
Dim AsyncResult = Dns.BeginGetHostAddresses(Host, Nothing, Nothing)
|
||||||
DnsTask.Wait(CancelToken.Token)
|
If WaitHandle.WaitAny(New WaitHandle() {AsyncResult.AsyncWaitHandle, CancelToken.WaitHandle}) Then Throw New TimeoutException("DNS 解析超时")
|
||||||
|
Candidates = Dns.EndGetHostAddresses(AsyncResult).Distinct.ToArray
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Log(ex, $"DNS 解析失败({Host})")
|
Log(ex, $"DNS 解析失败({Host})")
|
||||||
DNSFailureRecord(Host) = Date.Now
|
DNSFailureRecord(Host) = Date.Now
|
||||||
Return Nothing
|
Return Nothing
|
||||||
End Try
|
End Try
|
||||||
Dim Candidates As IPAddress() = DnsTask.Result.ToArray
|
|
||||||
If Not Candidates.Any Then
|
If Not Candidates.Any Then
|
||||||
Log($"[Net] DNS 解析无结果({Host})")
|
Log($"[Net] DNS 解析无结果({Host})")
|
||||||
Return Nothing
|
Return Nothing
|
||||||
End If
|
End If
|
||||||
'若同时存在 IPv4 和 IPv6 地址,仅选择其中一类(因为 GFW 可能只屏蔽了 IPv4 或 IPv6)
|
'若同时存在 IPv4 和 IPv6 地址,仅选择其中一类(因为 GFW 可能只屏蔽了 IPv4 或 IPv6)
|
||||||
Dim GetIPReliability = Function(Key) IPReliability.GetOrDefault(Key.ToString, 0)
|
Dim Reliabilities = Candidates.ToDictionary(Function(i) i, Function(i) IPReliability.GetOrDefault(i.ToString, 0))
|
||||||
Dim IPv4Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetwork).ToArray
|
Dim IPv4Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetwork).ToArray
|
||||||
Dim IPv6Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetworkV6).ToArray
|
Dim IPv6Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetworkV6).ToArray
|
||||||
If IPv4Targets.Any AndAlso IPv6Targets.Any Then
|
If IPv4Targets.Any AndAlso IPv6Targets.Any Then
|
||||||
Dim IPv4Reliability = IPv4Targets.Average(Function(i) GetIPReliability(i))
|
Dim IPv4Reliability = IPv4Targets.Max(Function(i) Reliabilities(i))
|
||||||
Dim IPv6Reliability = IPv6Targets.Average(Function(i) GetIPReliability(i))
|
Dim IPv6Reliability = IPv6Targets.Max(Function(i) Reliabilities(i))
|
||||||
If Host = "api.modrinth.com" Then IPv6Reliability -= 0.1 '让 Modrinth 优先使用 IPv4 地址(#6887)
|
If Host = "api.modrinth.com" Then IPv6Reliability -= 0.1 '让 Modrinth 优先使用 IPv4 地址(#6887)
|
||||||
|
If ModeDebug Then Log($"[Net] DNS IPv4/IPv6 选择({Host}),IPv4 {IPv4Reliability:0.000},IPv6 {IPv6Reliability:0.000}")
|
||||||
Candidates = If(IPv4Reliability >= IPv6Reliability, IPv4Targets, IPv6Targets)
|
Candidates = If(IPv4Reliability >= IPv6Reliability, IPv4Targets, IPv6Targets)
|
||||||
End If
|
End If
|
||||||
'选择可靠度最高的 IP
|
'选择可靠度最高的 IP
|
||||||
Dim MaxReliability As Double = Candidates.Max(Function(i) GetIPReliability(i))
|
Dim Target As IPAddress = Candidates.MaxBy(Function(i) Reliabilities(i))
|
||||||
Dim Target As IPAddress = Candidates.First(Function(i) GetIPReliability(i) = MaxReliability)
|
Request.Headers.Host = Request.RequestUri.Authority
|
||||||
Dim TargetIp As String = If(Target.AddressFamily = AddressFamily.InterNetworkV6, $"[{Target}]", Target.ToString)
|
Request.RequestUri = (New UriBuilder(Request.RequestUri) With {.Host = If(Target.AddressFamily = AddressFamily.InterNetworkV6, $"[{Target}]", Target.ToString)}).Uri
|
||||||
If Target IsNot Candidates.First Then
|
Return Target.ToString
|
||||||
'优选结果与系统默认 IP 不一致,替换域名并设置 Host 头
|
|
||||||
If ModeDebug Then Log($"[Net] DNS 解析结果:{Host} → {Target},所有可能的 IP 与可靠度:{DnsTask.Result.Select(Function(i) $"{i} → {GetIPReliability(i):0.000}").Join(";")}")
|
|
||||||
Request.Headers.Host = Host
|
|
||||||
Dim Builder As New UriBuilder(Request.RequestUri)
|
|
||||||
Builder.Host = TargetIp
|
|
||||||
Request.RequestUri = Builder.Uri
|
|
||||||
End If
|
|
||||||
Return TargetIp
|
|
||||||
End Function
|
End Function
|
||||||
Private DNSFailureRecord As New SafeDictionary(Of String, Date)
|
Private DNSFailureRecord As New SafeDictionary(Of String, Date)
|
||||||
''' <summary>
|
''' <summary>
|
||||||
@@ -369,8 +361,10 @@ RequestFinished:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Private Sub RecordIPReliability(IP As String, Result As Double)
|
Private Sub RecordIPReliability(IP As String, Result As Double)
|
||||||
If IP Is Nothing Then Return
|
If IP Is Nothing Then Return
|
||||||
|
SyncLock IPReliability.SyncRoot
|
||||||
If Not IPReliability.ContainsKey(IP) Then IPReliability(IP) = 0
|
If Not IPReliability.ContainsKey(IP) Then IPReliability(IP) = 0
|
||||||
IPReliability(IP) = (IPReliability(IP) + Result) / 2
|
IPReliability(IP) = (IPReliability(IP) + Result) / 2
|
||||||
|
End SyncLock
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
@@ -418,12 +412,10 @@ RequestFinished:
|
|||||||
''' 基于限速,当前可以下载的剩余量。
|
''' 基于限速,当前可以下载的剩余量。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public NetTaskSpeedLimitLeft As Long = -1
|
Public NetTaskSpeedLimitLeft As Long = -1
|
||||||
Private ReadOnly NetTaskSpeedLimitLeftLock As New Object
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 正在运行中的线程数。
|
''' 正在运行中的线程数。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public NetTaskThreadCount As Integer = 0
|
Public NetTaskThreadCount As Integer = 0
|
||||||
Private ReadOnly NetTaskThreadCountLock As New Object
|
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 下载源。
|
''' 下载源。
|
||||||
@@ -760,7 +752,6 @@ RequestFinished:
|
|||||||
''' 文件的已下载大小。
|
''' 文件的已下载大小。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public DownloadDone As Long = 0
|
Public DownloadDone As Long = 0
|
||||||
Private ReadOnly LockDone As New Object
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 文件的校验规则。
|
''' 文件的校验规则。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
@@ -840,14 +831,12 @@ RequestFinished:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Private ReadOnly Property ConnectAverage As Integer
|
Private ReadOnly Property ConnectAverage As Integer
|
||||||
Get
|
Get
|
||||||
SyncLock LockCount
|
Dim CurrentConnectCount As Integer = ConnectCount '防止竞态条件
|
||||||
Return If(ConnectCount = 0, -1, ConnectTime / ConnectCount)
|
Return If(CurrentConnectCount = 0, -1, ConnectTime / CurrentConnectCount)
|
||||||
End SyncLock
|
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
|
|
||||||
Private Const FilePieceLimit As Long = 256 * 1024
|
Private Const FilePieceLimit As Long = 256 * 1024
|
||||||
Public ReadOnly LockCount As New Object
|
|
||||||
Public ReadOnly LockState As New Object
|
Public ReadOnly LockState As New Object
|
||||||
Public ReadOnly LockChain As New Object
|
Public ReadOnly LockChain As New Object
|
||||||
Public ReadOnly LockSource As New Object
|
Public ReadOnly LockSource As New Object
|
||||||
@@ -929,7 +918,7 @@ StartSingleThreadDownload:
|
|||||||
If Source Is Nothing Then Return Nothing
|
If Source Is Nothing Then Return Nothing
|
||||||
Dim TargetUrl As String = Source.Url
|
Dim TargetUrl As String = Source.Url
|
||||||
If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("bmclapi") OrElse TargetUrl.Contains("github.com") OrElse
|
If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("bmclapi") OrElse TargetUrl.Contains("github.com") OrElse
|
||||||
TargetUrl.Contains("optifine.net") OrElse TargetUrl.Contains("modrinth") OrElse TargetUrl.Contains("momot.rs") Then Return Nothing
|
TargetUrl.Contains("optifine.net") OrElse TargetUrl.Contains("momot.rs") Then Return Nothing
|
||||||
'寻找最大碎片
|
'寻找最大碎片
|
||||||
'FUTURE: 下载引擎重做,计算下载源平均链接时间和线程下载速度,按最高时间节省来开启多线程
|
'FUTURE: 下载引擎重做,计算下载源平均链接时间和线程下载速度,按最高时间节省来开启多线程
|
||||||
Dim FilePieceMax As NetThread = Threads
|
Dim FilePieceMax As NetThread = Threads
|
||||||
@@ -962,9 +951,7 @@ StartThread:
|
|||||||
|
|
||||||
End SyncLock
|
End SyncLock
|
||||||
'开始线程
|
'开始线程
|
||||||
SyncLock NetTaskThreadCountLock
|
Interlocked.Increment(NetTaskThreadCount)
|
||||||
NetTaskThreadCount += 1
|
|
||||||
End SyncLock
|
|
||||||
SyncLock LockSource
|
SyncLock LockSource
|
||||||
If Not HasAvailableSource(False) Then SourcesOnce.First.SingleThread = ThreadInfo
|
If Not HasAvailableSource(False) Then SourcesOnce.First.SingleThread = ThreadInfo
|
||||||
End SyncLock
|
End SyncLock
|
||||||
@@ -986,7 +973,7 @@ StartThread:
|
|||||||
CancelToken As CancellationTokenSource = Nothing, HostIp As String = Nothing
|
CancelToken As CancellationTokenSource = Nothing, HostIp As String = Nothing
|
||||||
'部分下载源真的特别慢,并且只需要一个请求,例如 Ping 为 20s,如果增长太慢,就会造成类似 2.5s 5s 7.5s 10s 12.5s... 的极大延迟
|
'部分下载源真的特别慢,并且只需要一个请求,例如 Ping 为 20s,如果增长太慢,就会造成类似 2.5s 5s 7.5s 10s 12.5s... 的极大延迟
|
||||||
'延迟过长会导致某些特别慢的链接迟迟不被掐死
|
'延迟过长会导致某些特别慢的链接迟迟不被掐死
|
||||||
Dim Timeout As Integer = Math.Min(Math.Max(ConnectAverage, 10000) * (1 + Th.Source.FailCount), 30000)
|
Dim Timeout As Integer = Math.Min(Math.Max(ConnectAverage, 15000) * (1 + Th.Source.FailCount), 30000)
|
||||||
Th.State = NetState.Connecting
|
Th.State = NetState.Connecting
|
||||||
Try
|
Try
|
||||||
Dim HttpDataCount As Integer = 0
|
Dim HttpDataCount As Integer = 0
|
||||||
@@ -994,8 +981,8 @@ StartThread:
|
|||||||
HttpRequest = New HttpRequestMessage(HttpMethod.Get, Th.Source.Url)
|
HttpRequest = New HttpRequestMessage(HttpMethod.Get, Th.Source.Url)
|
||||||
SecretHeadersSign(Th.Source.Url, HttpRequest, SimulateBrowserHeaders)
|
SecretHeadersSign(Th.Source.Url, HttpRequest, SimulateBrowserHeaders)
|
||||||
CancelToken = New CancellationTokenSource(Timeout)
|
CancelToken = New CancellationTokenSource(Timeout)
|
||||||
HostIp = DNSLookup(HttpRequest, CancelToken) 'DNS 预解析
|
HostIp = DNSLookup(HttpRequest, CancelToken.Token) 'DNS 预解析
|
||||||
If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New RangeHeaderValue(Th.DownloadStart, Nothing)
|
If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New Headers.RangeHeaderValue(Th.DownloadStart, Nothing)
|
||||||
Dim ContentLength As Long = 0
|
Dim ContentLength As Long = 0
|
||||||
Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
|
Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
|
||||||
If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查
|
If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查
|
||||||
@@ -1032,7 +1019,7 @@ StartThread:
|
|||||||
Dim DriveName As String = Drive.Name.First.ToString
|
Dim DriveName As String = Drive.Name.First.ToString
|
||||||
Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ContentLength * 1.1, 0) +
|
Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ContentLength * 1.1, 0) +
|
||||||
If(LocalPath.StartsWithF(DriveName), ContentLength + 5 * 1024 * 1024, 0)
|
If(LocalPath.StartsWithF(DriveName), ContentLength + 5 * 1024 * 1024, 0)
|
||||||
If Drive.TotalFreeSpace < RequiredSpace Then
|
If RequiredSpace > 0 AndAlso Drive.TotalFreeSpace < RequiredSpace Then
|
||||||
Throw New Exception(DriveName & " 盘空间不足,无法进行下载。" & vbCrLf & "需要至少 " & GetString(RequiredSpace) & " 空间,但当前仅剩余 " & GetString(Drive.TotalFreeSpace) & "。" &
|
Throw New Exception(DriveName & " 盘空间不足,无法进行下载。" & vbCrLf & "需要至少 " & GetString(RequiredSpace) & " 空间,但当前仅剩余 " & GetString(Drive.TotalFreeSpace) & "。" &
|
||||||
If(PathTemp.StartsWithF(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", ""))
|
If(PathTemp.StartsWithF(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", ""))
|
||||||
End If
|
End If
|
||||||
@@ -1040,7 +1027,7 @@ StartThread:
|
|||||||
End If
|
End If
|
||||||
ElseIf FileSize < 0 Then
|
ElseIf FileSize < 0 Then
|
||||||
Throw New Exception("非首线程运行时,尚未获取文件大小")
|
Throw New Exception("非首线程运行时,尚未获取文件大小")
|
||||||
ElseIf Th.DownloadStart > 0 AndAlso ContentLength = FileSize Then
|
ElseIf Th.DownloadStart > 0 AndAlso ContentLength >= FileSize Then
|
||||||
NotSupportRange:
|
NotSupportRange:
|
||||||
SyncLock LockSource
|
SyncLock LockSource
|
||||||
If SourcesOnce.Contains(Th.Source) Then GoTo SourceBreak
|
If SourcesOnce.Contains(Th.Source) Then GoTo SourceBreak
|
||||||
@@ -1076,11 +1063,9 @@ NotSupportRange:
|
|||||||
Threading.Thread.Sleep(16)
|
Threading.Thread.Sleep(16)
|
||||||
End While
|
End While
|
||||||
Dim RealDataCount As Integer = If(IsUnknownSize, HttpDataCount, Math.Min(HttpDataCount, Th.DownloadUndone))
|
Dim RealDataCount As Integer = If(IsUnknownSize, HttpDataCount, Math.Min(HttpDataCount, Th.DownloadUndone))
|
||||||
SyncLock NetTaskSpeedLimitLeftLock
|
If NetTaskSpeedLimitHigh > 0 Then Interlocked.Add(NetTaskSpeedLimitLeft, -RealDataCount)
|
||||||
If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft -= RealDataCount
|
|
||||||
End SyncLock
|
|
||||||
Dim DeltaTime = GetTimeMs() - Th.LastReceiveTime
|
Dim DeltaTime = GetTimeMs() - Th.LastReceiveTime
|
||||||
If DeltaTime > 1000000 Then DeltaTime = 1 '避免时间刻反转导致出现极大值
|
If DeltaTime > 100000000 Then DeltaTime = 1 '避免时间刻反转导致出现极大值
|
||||||
If RealDataCount > 0 Then
|
If RealDataCount > 0 Then
|
||||||
'有数据
|
'有数据
|
||||||
If Th.DownloadDone = 0 Then
|
If Th.DownloadDone = 0 Then
|
||||||
@@ -1089,27 +1074,21 @@ NotSupportRange:
|
|||||||
SyncLock LockState
|
SyncLock LockState
|
||||||
If State < NetState.Downloading Then State = NetState.Downloading
|
If State < NetState.Downloading Then State = NetState.Downloading
|
||||||
End SyncLock
|
End SyncLock
|
||||||
SyncLock LockCount
|
Interlocked.Increment(ConnectCount)
|
||||||
ConnectCount += 1
|
Interlocked.Add(ConnectTime, GetTimeMs() - Th.InitTime)
|
||||||
ConnectTime += GetTimeMs() - Th.InitTime
|
|
||||||
End SyncLock
|
|
||||||
End If
|
End If
|
||||||
SyncLock LockCount
|
|
||||||
Th.Source.FailCount = 0
|
Th.Source.FailCount = 0
|
||||||
For Each Task In Tasks
|
For Each Task In Tasks
|
||||||
Task.FailCount = 0
|
Task.FailCount = 0
|
||||||
Next
|
Next
|
||||||
End SyncLock
|
Interlocked.Add(NetManager.DownloadDone, RealDataCount)
|
||||||
NetManager.DownloadDone += RealDataCount
|
Interlocked.Add(DownloadDone, RealDataCount)
|
||||||
SyncLock LockDone
|
|
||||||
DownloadDone += RealDataCount
|
|
||||||
End SyncLock
|
|
||||||
Th.DownloadDone += RealDataCount
|
Th.DownloadDone += RealDataCount
|
||||||
ResultStream.Write(ResponseBytes, 0, RealDataCount)
|
ResultStream.Write(ResponseBytes, 0, RealDataCount)
|
||||||
'已完成
|
'已完成
|
||||||
If Th.DownloadUndone = 0 AndAlso Not IsUnknownSize Then Exit While
|
If Th.DownloadUndone = 0 AndAlso Not IsUnknownSize Then Exit While
|
||||||
'检查速度是否过慢
|
'检查速度是否过慢
|
||||||
If DeltaTime > 5000 AndAlso DeltaTime > RealDataCount AndAlso '数据包间隔大于 5s,且速度小于 1K/s
|
If Th.LastReceiveTime > 0 AndAlso DeltaTime > 5000 AndAlso DeltaTime > RealDataCount AndAlso '数据包间隔大于 5s,且速度小于 1K/s
|
||||||
Th.Source.SingleThread Is Nothing Then '且并非单线程下载
|
Th.Source.SingleThread Is Nothing Then '且并非单线程下载
|
||||||
Throw New TimeoutException("由于速度过慢断开链接,下载 " & RealDataCount & " B,消耗 " & DeltaTime & " ms。")
|
Throw New TimeoutException("由于速度过慢断开链接,下载 " & RealDataCount & " B,消耗 " & DeltaTime & " ms。")
|
||||||
End If
|
End If
|
||||||
@@ -1147,9 +1126,7 @@ SourceBreak:
|
|||||||
CancelToken?.Dispose()
|
CancelToken?.Dispose()
|
||||||
If Not IsNoSplit Then ResultStream?.Dispose()
|
If Not IsNoSplit Then ResultStream?.Dispose()
|
||||||
'改变计数
|
'改变计数
|
||||||
SyncLock NetTaskThreadCountLock
|
Interlocked.Decrement(NetTaskThreadCount)
|
||||||
NetTaskThreadCount -= 1
|
|
||||||
End SyncLock
|
|
||||||
'合并
|
'合并
|
||||||
If ((FileSize >= 0 AndAlso DownloadDone >= FileSize) OrElse (FileSize = -1 AndAlso DownloadDone > 0)) AndAlso
|
If ((FileSize >= 0 AndAlso DownloadDone >= FileSize) OrElse (FileSize = -1 AndAlso DownloadDone > 0)) AndAlso
|
||||||
State < NetState.Merging AndAlso Th.State <> NetState.Interrupted Then Merge(Th)
|
State < NetState.Merging AndAlso Th.State <> NetState.Interrupted Then Merge(Th)
|
||||||
@@ -1157,12 +1134,10 @@ SourceBreak:
|
|||||||
End Sub
|
End Sub
|
||||||
Private Sub SourceFail(Th As NetThread, ex As Exception, IsMergeFailure As Boolean)
|
Private Sub SourceFail(Th As NetThread, ex As Exception, IsMergeFailure As Boolean)
|
||||||
'状态变更
|
'状态变更
|
||||||
SyncLock LockCount
|
Interlocked.Increment(Th.Source.FailCount)
|
||||||
Th.Source.FailCount += 1
|
|
||||||
For Each Task In Tasks
|
For Each Task In Tasks
|
||||||
Task.FailCount += 1
|
Interlocked.Increment(Task.FailCount)
|
||||||
Next
|
Next
|
||||||
End SyncLock
|
|
||||||
Th.State = NetState.Interrupted
|
Th.State = NetState.Interrupted
|
||||||
Th.Source.Ex = ex
|
Th.Source.Ex = ex
|
||||||
'根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传)
|
'根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传)
|
||||||
@@ -1241,10 +1216,8 @@ SourceBreak:
|
|||||||
SyncLock LockChain
|
SyncLock LockChain
|
||||||
Threads = Nothing
|
Threads = Nothing
|
||||||
End SyncLock
|
End SyncLock
|
||||||
NetManager.DownloadDone -= DownloadDone
|
Interlocked.Add(NetManager.DownloadDone, -DownloadDone)
|
||||||
SyncLock LockDone
|
|
||||||
DownloadDone = 0
|
DownloadDone = 0
|
||||||
End SyncLock
|
|
||||||
SpeedLastDone = 0
|
SpeedLastDone = 0
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
@@ -1271,7 +1244,7 @@ Retry:
|
|||||||
SyncLock LockChain
|
SyncLock LockChain
|
||||||
'合并文件
|
'合并文件
|
||||||
If IsNoSplit Then
|
If IsNoSplit Then
|
||||||
'仅有一个线程,从缓存中输出
|
'仅有一个线程,从内存中输出
|
||||||
If ModeDebug Then Log($"[Download] {LocalName}:下载结束,从内存输出文件")
|
If ModeDebug Then Log($"[Download] {LocalName}:下载结束,从内存输出文件")
|
||||||
Cache.Position = 0
|
Cache.Position = 0
|
||||||
WriteFile(LocalPath, Cache)
|
WriteFile(LocalPath, Cache)
|
||||||
@@ -1321,6 +1294,7 @@ Retry:
|
|||||||
End SyncLock
|
End SyncLock
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
RetryCount += 1
|
RetryCount += 1
|
||||||
|
If State > NetState.Merging Then Return '通常是因为在合并时被中断了
|
||||||
Log(ex, $"合并文件出错,第 {RetryCount} 次尝试({LocalName})")
|
Log(ex, $"合并文件出错,第 {RetryCount} 次尝试({LocalName})")
|
||||||
'重新尝试合并
|
'重新尝试合并
|
||||||
If RetryCount < 3 Then
|
If RetryCount < 3 Then
|
||||||
@@ -1372,9 +1346,7 @@ Retry:
|
|||||||
Private Sub AbortInternal()
|
Private Sub AbortInternal()
|
||||||
On Error Resume Next
|
On Error Resume Next
|
||||||
Reset()
|
Reset()
|
||||||
SyncLock NetManager.LockRemain
|
Interlocked.Decrement(NetManager.FileRemain)
|
||||||
NetManager.FileRemain -= 1
|
|
||||||
End SyncLock
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'状态改变接口
|
'状态改变接口
|
||||||
@@ -1386,9 +1358,7 @@ Retry:
|
|||||||
If State >= NetState.Finished Then Return
|
If State >= NetState.Finished Then Return
|
||||||
State = NetState.Finished
|
State = NetState.Finished
|
||||||
End SyncLock
|
End SyncLock
|
||||||
SyncLock NetManager.LockRemain
|
Interlocked.Decrement(NetManager.FileRemain)
|
||||||
NetManager.FileRemain -= 1
|
|
||||||
End SyncLock
|
|
||||||
If PrintLog Then Log($"[Download] {LocalName}:已完成")
|
If PrintLog Then Log($"[Download] {LocalName}:已完成")
|
||||||
For Each Task In Tasks
|
For Each Task In Tasks
|
||||||
Task.OnFileFinish(Me)
|
Task.OnFileFinish(Me)
|
||||||
@@ -1522,8 +1492,8 @@ FinishExCatch:
|
|||||||
If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径:" & File.LocalPath)
|
If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径:" & File.LocalPath)
|
||||||
Directory.CreateDirectory(GetPathFromFullPath(File.LocalPath)) '创建目标文件夹
|
Directory.CreateDirectory(GetPathFromFullPath(File.LocalPath)) '创建目标文件夹
|
||||||
Next
|
Next
|
||||||
'接入下载管理器
|
'接入下载管理器,获取新开始下载的文件列表
|
||||||
NetManager.Start(Me)
|
Dim NewFiles = NetManager.Start(Me)
|
||||||
|
|
||||||
'====================================
|
'====================================
|
||||||
' 已存在文件查找
|
' 已存在文件查找
|
||||||
@@ -1531,9 +1501,8 @@ FinishExCatch:
|
|||||||
|
|
||||||
'整理允许进行查找的文件
|
'整理允许进行查找的文件
|
||||||
Dim FilesToCheck As New List(Of NetFile)
|
Dim FilesToCheck As New List(Of NetFile)
|
||||||
Dim DisabledCopy As Boolean = Setup.Get("SystemDebugSkipCopy") '在设置中禁用了复制
|
For Each File In NewFiles
|
||||||
For Each File In Files
|
If File.Check?.CanUseExistsFile Then
|
||||||
If Not DisabledCopy AndAlso File.Check?.CanUseExistsFile Then
|
|
||||||
FilesToCheck.Add(File)
|
FilesToCheck.Add(File)
|
||||||
Else '不允许,直接开始下载
|
Else '不允许,直接开始下载
|
||||||
SyncLock LockState
|
SyncLock LockState
|
||||||
@@ -1570,7 +1539,7 @@ FinishExCatch:
|
|||||||
End Sub
|
End Sub
|
||||||
Private Sub CheckExistingFiles(Files As List(Of NetFile), FolderList As List(Of String))
|
Private Sub CheckExistingFiles(Files As List(Of NetFile), FolderList As List(Of String))
|
||||||
Try
|
Try
|
||||||
If ModeDebug Then Log($"[Download] 文件检查线程已启动,分配的文件数:{Files.Count}")
|
If ModeDebug Then Log($"[Download] 文件检查开始,本线程负责的文件数:{Files.Count}")
|
||||||
'列出 MC 文件夹中的各个版本文件夹
|
'列出 MC 文件夹中的各个版本文件夹
|
||||||
Dim VersionFolders As New List(Of String)
|
Dim VersionFolders As New List(Of String)
|
||||||
For Each McFolder In FolderList
|
For Each McFolder In FolderList
|
||||||
@@ -1584,7 +1553,7 @@ FinishExCatch:
|
|||||||
'处理每个文件
|
'处理每个文件
|
||||||
For Each File As NetFile In Files
|
For Each File As NetFile In Files
|
||||||
Dim Target As String = CheckExistingFile(FolderList, VersionFolders, File)
|
Dim Target As String = CheckExistingFile(FolderList, VersionFolders, File)
|
||||||
If File.State >= NetState.WaitingToDownload Then Return '中断
|
If File.State >= NetState.WaitingToDownload Then Continue For '中断
|
||||||
'已找到相同文件
|
'已找到相同文件
|
||||||
If Target IsNot Nothing Then
|
If Target IsNot Nothing Then
|
||||||
File.IsCopy = True
|
File.IsCopy = True
|
||||||
@@ -1594,6 +1563,8 @@ Retry:
|
|||||||
If Target <> File.LocalPath Then
|
If Target <> File.LocalPath Then
|
||||||
Log($"[Download] 复制已存在的文件:{Target} → {File.LocalPath}")
|
Log($"[Download] 复制已存在的文件:{Target} → {File.LocalPath}")
|
||||||
CopyFile(Target, File.LocalPath)
|
CopyFile(Target, File.LocalPath)
|
||||||
|
Else
|
||||||
|
If ModeDebug Then Log($"[Download] 需要下载的文件已存在,并通过校验:{Target}")
|
||||||
End If
|
End If
|
||||||
File.Finish(False)
|
File.Finish(False)
|
||||||
Continue For
|
Continue For
|
||||||
@@ -1619,6 +1590,8 @@ Retry:
|
|||||||
Private Function CheckExistingFile(FolderList As List(Of String), VersionFolders As List(Of String), File As NetFile) As String
|
Private Function CheckExistingFile(FolderList As List(Of String), VersionFolders As List(Of String), File As NetFile) As String
|
||||||
'目标文件已存在
|
'目标文件已存在
|
||||||
If File.Check.Check(File.LocalPath) Is Nothing Then Return File.LocalPath
|
If File.Check.Check(File.LocalPath) Is Nothing Then Return File.LocalPath
|
||||||
|
'在设置中禁用了复制
|
||||||
|
If Setup.Get("SystemDebugSkipCopy") Then Return Nothing
|
||||||
'没有可用的检查规则,只能开始下载
|
'没有可用的检查规则,只能开始下载
|
||||||
If File.Check.Hash Is Nothing AndAlso File.Check.ActualSize < 0 Then Return Nothing
|
If File.Check.Hash Is Nothing AndAlso File.Check.ActualSize < 0 Then Return Nothing
|
||||||
'大致判断文件类别
|
'大致判断文件类别
|
||||||
@@ -1633,7 +1606,7 @@ Retry:
|
|||||||
Return Nothing
|
Return Nothing
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Dim Type = TypeIndexes.MaxOf(Function(kv) kv.Item2).FolderName.TrimStart("\"c)
|
Dim Type = TypeIndexes.MaxBy(Function(kv) kv.Item2).FolderName.TrimStart("\"c)
|
||||||
'根据类别进行查找
|
'根据类别进行查找
|
||||||
Static Sizes As New SafeDictionary(Of String, Long)
|
Static Sizes As New SafeDictionary(Of String, Long)
|
||||||
Select Case Type
|
Select Case Type
|
||||||
@@ -1757,8 +1730,7 @@ Retry:
|
|||||||
''' <summary>
|
''' <summary>
|
||||||
''' 需要下载的文件。为“本地地址 - 文件对象”键值对。
|
''' 需要下载的文件。为“本地地址 - 文件对象”键值对。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Files As New Dictionary(Of String, NetFile)
|
Public AllFiles As New SafeDictionary(Of String, NetFile)
|
||||||
Public ReadOnly LockFiles As New Object
|
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 当前的所有下载任务。
|
''' 当前的所有下载任务。
|
||||||
@@ -1768,25 +1740,12 @@ Retry:
|
|||||||
''' <summary>
|
''' <summary>
|
||||||
''' 已下载完成的大小。
|
''' 已下载完成的大小。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Property DownloadDone As Long
|
Public DownloadDone As Long = 0
|
||||||
Get
|
|
||||||
Return _DownloadDone
|
|
||||||
End Get
|
|
||||||
Set(value As Long)
|
|
||||||
SyncLock LockDone
|
|
||||||
_DownloadDone = value
|
|
||||||
End SyncLock
|
|
||||||
End Set
|
|
||||||
End Property
|
|
||||||
Private _DownloadDone As Long = 0
|
|
||||||
Private ReadOnly LockDone As New Object
|
|
||||||
|
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 尚未完成下载的文件数。
|
''' 尚未完成下载的文件数。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public FileRemain As Integer = 0
|
Public FileRemain As Integer = 0
|
||||||
Public ReadOnly LockRemain As New Object
|
|
||||||
|
|
||||||
'这些属性由 RefreshStat 刷新
|
'这些属性由 RefreshStat 刷新
|
||||||
''' <summary>
|
''' <summary>
|
||||||
@@ -1855,9 +1814,9 @@ Retry:
|
|||||||
Thread.Sleep(20)
|
Thread.Sleep(20)
|
||||||
'获取文件列表
|
'获取文件列表
|
||||||
Dim AllFiles As List(Of NetFile)
|
Dim AllFiles As List(Of NetFile)
|
||||||
SyncLock LockFiles
|
SyncLock Me.AllFiles.SyncRoot
|
||||||
If Id = 0 AndAlso FileRemain = 0 AndAlso Files.Any() Then Files.Clear() '若已完成,则清空
|
If Id = 0 AndAlso FileRemain = 0 AndAlso Me.AllFiles.Any() Then Me.AllFiles.Clear() '若已完成,则清空
|
||||||
AllFiles = Files.Values.ToList()
|
AllFiles = Me.AllFiles.Values.ToList()
|
||||||
End SyncLock
|
End SyncLock
|
||||||
Dim WaitingFiles As New List(Of NetFile)
|
Dim WaitingFiles As New List(Of NetFile)
|
||||||
Dim OngoingFiles As New List(Of NetFile)
|
Dim OngoingFiles As New List(Of NetFile)
|
||||||
@@ -1865,7 +1824,7 @@ Retry:
|
|||||||
If File.Uuid Mod 2 = Id Then Continue For
|
If File.Uuid Mod 2 = Id Then Continue For
|
||||||
If File.State = NetState.WaitingToDownload Then
|
If File.State = NetState.WaitingToDownload Then
|
||||||
WaitingFiles.Add(File)
|
WaitingFiles.Add(File)
|
||||||
ElseIf File.State < NetState.Merging Then
|
ElseIf File.State < NetState.Merging AndAlso File.State >= NetState.WaitingToDownload Then
|
||||||
OngoingFiles.Add(File)
|
OngoingFiles.Add(File)
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
@@ -1908,7 +1867,7 @@ Retry:
|
|||||||
Dim NextTick As Long = GetTimeMs()
|
Dim NextTick As Long = GetTimeMs()
|
||||||
While True
|
While True
|
||||||
'增加限速余量
|
'增加限速余量
|
||||||
If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft = NetTaskSpeedLimitHigh / 10
|
If NetTaskSpeedLimitHigh > 0 Then Interlocked.Add(NetTaskSpeedLimitLeft, CLng(NetTaskSpeedLimitHigh / 10))
|
||||||
'刷新公开属性
|
'刷新公开属性
|
||||||
RefreshStat()
|
RefreshStat()
|
||||||
'等待 100 ms
|
'等待 100 ms
|
||||||
@@ -1931,7 +1890,7 @@ Retry:
|
|||||||
''' <summary>
|
''' <summary>
|
||||||
''' 开始一个下载任务。
|
''' 开始一个下载任务。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Sub Start(Task As LoaderDownload)
|
Public Function Start(Task As LoaderDownload) As List(Of NetFile)
|
||||||
StartManager()
|
StartManager()
|
||||||
'清理缓存
|
'清理缓存
|
||||||
SyncLock DownloadCacheLock '防止同时开启多个下载任务时重复清理
|
SyncLock DownloadCacheLock '防止同时开启多个下载任务时重复清理
|
||||||
@@ -1943,45 +1902,30 @@ Retry:
|
|||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Log(ex, "清理下载缓存失败")
|
Log(ex, "清理下载缓存失败")
|
||||||
End Try
|
End Try
|
||||||
End If
|
|
||||||
IsDownloadCacheCleared = True
|
IsDownloadCacheCleared = True
|
||||||
|
End If
|
||||||
End SyncLock
|
End SyncLock
|
||||||
'文件处理
|
|
||||||
SyncLock LockFiles
|
|
||||||
'添加每个文件
|
'添加每个文件
|
||||||
|
Dim NewFiles As New List(Of NetFile)
|
||||||
For i = 0 To Task.Files.Count - 1
|
For i = 0 To Task.Files.Count - 1
|
||||||
Dim File = Task.Files(i)
|
Dim File As NetFile = Task.Files(i)
|
||||||
If Files.ContainsKey(File.LocalPath) Then
|
If AllFiles.ContainsKey(File.LocalPath) AndAlso AllFiles(File.LocalPath).State < NetState.Finished Then
|
||||||
'已有该文件
|
'该文件正在被另一个任务下载
|
||||||
If Files(File.LocalPath).State >= NetState.Finished Then
|
If ModeDebug Then Log($"[Download] {File.LocalName}:无需开始,该文件已在下载中,目标 {File.LocalPath}")
|
||||||
'该文件已经下载过一次,且下载完成
|
File = AllFiles(File.LocalPath) '将列表中的文件替换成下载中的文件,即两个任务指向同一个文件;抛弃现在的 File 对象
|
||||||
'将已下载的文件替换成当前文件,重新下载
|
Task.Files(i) = File
|
||||||
File.Tasks.Add(Task)
|
|
||||||
Files(File.LocalPath) = File
|
|
||||||
SyncLock LockRemain
|
|
||||||
FileRemain += 1
|
|
||||||
End SyncLock
|
|
||||||
If ModeDebug Then Log($"[Download] {File.LocalName}:重新加入下载列表,目标 {File.LocalPath}")
|
|
||||||
Else
|
Else
|
||||||
'该文件正在下载中
|
'常规情况(该文件可能已在其他任务中下载完成,但这并不影响)
|
||||||
'将当前文件替换成下载中的文件,即两个任务指向同一个文件
|
If ModeDebug Then Log($"[Download] {File.LocalName}:开始,目标 {File.LocalPath}")
|
||||||
File = Files(File.LocalPath)
|
AllFiles(File.LocalPath) = File
|
||||||
File.Tasks.Add(Task)
|
NewFiles.Add(File)
|
||||||
|
Interlocked.Increment(FileRemain)
|
||||||
End If
|
End If
|
||||||
Else
|
|
||||||
'没有该文件
|
|
||||||
File.Tasks.Add(Task)
|
File.Tasks.Add(Task)
|
||||||
Files.Add(File.LocalPath, File)
|
|
||||||
SyncLock LockRemain
|
|
||||||
FileRemain += 1
|
|
||||||
End SyncLock
|
|
||||||
If ModeDebug Then Log($"[Download] {File.LocalName}:已加入下载列表,目标 {File.LocalPath}")
|
|
||||||
End If
|
|
||||||
Task.Files(i) = File '回设
|
|
||||||
Next
|
Next
|
||||||
End SyncLock
|
|
||||||
Tasks.Add(Task)
|
Tasks.Add(Task)
|
||||||
End Sub
|
Return NewFiles
|
||||||
|
End Function
|
||||||
|
|
||||||
End Class
|
End Class
|
||||||
|
|
||||||
|
|||||||
@@ -846,6 +846,11 @@ NoSubtitle:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public SearchText As String = Nothing
|
Public SearchText As String = Nothing
|
||||||
''' <summary>
|
''' <summary>
|
||||||
|
''' 在进行中文搜索时,CurseForge 的替代搜索文本。
|
||||||
|
''' 由于 CurseForge API 在有任意关键词未匹配的时候就不显示结果,所以不能使用与 Modrinth 相同的算法。
|
||||||
|
''' </summary>
|
||||||
|
Public CurseForgeAltSearchText As String = Nothing
|
||||||
|
''' <summary>
|
||||||
''' 允许的来源。
|
''' 允许的来源。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Source As CompSourceType = CompSourceType.Any
|
Public Source As CompSourceType = CompSourceType.Any
|
||||||
@@ -884,7 +889,7 @@ NoSubtitle:
|
|||||||
If Tag <> "" Then Address += "&categoryId=" & Tag.BeforeFirst("/")
|
If Tag <> "" Then Address += "&categoryId=" & Tag.BeforeFirst("/")
|
||||||
If ModLoader <> CompModLoaderType.Any Then Address += "&modLoaderType=" & CType(ModLoader, Integer)
|
If ModLoader <> CompModLoaderType.Any Then Address += "&modLoaderType=" & CType(ModLoader, Integer)
|
||||||
If Not String.IsNullOrEmpty(GameVersion) Then Address += "&gameVersion=" & GameVersion
|
If Not String.IsNullOrEmpty(GameVersion) Then Address += "&gameVersion=" & GameVersion
|
||||||
If Not String.IsNullOrEmpty(SearchText) Then Address += "&searchFilter=" & Net.WebUtility.UrlEncode(SearchText)
|
If Not String.IsNullOrEmpty(If(CurseForgeAltSearchText, SearchText)) Then Address += "&searchFilter=" & Net.WebUtility.UrlEncode(If(CurseForgeAltSearchText, SearchText))
|
||||||
If Storage.CurseForgeOffset > 0 Then Address += "&index=" & Storage.CurseForgeOffset
|
If Storage.CurseForgeOffset > 0 Then Address += "&index=" & Storage.CurseForgeOffset
|
||||||
Return Address
|
Return Address
|
||||||
End Function
|
End Function
|
||||||
@@ -995,62 +1000,86 @@ NoSubtitle:
|
|||||||
'构造搜索请求
|
'构造搜索请求
|
||||||
Dim SearchEntries As New List(Of SearchEntry(Of CompDatabaseEntry))
|
Dim SearchEntries As New List(Of SearchEntry(Of CompDatabaseEntry))
|
||||||
For Each Entry In CompDatabase
|
For Each Entry In CompDatabase
|
||||||
If Entry.ChineseName.Contains("动态的树") Then Continue For '这玩意儿附属太多了
|
|
||||||
SearchEntries.Add(New SearchEntry(Of CompDatabaseEntry) With {
|
SearchEntries.Add(New SearchEntry(Of CompDatabaseEntry) With {
|
||||||
.Item = Entry,
|
.Item = Entry,
|
||||||
.SearchSource = New List(Of KeyValuePair(Of String, Double)) From {
|
.SearchSource = New List(Of SearchSource) From {
|
||||||
New KeyValuePair(Of String, Double)(Entry.ChineseName & If(Entry.CurseForgeSlug, "") & If(Entry.ModrinthSlug, ""), 1)
|
New SearchSource(Entry.ChineseName.BeforeFirst(" (").Split({"/"c}, StringSplitOptions.RemoveEmptyEntries), 1), '部分 Mod 有别名
|
||||||
|
New SearchSource(Entry.ChineseName.AfterFirst(" (") & If(Entry.CurseForgeSlug, "") & If(Entry.ModrinthSlug, ""), 0.5)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Next
|
Next
|
||||||
'获取搜索结果
|
Dim SearchResults = Search(SearchEntries, Request.SearchText, 40, 0.2)
|
||||||
Dim SearchResults = Search(SearchEntries, Request.SearchText, 3)
|
|
||||||
If Not SearchResults.Any() 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 个
|
Dim ExtractWords =
|
||||||
If Not SearchResults(i).AbsoluteRight AndAlso i >= Math.Min(2, SearchResults.Count - 1) Then Exit For '把 3 个结果拼合以提高准确度
|
Function(Result As SearchEntry(Of CompDatabaseEntry)) As String()
|
||||||
If SearchResults(i).Item.CurseForgeSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.CurseForgeSlug.Replace("-", " ").Replace("/", " ") & " "
|
Dim Word As String = ""
|
||||||
If SearchResults(i).Item.ModrinthSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.ModrinthSlug.Replace("-", " ").Replace("/", " ") & " "
|
If Result.Item.CurseForgeSlug IsNot Nothing Then Word += Result.Item.CurseForgeSlug.Replace("-", " ").Replace("/", " ") & " "
|
||||||
SearchResult += SearchResults(i).Item.ChineseName.AfterLast(" (").TrimEnd(") ").BeforeFirst(" - ").
|
If Result.Item.ModrinthSlug IsNot Nothing Then Word += Result.Item.ModrinthSlug.Replace("-", " ").Replace("/", " ") & " "
|
||||||
Replace(":", "").Replace("(", "").Replace(")", "").ToLower.Replace("/", " ") & " "
|
Word += Result.Item.ChineseName.AfterLast(" (").TrimEnd(") ").BeforeFirst(" - ").
|
||||||
|
Replace(":", "").Replace("(", "").Replace(")", "").ToLower.Replace("/", " ").Replace("-", " ")
|
||||||
|
Dim Words = Word.ToLower.Split(" ")
|
||||||
|
Words = Words.Select(Function(w) w.TrimStart("{[(").TrimEnd("}])")).Where(
|
||||||
|
Function(w)
|
||||||
|
If w.Length <= 1 Then Return False '单字词
|
||||||
|
If {"the", "of", "mod", "and"}.Contains(w) Then Return False '常见词
|
||||||
|
If Val(w) > 0 Then Return False '数字
|
||||||
|
If w.Split(" ").Count > 3 AndAlso w.Contains("ftb") Then Return False '神秘 FTB
|
||||||
|
Return True
|
||||||
|
End Function).Distinct.ToArray
|
||||||
|
Return Words
|
||||||
|
End Function
|
||||||
|
Dim WordWeights As New Dictionary(Of String, Double) '各个单词及其出现的权重
|
||||||
|
For Each Result In SearchResults
|
||||||
|
For Each Word In ExtractWords(Result)
|
||||||
|
Dim Similarity = If(Result.SearchSource.Any(Function(s) s.Aliases.Contains(Request.SearchText)), 100000, Result.Similarity) '完全匹配为 100000
|
||||||
|
If Not WordWeights.ContainsKey(Word) Then WordWeights.Add(Word, 0)
|
||||||
|
WordWeights(Word) += Similarity
|
||||||
Next
|
Next
|
||||||
Log("[Comp] 中文搜索原始关键词:" & SearchResult, LogLevel.Developer)
|
|
||||||
'去除常见连接词
|
|
||||||
Dim RealFilter As String = ""
|
|
||||||
For Each Word In SearchResult.Split(" ")
|
|
||||||
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
|
Next
|
||||||
Request.SearchText = RealFilter
|
If Not WordWeights.Any() Then Throw New Exception("无搜索结果,请尝试搜索英文名称")
|
||||||
Log("[Comp] 中文搜索最终关键词:" & RealFilter, LogLevel.Developer)
|
'根据权重选取英文单词
|
||||||
|
Dim SortedWords = WordWeights.OrderByDescending(Function(w) w.Value).ToList
|
||||||
|
If SortedWords.First.Value >= 100000 Then '如果有完全匹配的,就只选完全匹配的
|
||||||
|
Request.SearchText = SortedWords.Where(Function(w) w.Value >= 100000).Select(Function(w) w.Key).Join(" ")
|
||||||
|
Else '否则,CurseForge 选第一个结果,Modrinth 选前 5 个单词
|
||||||
|
Request.SearchText = SortedWords.Take(5).Select(Function(w) w.Key).Join(" ")
|
||||||
|
Request.CurseForgeAltSearchText = ExtractWords(SearchResults.First).Join(" ")
|
||||||
|
Log("[Comp] 中文搜索基础关键词(CurseForge):" & Request.CurseForgeAltSearchText, LogLevel.Developer)
|
||||||
|
End If
|
||||||
|
Log("[Comp] 中文搜索基础关键词:" & Request.SearchText, LogLevel.Developer)
|
||||||
End If
|
End If
|
||||||
|
|
||||||
'驼峰英文请求关键字处理
|
|
||||||
Dim SpacedKeywords = Request.SearchText.RegexReplace("([A-Z]+|[a-z]+?)(?=[A-Z]+[a-z]+[a-z ]*)", "$& ")
|
|
||||||
Dim ConnectedKeywords = Request.SearchText.Replace(" ", "")
|
|
||||||
Dim AllPossibleKeywords = (SpacedKeywords & " " & If(IsChineseSearch, Request.SearchText, ConnectedKeywords & " " & RawFilter)).ToLower
|
|
||||||
|
|
||||||
'最终处理关键字:分割、去重
|
'最终处理关键字:分割、去重
|
||||||
Dim RightKeywords As New List(Of String)
|
Dim ProcessKeywords =
|
||||||
For Each Keyword In AllPossibleKeywords.Split(" ")
|
Sub(ByRef Text As String)
|
||||||
|
If Text Is Nothing Then Return
|
||||||
|
Text = Text.ToLowerInvariant
|
||||||
|
Dim Words As New List(Of String)
|
||||||
|
For Each Keyword In Text.Split(" ")
|
||||||
Keyword = Keyword.Trim("["c, "]"c)
|
Keyword = Keyword.Trim("["c, "]"c)
|
||||||
If Keyword = "" Then Continue For
|
If Keyword = "" Then Continue For
|
||||||
If {"forge", "fabric", "for", "mod", "quilt"}.Contains(Keyword) Then '#208
|
If {"forge", "fabric", "for", "mod", "quilt"}.Contains(Keyword) Then '#208
|
||||||
Log("[Comp] 已跳过搜索关键词:" & Keyword, LogLevel.Developer)
|
Log("[Comp] 已跳过搜索关键词:" & Keyword, LogLevel.Developer)
|
||||||
Continue For
|
Continue For
|
||||||
End If
|
End If
|
||||||
RightKeywords.Add(Keyword)
|
Words.Add(Keyword)
|
||||||
Next
|
Next
|
||||||
If RawFilter.Length > 0 AndAlso Not RightKeywords.Any() Then
|
If RawFilter.Length > 0 AndAlso Not Words.Any() Then
|
||||||
Request.SearchText = RawFilter '全都被过滤掉了
|
Text = RawFilter '全都被过滤掉了
|
||||||
Else
|
Else
|
||||||
Request.SearchText = Join(RightKeywords.Distinct.ToList, " ").ToLower
|
Text = Join(Words.Distinct.ToList, " ")
|
||||||
End If
|
End If
|
||||||
|
|
||||||
'例外项:OptiForge、OptiFabric(拆词后因为包含 Forge/Fabric 导致无法搜到实际的 Mod)
|
'例外项:OptiForge、OptiFabric(拆词后因为包含 Forge/Fabric 导致无法搜到实际的 Mod)
|
||||||
If RawFilter.Replace(" ", "").ContainsF("optiforge", True) Then Request.SearchText = "optiforge"
|
If RawFilter.Replace(" ", "").ContainsF("optiforge", True) Then Text = "optiforge"
|
||||||
If RawFilter.Replace(" ", "").ContainsF("optifabric", True) Then Request.SearchText = "optifabric"
|
If RawFilter.Replace(" ", "").ContainsF("optifabric", True) Then Text = "optifabric"
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
If Request.CurseForgeAltSearchText IsNot Nothing Then
|
||||||
|
ProcessKeywords(Request.CurseForgeAltSearchText)
|
||||||
|
Log("[Comp] 工程列表搜索最终文本(CurseForge):" & Request.CurseForgeAltSearchText, LogLevel.Debug)
|
||||||
|
End If
|
||||||
|
ProcessKeywords(Request.SearchText)
|
||||||
Log("[Comp] 工程列表搜索最终文本:" & Request.SearchText, LogLevel.Debug)
|
Log("[Comp] 工程列表搜索最终文本:" & Request.SearchText, LogLevel.Debug)
|
||||||
Task.Progress = 0.1
|
Task.Progress = 0.1
|
||||||
|
|
||||||
@@ -1195,7 +1224,7 @@ Retry:
|
|||||||
Not Storage.Results.Any(Function(b) r.IsLike(b))).ToList
|
Not Storage.Results.Any(Function(b) r.IsLike(b))).ToList
|
||||||
'加入列表
|
'加入列表
|
||||||
RealResults.AddRange(RawResults)
|
RealResults.AddRange(RawResults)
|
||||||
Log($"[Comp] 去重、筛选后累计新增结果 {RealResults.Count} 个")
|
Log($"[Comp] 去重、筛选后累计新增结果 {RealResults.Count} 个(目前已有结果 {Storage.Results.Count} 个)")
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
|
|
||||||
@@ -1241,16 +1270,19 @@ Retry:
|
|||||||
For Each Result As CompProject In RealResults
|
For Each Result As CompProject In RealResults
|
||||||
Scores.Add(Result, If(Result.WikiId > 0, 0.2, 0) +
|
Scores.Add(Result, If(Result.WikiId > 0, 0.2, 0) +
|
||||||
Math.Log10(Math.Max(Result.DownloadCount, 1) * GetDownloadCountMult(Result)) / 9)
|
Math.Log10(Math.Max(Result.DownloadCount, 1) * GetDownloadCountMult(Result)) / 9)
|
||||||
Entry.Add(New SearchEntry(Of CompProject) With {.Item = Result, .SearchSource = New List(Of KeyValuePair(Of String, Double)) From {
|
Entry.Add(New SearchEntry(Of CompProject) With {.Item = Result, .SearchSource = New List(Of SearchSource) From {
|
||||||
New KeyValuePair(Of String, Double)(If(IsChineseSearch, Result.TranslatedName, Result.RawName), 1),
|
New SearchSource(If(IsChineseSearch, Result.TranslatedName, Result.RawName).Split({"/"c}, StringSplitOptions.RemoveEmptyEntries), 1),
|
||||||
New KeyValuePair(Of String, Double)(Result.Description, 0.05)}})
|
New SearchSource(Result.Description, 0.05)}})
|
||||||
Next
|
Next
|
||||||
Dim SearchResult = Search(Entry, RawFilter, 101, -1)
|
Dim SearchResult = Search(Entry, RawFilter, 101, -1)
|
||||||
For Each OneResult In SearchResult
|
For Each OneResult In SearchResult
|
||||||
Scores(OneResult.Item) += OneResult.Similarity / SearchResult(0).Similarity '最高 1 分的相似度分
|
Scores(OneResult.Item) +=
|
||||||
|
If(OneResult.AbsoluteRight, 10, OneResult.Similarity) /
|
||||||
|
If(SearchResult.First.AbsoluteRight, 10, SearchResult.First.Similarity) '最高 1 分的相似度分
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
'根据排序分得出结果并添加
|
'根据排序分得出结果并添加
|
||||||
|
If Task.IsAborted Then Throw New ThreadInterruptedException '#8246
|
||||||
Storage.Results.AddRange(
|
Storage.Results.AddRange(
|
||||||
Scores.OrderByDescending(Function(s) s.Value).Select(Function(r) r.Key))
|
Scores.OrderByDescending(Function(s) s.Value).Select(Function(r) r.Key))
|
||||||
|
|
||||||
@@ -1430,7 +1462,10 @@ Retry:
|
|||||||
End If
|
End If
|
||||||
'GameVersions
|
'GameVersions
|
||||||
Dim RawVersions As List(Of String) = Data("gameVersions").Select(Function(t) t.ToString.Trim.ToLower).ToList
|
Dim RawVersions As List(Of String) = Data("gameVersions").Select(Function(t) t.ToString.Trim.ToLower).ToList
|
||||||
GameVersions = RawVersions.Where(Function(v) McVersion.IsFormatFit(v)).Select(Function(v) v.Replace("-snapshot", " 预览版")).ToList
|
GameVersions = RawVersions.
|
||||||
|
Where(Function(v) McVersion.IsFormatFit(v)).
|
||||||
|
Select(Function(v) v.Replace("-snapshot", " 预览版")).
|
||||||
|
Distinct.ToList
|
||||||
If GameVersions.Count > 1 Then
|
If GameVersions.Count > 1 Then
|
||||||
GameVersions = GameVersions.SortByComparison(AddressOf CompareVersionGE).ToList
|
GameVersions = GameVersions.SortByComparison(AddressOf CompareVersionGE).ToList
|
||||||
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)} '整合包理应只 “支持” 一个版本
|
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)} '整合包理应只 “支持” 一个版本
|
||||||
@@ -1492,7 +1527,8 @@ Retry:
|
|||||||
'GameVersions
|
'GameVersions
|
||||||
Dim RawVersions As List(Of String) = Data("game_versions").Select(Function(t) t.ToString.Trim.ToLower).ToList
|
Dim RawVersions As List(Of String) = Data("game_versions").Select(Function(t) t.ToString.Trim.ToLower).ToList
|
||||||
GameVersions = RawVersions.Where(Function(v) v.Contains(".")).
|
GameVersions = RawVersions.Where(Function(v) v.Contains(".")).
|
||||||
Select(Function(v) If(v.Contains("-"), v.BeforeFirst("-") & " 预览版", If(v.StartsWithF("b1."), "远古版本", v))).ToList
|
Select(Function(v) If(v.Contains("-"), v.BeforeFirst("-") & " 预览版", If(v.StartsWithF("b1."), "远古版本", v))).
|
||||||
|
Distinct.ToList
|
||||||
If GameVersions.Count > 1 Then
|
If GameVersions.Count > 1 Then
|
||||||
GameVersions = GameVersions.SortByComparison(AddressOf CompareVersionGE).ToList
|
GameVersions = GameVersions.SortByComparison(AddressOf CompareVersionGE).ToList
|
||||||
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)} '整合包理应只 “支持” 一个版本
|
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)} '整合包理应只 “支持” 一个版本
|
||||||
@@ -1648,7 +1684,7 @@ Retry:
|
|||||||
Next
|
Next
|
||||||
Else
|
Else
|
||||||
'Modrinth
|
'Modrinth
|
||||||
ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version")
|
ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version?include_changelog=false")
|
||||||
End If
|
End If
|
||||||
CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)).
|
CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)).
|
||||||
Where(Function(a) a.Available).ToList.
|
Where(Function(a) a.Available).ToList.
|
||||||
|
|||||||
@@ -1176,17 +1176,17 @@
|
|||||||
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
|
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
|
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
|
||||||
Case 1
|
Case 1
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10)) '至少 10s,要不然有时候远端服务器来不及完成
|
Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10))) '至少 20s,要不然 Modrinth 返回不过来
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
|
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
|
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
|
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
|
||||||
Case Else
|
Case Else
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10))
|
Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10)))
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
|
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
|
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
|
||||||
End Select
|
End Select
|
||||||
Else
|
Else
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10))
|
Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10)))
|
||||||
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
|
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
|
||||||
End If
|
End If
|
||||||
Dim Exs As String = ""
|
Dim Exs As String = ""
|
||||||
|
|||||||
@@ -95,6 +95,7 @@
|
|||||||
Try
|
Try
|
||||||
'确定文件存在
|
'确定文件存在
|
||||||
If Not File.Exists(PathJava) Then Throw New FileNotFoundException("未找到 java.exe 文件", PathJava)
|
If Not File.Exists(PathJava) Then Throw New FileNotFoundException("未找到 java.exe 文件", PathJava)
|
||||||
|
If PathJava.ContainsF("finalshell", True) Then Throw New Exception("不兼容 FinalShell 的 Java") '#8080
|
||||||
If File.Exists(PathFolder & "pdf-bookmark") Then Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326
|
If File.Exists(PathFolder & "pdf-bookmark") Then Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326
|
||||||
IsJre = Not File.Exists(PathFolder & "javac.exe")
|
IsJre = Not File.Exists(PathFolder & "javac.exe")
|
||||||
'运行 -version
|
'运行 -version
|
||||||
|
|||||||
@@ -1314,40 +1314,6 @@ Retry:
|
|||||||
|
|
||||||
Private McLaunchArgument As String
|
Private McLaunchArgument As String
|
||||||
|
|
||||||
''' <summary>
|
|
||||||
''' 释放 Java Wrapper 并返回完整文件路径。
|
|
||||||
''' </summary>
|
|
||||||
Public Function ExtractJavaWrapper() As String
|
|
||||||
Dim WrapperPath As String = PathPure & "JavaWrapper.jar"
|
|
||||||
Log("[Java] 选定的 Java Wrapper 路径:" & WrapperPath)
|
|
||||||
SyncLock ExtractJavaWrapperLock '避免 OptiFine 和 Forge 安装时同时释放 Java Wrapper 导致冲突
|
|
||||||
Try
|
|
||||||
WriteFile(WrapperPath, GetResources("JavaWrapper"))
|
|
||||||
Catch ex As Exception
|
|
||||||
If File.Exists(WrapperPath) Then
|
|
||||||
'因为未知原因 Java Wrapper 可能变为只读文件(#4243)
|
|
||||||
Log(ex, "Java Wrapper 文件释放失败,但文件已存在,将在删除后尝试重新生成", LogLevel.Developer)
|
|
||||||
Try
|
|
||||||
File.Delete(WrapperPath)
|
|
||||||
WriteFile(WrapperPath, GetResources("JavaWrapper"))
|
|
||||||
Catch ex2 As Exception
|
|
||||||
Log(ex2, "Java Wrapper 文件重新释放失败,将尝试更换文件名重新生成", LogLevel.Developer)
|
|
||||||
WrapperPath = PathPure & "JavaWrapper2.jar"
|
|
||||||
Try
|
|
||||||
WriteFile(WrapperPath, GetResources("JavaWrapper"))
|
|
||||||
Catch ex3 As Exception
|
|
||||||
Throw New FileNotFoundException("释放 Java Wrapper 最终尝试失败", ex3)
|
|
||||||
End Try
|
|
||||||
End Try
|
|
||||||
Else
|
|
||||||
Throw New FileNotFoundException("释放 Java Wrapper 失败", ex)
|
|
||||||
End If
|
|
||||||
End Try
|
|
||||||
End SyncLock
|
|
||||||
Return WrapperPath
|
|
||||||
End Function
|
|
||||||
Private ExtractJavaWrapperLock As New Object
|
|
||||||
|
|
||||||
'主方法,合并 Jvm、Game、Replace 三部分的参数数据
|
'主方法,合并 Jvm、Game、Replace 三部分的参数数据
|
||||||
Private Sub McLaunchArgumentMain(Loader As LoaderTask(Of String, List(Of McLibToken)))
|
Private Sub McLaunchArgumentMain(Loader As LoaderTask(Of String, List(Of McLibToken)))
|
||||||
McLaunchLog("开始获取 Minecraft 启动参数")
|
McLaunchLog("开始获取 Minecraft 启动参数")
|
||||||
@@ -1393,6 +1359,8 @@ Retry:
|
|||||||
'自定义
|
'自定义
|
||||||
Dim ArgumentGame As String = Setup.Get("VersionAdvanceGame", Instance:=McInstanceSelected)
|
Dim ArgumentGame As String = Setup.Get("VersionAdvanceGame", Instance:=McInstanceSelected)
|
||||||
Arguments += " " & ArgumentReplace(If(ArgumentGame = "", Setup.Get("LaunchAdvanceGame"), ArgumentGame))
|
Arguments += " " & ArgumentReplace(If(ArgumentGame = "", Setup.Get("LaunchAdvanceGame"), ArgumentGame))
|
||||||
|
'GC
|
||||||
|
Arguments = ProcessGCArguments(Arguments, McLaunchJavaSelected, McInstanceSelected)
|
||||||
'进行参数替换
|
'进行参数替换
|
||||||
Dim ReplaceArguments = McLaunchArgumentsReplace(McInstanceSelected, Loader)
|
Dim ReplaceArguments = McLaunchArgumentsReplace(McInstanceSelected, Loader)
|
||||||
If String.IsNullOrWhiteSpace(ReplaceArguments("${version_type}")) Then
|
If String.IsNullOrWhiteSpace(ReplaceArguments("${version_type}")) Then
|
||||||
@@ -1754,6 +1722,72 @@ NextInstance:
|
|||||||
Return GameArguments
|
Return GameArguments
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
|
'工具方法
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' 释放 Java Wrapper 并返回完整文件路径。
|
||||||
|
''' </summary>
|
||||||
|
Public Function ExtractJavaWrapper() As String
|
||||||
|
Dim WrapperPath As String = PathPure & "JavaWrapper.jar"
|
||||||
|
Log("[Java] 选定的 Java Wrapper 路径:" & WrapperPath)
|
||||||
|
Static Lock As New Object
|
||||||
|
SyncLock Lock '避免 OptiFine 和 Forge 安装时同时释放 Java Wrapper 导致冲突
|
||||||
|
Try
|
||||||
|
WriteFile(WrapperPath, GetResources("JavaWrapper"))
|
||||||
|
Catch ex As Exception
|
||||||
|
If File.Exists(WrapperPath) Then
|
||||||
|
'因为未知原因 Java Wrapper 可能变为只读文件(#4243)
|
||||||
|
Log(ex, "Java Wrapper 文件释放失败,但文件已存在,将在删除后尝试重新生成", LogLevel.Developer)
|
||||||
|
Try
|
||||||
|
File.Delete(WrapperPath)
|
||||||
|
WriteFile(WrapperPath, GetResources("JavaWrapper"))
|
||||||
|
Catch ex2 As Exception
|
||||||
|
Log(ex2, "Java Wrapper 文件重新释放失败,将尝试更换文件名重新生成", LogLevel.Developer)
|
||||||
|
WrapperPath = PathPure & "JavaWrapper2.jar"
|
||||||
|
Try
|
||||||
|
WriteFile(WrapperPath, GetResources("JavaWrapper"))
|
||||||
|
Catch ex3 As Exception
|
||||||
|
Throw New FileNotFoundException("释放 Java Wrapper 最终尝试失败", ex3)
|
||||||
|
End Try
|
||||||
|
End Try
|
||||||
|
Else
|
||||||
|
Throw New FileNotFoundException("释放 Java Wrapper 失败", ex)
|
||||||
|
End If
|
||||||
|
End Try
|
||||||
|
End SyncLock
|
||||||
|
Return WrapperPath
|
||||||
|
End Function
|
||||||
|
''' <summary>
|
||||||
|
''' 根据设置的 GC 方式返回对应的 JVM 参数。
|
||||||
|
''' </summary>
|
||||||
|
Private Function ProcessGCArguments(Arguments As String, SelectedJava As JavaEntry, Optional TargetInstance As McInstance = Nothing) As String
|
||||||
|
'0:在 Java 21+ 使用分代 ZGC,20~15 使用非分代的 ZGC,14- 使用 G1GC
|
||||||
|
'1:在 Java 21+ 使用分代 ZGC,20- 使用 G1GC
|
||||||
|
'2:仅 G1GC
|
||||||
|
'3:不指定
|
||||||
|
Dim SetupType As Integer = Setup.Get("LaunchAdvanceGC")
|
||||||
|
If TargetInstance IsNot Nothing AndAlso Setup.Get("VersionAdvanceGC", TargetInstance) > 0 Then SetupType = Setup.Get("VersionAdvanceGC", TargetInstance) - 1 '去掉默认
|
||||||
|
If SetupType = 3 Then Return Arguments.Trim '不指定时直接返回
|
||||||
|
Dim UseG1GC As Boolean =
|
||||||
|
(SetupType = 0 AndAlso SelectedJava.MajorVersion < 15) OrElse
|
||||||
|
(SetupType = 1 AndAlso SelectedJava.MajorVersion < 21) OrElse
|
||||||
|
SetupType = 2
|
||||||
|
McLaunchLog($"GC 设置:{SetupType},选取 {If(UseG1GC, "G1GC", "ZGC")},Java 版本:{SelectedJava.MajorVersion}")
|
||||||
|
'移除
|
||||||
|
Arguments = RegexReplace(Arguments,
|
||||||
|
"( )*-XX:[+-]?(Use\w+GC|ZGenerational|UseCompactObjectHeaders|G1\w+Percent|G1\w+Size|MaxGCPauseMillis)(=[^\s]+)?", "").Trim
|
||||||
|
'添加
|
||||||
|
If UseG1GC Then
|
||||||
|
Arguments = Arguments.Replace("-XX:+UnlockExperimentalVMOptions", "")
|
||||||
|
Arguments = "-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M " + Arguments
|
||||||
|
Else
|
||||||
|
Arguments = "-XX:+UseZGC " + Arguments
|
||||||
|
If SelectedJava.MajorVersion = 21 OrElse SelectedJava.MajorVersion = 22 Then Arguments = "-XX:+ZGenerational " + Arguments 'Java 23 起默认启用分代 ZGC,不需要再添加参数
|
||||||
|
If SelectedJava.MajorVersion >= 25 Then Arguments = "-XX:+UseCompactObjectHeaders " + Arguments
|
||||||
|
End If
|
||||||
|
Return Arguments.Trim
|
||||||
|
End Function
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
|
|
||||||
#Region "解压 Natives"
|
#Region "解压 Natives"
|
||||||
|
|||||||
@@ -1426,7 +1426,7 @@ OnLoaded:
|
|||||||
'确认最新版本,若为快照则加入常用列表
|
'确认最新版本,若为快照则加入常用列表
|
||||||
Dim LargestInstance As McInstance = InstanceList.
|
Dim LargestInstance As McInstance = InstanceList.
|
||||||
Where(Function(v) v.State = McInstanceState.Original OrElse v.State = McInstanceState.Snapshot).
|
Where(Function(v) v.State = McInstanceState.Original OrElse v.State = McInstanceState.Snapshot).
|
||||||
MaxOf(Function(v) v.ReleaseTime)
|
MaxBy(Function(v) v.ReleaseTime)
|
||||||
If LargestInstance IsNot Nothing AndAlso LargestInstance.State = McInstanceState.Snapshot Then
|
If LargestInstance IsNot Nothing AndAlso LargestInstance.State = McInstanceState.Snapshot Then
|
||||||
InstanceUseful.Add(LargestInstance)
|
InstanceUseful.Add(LargestInstance)
|
||||||
InstanceList.Remove(LargestInstance)
|
InstanceList.Remove(LargestInstance)
|
||||||
|
|||||||
@@ -636,9 +636,8 @@ Retry:
|
|||||||
Dim Request As New McInstallRequest With {.NewInstanceName = InstanceName, .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\"}
|
Dim Request As New McInstallRequest With {.NewInstanceName = InstanceName, .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\"}
|
||||||
For Each Component As JObject In PackJson("components")
|
For Each Component As JObject In PackJson("components")
|
||||||
If Not Component.ContainsKey("uid") Then Continue For
|
If Not Component.ContainsKey("uid") Then Continue For
|
||||||
Select Case Component("uid").ToString
|
Dim UID As String = Component("uid").ToString
|
||||||
Case "org.lwjgl"
|
Select Case UID
|
||||||
Log("[ModPack] 已跳过 LWJGL 项")
|
|
||||||
Case "net.minecraft"
|
Case "net.minecraft"
|
||||||
Request.MinecraftName = Component("version")
|
Request.MinecraftName = Component("version")
|
||||||
Case "net.minecraftforge"
|
Case "net.minecraftforge"
|
||||||
@@ -647,9 +646,13 @@ Retry:
|
|||||||
Request.NeoForgeVersion = Component("version")
|
Request.NeoForgeVersion = Component("version")
|
||||||
Case "net.fabricmc.fabric-loader"
|
Case "net.fabricmc.fabric-loader"
|
||||||
Request.FabricVersion = Component("version")
|
Request.FabricVersion = Component("version")
|
||||||
Case Else
|
|
||||||
'Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
|
'Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
|
||||||
NotifyIncompatibleLoader(Component("uid"))
|
Case Else
|
||||||
|
If UID.StartsWithF("org.lwjgl") Then '#8210
|
||||||
|
Log("[ModPack] 已跳过 LWJGL 项:" & UID)
|
||||||
|
Else
|
||||||
|
NotifyIncompatibleLoader(UID)
|
||||||
|
End If
|
||||||
End Select
|
End Select
|
||||||
Next
|
Next
|
||||||
'构造加载器
|
'构造加载器
|
||||||
|
|||||||
@@ -283,9 +283,9 @@
|
|||||||
Try
|
Try
|
||||||
Reader = New NAudio.Wave.AudioFileReader(MusicCurrent)
|
Reader = New NAudio.Wave.AudioFileReader(MusicCurrent)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Log(ex,"[Music] 使用 AudioFileReader 加载音频文件失败,将换用 Media Foundation 加载音频文件。")
|
Log(ex, "使用 AudioFileReader 加载音频文件失败,换用 MediaFoundationReader 重试", LogLevel.Developer)
|
||||||
End Try
|
|
||||||
Reader = New NAudio.Wave.MediaFoundationReader(MusicCurrent)
|
Reader = New NAudio.Wave.MediaFoundationReader(MusicCurrent)
|
||||||
|
End Try
|
||||||
CurrentWave.Init(Reader)
|
CurrentWave.Init(Reader)
|
||||||
CurrentWave.Play()
|
CurrentWave.Play()
|
||||||
'第一次打开的暂停
|
'第一次打开的暂停
|
||||||
@@ -316,9 +316,7 @@
|
|||||||
Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Red)
|
Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Red)
|
||||||
Thread.Sleep(1000000000)
|
Thread.Sleep(1000000000)
|
||||||
End If
|
End If
|
||||||
If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then
|
If Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse
|
||||||
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 不支持播放音频属性在中途发生变化的音乐", HintType.Red)
|
|
||||||
ElseIf Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse
|
|
||||||
ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4)
|
ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4)
|
||||||
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Red)
|
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Red)
|
||||||
Else
|
Else
|
||||||
|
|||||||
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
||||||
' 方法是按如下所示使用“*”
|
' 方法是按如下所示使用“*”
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2.12.2.0")>
|
<Assembly: AssemblyVersion("2.12.3.0")>
|
||||||
<Assembly: AssemblyFileVersion("2.12.2.0")>
|
<Assembly: AssemblyFileVersion("2.12.3.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("")>
|
<Assembly: NeutralResourcesLanguage("")>
|
||||||
|
|||||||
@@ -359,8 +359,38 @@ GroupDone:
|
|||||||
If Not Instance.IsLoaded Then Instance.Load()
|
If Not Instance.IsLoaded Then Instance.Load()
|
||||||
'只对 Mod 和数据包进行版本检测
|
'只对 Mod 和数据包进行版本检测
|
||||||
If File.Type = CompType.Mod OrElse File.Type = CompType.DataPack Then
|
If File.Type = CompType.Mod OrElse File.Type = CompType.DataPack Then
|
||||||
If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso
|
If Not File.GameVersions.Any( '判断是否有任何一个版本匹配
|
||||||
Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v = Instance.Version.VanillaName) Then Return False
|
Function(FileVersion)
|
||||||
|
Dim FileIsSnapshot As Boolean = FileVersion.Contains("预览版") OrElse Not FileVersion.Contains(".")
|
||||||
|
Dim InstanceIsSnapshot As Boolean = Instance.Version.VanillaName.Contains("snapshot") OrElse Not Instance.Version.VanillaName.Contains(".")
|
||||||
|
If FileIsSnapshot <> InstanceIsSnapshot Then
|
||||||
|
'只有一种是预览版
|
||||||
|
Return False
|
||||||
|
ElseIf Not FileIsSnapshot AndAlso Not InstanceIsSnapshot Then
|
||||||
|
'都不是预览版
|
||||||
|
Return FileVersion = Instance.Version.VanillaName
|
||||||
|
Else
|
||||||
|
'都是预览版
|
||||||
|
Dim FileIsNewFormat As Boolean = FileVersion.Contains(".") AndAlso Val(FileVersion.BeforeFirst(".")) > 1
|
||||||
|
Dim InstanceIsNewFormat As Boolean = Instance.Version.Drop > 250
|
||||||
|
If FileIsNewFormat <> InstanceIsNewFormat Then
|
||||||
|
'只有一种是新格式快照
|
||||||
|
Return False
|
||||||
|
ElseIf FileIsNewFormat AndAlso InstanceIsNewFormat Then
|
||||||
|
'都是新格式快照
|
||||||
|
Return FileVersion.BeforeFirst(" ") = Instance.Version.VanillaName.BeforeFirst("-")
|
||||||
|
Else
|
||||||
|
'都是旧格式快照
|
||||||
|
If FileVersion.Contains("w") AndAlso Instance.Version.VanillaName.Contains("w") Then
|
||||||
|
'都是 w 快照
|
||||||
|
Return FileVersion = Instance.Version.VanillaName
|
||||||
|
Else
|
||||||
|
'不全是 w 快照
|
||||||
|
Return True '只能假定相同,无法判断
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End Function) Then Return False
|
||||||
End If
|
End If
|
||||||
'加载器
|
'加载器
|
||||||
If Not AllowedLoaders.Any() Then Return True '无要求
|
If Not AllowedLoaders.Any() Then Return True '无要求
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ echo 你可以在 PCL 的 [设置 → 启动选项] 中查看已安装的 java
|
|||||||
echo ------------------------------
|
echo ------------------------------
|
||||||
echo 如果提示 ""You need to agree to the EULA in order to run the server"",请打开 eula.txt,按说明阅读并同意 Minecraft EULA 后,将该文件最后一行中的 eula=false 改为 eula=true。
|
echo 如果提示 ""You need to agree to the EULA in order to run the server"",请打开 eula.txt,按说明阅读并同意 Minecraft EULA 后,将该文件最后一行中的 eula=false 改为 eula=true。
|
||||||
echo ------------------------------
|
echo ------------------------------
|
||||||
""java"" -server -XX:+UseG1GC -Xmx4096M -Xms1024M -XX:+UseCompressedOops -jar {Id}-server.jar nogui
|
""java"" -server -XX:+UseG1GC -Xmx6144M -Xms1024M -jar {Id}-server.jar nogui
|
||||||
echo ----------------------
|
echo ----------------------
|
||||||
echo 服务端已停止。
|
echo 服务端已停止。
|
||||||
pause"
|
pause"
|
||||||
@@ -2102,7 +2102,7 @@ Retry:
|
|||||||
Dim OptiFineAsMod As Boolean = Request.OptiFineEntry IsNot Nothing AndAlso Modable '选择了 OptiFine 与任意 Mod 加载器
|
Dim OptiFineAsMod As Boolean = Request.OptiFineEntry IsNot Nothing AndAlso Modable '选择了 OptiFine 与任意 Mod 加载器
|
||||||
If OptiFineAsMod Then
|
If OptiFineAsMod Then
|
||||||
Log("[Download] OptiFine 将作为 Mod 进行下载")
|
Log("[Download] OptiFine 将作为 Mod 进行下载")
|
||||||
If Request.LiteLoaderEntry IsNot Nothing
|
If Request.LiteLoaderEntry IsNot Nothing Then
|
||||||
OptiFineFolder = ModsTempFolder & Request.MinecraftName & "\" '#8147
|
OptiFineFolder = ModsTempFolder & Request.MinecraftName & "\" '#8147
|
||||||
Else
|
Else
|
||||||
OptiFineFolder = ModsTempFolder
|
OptiFineFolder = ModsTempFolder
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
<local:ExportOption
|
<local:ExportOption
|
||||||
Title="整合包重要数据"
|
Title="整合包重要数据"
|
||||||
Description="脚本文件、内置资源包、数据包等"
|
Description="脚本文件、内置资源包、数据包等"
|
||||||
Rules="addons/|multiblocked/|modpack-update-checker/|global_packs/|global_resource_packs/|global_data_packs/|optional_data_packs/|moonlight-global-datapacks/|maps/|icon.png|mods-resourcepacks/|matmos/|resource_assorts/|resource_assorts.json|patchouli_books/|datapacks/|kubejs*/|!kubejs*/probe/|!kubejs*/exported/|!kubejs*/jsconfig.json|!kubejs*/README.txt|openloader/|worldshape/|resources/|scripts/|structures/|fontfiles/|oresources/|packmenu/|craftpresence/|pointblanks/|template*/|!template*/playerdata/|!template*/stats/"
|
Rules="hotai/|bansoukou/|addons/|multiblocked/|modpack-update-checker/|global_packs/|global_resource_packs/|global_data_packs/|optional_data_packs/|moonlight-global-datapacks/|maps/|icon.png|mods-resourcepacks/|matmos/|resource_assorts/|resource_assorts.json|patchouli_books/|datapacks/|kubejs*/|!kubejs*/probe/|!kubejs*/exported/|!kubejs*/jsconfig.json|!kubejs*/README.txt|openloader/|worldshape/|resources/|scripts/|structures/|fontfiles/|oresources/|packmenu/|craftpresence/|pointblanks/|template*/|!template*/playerdata/|!template*/stats/"
|
||||||
DefaultChecked="True" />
|
DefaultChecked="True" />
|
||||||
</local:MyCheckBox.Tag>
|
</local:MyCheckBox.Tag>
|
||||||
</local:MyCheckBox>
|
</local:MyCheckBox>
|
||||||
|
|||||||
@@ -368,9 +368,7 @@ Public Class PageInstanceExport
|
|||||||
CheckOptionsPcl.Checked = Ini.GetOrDefault("IncludeLauncher", True)
|
CheckOptionsPcl.Checked = Ini.GetOrDefault("IncludeLauncher", True)
|
||||||
CheckOptionsPclCustom.Checked = Ini.GetOrDefault("IncludeLauncherCustom", True)
|
CheckOptionsPclCustom.Checked = Ini.GetOrDefault("IncludeLauncherCustom", True)
|
||||||
CheckAdvancedInclude.Checked = Ini.GetOrDefault("DontCheckHostedAssets", False)
|
CheckAdvancedInclude.Checked = Ini.GetOrDefault("DontCheckHostedAssets", False)
|
||||||
If Not CheckAdvancedInclude.Checked Then '#7979,加个特判
|
If Not CheckAdvancedInclude.Checked Then CheckAdvancedModrinth.Checked = Ini.GetOrDefault("ModrinthUploadMode", False) '#7979,加个特判
|
||||||
CheckAdvancedModrinth.Checked = Ini.GetOrDefault("ModrinthUploadMode", False)
|
|
||||||
End If
|
|
||||||
ConfigPackPath = Ini.GetOrDefault("PackPath", Nothing)
|
ConfigPackPath = Ini.GetOrDefault("PackPath", Nothing)
|
||||||
'导出内容段
|
'导出内容段
|
||||||
RulesOverrides = Segments(1).Replace(vbCr, vbLf).Replace(vbLf & vbLf, vbLf).Split(vbLf).ToList
|
RulesOverrides = Segments(1).Replace(vbCr, vbLf).Replace(vbLf & vbLf, vbLf).Split(vbLf).ToList
|
||||||
|
|||||||
@@ -850,22 +850,22 @@ Install:
|
|||||||
'构造请求
|
'构造请求
|
||||||
Dim QueryList As New List(Of SearchEntry(Of McMod))
|
Dim QueryList As New List(Of SearchEntry(Of McMod))
|
||||||
For Each Entry As McMod In McModLoader.Output
|
For Each Entry As McMod In McModLoader.Output
|
||||||
Dim SearchSource As New List(Of KeyValuePair(Of String, Double))
|
Dim SearchSources As New List(Of SearchSource)
|
||||||
SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.DisplayName, 1))
|
SearchSources.Add(New SearchSource(Entry.DisplayName, 1))
|
||||||
SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.FileName, 1))
|
SearchSources.Add(New SearchSource(Entry.FileName, 1))
|
||||||
If Entry.Version IsNot Nothing Then
|
If Entry.Version IsNot Nothing Then
|
||||||
SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Version, 0.2))
|
SearchSources.Add(New SearchSource(Entry.Version, 0.2))
|
||||||
End If
|
End If
|
||||||
If Entry.Description IsNot Nothing AndAlso Entry.Description <> "" Then
|
If Entry.Description IsNot Nothing AndAlso Entry.Description <> "" Then
|
||||||
SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Description, 0.4))
|
SearchSources.Add(New SearchSource(Entry.Description, 0.4))
|
||||||
End If
|
End If
|
||||||
If Entry.Comp IsNot Nothing Then
|
If Entry.Comp IsNot Nothing Then
|
||||||
If Entry.Comp.RawName <> Entry.DisplayName Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.RawName, 1))
|
If Entry.Comp.RawName <> Entry.DisplayName Then SearchSources.Add(New SearchSource(Entry.Comp.RawName, 1))
|
||||||
If Entry.Comp.TranslatedName <> Entry.Comp.RawName Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.TranslatedName, 1))
|
If Entry.Comp.TranslatedName <> Entry.Comp.RawName Then SearchSources.Add(New SearchSource(Entry.Comp.TranslatedName, 1))
|
||||||
If Entry.Comp.Description <> Entry.Description Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.Description, 0.4))
|
If Entry.Comp.Description <> Entry.Description Then SearchSources.Add(New SearchSource(Entry.Comp.Description, 0.4))
|
||||||
SearchSource.Add(New KeyValuePair(Of String, Double)(String.Join("", Entry.Comp.Tags), 0.2))
|
SearchSources.Add(New SearchSource(String.Join("", Entry.Comp.Tags), 0.2))
|
||||||
End If
|
End If
|
||||||
QueryList.Add(New SearchEntry(Of McMod) With {.Item = Entry, .SearchSource = SearchSource})
|
QueryList.Add(New SearchEntry(Of McMod) With {.Item = Entry, .SearchSource = SearchSources})
|
||||||
Next
|
Next
|
||||||
'进行搜索
|
'进行搜索
|
||||||
SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=6, MinBlurSimilarity:=0.35).Select(Function(r) r.Item).ToList
|
SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=6, MinBlurSimilarity:=0.35).Select(Function(r) r.Item).ToList
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</local:MyCard>
|
</local:MyCard>
|
||||||
<local:MyCard Margin="0,0,0,15" Title="游戏内存">
|
<local:MyCard Margin="0,0,0,15" Title="内存分配">
|
||||||
<StackPanel Margin="25,40,25,15">
|
<StackPanel Margin="25,40,25,15">
|
||||||
<local:MyHint x:Name="LabRamWarn" Text="32 位 Java 只能分配最多 1 GB 的内存。强烈建议换用 64 位的 Java!" Theme="Yellow" Margin="0,0,0,12" />
|
<local:MyHint x:Name="LabRamWarn" Text="32 位 Java 只能分配最多 1 GB 的内存。强烈建议换用 64 位的 Java!" Theme="Yellow" Margin="0,0,0,12" />
|
||||||
<Grid Margin="0,0,0,3">
|
<Grid Margin="0,0,0,3">
|
||||||
@@ -204,6 +204,8 @@
|
|||||||
<RowDefinition Height="9" />
|
<RowDefinition Height="9" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="9" />
|
<RowDefinition Height="9" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
|
<RowDefinition Height="9" />
|
||||||
<RowDefinition Height="31" />
|
<RowDefinition Height="31" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@@ -213,12 +215,24 @@
|
|||||||
Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
|
Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
|
||||||
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数" Margin="0,0,25,0" />
|
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数" Margin="0,0,25,0" />
|
||||||
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。
例如,输入 --demo 则会以试玩模式启动游戏。

支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。
也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。

若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
|
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。
例如,输入 --demo 则会以试玩模式启动游戏。

支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。
也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。

若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
|
||||||
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" />
|
<TextBlock VerticalAlignment="Center" Grid.Row="4" HorizontalAlignment="Left" Text="内存管理" Margin="0,0,25,0" />
|
||||||
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3"
|
<local:MyComboBox x:Name="ComboAdvanceGC" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionAdvanceGC" Grid.Column="1">
|
||||||
|
<local:MyComboBoxItem Content="跟随全局设置" IsSelected="True" />
|
||||||
|
<local:MyComboBoxItem Content="尽量使用 ZGC(激进)"
|
||||||
|
ToolTipService.BetweenShowDelay="0" ToolTip="在 Java 21+ 使用分代 ZGC,20~15 使用非分代的 ZGC,14- 使用 G1GC。
在 Java 25+ 额外添加 -XX:+UseCompactObjectHeaders。

覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
|
||||||
|
<local:MyComboBoxItem Content="尽量使用分代 ZGC(平衡)"
|
||||||
|
ToolTipService.BetweenShowDelay="0" ToolTip="在 Java 21+ 使用分代 ZGC,20- 使用 G1GC。
在 Java 25+ 额外添加 -XX:+UseCompactObjectHeaders。

覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
|
||||||
|
<local:MyComboBoxItem Content="仅 G1GC"
|
||||||
|
ToolTipService.BetweenShowDelay="0" ToolTip="固定使用以下参数:
-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M

覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
|
||||||
|
<local:MyComboBoxItem Content="不指定(可自定义)"
|
||||||
|
ToolTipService.BetweenShowDelay="0" ToolTip="不自动添加 GC 参数。

仅当选择此项时,你可以在 “Java 虚拟机参数” 设置中手动添加 GC 参数。" />
|
||||||
|
</local:MyComboBox>
|
||||||
|
<TextBlock Grid.Row="6" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" />
|
||||||
|
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="6" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3"
|
||||||
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。

在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
|
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。

在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
|
||||||
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="VersionAdvanceRunWait" Visibility="Collapsed"
|
<local:MyCheckBox Grid.Row="7" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="VersionAdvanceRunWait" Visibility="Collapsed"
|
||||||
Text="等待命令执行完成后再继续启动" Margin="0,5,0,0" />
|
Text="等待命令执行完成后再继续启动" Margin="0,5,0,0" />
|
||||||
<StackPanel Margin="0,12,0,4" Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Left">
|
<StackPanel Margin="0,12,0,4" Grid.Row="8" Grid.ColumnSpan="2" HorizontalAlignment="Left">
|
||||||
<local:MyCheckBox Height="28" Text="禁止更新 Mod" x:Name="CheckAdvanceDisableModUpdate" Tag="VersionAdvanceDisableModUpdate"
|
<local:MyCheckBox Height="28" Text="禁止更新 Mod" x:Name="CheckAdvanceDisableModUpdate" Tag="VersionAdvanceDisableModUpdate"
|
||||||
ToolTip="禁止为此版本更新 Mod,以防止整合包玩家误操作"
|
ToolTip="禁止为此版本更新 Mod,以防止整合包玩家误操作"
|
||||||
ToolTipService.Placement="Right" />
|
ToolTipService.Placement="Right" />
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
'高级设置
|
'高级设置
|
||||||
TextAdvanceJvm.Text = Setup.Get("VersionAdvanceJvm", Instance:=PageInstanceLeft.Instance)
|
TextAdvanceJvm.Text = Setup.Get("VersionAdvanceJvm", Instance:=PageInstanceLeft.Instance)
|
||||||
TextAdvanceGame.Text = Setup.Get("VersionAdvanceGame", Instance:=PageInstanceLeft.Instance)
|
TextAdvanceGame.Text = Setup.Get("VersionAdvanceGame", Instance:=PageInstanceLeft.Instance)
|
||||||
|
ComboAdvanceGC.SelectedIndex = Setup.Get("VersionAdvanceGC", Instance:=PageInstanceLeft.Instance)
|
||||||
TextAdvanceRun.Text = Setup.Get("VersionAdvanceRun", Instance:=PageInstanceLeft.Instance)
|
TextAdvanceRun.Text = Setup.Get("VersionAdvanceRun", Instance:=PageInstanceLeft.Instance)
|
||||||
CheckAdvanceRunWait.Checked = Setup.Get("VersionAdvanceRunWait", Instance:=PageInstanceLeft.Instance)
|
CheckAdvanceRunWait.Checked = Setup.Get("VersionAdvanceRunWait", Instance:=PageInstanceLeft.Instance)
|
||||||
If Setup.Get("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) = 2 Then
|
If Setup.Get("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) = 2 Then
|
||||||
@@ -86,6 +87,7 @@
|
|||||||
Setup.Reset("VersionRamOptimize", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionRamOptimize", Instance:=PageInstanceLeft.Instance)
|
||||||
Setup.Reset("VersionAdvanceJvm", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionAdvanceJvm", Instance:=PageInstanceLeft.Instance)
|
||||||
Setup.Reset("VersionAdvanceGame", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionAdvanceGame", Instance:=PageInstanceLeft.Instance)
|
||||||
|
Setup.Reset("VersionAdvanceGC", Instance:=PageInstanceLeft.Instance)
|
||||||
Setup.Reset("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance)
|
||||||
Setup.Reset("VersionAdvanceAssetsV2", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionAdvanceAssetsV2", Instance:=PageInstanceLeft.Instance)
|
||||||
Setup.Reset("VersionAdvanceJava", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionAdvanceJava", Instance:=PageInstanceLeft.Instance)
|
||||||
@@ -93,7 +95,6 @@
|
|||||||
Setup.Reset("VersionAdvanceRunWait", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionAdvanceRunWait", Instance:=PageInstanceLeft.Instance)
|
||||||
Setup.Reset("VersionAdvanceDisableJLW", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionAdvanceDisableJLW", Instance:=PageInstanceLeft.Instance)
|
||||||
Setup.Reset("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance)
|
||||||
|
|
||||||
Setup.Reset("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance)
|
Setup.Reset("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance)
|
||||||
JavaSearchLoader.Start(IsForceRestart:=True)
|
JavaSearchLoader.Start(IsForceRestart:=True)
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@
|
|||||||
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change
|
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change
|
||||||
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value, Instance:=PageInstanceLeft.Instance)
|
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value, Instance:=PageInstanceLeft.Instance)
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboRamOptimize.SelectionChanged
|
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboRamOptimize.SelectionChanged, ComboAdvanceGC.SelectionChanged
|
||||||
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex, Instance:=PageInstanceLeft.Instance)
|
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex, Instance:=PageInstanceLeft.Instance)
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub CheckBoxLikeComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndieV2.SelectionChanged
|
Private Shared Sub CheckBoxLikeComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndieV2.SelectionChanged
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ Public Class PageLaunchRight
|
|||||||
Url = "https://pcl-bmcl.milu.ink/"
|
Url = "https://pcl-bmcl.milu.ink/"
|
||||||
Case 7
|
Case 7
|
||||||
Log("[Page] 主页预设:主页市场")
|
Log("[Page] 主页预设:主页市场")
|
||||||
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/JingHai-Lingyun/Custom.xaml"
|
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/p/Homepages/Homepage.Market/Custom.xaml"
|
||||||
Case 8
|
Case 8
|
||||||
Log("[Page] 主页预设:更新日志")
|
Log("[Page] 主页预设:更新日志")
|
||||||
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Joker2184/UpdateHomepage.xaml"
|
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Joker2184/UpdateHomepage.xaml"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -144,13 +144,13 @@
|
|||||||
If Not Entry.ShowInSearch OrElse (Val(VersionBranchCode) <> 50 AndAlso Not Entry.ShowInSnapshot) Then Continue For
|
If Not Entry.ShowInSearch OrElse (Val(VersionBranchCode) <> 50 AndAlso Not Entry.ShowInSnapshot) Then Continue For
|
||||||
QueryList.Add(New SearchEntry(Of HelpEntry) With {
|
QueryList.Add(New SearchEntry(Of HelpEntry) With {
|
||||||
.Item = Entry,
|
.Item = Entry,
|
||||||
.SearchSource = New List(Of KeyValuePair(Of String, Double)) From {
|
.SearchSource = New List(Of SearchSource) From {
|
||||||
New KeyValuePair(Of String, Double)(Entry.Title, 1),
|
New SearchSource(Entry.Title, 1),
|
||||||
New KeyValuePair(Of String, Double)(Entry.Desc, 0.5),
|
New SearchSource(Entry.Desc, 0.5),
|
||||||
New KeyValuePair(Of String, Double)(Entry.Search, 1.5)
|
New SearchSource(Entry.Search, 1.5)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
'New KeyValuePair(Of String, Double)(If(Entry.IsEvent, If(Entry.EventData, ""), Entry.XamlContent), 0.2)
|
'New SearchSource(If(Entry.IsEvent, If(Entry.EventData, ""), Entry.XamlContent), 0.2)
|
||||||
Next
|
Next
|
||||||
'进行搜索,构造列表
|
'进行搜索,构造列表
|
||||||
Dim SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=5, MinBlurSimilarity:=0.08)
|
Dim SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=5, MinBlurSimilarity:=0.08)
|
||||||
|
|||||||
@@ -101,12 +101,13 @@
|
|||||||
{"LaunchArgumentWindowHeight", New SetupEntry(480)},
|
{"LaunchArgumentWindowHeight", New SetupEntry(480)},
|
||||||
{"LaunchArgumentWindowType", New SetupEntry(1)},
|
{"LaunchArgumentWindowType", New SetupEntry(1)},
|
||||||
{"LaunchArgumentRam", New SetupEntry(False, Source:=SetupSource.Registry)},
|
{"LaunchArgumentRam", New SetupEntry(False, Source:=SetupSource.Registry)},
|
||||||
{"LaunchAdvanceJvm", New SetupEntry("-XX:+UseG1GC -XX:-UseAdaptiveSizePolicy -XX:-OmitStackTraceInFastThrow -Djdk.lang.Process.allowAmbiguousCommands=true -Dfml.ignoreInvalidMinecraftCertificates=True -Dfml.ignorePatchDiscrepancies=True -Dlog4j2.formatMsgNoLookups=true")},
|
{"LaunchAdvanceJvm", New SetupEntry("-XX:-OmitStackTraceInFastThrow -Djdk.lang.Process.allowAmbiguousCommands=true -Dfml.ignoreInvalidMinecraftCertificates=True -Dfml.ignorePatchDiscrepancies=True -Dlog4j2.formatMsgNoLookups=true")},
|
||||||
{"LaunchAdvanceGame", New SetupEntry("")},
|
{"LaunchAdvanceGame", New SetupEntry("")},
|
||||||
{"LaunchAdvanceRun", New SetupEntry("")},
|
{"LaunchAdvanceRun", New SetupEntry("")},
|
||||||
{"LaunchAdvanceRunWait", New SetupEntry(True)},
|
{"LaunchAdvanceRunWait", New SetupEntry(True)},
|
||||||
{"LaunchAdvanceDisableJLW", New SetupEntry(False)},
|
{"LaunchAdvanceDisableJLW", New SetupEntry(False)},
|
||||||
{"LaunchAdvanceGraphicCard", New SetupEntry(True, Source:=SetupSource.Registry)},
|
{"LaunchAdvanceGraphicCard", New SetupEntry(True, Source:=SetupSource.Registry)},
|
||||||
|
{"LaunchAdvanceGC", New SetupEntry(1)},
|
||||||
{"LaunchRamType", New SetupEntry(0)},
|
{"LaunchRamType", New SetupEntry(0)},
|
||||||
{"LaunchRamCustom", New SetupEntry(15)},
|
{"LaunchRamCustom", New SetupEntry(15)},
|
||||||
{"LinkLastAutoJoinInviteCode", New SetupEntry("", Source:=SetupSource.Registry)},
|
{"LinkLastAutoJoinInviteCode", New SetupEntry("", Source:=SetupSource.Registry)},
|
||||||
@@ -180,6 +181,7 @@
|
|||||||
{"VersionAdvanceRunWait", New SetupEntry(True, Source:=SetupSource.Instance)},
|
{"VersionAdvanceRunWait", New SetupEntry(True, Source:=SetupSource.Instance)},
|
||||||
{"VersionAdvanceDisableJLW", New SetupEntry(False, Source:=SetupSource.Instance)},
|
{"VersionAdvanceDisableJLW", New SetupEntry(False, Source:=SetupSource.Instance)},
|
||||||
{"VersionAdvanceDisableModUpdate", New SetupEntry(False, Source:=SetupSource.Instance)},
|
{"VersionAdvanceDisableModUpdate", New SetupEntry(False, Source:=SetupSource.Instance)},
|
||||||
|
{"VersionAdvanceGC", New SetupEntry(0, Source:=SetupSource.Instance)},
|
||||||
{"VersionRamType", New SetupEntry(2, Source:=SetupSource.Instance)},
|
{"VersionRamType", New SetupEntry(2, Source:=SetupSource.Instance)},
|
||||||
{"VersionRamCustom", New SetupEntry(15, Source:=SetupSource.Instance)},
|
{"VersionRamCustom", New SetupEntry(15, Source:=SetupSource.Instance)},
|
||||||
{"VersionRamOptimize", New SetupEntry(0, Source:=SetupSource.Instance)},
|
{"VersionRamOptimize", New SetupEntry(0, Source:=SetupSource.Instance)},
|
||||||
@@ -529,72 +531,57 @@
|
|||||||
FrmMain.ImgBack.Margin = New Thickness(-(Value + 1) / 1.8)
|
FrmMain.ImgBack.Margin = New Thickness(-(Value + 1) / 1.8)
|
||||||
End Sub
|
End Sub
|
||||||
Public Sub UiBackgroundSuit(Value As Integer)
|
Public Sub UiBackgroundSuit(Value As Integer)
|
||||||
If IsNothing(FrmMain.ImgBack.Background) Then Return
|
If FrmMain.ImgBack.Background Is Nothing Then Return
|
||||||
Dim Width As Double = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
|
Dim Brush As ImageBrush = CType(FrmMain.ImgBack.Background, ImageBrush)
|
||||||
Dim Height As Double = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
|
|
||||||
If Value = 0 Then
|
If Value = 0 Then
|
||||||
'智能:当图片较小时平铺,较大时适应
|
'智能:当图片较小时平铺,较大时适应
|
||||||
If Width < FrmMain.PanMain.ActualWidth / 2 AndAlso Height < FrmMain.PanMain.ActualHeight / 2 Then
|
If Brush.ImageSource.Width < FrmMain.PanMain.ActualWidth / 2 AndAlso Brush.ImageSource.Height < FrmMain.PanMain.ActualHeight / 2 Then
|
||||||
Value = 4 '平铺
|
Value = 4 '平铺
|
||||||
Else
|
Else
|
||||||
Value = 2 '适应
|
Value = 2 '适应
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).TileMode = TileMode.None
|
Brush.Stretch = Stretch.UniformToFill
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Viewport = New Rect(0, 0, 1, 1)
|
Brush.TileMode = TileMode.None
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).ViewportUnits = BrushMappingMode.RelativeToBoundingBox
|
Brush.Viewport = New Rect(0, 0, 1, 1)
|
||||||
|
Brush.ViewportUnits = BrushMappingMode.RelativeToBoundingBox
|
||||||
Select Case Value
|
Select Case Value
|
||||||
Case 1 '居中
|
|
||||||
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Center
|
|
||||||
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Center
|
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
|
|
||||||
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
|
|
||||||
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
|
|
||||||
Case 2 '适应
|
Case 2 '适应
|
||||||
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Stretch
|
|
||||||
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Stretch
|
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.UniformToFill
|
|
||||||
FrmMain.ImgBack.Width = Double.NaN
|
|
||||||
FrmMain.ImgBack.Height = Double.NaN
|
|
||||||
Case 3 '拉伸
|
Case 3 '拉伸
|
||||||
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Stretch
|
Brush.Stretch = Stretch.Fill
|
||||||
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Stretch
|
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.Fill
|
|
||||||
FrmMain.ImgBack.Width = Double.NaN
|
|
||||||
FrmMain.ImgBack.Height = Double.NaN
|
|
||||||
Case 4 '平铺
|
Case 4 '平铺
|
||||||
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Stretch
|
Brush.Stretch = Stretch.None
|
||||||
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Stretch
|
Brush.TileMode = TileMode.Tile
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
|
Brush.Viewport = New Rect(0, 0, Brush.ImageSource.Width, Brush.ImageSource.Height)
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).TileMode = TileMode.Tile
|
Brush.ViewportUnits = BrushMappingMode.Absolute
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Viewport = New Rect(0, 0, CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width, CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height)
|
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).ViewportUnits = BrushMappingMode.Absolute
|
Case 1 '中
|
||||||
FrmMain.ImgBack.Width = Double.NaN
|
Brush.AlignmentX = AlignmentX.Center
|
||||||
FrmMain.ImgBack.Height = Double.NaN
|
Brush.AlignmentY = AlignmentY.Center
|
||||||
Case 5 '左上
|
Case 5 '左上
|
||||||
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Left
|
Brush.AlignmentX = AlignmentX.Left
|
||||||
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Top
|
Brush.AlignmentY = AlignmentY.Top
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
|
|
||||||
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
|
|
||||||
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
|
|
||||||
Case 6 '右上
|
Case 6 '右上
|
||||||
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Right
|
Brush.AlignmentX = AlignmentX.Right
|
||||||
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Top
|
Brush.AlignmentY = AlignmentY.Top
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
|
|
||||||
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
|
|
||||||
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
|
|
||||||
Case 7 '左下
|
Case 7 '左下
|
||||||
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Left
|
Brush.AlignmentX = AlignmentX.Left
|
||||||
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Bottom
|
Brush.AlignmentY = AlignmentY.Bottom
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
|
|
||||||
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
|
|
||||||
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
|
|
||||||
Case 8 '右下
|
Case 8 '右下
|
||||||
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Right
|
Brush.AlignmentX = AlignmentX.Right
|
||||||
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Bottom
|
Brush.AlignmentY = AlignmentY.Bottom
|
||||||
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
|
Case 9 '左
|
||||||
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
|
Brush.AlignmentX = AlignmentX.Left
|
||||||
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
|
Brush.AlignmentY = AlignmentY.Center
|
||||||
|
Case 10 '右
|
||||||
|
Brush.AlignmentX = AlignmentX.Right
|
||||||
|
Brush.AlignmentY = AlignmentY.Center
|
||||||
|
Case 11 '上
|
||||||
|
Brush.AlignmentX = AlignmentX.Center
|
||||||
|
Brush.AlignmentY = AlignmentY.Top
|
||||||
|
Case 12 '下
|
||||||
|
Brush.AlignmentX = AlignmentX.Center
|
||||||
|
Brush.AlignmentY = AlignmentY.Bottom
|
||||||
End Select
|
End Select
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</local:MyCard>
|
</local:MyCard>
|
||||||
<local:MyCard Margin="0,0,0,15" Title="游戏内存">
|
<local:MyCard Margin="0,0,0,15" Title="内存分配">
|
||||||
<StackPanel Margin="25,40,25,15">
|
<StackPanel Margin="25,40,25,15">
|
||||||
<local:MyHint x:Name="LabRamWarn" Visibility="Visible" Text="32 位 Java 只能分配最多 1 GB 的内存。强烈建议换用 64 位的 Java!" Theme="Yellow" Margin="0,0,0,12" />
|
<local:MyHint x:Name="LabRamWarn" Visibility="Visible" Text="32 位 Java 只能分配最多 1 GB 的内存。强烈建议换用 64 位的 Java!" Theme="Yellow" Margin="0,0,0,12" />
|
||||||
<Grid Margin="0,0,0,3">
|
<Grid Margin="0,0,0,3">
|
||||||
@@ -231,6 +231,8 @@
|
|||||||
<RowDefinition Height="9" />
|
<RowDefinition Height="9" />
|
||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="9" />
|
||||||
|
<RowDefinition Height="28" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
@@ -249,13 +251,24 @@
|
|||||||
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
|
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
|
||||||
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="LaunchAdvanceRunWait" Visibility="Collapsed"
|
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="LaunchAdvanceRunWait" Visibility="Collapsed"
|
||||||
Text="等待命令执行完成后再继续启动" Margin="0,8,0,7" />
|
Text="等待命令执行完成后再继续启动" Margin="0,8,0,7" />
|
||||||
<StackPanel Margin="0,12,0,4" Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Left">
|
<TextBlock VerticalAlignment="Center" Grid.Row="7" HorizontalAlignment="Left" Text="内存管理" Margin="0,0,25,0" />
|
||||||
|
<local:MyComboBox x:Name="ComboAdvanceGC" Grid.Row="7" Grid.ColumnSpan="2" Tag="LaunchAdvanceGC" Grid.Column="1">
|
||||||
|
<local:MyComboBoxItem Content="尽量使用 ZGC(激进)"
|
||||||
|
ToolTipService.BetweenShowDelay="0" ToolTip="在 Java 21+ 使用分代 ZGC,20~15 使用非分代的 ZGC,14- 使用 G1GC。
在 Java 25+ 额外添加 -XX:+UseCompactObjectHeaders。

覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
|
||||||
|
<local:MyComboBoxItem Content="尽量使用分代 ZGC(平衡)" IsSelected="True"
|
||||||
|
ToolTipService.BetweenShowDelay="0" ToolTip="在 Java 21+ 使用分代 ZGC,20- 使用 G1GC。
在 Java 25+ 额外添加 -XX:+UseCompactObjectHeaders。

覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
|
||||||
|
<local:MyComboBoxItem Content="仅 G1GC"
|
||||||
|
ToolTipService.BetweenShowDelay="0" ToolTip="固定使用以下参数:
-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M

覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
|
||||||
|
<local:MyComboBoxItem Content="不指定(可自定义)"
|
||||||
|
ToolTipService.BetweenShowDelay="0" ToolTip="不自动添加 GC 参数。

仅当选择此项时,你可以在 “Java 虚拟机参数” 设置中手动添加 GC 参数。" />
|
||||||
|
</local:MyComboBox>
|
||||||
|
<StackPanel Margin="0,12,0,4" Grid.Row="8" Grid.ColumnSpan="2" HorizontalAlignment="Left">
|
||||||
<local:MyCheckBox Height="28" Text="禁用 Java Launch Wrapper" x:Name="CheckAdvanceDisableJLW" Tag="LaunchAdvanceDisableJLW"
|
<local:MyCheckBox Height="28" Text="禁用 Java Launch Wrapper" x:Name="CheckAdvanceDisableJLW" Tag="LaunchAdvanceDisableJLW"
|
||||||
ToolTipService.Placement="Right" ToolTip="PCL 会使用 Java Launch Wrapper 来修复老版本 Java 在中文路径下无法启动的问题。
如果这被反作弊拦截,或遇到其他问题,也可以将其关闭。" />
|
ToolTipService.Placement="Right" ToolTip="PCL 会使用 Java Launch Wrapper 来修复老版本 Java 在中文路径下无法启动的问题。
如果这被反作弊拦截,或遇到其他问题,也可以将其关闭。" />
|
||||||
<local:MyCheckBox Height="28" Text="使用高性能显卡" x:Name="CheckAdvanceGraphicCard" Tag="LaunchAdvanceGraphicCard"
|
<local:MyCheckBox Height="28" Text="使用高性能显卡" x:Name="CheckAdvanceGraphicCard" Tag="LaunchAdvanceGraphicCard"
|
||||||
ToolTipService.Placement="Right" ToolTip="自动在 Windows 设置 → 系统 → 屏幕 → 显示卡 中将 PCL 和 Java 改为使用高性能显卡。
如果同时有集成显卡和独立显卡,这能确保 MC 使用独立显卡进行渲染,以大幅提高帧率。" />
|
ToolTipService.Placement="Right" ToolTip="自动在 Windows 设置 → 系统 → 屏幕 → 显示卡 中将 PCL 和 Java 改为使用高性能显卡。
如果同时有集成显卡和独立显卡,这能确保 MC 使用独立显卡进行渲染,以大幅提高帧率。" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<local:MyHint Text="版本独立设置中还有更多高级选项可供调整。" Margin="0,5,0,10" Theme="Blue" Grid.Row="7" Grid.ColumnSpan="2"
|
<local:MyHint Text="版本独立设置中还有更多高级选项可供调整。" Margin="0,5,0,10" Theme="Blue" Grid.Row="9" Grid.ColumnSpan="2"
|
||||||
CanClose="True" RelativeSetup="HintMoreAdvancedSetup" />
|
CanClose="True" RelativeSetup="HintMoreAdvancedSetup" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</local:MyCard>
|
</local:MyCard>
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
TextAdvanceJvm.Text = Setup.Get("LaunchAdvanceJvm")
|
TextAdvanceJvm.Text = Setup.Get("LaunchAdvanceJvm")
|
||||||
TextAdvanceGame.Text = Setup.Get("LaunchAdvanceGame")
|
TextAdvanceGame.Text = Setup.Get("LaunchAdvanceGame")
|
||||||
TextAdvanceRun.Text = Setup.Get("LaunchAdvanceRun")
|
TextAdvanceRun.Text = Setup.Get("LaunchAdvanceRun")
|
||||||
|
ComboAdvanceGC.SelectedIndex = Setup.Get("LaunchAdvanceGC")
|
||||||
CheckAdvanceRunWait.Checked = Setup.Get("LaunchAdvanceRunWait")
|
CheckAdvanceRunWait.Checked = Setup.Get("LaunchAdvanceRunWait")
|
||||||
CheckAdvanceDisableJLW.Checked = Setup.Get("LaunchAdvanceDisableJLW")
|
CheckAdvanceDisableJLW.Checked = Setup.Get("LaunchAdvanceDisableJLW")
|
||||||
CheckAdvanceGraphicCard.Checked = Setup.Get("LaunchAdvanceGraphicCard")
|
CheckAdvanceGraphicCard.Checked = Setup.Get("LaunchAdvanceGraphicCard")
|
||||||
@@ -85,6 +86,7 @@
|
|||||||
Setup.Reset("LaunchAdvanceJvm")
|
Setup.Reset("LaunchAdvanceJvm")
|
||||||
Setup.Reset("LaunchAdvanceGame")
|
Setup.Reset("LaunchAdvanceGame")
|
||||||
Setup.Reset("LaunchAdvanceRun")
|
Setup.Reset("LaunchAdvanceRun")
|
||||||
|
Setup.Reset("LaunchAdvanceGC")
|
||||||
Setup.Reset("LaunchAdvanceRunWait")
|
Setup.Reset("LaunchAdvanceRunWait")
|
||||||
Setup.Reset("LaunchAdvanceDisableJLW")
|
Setup.Reset("LaunchAdvanceDisableJLW")
|
||||||
Setup.Reset("LaunchAdvanceGraphicCard")
|
Setup.Reset("LaunchAdvanceGraphicCard")
|
||||||
@@ -111,7 +113,7 @@
|
|||||||
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change
|
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change
|
||||||
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value)
|
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value)
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndieV2.SelectionChanged, ComboArgumentVisibie.SelectionChanged, ComboArgumentWindowType.SelectionChanged, ComboArgumentPriority.SelectionChanged
|
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndieV2.SelectionChanged, ComboArgumentVisibie.SelectionChanged, ComboArgumentWindowType.SelectionChanged, ComboArgumentPriority.SelectionChanged, ComboAdvanceGC.SelectionChanged
|
||||||
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex)
|
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex)
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckAdvanceRunWait.Change, CheckArgumentRam.Change, CheckAdvanceDisableJLW.Change, CheckAdvanceGraphicCard.Change
|
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckAdvanceRunWait.Change, CheckArgumentRam.Change, CheckAdvanceDisableJLW.Change, CheckAdvanceGraphicCard.Change
|
||||||
|
|||||||
@@ -94,10 +94,14 @@
|
|||||||
<local:MyComboBoxItem Content="适应" ToolTip="拉伸图片并保持长宽比不变,直至填满整个窗口" />
|
<local:MyComboBoxItem Content="适应" ToolTip="拉伸图片并保持长宽比不变,直至填满整个窗口" />
|
||||||
<local:MyComboBoxItem Content="拉伸" ToolTip="拉伸图片使其恰好填满整个窗口,很可能会导致长宽比的改变" />
|
<local:MyComboBoxItem Content="拉伸" ToolTip="拉伸图片使其恰好填满整个窗口,很可能会导致长宽比的改变" />
|
||||||
<local:MyComboBoxItem Content="平铺" />
|
<local:MyComboBoxItem Content="平铺" />
|
||||||
<local:MyComboBoxItem Content="居于左上" />
|
<local:MyComboBoxItem Content="左上" />
|
||||||
<local:MyComboBoxItem Content="居于右上" />
|
<local:MyComboBoxItem Content="右上" />
|
||||||
<local:MyComboBoxItem Content="居于左下" />
|
<local:MyComboBoxItem Content="左下" />
|
||||||
<local:MyComboBoxItem Content="居于右下" />
|
<local:MyComboBoxItem Content="右下" />
|
||||||
|
<local:MyComboBoxItem Content="左" />
|
||||||
|
<local:MyComboBoxItem Content="右" />
|
||||||
|
<local:MyComboBoxItem Content="上" />
|
||||||
|
<local:MyComboBoxItem Content="下" />
|
||||||
</local:MyComboBox>
|
</local:MyComboBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid x:Name="PanBackgroundOpacity" Height="22" Margin="0,0,0,7" Visibility="Collapsed">
|
<Grid x:Name="PanBackgroundOpacity" Height="22" Margin="0,0,0,7" Visibility="Collapsed">
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user