This commit is contained in:
龙腾猫跃
2025-07-22 21:09:24 +08:00
parent 3e474b89ef
commit add4153067
52 changed files with 2727 additions and 2094 deletions
+4
View File
@@ -30,6 +30,10 @@
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="13.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
+19 -43
View File
@@ -181,53 +181,29 @@ WaitRetry:
End Sub
'动态 DLL 调用
Private Shared AssemblyNAudio As Assembly
Private Shared AssemblyJson As Assembly
Private Shared AssemblyDialog As Assembly
Private Shared AssemblyImazenWebp As Assembly
Private Shared ReadOnly AssemblyNAudioLock As New Object
Private Shared ReadOnly AssemblyJsonLock As New Object
Private Shared ReadOnly AssemblyDialogLock As New Object
Private Shared ReadOnly AssemblyImazenWebpLock As New Object
Private Declare Function SetDllDirectory Lib "kernel32" Alias "SetDllDirectoryA" (lpPathName As String) As Boolean
Public Shared Function AssemblyResolve(sender As Object, args As ResolveEventArgs) As Assembly
If args.Name.StartsWithF("NAudio") Then
SyncLock AssemblyNAudioLock
If AssemblyNAudio Is Nothing Then
Log("[Start] 加载 DLL:NAudio")
AssemblyNAudio = Assembly.Load(GetResources("NAudio"))
End If
Return AssemblyNAudio
End SyncLock
ElseIf args.Name.StartsWithF("Newtonsoft.Json") Then
SyncLock AssemblyJsonLock
If AssemblyJson Is Nothing Then
Log("[Start] 加载 DLL:Json")
AssemblyJson = Assembly.Load(GetResources("Json"))
End If
Return AssemblyJson
End SyncLock
ElseIf args.Name.StartsWithF("Ookii.Dialogs.Wpf") Then
SyncLock AssemblyDialogLock
If AssemblyDialog Is Nothing Then
Log("[Start] 加载 DLL:Dialogs")
AssemblyDialog = Assembly.Load(GetResources("Dialogs"))
End If
Return AssemblyDialog
End SyncLock
ElseIf args.Name.StartsWithF("Imazen.WebP") Then
SyncLock AssemblyImazenWebpLock
If AssemblyImazenWebp Is Nothing Then
Log("[Start] 加载 DLL:Imazen.WebP")
AssemblyImazenWebp = Assembly.Load(GetResources("Imazen_WebP"))
SetDllDirectory(PathPure.TrimEnd("\"))
Public Shared Function AssemblyResolve(sender As Object, Args As ResolveEventArgs) As Assembly
'缓存
Static Prefixes As String() = {"NAudio", "Newtonsoft.Json", "Ookii.Dialogs.Wpf", "Imazen.WebP", "CacheCow.Common", "CacheCow.Client.FileStore", "CacheCow.Client", "System.Net.Http.Formatting"}
Static Locks As New Dictionary(Of String, Object)(StringComparer.Ordinal)
Static LoadedAssembly As New Dictionary(Of String, Assembly)(StringComparer.Ordinal)
'查找对应的 DLL
Dim Prefix As String = Prefixes.FirstOrDefault(Function(p) Args.Name.StartsWithF(p))
If Prefix Is Nothing Then Return Nothing
'加载 DLL
If Not Locks.ContainsKey(Prefix) Then Locks(Prefix) = New Object()
SyncLock Locks(Prefix)
If Not LoadedAssembly.ContainsKey(Prefix) Then
Log($"[Start] 加载 DLL:{Prefix}")
LoadedAssembly(Prefix) = Assembly.Load(GetResources(Prefix))
'WebP 特判
If Prefix = "Imazen.WebP" Then
SetDllDirectory(PathPure.TrimEnd("\"c))
WriteFile(PathPure & "libwebp.dll", GetResources("libwebp64"))
End If
Return AssemblyImazenWebp
End SyncLock
Else
Return Nothing
End If
Return LoadedAssembly(Prefix)
End SyncLock
End Function
'切换窗口
+33 -35
View File
@@ -83,6 +83,13 @@ Public Class FormMain
'3:BUG+ IMP* FEAT-
'2:BUG* IMP-
'1:BUG-
If LastVersion < 363 Then 'Snapshot 2.10.4
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:下载资源时,会单独记忆每种资源上次下载到的文件夹,以防混淆"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:网络底层框架与下载稳定性"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法启动一部分 LabyMod 和 GTNH 客户端"))
FeatureCount += 22
BugCount += 26
End If
If LastVersion < 362 Then 'Snapshot 2.10.3
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法安装部分使用老版本 PCL 导出的整合包"))
End If
@@ -204,8 +211,6 @@ Public Class FormMain
End Sub, "UpdateLog Output")
End Sub
Private ReadOnly Helper As New DragFileHelper()
'窗口加载
Private IsWindowLoadFinished As Boolean = False
Public Sub New()
@@ -228,7 +233,7 @@ Public Class FormMain
If Not Setup.IsUnset("LaunchArgumentIndie") Then
Log("[Start] 从老 PCL 迁移版本隔离")
Setup.Set("LaunchArgumentIndieV2", Setup.Get("LaunchArgumentIndie"))
ElseIf Not Setup.IsUnset("WindowHeight") Then
ElseIf Not Setup.IsUnset("LaunchVersionSelect") Then
Log("[Start] 从老 PCL 升级,但此前未调整版本隔离,使用老的版本隔离默认值")
Setup.Set("LaunchArgumentIndieV2", Setup.GetDefault("LaunchArgumentIndie"))
Else
@@ -244,36 +249,24 @@ Public Class FormMain
[AddHandler](DragDrop.DragOverEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True)
'加载 UI
InitializeComponent()
Opacity = 0
'旧代码
''开启管理员权限下的文件拖拽,但下列代码也没用(#2531)
'If IsAdmin() Then
' Log("[Start] PCL 正以管理员权限运行")
'开启管理员权限下的文件拖拽
If IsAdmin() Then
Static Helper As New DragHelper
AddHandler SourceInitialized,
Sub()
Dim WpfHelper As New WindowInteropHelper(Me)
Helper.HwndIntPtrSource = HwndSource.FromHwnd(WpfHelper.Handle)
Helper.AddHook()
End Sub
AddHandler Closing, Sub() Helper.RemoveDragHook()
AddHandler Helper.DragDrop, Sub() FileDrag(Helper.DropFilePaths)
End If
'If IsAdmin() Then '下列代码没用(#2531)
' ChangeWindowMessageFilter(&H233, 1)
' ChangeWindowMessageFilter(&H4A, 1)
' ChangeWindowMessageFilter(&H49, 1)
'End If
'开启管理员权限下的文件拖拽
If IsAdmin() Then
AddHandler Me.SourceInitialized,
Sub(sender, e)
Dim wpfHelper As New WindowInteropHelper(Me)
Helper.HwndIntPtrSource = HwndSource.FromHwnd(wpfHelper.Handle)
Helper.AddHook()
End Sub
AddHandler Me.Closing,
Sub(sender, e)
Helper.RemoveDragHook()
End Sub
AddHandler Helper.DragDrop,
Sub(sender, e)
Me.FileDrag(Helper.DropFilePaths)
End Sub
End If
'切换到首页
If Not IsNothing(FrmLaunchLeft.Parent) Then FrmLaunchLeft.SetValue(ContentPresenter.ContentProperty, Nothing)
If Not IsNothing(FrmLaunchRight.Parent) Then FrmLaunchRight.SetValue(ContentPresenter.ContentProperty, Nothing)
@@ -390,7 +383,7 @@ Public Class FormMain
Catch ex As Exception
Log(ex, "清理自动更新文件失败")
End Try
End Sub, "Start Loader", ThreadPriority.Lowest)
End Sub, "初始化", ThreadPriority.Lowest)
Log("[Start] 第三阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
End Sub
@@ -616,11 +609,12 @@ Public Class FormMain
'按键事件
Private Sub FormMain_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If e.IsRepeat Then Return
'调用弹窗:回车选择第一个,Esc 选择最后一个
If PanMsg.Children.Count > 0 Then
'修复按下 Alt 后误认为弹出系统菜单导致的冻结
If e.SystemKey = Key.LeftAlt OrElse e.SystemKey = Key.RightAlt Then e.Handled = True
'在有弹窗时:回车选择第一个,Esc 选择最后一个
If PanMsg.Children.Any Then
If e.Key = Key.Enter Then
CType(PanMsg.Children(0), Object).Btn1_Click()
Return
ElseIf e.Key = Key.Escape Then
Dim Msg As Object = PanMsg.Children(0)
If TypeOf Msg IsNot MyMsgInput AndAlso TypeOf Msg IsNot MyMsgSelect AndAlso Msg.Btn3.Visibility = Visibility.Visible Then
@@ -630,9 +624,14 @@ Public Class FormMain
Else
Msg.Btn1_Click()
End If
End If
Return
End If
End If
'==========================
' 在没有弹窗时:继续检查……
'==========================
'按 ESC 返回上一级
If e.Key = Key.Escape Then TriggerPageBack()
'更改隐藏版本可见性
@@ -666,8 +665,6 @@ Public Class FormMain
FrmLaunchLeft.LaunchButtonClick()
End If
End If
'修复按下 Alt 后误认为弹出系统菜单导致的冻结
If e.SystemKey = Key.LeftAlt OrElse e.SystemKey = Key.RightAlt Then e.Handled = True
End Sub
Private Sub FormMain_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseDown
'鼠标侧键返回上一级
@@ -732,6 +729,7 @@ Public Class FormMain
End Sub
Private Sub FrmMain_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop
Try
ShowWindowToTop()
If e.Data.GetDataPresent(DataFormats.Text) Then
'获取文本
Try
+29 -13
View File
@@ -13,13 +13,13 @@ Public Module ModBase
#Region "声明"
'下列版本信息由更新器自动修改
Public Const VersionBaseName As String = "2.10.3" '不含分支前缀的显示用版本名
Public Const VersionStandardCode As String = "2.10.3." & VersionBranchCode '标准格式的四段式版本号
Public Const VersionBaseName As String = "2.10.4" '不含分支前缀的显示用版本名
Public Const VersionStandardCode As String = "2.10.4." & VersionBranchCode '标准格式的四段式版本号
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
#If BETA Then
Public Const VersionCode As Integer = 361 'Release
#Else
Public Const VersionCode As Integer = 362 'Snapshot
Public Const VersionCode As Integer = 363 'Snapshot
#End If
'自动生成的版本信息
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -1551,7 +1551,7 @@ RetryDir:
''' <summary>
''' 获取 JSON 对象。
''' </summary>
Public Function GetJson(Data As String)
Public Function GetJson(Data As String) As JToken
Try
Return JsonConvert.DeserializeObject(Data, New JsonSerializerSettings With {.DateTimeZoneHandling = DateTimeZoneHandling.Local})
Catch ex As Exception
@@ -2131,6 +2131,19 @@ RetryDir:
End Function
End Class
''' <summary>
''' 将二维数组转换为字典。
''' </summary>
<Extension> Public Function ToDictionary(Of T)(arr As T(,)) As Dictionary(Of T, T)
Dim result As New Dictionary(Of T, T)
If arr.Length = 0 Then Return result
If arr.GetLength(1) <> 2 Then Throw New ArgumentException("数组必须为两列,第一列为 Key,第二列为 Value。")
For i As Integer = 0 To arr.GetLength(0) - 1
result(arr(i, 0)) = arr(i, 1)
Next
Return result
End Function
''' <summary>
''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。
''' </summary>
@@ -2179,10 +2192,10 @@ RetryDir:
End Function
''' <summary>
''' 判断当前系统语言是否为 zh-CN。
''' 判断当前系统语言是否为中文。
''' </summary>
Public Function IsSystemLanguageChinese() As Boolean
Return CultureInfo.CurrentCulture.Name = "zh-CN" OrElse CultureInfo.CurrentUICulture.Name = "zh-CN"
Return CultureInfo.CurrentCulture.Name.StartsWithF("zh-") OrElse CultureInfo.CurrentUICulture.Name.StartsWithF("zh-")
End Function
Private Uuid As Integer = 1
@@ -2225,6 +2238,9 @@ NextElement:
Next i
Return ResultArray
End Function
<Extension> Public Function Any(Arr As UIElementCollection) As Boolean
Return Arr?.Count > 0
End Function
''' <summary>
''' 获取格式类似于“11:08:52.037”的当前时间的字符串。
@@ -2462,7 +2478,7 @@ NextElement:
''' </summary>
Public Sub RunInThread(Action As Action)
If RunInUi() Then
RunInNewThread(Action, "Runtime Invoke " & GetUuid() & "#")
RunInNewThread(Action, "Invoke " & GetUuid())
Else
Action()
End If
@@ -2760,11 +2776,11 @@ Retry:
Using Reader As New XamlXmlReader(Stream)
While Reader.Read()
For Each BlackListType In {GetType(WebBrowser), GetType(Frame), GetType(MediaElement), GetType(ObjectDataProvider), GetType(XamlReader), GetType(Window), GetType(XmlDataProvider)}
If Reader.Type IsNot Nothing AndAlso BlackListType.IsAssignableFrom(Reader.Type.UnderlyingType) Then Throw New UnauthorizedAccessException($"不允许使用 {BlackListType.Name} 类型。")
If Reader.Value IsNot Nothing AndAlso Reader.Value = BlackListType.Name Then Throw New UnauthorizedAccessException($"不允许使用 {BlackListType.Name} 值。")
If Reader.Type IsNot Nothing AndAlso BlackListType.IsAssignableFrom(Reader.Type.UnderlyingType) Then Throw New UnauthorizedAccessException($"基于安全考虑,不允许使用 {BlackListType.Name} 类型。")
If Reader.Value IsNot Nothing AndAlso Reader.Value = BlackListType.Name Then Throw New UnauthorizedAccessException($"基于安全考虑,不允许使用 {BlackListType.Name} 值。")
Next
For Each BlackListMember In {"Code", "FactoryMethod", "Static"}
If Reader.Member IsNot Nothing AndAlso Reader.Member.Name = BlackListMember Then Throw New UnauthorizedAccessException($"不允许使用 {BlackListMember} 成员。")
If Reader.Member IsNot Nothing AndAlso Reader.Member.Name = BlackListMember Then Throw New UnauthorizedAccessException($"基于安全考虑,不允许使用 {BlackListMember} 成员。")
Next
End While
End Using
@@ -2922,7 +2938,7 @@ Retry:
'处理错误会导致再次调用 Log() 导致无限循环
'输出日志
Dim AppendText As String = "[" & GetTimeNow() & "] " & Text & vbCrLf '减轻同步锁占用
Dim AppendText As String = $"[{GetTimeNow()}] <{If(Thread.CurrentThread.Name = "", "主线程", Thread.CurrentThread.Name)}> {Text}{vbCrLf}" '减轻同步锁占用
If ModeDebug Then
SyncLock LogListLock
LogList.Append(AppendText)
@@ -2986,7 +3002,7 @@ Retry:
Dim ExFull As String = Desc & ":" & GetExceptionDetail(Ex)
'输出日志
Dim AppendText As String = "[" & GetTimeNow() & "] " & Desc & ":" & GetExceptionDetail(Ex, True) & vbCrLf '减轻同步锁占用
Dim AppendText As String = $"[{GetTimeNow()}] <{If(Thread.CurrentThread.Name = "", "主线程", Thread.CurrentThread.Name)}> {Desc}:{GetExceptionDetail(Ex, True)}{vbCrLf}" '减轻同步锁占用
If ModeDebug Then
SyncLock LogListLock
LogList.Append(AppendText)
@@ -3048,7 +3064,7 @@ Retry:
If ForceOpenLog OrElse (ShowMsgbox AndAlso MyMsgBox("若你在汇报一个 Bug,请点击 打开文件夹 按钮,并上传 Log(1~5).txt 中包含错误信息的文件。" & vbCrLf & "游戏崩溃一般与启动器无关,请不要因为游戏崩溃而提交反馈。", "反馈提交提醒", "打开文件夹", "不需要") = 1) Then
OpenExplorer(Path & "PCL\Log1.txt")
End If
OpenWebsite("https://github.com/Hex-Dragon/PCL2/issues/")
OpenWebsite("https://github.com/Meloong-Git/PCL/issues/")
End Sub
Public Function CanFeedback(ShowHint As Boolean) As Boolean
If False.Equals(PageSetupSystem.IsLauncherNewest) Then
@@ -339,7 +339,7 @@
[Error] = ex
State = LoadState.Failed
End Try
End Sub) With {.Name = Name, .Priority = ThreadPriority}
End Sub) With {.Name = "L/" & Name, .Priority = ThreadPriority}
LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted
End Sub
Public Overrides Sub Abort()
File diff suppressed because it is too large Load Diff
@@ -1076,7 +1076,7 @@ Retry:
Try
'获取工程列表
Log("[Comp] 开始从 CurseForge 获取工程列表:" & CurseForgeUrl)
Dim RequestResult As JObject = DlModRequest(CurseForgeUrl, IsJson:=True)
Dim RequestResult As JObject = DlModRequest(CurseForgeUrl)
Task.Progress += 0.2
Dim ProjectList As New List(Of CompProject)
For Each JsonEntry As JObject In RequestResult("data")
@@ -1107,7 +1107,7 @@ Retry:
Sub()
Try
Log("[Comp] 开始从 Modrinth 获取工程列表:" & ModrinthUrl)
Dim RequestResult As JObject = DlModRequest(ModrinthUrl, IsJson:=True)
Dim RequestResult As JObject = DlModRequest(ModrinthUrl)
Task.Progress += 0.2
Dim ProjectList As New List(Of CompProject)
For Each JsonEntry As JObject In RequestResult("hits")
@@ -1396,7 +1396,7 @@ Retry:
'DownloadAddress
Dim Url = Data("downloadUrl").ToString
If Url = "" Then Url = $"https://media.forgecdn.net/files/{CInt(Id.ToString.Substring(0, 4))}/{CInt(Id.ToString.Substring(4))}/{FileName}"
Url = Url.Replace(FileName, Net.WebUtility.UrlEncode(FileName)) '对文件名进行编码
Url = Url.Replace(FileName, WebUtility.UrlEncode(FileName)) '对文件名进行编码
DownloadUrls = HandleCurseForgeDownloadUrls(Url) '对脑残 CurseForge 的下载地址进行多种修正
DownloadUrls.AddRange(DownloadUrls.Select(Function(u) DlSourceModGet(u)).ToList) '添加镜像源,这个写法是为了让镜像源排在后面
DownloadUrls = DownloadUrls.Distinct.ToList '最终去重
@@ -1492,9 +1492,8 @@ Retry:
Return {
Url.Replace("-service.overwolf.wtf", ".forgecdn.net").Replace("://edge.", "://mediafilez.").Replace("://media.", "://mediafilez."),
Url.Replace("://edge.", "://mediafilez.").Replace("://media.", "://mediafilez."),
Url.Replace("-service.overwolf.wtf", ".forgecdn.net").Replace("://edge.", "://media."),
Url.Replace("-service.overwolf.wtf", ".forgecdn.net"),
Url.Replace("://edge.", "://media."),
Url.Replace("://media.", "://edge."),
Url
}.Distinct.ToList
End Function
@@ -1591,27 +1590,40 @@ Retry:
If CompProjectCache.ContainsKey(ProjectId) Then '存在缓存
TargetProject = CompProjectCache(ProjectId)
ElseIf FromCurseForge Then 'CurseForge
TargetProject = New CompProject(DlModRequest("https://api.curseforge.com/v1/mods/" & ProjectId, IsJson:=True)("data"))
TargetProject = New CompProject(DlModRequest("https://api.curseforge.com/v1/mods/" & ProjectId)("data"))
Else 'Modrinth
TargetProject = New CompProject(DlModRequest("https://api.modrinth.com/v2/project/" & ProjectId, IsJson:=True))
TargetProject = New CompProject(DlModRequest("https://api.modrinth.com/v2/project/" & ProjectId))
End If
'获取工程对象的文件列表
If Not CompFilesCache.ContainsKey(ProjectId) Then '有缓存也不能直接返回,这时候前置可能没获取(#5173)
Log("[Comp] 开始获取文件列表:" & ProjectId)
Dim ResultJsonArray As JArray
Dim ResultJsonArray As JArray = Nothing
If FromCurseForge Then
'CurseForge
For RetryCount As Integer = 0 To 2
Dim ResultJson As JObject = DlModRequest($"https://api.curseforge.com/v1/mods/{ProjectId}/files?pageSize=" &
(10000 + RetryCount)) '每次重试多请求一个文件,以避免触发 CDN 缓存
'HMCL 一次性请求了 10000 个文件,虽然不知道会不会出问题但先这样吧……(#5522)
ResultJsonArray = DlModRequest($"https://api.curseforge.com/v1/mods/{ProjectId}/files?pageSize=10000", IsJson:=True)("data")
'之前只请求一部分文件的方法备份如下:
'If TargetProject.Type = CompType.Mod Then 'Mod 使用每个版本最新的文件
' ResultJsonArray = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(TargetProject.CurseForgeFileIds, ",") & "]}", "application/json"))("data")
' ResultJsonArray = DlModRequest("https://api.curseforge.com/v1/mods/files", HttpMethod.Post, "{""fileIds"": [" & Join(TargetProject.CurseForgeFileIds, ",") & "]}", "application/json")("data")
'Else '否则使用全部文件
' ResultJsonArray = DlModRequest($"https://api.curseforge.com/v1/mods/{ProjectId}/files?pageSize=999", IsJson:=True)("data")
' ResultJsonArray = DlModRequest($"https://api.curseforge.com/v1/mods/{ProjectId}/files?pageSize=999")("data")
'End If
If ResultJson("pagination")("resultCount").ToObject(Of Integer) = ResultJson("pagination")("totalCount").ToObject(Of Integer) Then
ResultJsonArray = ResultJson("data")
Exit For
ElseIf RetryCount < 2 Then
Log($"[Comp] CurseForge 返回的文件列表存在缺失,即将进行第 {RetryCount + 1} 次重试", LogLevel.Debug) '#6224
Log($"[Comp] 返回的原始内容如下:{vbCrLf}{ResultJson}")
Else
Log($"[Comp] CurseForge 返回的文件列表存在缺失,返回的原始内容如下:{vbCrLf}{ResultJson}")
Throw New Exception("CurseForge 返回的文件列表存在缺失")
End If
Next
Else
'Modrinth
ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version", IsJson:=True)
ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version")
End If
CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)).
Where(Function(a) a.Available).ToList.
@@ -1625,10 +1637,10 @@ Retry:
Log($"[Comp] {ProjectId} 文件列表中还需要获取信息的前置:{Join(UndoneDeps, ",")}")
Dim Projects As JArray
If TargetProject.FromCurseForge Then
Projects = GetJson(DlModRequest("https://api.curseforge.com/v1/mods",
"POST", "{""modIds"": [" & Join(UndoneDeps, ",") & "]}", "application/json"))("data")
Projects = DlModRequest("https://api.curseforge.com/v1/mods",
HttpMethod.Post, "{""modIds"": [" & Join(UndoneDeps, ",") & "]}", "application/json")("data")
Else
Projects = DlModRequest($"https://api.modrinth.com/v2/projects?ids=[""{Join(UndoneDeps, """,""")}""]", IsJson:=True)
Projects = DlModRequest($"https://api.modrinth.com/v2/projects?ids=[""{Join(UndoneDeps, """,""")}""]")
End If
For Each Project In Projects
Dim Unused As New CompProject(Project) '在 New 的时候会添加缓存以便之后读取
@@ -1018,9 +1018,9 @@ NextStack:
End If
Case CrashReason.特定实体导致崩溃
If Additional.Count = 1 Then
Results.Add("游戏似乎因为实体 " & Additional.First & " 出现了问题。\n\n你可以创建一个新世界,并生成一个该实体,然后观察游戏的运行情况:\n - 若正常运行,则是该实体导致出错,你或许需要使用一些方式删除此实体。\n - 若仍然出错,问题就可能来自其他原因……\h")
Results.Add("游戏似乎因为实体 " & Additional.First & " 出现了问题。\n\n你可以创建一个新世界,并生成一个该实体,然后观察游戏的运行情况。\h")
Else
Results.Add("游戏似乎因为世界中的某些实体出现了问题。\n\n你可以创建一个新世界,并生成各种实体,观察游戏的运行情况:\n - 若正常运行,则是某些实体导致出错,你或许需要删除该世界。\n - 若仍然出错,问题就可能来自其他原因……\h")
Results.Add("游戏似乎因为世界中的某些实体出现了问题。\n\n你可以创建一个新世界,并生成各种实体,然后观察游戏的运行情况。\h")
End If
Case CrashReason.OptiFine与Forge不兼容
Results.Add("由于 OptiFine 与当前版本的 Forge 不兼容,导致了游戏崩溃。\n\n请前往 OptiFine 官网(https://optifine.net/downloads)查看 OptiFine 所兼容的 Forge 版本,并严格按照对应版本重新安装游戏。")
@@ -198,7 +198,7 @@
Private IsNewClientVersionHinted As Boolean = False
Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult))
Dim StartTime As Long = GetTimeTick()
Dim Json As JObject = NetGetCodeByRequestRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json", IsJson:=True)
Dim Json As JObject = GetJson(NetRequestByClientRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json"))
Try
Dim Versions As JArray = Json("versions")
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
@@ -235,7 +235,7 @@
''' </summary>
Public DlClientListBmclapiLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain)
Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of String, DlClientListResult))
Dim Json As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json", IsJson:=True)
Dim Json As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json"))
Try
Dim Versions As JArray = Json("versions")
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
@@ -377,7 +377,7 @@
''' </summary>
Public DlOptiFineListOfficialLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Official", AddressOf DlOptiFineListOfficialMain)
Private Sub DlOptiFineListOfficialMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
Dim Result As String = NetGetCodeByClient("https://optifine.net/downloads", Encoding.Default)
Dim Result As String = NetRequestByClientRetry("https://optifine.net/downloads", Encoding:=Encoding.Default)
If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
Try
'获取所有版本信息
@@ -413,7 +413,7 @@
''' </summary>
Public DlOptiFineListBmclapiLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Bmclapi", AddressOf DlOptiFineListBmclapiMain)
Private Sub DlOptiFineListBmclapiMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
Dim Json As JArray = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/optifine/versionList", IsJson:=True)
Dim Json As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/optifine/versionList"))
Try
Dim Versions As New List(Of DlOptiFineListEntry)
For Each Token As JObject In Json
@@ -483,7 +483,7 @@
''' </summary>
Public DlForgeListOfficialLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Official", AddressOf DlForgeListOfficialMain)
Private Sub DlForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
Dim Result As String = NetGetCodeByRequestRetry("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.2.4.html", Encoding.Default, "text/html", UseBrowserUserAgent:=True)
Dim Result As String = NetRequestByClientRetry("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.2.4.html", Encoding:=Encoding.Default, Accept:="text/html", UseBrowserUserAgent:=True)
If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
'获取所有版本信息
Dim Names As List(Of String) = RegexSearch(Result, "(?<=a href=""index_)[0-9.]+(_pre[0-9]?)?(?=.html)")
@@ -497,7 +497,7 @@
''' </summary>
Public DlForgeListBmclapiLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Bmclapi", AddressOf DlForgeListBmclapiMain)
Private Sub DlForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
Dim Result As String = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/forge/minecraft", Encoding.Default)
Dim Result As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/minecraft", Encoding:=Encoding.Default)
If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
'获取所有版本信息
Dim Names As List(Of String) = RegexSearch(Result, "[0-9.]+(_pre[0-9]?)?")
@@ -629,7 +629,7 @@
Public Sub DlForgeVersionOfficialMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
Dim Result As String
Try
Result = NetGetCodeByLoader("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_" &
Result = NetRequestByLoader("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_" &
Loader.Input.Replace("-", "_") & '兼容 Forge 1.7.10-pre4,#4057
".html", UseBrowserUserAgent:=True)
Catch ex As Exception
@@ -700,9 +700,8 @@
''' Forge 版本列表,BMCLAPI。
''' </summary>
Public Sub DlForgeVersionBmclapiMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
Dim Json As JArray = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/forge/minecraft/" &
Loader.Input.Replace("-", "_"), '兼容 Forge 1.7.10-pre4,#4057
IsJson:=True)
Dim Json As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/minecraft/" &
Loader.Input.Replace("-", "_"))) '兼容 Forge 1.7.10-pre4,#4057
Dim Versions As New List(Of DlForgeVersionEntry)
Try
Dim Recommended As String = McDownloadForgeRecommendedGet(Loader.Input)
@@ -836,8 +835,8 @@
Public DlNeoForgeListOfficialLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Official", AddressOf DlNeoForgeListOfficialMain)
Private Sub DlNeoForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
'获取版本列表 JSON
Dim ResultLatest As String = NetGetCodeByLoader("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge", UseBrowserUserAgent:=True, IsJson:=True)
Dim ResultLegacy As String = NetGetCodeByLoader("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge", UseBrowserUserAgent:=True, IsJson:=True)
Dim ResultLatest As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge")
Dim ResultLegacy As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge")
If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
'解析
Try
@@ -854,8 +853,8 @@
Public DlNeoForgeListBmclapiLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Bmclapi", AddressOf DlNeoForgeListBmclapiMain)
Public Sub DlNeoForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
'获取版本列表 JSON
Dim ResultLatest As String = NetGetCodeByLoader("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/neoforge", UseBrowserUserAgent:=True, IsJson:=True)
Dim ResultLegacy As String = NetGetCodeByLoader("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/forge", UseBrowserUserAgent:=True, IsJson:=True)
Dim ResultLatest As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/neoforge")
Dim ResultLegacy As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/forge")
If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
'解析
Try
@@ -960,7 +959,7 @@
''' </summary>
Public DlLiteLoaderListOfficialLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Official", AddressOf DlLiteLoaderListOfficialMain)
Private Sub DlLiteLoaderListOfficialMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
Dim Result As JObject = NetGetCodeByRequestRetry("https://dl.liteloader.com/versions/versions.json", IsJson:=True)
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://dl.liteloader.com/versions/versions.json"))
Try
Dim Json As JObject = Result("versions")
Dim Versions As New List(Of DlLiteLoaderListEntry)
@@ -988,7 +987,7 @@
''' </summary>
Public DlLiteLoaderListBmclapiLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Bmclapi", AddressOf DlLiteLoaderListBmclapiMain)
Private Sub DlLiteLoaderListBmclapiMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
Dim Result As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json", IsJson:=True)
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json"))
Try
Dim Json As JObject = Result("versions")
Dim Versions As New List(Of DlLiteLoaderListEntry)
@@ -1059,7 +1058,7 @@
''' </summary>
Public DlFabricListOfficialLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Official", AddressOf DlFabricListOfficialMain)
Private Sub DlFabricListOfficialMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
Dim Result As JObject = NetGetCodeByRequestRetry("https://meta.fabricmc.net/v2/versions", IsJson:=True)
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://meta.fabricmc.net/v2/versions"))
Try
Dim Output = New DlFabricListResult With {.IsOfficial = True, .SourceName = "Fabric 官方源", .Value = Result}
If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
@@ -1074,7 +1073,7 @@
''' </summary>
Public DlFabricListBmclapiLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Bmclapi", AddressOf DlFabricListBmclapiMain)
Private Sub DlFabricListBmclapiMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
Dim Result As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/fabric-meta/v2/versions", IsJson:=True)
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/fabric-meta/v2/versions"))
Try
Dim Output = New DlFabricListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Result}
If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
@@ -1101,50 +1100,14 @@
#Region "DlMod | Mod 镜像源请求"
''' <summary>
''' 对可能涉及 Mod 镜像源的请求进行处理,返回字符串或 JObject。
''' 调用 NetGetCodeByRequest,会进行重试。
''' </summary>
Public Function DlModRequest(Url As String, Optional IsJson As Boolean = False) As Object
Dim Urls As New List(Of KeyValuePair(Of String, Integer))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 5))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 20))
'Dim McimUrl As String = DlSourceModGet(Url)
'If McimUrl <> Url Then
' Select Case Setup.Get("ToolDownloadMod")
' Case 0
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 5))
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 15))
' Case 1
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 5))
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 5))
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 15))
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
' Case Else
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 5))
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 15))
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
' End Select
'End If
Dim Exs As String = ""
For Each Source In Urls
Try
Return NetGetCodeByRequestOnce(Source.Key, Encode:=Encoding.UTF8, Timeout:=Source.Value * 1000, IsJson:=IsJson, UseBrowserUserAgent:=True)
Catch ex As Exception
Exs += ex.Message + vbCrLf
End Try
Next
Throw New Exception(Exs)
End Function
''' <summary>
''' 对可能涉及 Mod 镜像源的请求进行处理。
''' 对可能涉及 Mod 镜像源的请求进行处理,返回 JToken。
''' 调用 NetRequest,会进行重试。
''' </summary>
Public Function DlModRequest(Url As String, Method As String, Data As String, ContentType As String) As String
Public Function DlModRequest(Url As String, Optional Method As HttpMethod = Nothing,
Optional Content As String = Nothing, Optional ContentType As String = Nothing) As JToken
Dim Urls As New List(Of KeyValuePair(Of String, Integer))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 5))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 20))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
'Dim McimUrl As String = DlSourceModGet(Url)
'If McimUrl <> Url Then
' Select Case Setup.Get("ToolDownloadMod")
@@ -1166,7 +1129,7 @@
Dim Exs As String = ""
For Each Source In Urls
Try
Return NetRequestOnce(Source.Key, Method, Data, ContentType, Timeout:=Source.Value * 1000)
Return GetJson(NetRequestByClient(Source.Key, Method, Content, ContentType, Timeout:=Source.Value * 1000, Encoding:=Encoding.UTF8))
Catch ex As Exception
Exs += ex.Message + vbCrLf
End Try
@@ -117,7 +117,7 @@
If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败")
If ModeDebug Then Log("[Java] Java 检查输出:" & PathFolder & "java.exe" & vbCrLf & Output)
If Output.Contains("/lib/ext exists") Then Throw New ApplicationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试")
If Output.Contains("a fatal error") Then Throw New ApplicationException("由于操作系统或 JVM 存在问题,无法运行该 Java。")
If Output.Contains("a fatal error") Then Throw New ApplicationException("无法运行该 Java,该 Java 或系统存在问题")
'获取详细信息
Dim VersionString = If(RegexSeek(Output, "(?<=version "")[^""]+"), If(RegexSeek(Output, "(?<=openjdk )[0-9]+"), "")).Replace("_", ".").Split("-").First
If VersionString.Split(".").Count > 4 Then VersionString = VersionString.Replace(".0.", ".") '#3493,VersionString = "21.0.2.0.2"
@@ -460,10 +460,12 @@ NoUserJava:
''' 将 Java 按照适用性排序。
''' </summary>
Public Function JavaSorter(Left As JavaEntry, Right As JavaEntry) As Boolean
Dim PathInfo As New DirectoryInfo(ShortenPath(Path))
Dim PathMcInfo As New DirectoryInfo(ShortenPath(PathMcFolder))
'1. 尽量在当前文件夹或当前 Minecraft 文件夹
Dim ProgramPathParent As String, MinecraftPathParent As String = ""
ProgramPathParent = If(New DirectoryInfo(Path).Parent, New DirectoryInfo(Path)).FullName
If PathMcFolder <> "" Then MinecraftPathParent = If(New DirectoryInfo(PathMcFolder).Parent, New DirectoryInfo(PathMcFolder)).FullName
ProgramPathParent = If(PathInfo.Parent, PathInfo).FullName
If PathMcFolder <> "" Then MinecraftPathParent = If(PathMcInfo.Parent, PathMcInfo).FullName
If Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Not Right.PathFolder.StartsWithF(ProgramPathParent) Then Return True
If Not Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Right.PathFolder.StartsWithF(ProgramPathParent) Then Return False
If PathMcFolder <> "" Then
@@ -530,7 +532,7 @@ NoUserJava:
If Disk.DriveType = DriveType.Network Then Continue For '跳过网络驱动器(#3705)
JavaSearchFolder(Disk.Name, JavaPreList, False)
Next
'查找 ~/.jdks 文件夹中的 Java
'查找 .jdks 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.jdks\", JavaPreList, False)
'查找 APPDATA 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\", JavaPreList, False)
@@ -680,8 +682,8 @@ Wait:
'若该目录有 Java,则加入结果
If File.Exists(Path & "javaw.exe") Then Results(Path) = Source
'查找其下的所有文件夹
'不应使用网易的 Java:https://github.com/HMeloong-Git/PCL/issues/1279#issuecomment-2761489121
Dim Keywords = {"java", "jdk", "env", "环境", "run", "软件", "jre", "mc", "dragon",
'不应使用网易的 Java:https://github.com/Meloong-Git/PCL/issues/1279#issuecomment-2761489121
Dim Keywords = {"java", "jdk", "env", "环境", "run", "软件", "jre", "mc", "dragon", "bin",
"soft", "cache", "temp", "corretto", "roaming", "users", "craft", "program", "世界", "net",
"游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", "client", "整合",
"应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot",
@@ -748,7 +750,7 @@ Wait:
Private LastJavaBaseDir As String = Nothing '用于在下载中断或失败时删除未完成下载的 Java 文件夹,防止残留只下了一半但 -version 能跑的 Java
Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile)))
Log("[Java] 开始获取 Java 下载信息")
Dim IndexFileStr As String = NetGetCodeByLoader(DlVersionListOrder(
Dim IndexFileStr As String = NetRequestByLoader(DlVersionListOrder(
{"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
{"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"}
), IsJson:=True)
@@ -760,7 +762,7 @@ Wait:
Dim Address As String = TargetEntry.Value("manifest")("url")
Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}")
'获取文件列表
Dim ListFileStr As String = NetGetCodeByLoader(DlSourceOrder({Address}, {Address.Replace("piston-meta.mojang.com", "bmclapi2.bangbang93.com")}), IsJson:=True)
Dim ListFileStr As String = NetRequestByLoader(DlSourceOrder({Address}, {Address.Replace("piston-meta.mojang.com", "bmclapi2.bangbang93.com")}), IsJson:=True)
LastJavaBaseDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\runtime\" & TargetEntry.Key & "\"
Dim Results As New List(Of NetFile)
For Each File As JProperty In CType(GetJson(ListFileStr), JObject)("files")
@@ -684,11 +684,10 @@ LoginFinish:
'发送登录请求
Dim RequestData As New JObject(
New JProperty("accessToken", AccessToken), New JProperty("clientToken", ClientToken), New JProperty("requestUser", True))
NetRequestRetry(
Url:=Data.Input.BaseUrl & "/validate",
Method:="POST",
Data:=RequestData.ToString(0),
Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh-CN"}},
NetRequestByClientRetry(
Data.Input.BaseUrl & "/validate", HttpMethod.Post,
Content:=RequestData.ToString(Newtonsoft.Json.Formatting.None),
Headers:={{"Accept-Language", "zh-CN"}},
ContentType:="application/json; charset=utf-8") '没有返回值的
'将登录结果输出
Data.Output.AccessToken = AccessToken
@@ -701,10 +700,9 @@ LoginFinish:
End Sub
Private Sub McLoginRequestRefresh(ByRef Data As LoaderTask(Of McLoginServer, McLoginResult), RequestUser As Boolean)
McLaunchLog("刷新登录开始(Refresh, " & Data.Input.Token & ")")
Dim LoginJson As JObject = GetJson(NetRequestRetry(
Url:=Data.Input.BaseUrl & "/refresh",
Method:="POST",
Data:=New JObject(
Dim LoginJson As JObject = GetJson(NetRequestByClientRetry(
Data.Input.BaseUrl & "/refresh", HttpMethod.Post,
Content:=New JObject(
New JProperty("selectedProfile", New JObject(
New JProperty("name", Setup.Get($"Cache{Data.Input.Token}Name")),
New JProperty("id", Setup.Get($"Cache{Data.Input.Token}Uuid"))
@@ -712,7 +710,7 @@ LoginFinish:
New JProperty("accessToken", Setup.Get($"Cache{Data.Input.Token}Access")),
New JProperty("requestUser", True)
).ToString(Newtonsoft.Json.Formatting.None),
Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh-CN"}},
Headers:={{"Accept-Language", "zh-CN"}},
ContentType:="application/json; charset=utf-8"))
'将登录结果输出
If LoginJson("selectedProfile") Is Nothing Then Throw New Exception("选择的角色 " & Setup.Get("Cache" & Data.Input.Token & "Name") & " 无效!")
@@ -739,11 +737,10 @@ LoginFinish:
New JProperty("username", Data.Input.UserName),
New JProperty("password", Data.Input.Password),
New JProperty("requestUser", True))
Dim LoginJson As JObject = GetJson(NetRequestRetry(
Url:=Data.Input.BaseUrl & "/authenticate",
Method:="POST",
Data:=RequestData.ToString(0),
Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh-CN"}},
Dim LoginJson As JObject = GetJson(NetRequestByClientRetry(
Data.Input.BaseUrl & "/authenticate", HttpMethod.Post,
Content:=RequestData.ToString(Newtonsoft.Json.Formatting.None),
Headers:={{"Accept-Language", "zh-CN"}},
ContentType:="application/json; charset=utf-8"))
'检查登录结果
If LoginJson("availableProfiles").Count = 0 Then
@@ -858,8 +855,9 @@ LoginFinish:
'初始请求
Retry:
McLaunchLog("开始微软登录步骤 1/6(原始登录)")
Dim PrepareJson As JObject = GetJson(NetRequestRetry("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", "POST",
$"client_id={OAuthClientId}&tenant=/consumers&scope=XboxLive.signin%20offline_access", "application/x-www-form-urlencoded"))
Dim PrepareJson As JObject = GetJson(NetRequestByClientRetry("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", HttpMethod.Post,
Content:=$"client_id={OAuthClientId}&tenant=/consumers&scope=XboxLive.signin%20offline_access",
Accept:="application/x-www-form-urlencoded"))
McLaunchLog("网页登录地址:" & PrepareJson("verification_uri").ToString)
'弹窗
@@ -888,9 +886,11 @@ Retry:
Dim Result As String
Try
Result = NetRequestMultiple("https://login.live.com/oauth20_token.srf", "POST",
$"client_id={OAuthClientId}&refresh_token={Uri.EscapeDataString(Code)}&grant_type=refresh_token&scope=XboxLive.signin%20offline_access",
"application/x-www-form-urlencoded", 2)
Result = NetRequestByClientMultiple("https://login.live.com/oauth20_token.srf", HttpMethod.Post,
Content:=$"client_id={OAuthClientId}&refresh_token={Uri.EscapeDataString(Code)}&grant_type=refresh_token&scope=XboxLive.signin%20offline_access",
ContentType:="application/x-www-form-urlencoded",
Headers:={{"Accept-Language", "en-US,en;q=0.5"}, {"X-Requested-With", "XMLHttpRequest"}},
ThreadCount:=2)
Catch ex As Exception
If ex.Message.ContainsF("must sign in again", True) OrElse ex.Message.ContainsF("password expired", True) OrElse
(ex.Message.Contains("refresh_token") AndAlso ex.Message.Contains("is not valid")) Then '#269
@@ -918,8 +918,8 @@ Retry:
""RelyingParty"": ""http://auth.xboxlive.com"",
""TokenType"": ""JWT""
}"
Dim Result As String = NetRequestMultiple("https://user.auth.xboxlive.com/user/authenticate", "POST", Request, "application/json", 3)
Dim Result As String = NetRequestByClientMultiple("https://user.auth.xboxlive.com/user/authenticate", HttpMethod.Post,
Content:=Request, ContentType:="application/json")
Dim ResultJson As JObject = GetJson(Result)
Dim XBLToken As String = ResultJson("Token").ToString
Return XBLToken
@@ -940,7 +940,8 @@ Retry:
}"
Dim Result As String
Try
Result = NetRequestMultiple("https://xsts.auth.xboxlive.com/xsts/authorize", "POST", Request, "application/json", 3)
Result = NetRequestByClientMultiple("https://xsts.auth.xboxlive.com/xsts/authorize", HttpMethod.Post,
Content:=Request, ContentType:="application/json")
Catch ex As Net.WebException
'参考 https://github.com/PrismarineJS/prismarine-auth/blob/master/src/common/Constants.js
If ex.Message.Contains("2148916227") Then
@@ -971,10 +972,15 @@ Retry:
End If
End Try
Try '这个 Try 块仅为了追踪 #6683 而添加
Dim ResultJson As JObject = GetJson(Result)
Dim XSTSToken As String = ResultJson("Token").ToString
Dim UHS As String = ResultJson("DisplayClaims")("xui")(0)("uhs").ToString
Return {XSTSToken, UHS}
Catch
Log("[Launch] 返回内容:" & vbCrLf & Result)
Throw
End Try
End Function
'微软登录步骤 4:从 {XSTSToken, UHS} 获取 Minecraft AccessToken
Private Function MsLoginStep4(Tokens As String()) As String
@@ -983,7 +989,8 @@ Retry:
Dim Request As String = New JObject(New JProperty("identityToken", $"XBL3.0 x={Tokens(1)};{Tokens(0)}")).ToString(0)
Dim Result As String
Try
Result = NetRequestRetry("https://api.minecraftservices.com/authentication/login_with_xbox", "POST", Request, "application/json")
Result = NetRequestByClientRetry("https://api.minecraftservices.com/authentication/login_with_xbox", HttpMethod.Post,
Content:=Request, ContentType:="application/json")
Catch ex As Net.WebException
Dim Message As String = GetExceptionSummary(ex)
If Message.Contains("(429)") Then
@@ -1005,7 +1012,8 @@ Retry:
Private Sub MsLoginStep5(AccessToken As String)
McLaunchLog("开始微软登录步骤 5/6")
Dim Result As String = NetRequestMultiple("https://api.minecraftservices.com/entitlements/mcstore", "GET", "", "application/json", 2, New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}})
Dim Result As String = NetRequestByClientMultiple("https://api.minecraftservices.com/entitlements/mcstore",
ContentType:="application/json", ThreadCount:=2, Headers:={{"Authorization", "Bearer " & AccessToken}})
Try
Dim ResultJson As JObject = GetJson(Result)
If Not (ResultJson.ContainsKey("items") AndAlso ResultJson("items").Any) Then
@@ -1026,7 +1034,8 @@ Retry:
Dim Result As String
Try
Result = NetRequestMultiple("https://api.minecraftservices.com/minecraft/profile", "GET", "", "application/json", 2, New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}})
Result = NetRequestByClientMultiple("https://api.minecraftservices.com/minecraft/profile",
ContentType:="application/json", ThreadCount:=2, Headers:={{"Authorization", "Bearer " & AccessToken}})
Catch ex As Net.WebException
Dim Message As String = GetExceptionSummary(ex)
If Message.Contains("(429)") Then
@@ -1099,7 +1108,7 @@ Retry:
If Len(Uuid) = 32 Then Return Uuid
'从官网获取
Try
Dim GotJson As JObject = NetGetCodeByRequestRetry("https://api.mojang.com/users/profiles/minecraft/" & Name, IsJson:=True)
Dim GotJson As JObject = GetJson(NetRequestByClientRetry("https://api.mojang.com/users/profiles/minecraft/" & Name))
If GotJson Is Nothing Then Throw New FileNotFoundException("正版玩家档案不存在(" & Name & ")")
Uuid = If(GotJson("id"), "")
Catch ex As Exception
@@ -1205,6 +1214,12 @@ Retry:
End If
End If
'LiteLoader 检测
If McVersionCurrent.Version.HasLiteLoader AndAlso McVersionCurrent.Version.IsStandardVersion Then '不管非标准版本
'最高 Java 8
MaxVer = If(New Version(1, 8, 999, 999) < MaxVer, New Version(1, 8, 999, 999), MaxVer)
End If
'统一通行证检测
If Setup.Get("LoginType") = McLoginType.Nide Then
'至少 Java 8u101
@@ -1356,16 +1371,6 @@ Retry:
If McLaunchJavaSelected.VersionCode >= 18 Then
If Not Arguments.Contains("-Dfile.encoding=") Then Arguments = "-Dfile.encoding=COMPAT " & Arguments
End If
'替换参数
Dim ReplaceArguments = McLaunchArgumentsReplace(McVersionCurrent, Loader)
If String.IsNullOrWhiteSpace(ReplaceArguments("${version_type}")) Then
'若自定义信息为空,则去掉该部分
Arguments = Arguments.Replace(" --versionType ${version_type}", "")
ReplaceArguments("${version_type}") = """"""
End If
For Each entry As KeyValuePair(Of String, String) In ReplaceArguments
Arguments = Arguments.Replace(entry.Key, If(entry.Value.Contains(" ") OrElse entry.Value.Contains(":\"), """" & entry.Value & """", entry.Value))
Next
'MJSB
Arguments = Arguments.Replace(" -Dos.name=Windows 10", " -Dos.name=""Windows 10""")
'全屏
@@ -1374,31 +1379,47 @@ Retry:
For Each Arg In CurrentLaunchOptions.ExtraArgs
Arguments += " " & Arg.Trim
Next
'自定义
Dim ArgumentGame As String = Setup.Get("VersionAdvanceGame", Version:=McVersionCurrent)
Arguments += " " & If(ArgumentGame = "", Setup.Get("LaunchAdvanceGame"), ArgumentGame)
'进行参数替换
Dim ReplaceArguments = McLaunchArgumentsReplace(McVersionCurrent, Loader)
If String.IsNullOrWhiteSpace(ReplaceArguments("${version_type}")) Then
'若自定义信息为空,则去掉该部分
Arguments = Arguments.Replace(" --versionType ${version_type}", "")
ReplaceArguments("${version_type}") = """"""
End If
Dim FinalArguments As String = ""
For Each Argument In Arguments.Split(" ")
For Each Entry As KeyValuePair(Of String, String) In ReplaceArguments
Argument = Argument.Replace(Entry.Key, Entry.Value)
Next
If (Argument.Contains(" ") OrElse Argument.Contains(":\")) AndAlso Not Argument.EndsWithF("""") Then Argument = $"""{Argument}"""
FinalArguments += Argument & " "
Next
FinalArguments = FinalArguments.TrimEnd
'进服
Dim Server As String = If(String.IsNullOrEmpty(CurrentLaunchOptions.ServerIp), Setup.Get("VersionServerEnter", McVersionCurrent), CurrentLaunchOptions.ServerIp)
If Server.Length > 0 Then
If McVersionCurrent.ReleaseTime > New Date(2023, 4, 4) Then
'QuickPlay
Arguments += $" --quickPlayMultiplayer ""{Server}"""
FinalArguments += $" --quickPlayMultiplayer ""{Server}"""
Else
'老版本
If Server.Contains(":") Then
'包含端口号
Arguments += " --server " & Server.Split(":")(0) & " --port " & Server.Split(":")(1)
FinalArguments += $" --server {Server.Split(":")(0)} --port {Server.Split(":")(1)}"
Else
'不包含端口号
Arguments += " --server " & Server & " --port 25565"
FinalArguments += $" --server {Server} --port 25565"
End If
If McVersionCurrent.Version.HasOptiFine Then Hint("OptiFine 与自动进入服务器可能不兼容,有概率导致材质丢失甚至游戏崩溃!", HintType.Critical)
End If
End If
'自定义
Dim ArgumentGame As String = Setup.Get("VersionAdvanceGame", Version:=McVersionCurrent)
Arguments += " " & If(ArgumentGame = "", Setup.Get("LaunchAdvanceGame"), ArgumentGame)
'输出
McLaunchLog("Minecraft 启动参数:")
McLaunchLog(Arguments)
McLaunchArgument = Arguments
McLaunchLog(FinalArguments)
McLaunchArgument = FinalArguments
End Sub
'Jvm 部分(第一段)
@@ -1424,12 +1445,12 @@ Retry:
End If
'Authlib-Injector
If McLoginLoader.Output.Type = "Auth" Then
If (McLaunchJavaSelected.VersionCode >= 6) Then DataList.Add("-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT")
If McLaunchJavaSelected.VersionCode >= 6 Then DataList.Add("-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT") '信任系统根证书(5252#)
Dim Server As String = If(McLoginLoader.Input.Type = McLoginType.Legacy,
"http://hiperauth.tech/api/yggdrasil-hiper/", 'HiPer 登录
Setup.Get("VersionServerAuthServer", McVersionCurrent))
Try
Dim Response As String = NetGetCodeByRequestRetry(Server, Encoding.UTF8)
Dim Response As String = NetRequestByClientRetry(Server, Encoding:=Encoding.UTF8)
DataList.Insert(0, "-javaagent:""" & PathPure & "authlib-injector.jar""=" & Server &
" -Dauthlibinjector.side=client" &
" -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response)))
@@ -1494,12 +1515,12 @@ NextVersion:
End If
'Authlib-Injector
If McLoginLoader.Output.Type = "Auth" Then
If (McLaunchJavaSelected.VersionCode >= 6) Then DataList.Add("-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT")
If McLaunchJavaSelected.VersionCode >= 6 Then DataList.Add("-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT") '信任系统根证书(5252#)
Dim Server As String = If(McLoginLoader.Input.Type = McLoginType.Legacy,
"http://hiperauth.tech/api/yggdrasil-hiper/", 'HiPer 登录
Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent))
Try
Dim Response As String = NetGetCodeByRequestRetry(Server, Encoding.UTF8)
Dim Response As String = NetRequestByClientRetry(Server, Encoding:=Encoding.UTF8)
DataList.Insert(0, "-javaagent:""" & PathPure & "authlib-injector.jar""=" & Server &
" -Dauthlibinjector.side=client" &
" -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response)))
@@ -1533,10 +1554,8 @@ NextVersion:
DeDuplicateDataList.Add(CurrentEntry.Trim.Replace("McEmu= ", "McEmu="))
Next
'#3511 的清理
DeDuplicateDataList.Remove("-XX:MaxDirectMemorySize=256M")
'去重
DeDuplicateDataList.Remove("-XX:MaxDirectMemorySize=256M") '#3511 的清理
Dim Result As String = Join(DeDuplicateDataList.Distinct.ToList, " ")
'添加 MainClass
@@ -169,8 +169,8 @@ Public Module ModMinecraft
_McVersionCurrent = value '由于有可能是 Nothing,导致无法初始化,才得这样弄一圈
_McVersionLast = value
If value Is Nothing Then Return
'重置缓存的 Mod 文件夹
PageDownloadCompDetail.CachedFolder = Nothing
'重置缓存的下载文件夹
PageDownloadCompDetail.CachedFolder.Clear()
'统一通行证重判
If AniControlEnabled = 0 AndAlso
Setup.Get("VersionServerNide", Version:=value) <> Setup.Get("CacheNideServer") AndAlso
@@ -440,6 +440,33 @@ VersionSearchFinish:
''' </summary>
Public ReleaseTime As New Date(1970, 1, 1, 15, 0, 0)
''' <summary>
''' 获取该版本的 JSON 路径。
''' </summary>
Public Function GetJsonPath() As String
Dim JsonPath As String = Path & Name & ".json"
If Not File.Exists(JsonPath) Then
'尝试寻找 JSON 文件
JsonPath = Nothing
For Each JsonCandidatePath In Directory.GetFiles(Path, "*.json")
Try
Dim JsonCandidate As JObject = GetJson(ReadFile(JsonCandidatePath))
If Not JsonCandidate.ContainsKey("mainClass") Then Continue For
If Not JsonCandidate.ContainsKey("type") Then Continue For
If Not JsonCandidate.ContainsKey("id") Then Continue For
Catch
End Try
JsonPath = JsonCandidatePath
Exit For
Next
If JsonPath Is Nothing Then
Throw New Exception($"未找到版本 JSON 文件:{Path}{Name}.json")
Else
Log("[Minecraft] 未找到同名版本 JSON,自动换用 " & JsonPath, LogLevel.Debug)
End If
End If
Return JsonPath
End Function
''' <summary>
''' 该版本的 Json 文本。
''' </summary>
@@ -452,17 +479,7 @@ VersionSearchFinish:
Return TrimedJson.StartsWithF("{") AndAlso TrimedJson.EndsWithF("}")
End Function
If _JsonText Is Nothing Then
Dim JsonPath As String = Path & Name & ".json"
If Not File.Exists(JsonPath) Then
'如果文件夹下只有一个 JSON 文件,则将其作为版本 JSON
Dim JsonFiles As String() = Directory.GetFiles(Path, "*.json")
If JsonFiles.Count = 1 Then
JsonPath = JsonFiles(0)
Log("[Minecraft] 未找到同名版本 JSON,自动换用 " & JsonPath, LogLevel.Debug)
Else
Throw New Exception($"未找到版本 JSON 文件:{Path}{Name}.json")
End If
End If
Dim JsonPath As String = GetJsonPath()
_JsonText = ReadFile(JsonPath)
'如果 ReadFile 失败会返回空字符串;这可能是由于文件被临时占用,故延时后重试
If Not FastJsonCheck(_JsonText) Then
@@ -540,9 +557,15 @@ Recheck:
'继续循环
If Inherit.InheritVersion = InheritVersion Then Throw New Exception("版本依赖项出现嵌套:" & InheritVersion)
InheritVersion = Inherit.InheritVersion
'合并
'合并 Libraries 项:子版本放在前面,父版本放在后面(5978#:如果多个 jar 包中含有相同的类,Java 8 和之前的版本按照 -cp 指定的顺序选择第一个)
Dim CurrentLib As JArray = _JsonObject("libraries").DeepClone()
For Each LibToken In Inherit.JsonObject("libraries")
CurrentLib.Add(LibToken)
Next
'合并其他项:子版本优先于父版本
Inherit.JsonObject.Merge(_JsonObject)
_JsonObject = Inherit.JsonObject
_JsonObject("libraries") = CurrentLib
GoTo Recheck
End If
Catch ex As Exception
@@ -580,21 +603,19 @@ Recheck:
Get
If Not JsonVersionInited Then
JsonVersionInited = True
If File.Exists(Path & Name & ".jar") Then
Try
If Not File.Exists($"{Path}{Name}.jar") Then Exit Try
Using JarArchive As New ZipArchive(New FileStream(Path & Name & ".jar", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
Dim VersionJson As ZipArchiveEntry = JarArchive.GetEntry("version.json")
If VersionJson IsNot Nothing Then
If VersionJson Is Nothing Then Exit Try
Using VersionJsonStream As New StreamReader(VersionJson.Open)
_JsonVersion = GetJson(VersionJsonStream.ReadToEnd)
End Using
End If
End Using
Catch ex As Exception
Log(ex, "从版本 jar 中读取 version.json 失败")
Log(ex, $"从版本 jar 中读取 version.json 失败({Path}{Name}.jar)")
End Try
End If
End If
Return _JsonVersion
End Get
End Property
@@ -1538,7 +1559,7 @@ OnLoaded:
''' 要求玩家选择一个皮肤文件,并进行相关校验。
''' </summary>
Public Function McSkinSelect() As McSkinInfo
Dim FileName As String = SelectFile("皮肤文件(*.png;*.jpg;*.webp)|*.png;*.jpg;*.webp", "选择皮肤文件")
Dim FileName As String = SelectFile("皮肤文件(*.png;*.jpg;*.jpeg;*.webp)|*.png;*.jpg;*.jpeg;*.webp", "选择皮肤文件")
'验证有效性
If FileName = "" Then Return New McSkinInfo With {.IsVaild = False}
@@ -1589,7 +1610,7 @@ OnLoaded:
Case Else
Throw New ArgumentException("皮肤地址种类无效:" & If(Type, "null"))
End Select
Dim SkinString = NetGetCodeByRequestRetry(Url & Uuid)
Dim SkinString = NetRequestByClientRetry(Url & Uuid)
If SkinString = "" Then Throw New Exception("皮肤返回值为空,可能是未设置自定义皮肤的用户")
'处理皮肤地址
Dim SkinValue As String
@@ -1611,7 +1632,7 @@ OnLoaded:
Throw New Exception("用户未设置自定义皮肤")
Else
Dim SkinUrl As String = SkinJson("textures")("skin")("url").ToString
SkinValue = If(SkinUrl.Contains("minecraft.net"),SkinUrl.Replace("http:", "https:"),SkinUrl)
SkinValue = If(SkinUrl.Contains("minecraft.net/"), SkinUrl.Replace("http://", "https://"), SkinUrl)
End If
'保存缓存
WriteIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", Uuid, SkinValue)
@@ -1628,9 +1649,9 @@ OnLoaded:
Dim FileAddress As String = PathTemp & "Cache\Skin\" & GetHash(Address) & ".png"
SyncLock McSkinDownloadLock
If Not File.Exists(FileAddress) Then
NetDownloadByClient(Address, FileAddress & NetDownloadEnd)
NetDownloadByClient(Address, FileAddress & ".PCLDownloading")
File.Delete(FileAddress)
FileSystem.Rename(FileAddress & NetDownloadEnd, FileAddress)
FileSystem.Rename(FileAddress & ".PCLDownloading", FileAddress)
Log("[Minecraft] 皮肤下载成功:" & FileAddress)
End If
Return FileAddress
@@ -1773,10 +1794,10 @@ OnLoaded:
'获取当前支持库列表
Log("[Minecraft] 获取支持库列表:" & Version.Name)
McLibListGet = McLibListGetWithJson(Version.JsonObject)
If Not IncludeVersionJar Then Return McLibListGet
Dim Result = McLibListGetWithJson(Version.JsonObject)
'需要添加原版 Jar
If IncludeVersionJar Then
Dim RealVersion As McVersion
Dim RequiredJar As String = Version.JsonObject("jar")?.ToString
If Version.IsHmclFormatJson OrElse RequiredJar Is Nothing Then
@@ -1813,21 +1834,20 @@ OnLoaded:
ClientSHA1 = Nothing
End If
'把所需的原版 Jar 添加进去
McLibListGet.Add(New McLibToken With {.LocalPath = RealVersion.Path & RealVersion.Name & ".jar", .Size = 0, .IsNatives = False, .Url = ClientUrl, .SHA1 = ClientSHA1})
Result.Add(New McLibToken With {.LocalPath = RealVersion.Path & RealVersion.Name & ".jar", .Size = 0, .IsNatives = False, .Url = ClientUrl, .SHA1 = ClientSHA1})
End If
Return Result
End Function
''' <summary>
''' 获取 Minecraft 某一版本忽视继承的支持库列表,即结果中没有继承项。
''' </summary>
Public Function McLibListGetWithJson(JsonObject As JObject, Optional KeepSameNameDifferentVersionResult As Boolean = False, Optional CustomMcFolder As String = Nothing) As List(Of McLibToken)
CustomMcFolder = If(CustomMcFolder, PathMcFolder)
Dim BasicArray As New List(Of McLibToken)
'添加基础 Json 项
Dim AllLibs As JArray = JsonObject("libraries")
'转换为 LibToken
For Each Library As JObject In AllLibs.Children
Dim BasicArray As New List(Of McLibToken)
For Each Library As JObject In CType(JsonObject("libraries"), JArray).Children
'清理 null 项(BakaXL 会把没有的项序列化为 null,但会被 Newtonsoft 转换为 JValue,导致 Is Nothing = false;这导致了 #409)
For i = Library.Properties.Count - 1 To 0 Step -1
@@ -1946,8 +1966,7 @@ OnLoaded:
Try
Log("[Minecraft] 开始获取统一通行证下载信息")
'测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/
DownloadInfo = GetJson(NetGetCodeByLoader({
"https://auth.mc-user.com:233/" & Setup.Get("VersionServerNide", Version:=Version)}, IsJson:=True))
DownloadInfo = GetJson(NetRequestByClientRetry("https://auth.mc-user.com:233/" & Setup.Get("VersionServerNide", Version:=Version)))
Catch ex As Exception
Log(ex, "获取统一通行证下载信息失败")
End Try
@@ -1969,10 +1988,9 @@ OnLoaded:
'获取下载信息
Try
Log("[Minecraft] 开始获取 Authlib-Injector 下载信息")
DownloadInfo = GetJson(NetGetCodeByLoader({
DownloadInfo = GetJson(NetRequestByClientRetry(
"https://authlib-injector.yushi.moe/artifact/latest.json",
"https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json"
}, IsJson:=True))
BackupUrl:="https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json"))
Catch ex As Exception
Log(ex, "获取 Authlib-Injector 下载信息失败")
End Try
@@ -2017,12 +2035,16 @@ OnLoaded:
'获取
For Each Token As McLibToken In Libs
'检查文件
Dim Checker As New FileChecker(ActualSize:=If(Token.Size = 0, -1, Token.Size), Hash:=Token.SHA1)
Dim Checker As FileChecker
If Token.Name.ContainsF("labymod") Then
Checker = New FileChecker '不检查 LabyMod 的文件,它们提供的文件校验信息是错的(#3225)
Else
Checker = New FileChecker(ActualSize:=If(Token.Size = 0, -1, Token.Size), Hash:=Token.SHA1)
End If
If Checker.Check(Token.LocalPath) Is Nothing Then Continue For
'文件不符合,添加下载
Dim Urls As New List(Of String)
If Token.Url Is Nothing AndAlso Token.Name = "net.minecraftforge:forge:universal" Then
'特判修复 Forge 部分 universal 文件缺失 URL(#5455)
If Token.Url Is Nothing AndAlso Token.Name = "net.minecraftforge:forge:universal" Then '特判修复 Forge 部分 universal 文件缺失 URL(#5455)
Token.Url = "https://maven.minecraftforge.net" & Token.LocalPath.Replace(CustomMcFolder & "libraries", "").Replace("\", "/")
End If
If Token.Url IsNot Nothing Then
@@ -2194,16 +2216,16 @@ OnLoaded:
Dim LocalPath As String
If Json("map_to_resources") IsNot Nothing AndAlso Json("map_to_resources").ToObject(Of Boolean) Then
'Remap
LocalPath = Version.PathIndie & "resources\" & File.Name.Replace("/", "\")
LocalPath = $"{Version.PathIndie}resources\{File.Name}"
ElseIf Json("virtual") IsNot Nothing AndAlso Json("virtual").ToObject(Of Boolean) Then
'Virtual
LocalPath = PathMcFolder & "assets\virtual\legacy\" & File.Name.Replace("/", "\")
LocalPath = $"{PathMcFolder}assets\virtual\legacy\{File.Name}"
Else
'正常
LocalPath = PathMcFolder & "assets\objects\" & Left(File.Value("hash").ToString, 2) & "\" & File.Value("hash").ToString
LocalPath = $"{PathMcFolder}assets\objects\{Left(File.Value("hash").ToString, 2)}\{File.Value("hash")}"
End If
Result.Add(New McAssetsToken With {
.LocalPath = LocalPath,
.LocalPath = LocalPath.Replace("/", "\"),
.SourcePath = File.Name,
.Hash = File.Value("hash").ToString,
.Size = File.Value("size").ToString
@@ -1,7 +1,7 @@
Imports System.IO.Compression
Public Module ModMod
Private Const LocalModCacheVersion As Integer = 7
Private Const LocalModCacheVersion As Integer = 8
Public Class McMod
@@ -946,8 +946,8 @@ Finished:
Try
'步骤 1:获取 Hash 与对应的工程 ID
Dim ModrinthHashes = Mods.Select(Function(m) m.ModrinthHash).ToList()
Dim ModrinthVersion = CType(GetJson(DlModRequest("https://api.modrinth.com/v2/version_files", "POST",
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")), JObject)
Dim ModrinthVersion As JObject = DlModRequest("https://api.modrinth.com/v2/version_files", HttpMethod.Post,
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")
Log($"[Mod] 从 Modrinth 获取到 {ModrinthVersion.Count} 个本地 Mod 的对应信息")
'步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系
If ModrinthVersion.Count = 0 Then Return
@@ -967,9 +967,8 @@ Finished:
Log($"[Mod] 需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息")
'步骤 3:获取工程信息
If Not ModrinthMapping.Any() Then Return
Dim ModrinthProject = CType(GetJson(DlModRequest(
$"https://api.modrinth.com/v2/projects?ids=[""{ModrinthMapping.Keys.Join(""",""")}""]",
"GET", "", "application/json")), JArray)
Dim ModrinthProject As JArray = DlModRequest(
$"https://api.modrinth.com/v2/projects?ids=[""{ModrinthMapping.Keys.Join(""",""")}""]")
For Each ProjectJson In ModrinthProject
Dim Project As New CompProject(ProjectJson)
For Each Entry In ModrinthMapping(Project.Id)
@@ -978,9 +977,9 @@ Finished:
Next
Log($"[Mod] 已从 Modrinth 获取本地 Mod 信息,继续获取更新信息")
'步骤 4:获取更新信息
Dim ModrinthUpdate = CType(GetJson(DlModRequest("https://api.modrinth.com/v2/version_files/update", "POST",
Dim ModrinthUpdate As JObject = DlModRequest("https://api.modrinth.com/v2/version_files/update", HttpMethod.Post,
$"{{""hashes"": [""{ModrinthMapping.SelectMany(Function(l) l.Value.Select(Function(m) m.ModrinthHash)).Join(""",""")}""], ""algorithm"": ""sha1"",
""loaders"": [""{ModLoaders.Join(""",""").ToLower}""],""game_versions"": [""{McVersion}""]}}", "application/json")), JObject)
""loaders"": [""{ModLoaders.Join(""",""").ToLower}""],""game_versions"": [""{McVersion}""]}}", "application/json")
For Each Entry In Mods
If Not ModrinthUpdate.ContainsKey(Entry.ModrinthHash) OrElse Entry.CompFile Is Nothing Then Continue For
Dim UpdateFile As New CompFile(ModrinthUpdate(Entry.ModrinthHash), CompType.Mod)
@@ -1015,8 +1014,8 @@ Finished:
CurseForgeHashes.Add(Entry.CurseForgeHash)
If Loader.IsAbortedWithThread(CurrentTaskThread) Then Return
Next
Dim CurseForgeRaw = CType(CType(GetJson(DlModRequest("https://api.curseforge.com/v1/fingerprints/432", "POST",
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")), JObject)("data")("exactMatches"), JContainer)
Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432", HttpMethod.Post,
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches")
Log($"[Mod] 从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地 Mod 的对应信息")
'步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系
If Not CurseForgeRaw.Any() Then Return
@@ -1038,8 +1037,8 @@ Finished:
Log($"[Mod] 需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息")
'步骤 3:获取工程信息
If Not CurseForgeMapping.Any() Then Return
Dim CurseForgeProject = CType(GetJson(DlModRequest("https://api.curseforge.com/v1/mods", "POST",
$"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")), JObject)("data")
Dim CurseForgeProject = DlModRequest("https://api.curseforge.com/v1/mods", HttpMethod.Post,
$"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")("data")
Dim UpdateFileIds As New Dictionary(Of Integer, List(Of McMod)) 'FileId -> 本地 Mod 文件列表
Dim FileIdToProjectSlug As New Dictionary(Of Integer, String)
For Each ProjectJson In CurseForgeProject
@@ -1079,8 +1078,8 @@ Finished:
Log($"[Mod] 已从 CurseForge 获取本地 Mod 信息,需要获取 {UpdateFileIds.Count} 个用于检查更新的文件信息")
'步骤 4:获取更新文件信息
If Not UpdateFileIds.Any() Then Return
Dim CurseForgeFiles = CType(GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST",
$"{{""fileIds"": [{UpdateFileIds.Keys.Join(",")}]}}", "application/json")), JObject)("data")
Dim CurseForgeFiles = DlModRequest("https://api.curseforge.com/v1/mods/files", HttpMethod.Post,
$"{{""fileIds"": [{UpdateFileIds.Keys.Join(",")}]}}", "application/json")("data")
Dim UpdateFiles As New Dictionary(Of McMod, CompFile)
For Each FileJson In CurseForgeFiles
Dim File As New CompFile(FileJson, CompType.Mod)
@@ -244,7 +244,7 @@ Retry:
'获取 Mod 下载信息
ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
Sub(Task As LoaderTask(Of Integer, JArray))
Task.Output = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json"))("data")
Task.Output = DlModRequest("https://api.curseforge.com/v1/mods/files", HttpMethod.Post, "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json")("data")
'如果文件已被删除,则 API 会跳过那一项
If ModList.Count > Task.Output.Count Then Throw New Exception("整合包中的部分 Mod 版本已被 Mod 作者删除,所以没法继续安装了,请向整合包作者反馈该问题")
End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s
+1 -4
View File
@@ -1,6 +1,5 @@
'由于包含加解密等安全信息,本文件中的部分代码已被删除
Imports System.Net.Http
Imports System.Security.Cryptography
Friend Module ModSecret
@@ -14,7 +13,6 @@ Friend Module ModSecret
'CurseForge API Key
Public CurseForgeAPIKey As String = If(Environment.GetEnvironmentVariable("PCL_CURSEFORGE_API_KEY"), "")
Friend Sub SecretOnApplicationStart()
'提升 UI 线程优先级
Thread.CurrentThread.Priority = ThreadPriority.Highest
@@ -73,7 +71,7 @@ Friend Module ModSecret
#Region "网络鉴权"
Friend Function SecretCdnSign(UrlWithMark As String)
Friend Function SecretCdnSign(UrlWithMark As String) As String
If Not UrlWithMark.EndsWithF("{CDN}") Then Return UrlWithMark
Return UrlWithMark.Replace("{CDN}", "").Replace(" ", "%20")
End Function
@@ -92,7 +90,6 @@ Friend Module ModSecret
If Url.Contains("api.curseforge.com") Then Req.Headers.Add("x-api-key", CurseForgeAPIKey)
End Sub
#End Region
#Region "字符串加解密"
@@ -1,59 +0,0 @@
Imports System.Net
Public Class CookieWebClient
Inherits WebClient
Public Sub New(container As CookieContainer, Headers As Dictionary(Of String, String))
Me.New(container)
For Each keyVal In Headers
Me.Headers(keyVal.Key) = keyVal.Value
Next
End Sub
Public Sub New()
Me.New(New CookieContainer())
End Sub
Public Sub New(container As CookieContainer)
Me.container = container
End Sub
Private Shadows ReadOnly container As New CookieContainer()
''' <summary>
''' 以毫秒为单位的超时。
''' </summary>
Public Timeout As Integer = 600000
Protected Overrides Function GetWebRequest(address As Uri) As WebRequest
Dim r As WebRequest = MyBase.GetWebRequest(address)
Dim request = TryCast(r, HttpWebRequest)
If request IsNot Nothing Then
request.CookieContainer = container
request.Timeout = Timeout
End If
Return r
End Function
Protected Overrides Function GetWebResponse(request As WebRequest, result As IAsyncResult) As WebResponse
Dim response As WebResponse = MyBase.GetWebResponse(request, result)
ReadCookies(response)
Return response
End Function
Protected Overrides Function GetWebResponse(request As WebRequest) As WebResponse
Dim response As WebResponse = MyBase.GetWebResponse(request)
ReadCookies(response)
Return response
End Function
Private Sub ReadCookies(r As WebResponse)
Dim response = TryCast(r, HttpWebResponse)
If response IsNot Nothing Then
Dim cookies As CookieCollection = response.Cookies
container.Add(cookies)
End If
End Sub
End Class
@@ -1,11 +1,10 @@
Imports System
'来源:https://blog.csdn.net/simpleman2000/article/details/140952294
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Windows.Interop
Public Class DragFileHelper
Public Class DragHelper
Public Event DragDrop As EventHandler
@@ -32,22 +31,22 @@ Public Class DragFileHelper
Public Property HwndIntPtrSource As HwndSource
Public Sub AddHook()
Me.RemoveDragHook()
Me.HwndIntPtrSource.AddHook(AddressOf WndProc)
Dim handle As IntPtr = Me.HwndIntPtrSource.Handle
RemoveDragHook()
HwndIntPtrSource.AddHook(AddressOf WndProc)
Dim handle As IntPtr = HwndIntPtrSource.Handle
If IsUserAnAdmin() Then RevokeDragDrop(handle)
DragAcceptFiles(handle, True)
ChangeMessageFilter(handle)
End Sub
Public Sub RemoveDragHook()
Me.HwndIntPtrSource.RemoveHook(AddressOf WndProc)
DragAcceptFiles(Me.HwndIntPtrSource.Handle, False)
HwndIntPtrSource.RemoveHook(AddressOf WndProc)
DragAcceptFiles(HwndIntPtrSource.Handle, False)
End Sub
Private Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
Private Function WndProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr
Dim filePaths As String() = Nothing
Dim point As POINT = New POINT()
Dim point As New POINT()
If TryGetDropInfo(msg, wParam, filePaths, point) Then
DropPoint = point
@@ -59,31 +58,31 @@ Public Class DragFileHelper
End Function
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function ChangeWindowMessageFilterEx(ByVal hWnd As IntPtr, ByVal msg As UInteger, ByVal action As UInteger, ByRef pChangeFilterStruct As CHANGEFILTERSTRUCT) As Boolean
Private Shared Function ChangeWindowMessageFilterEx(hWnd As IntPtr, msg As UInteger, action As UInteger, ByRef pChangeFilterStruct As CHANGEFILTERSTRUCT) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function ChangeWindowMessageFilter(ByVal msg As UInteger, ByVal flags As UInteger) As Boolean
Private Shared Function ChangeWindowMessageFilter(msg As UInteger, flags As UInteger) As Boolean
End Function
<DllImport("shell32.dll")>
Private Shared Sub DragAcceptFiles(ByVal hWnd As IntPtr, ByVal fAccept As Boolean)
Private Shared Sub DragAcceptFiles(hWnd As IntPtr, fAccept As Boolean)
End Sub
<DllImport("shell32.dll", CharSet:=CharSet.Unicode)>
Private Shared Function DragQueryFile(ByVal hWnd As IntPtr, ByVal iFile As UInteger, ByVal lpszFile As StringBuilder, ByVal cch As Integer) As UInteger
Private Shared Function DragQueryFile(hWnd As IntPtr, iFile As UInteger, lpszFile As StringBuilder, cch As Integer) As UInteger
End Function
<DllImport("shell32.dll")>
Private Shared Function DragQueryPoint(ByVal hDrop As IntPtr, ByRef lppt As POINT) As Boolean
Private Shared Function DragQueryPoint(hDrop As IntPtr, ByRef lppt As POINT) As Boolean
End Function
<DllImport("shell32.dll")>
Private Shared Sub DragFinish(ByVal hDrop As IntPtr)
Private Shared Sub DragFinish(hDrop As IntPtr)
End Sub
<DllImport("ole32.dll")>
Private Shared Function RevokeDragDrop(ByVal hWnd As IntPtr) As Integer
Private Shared Function RevokeDragDrop(hWnd As IntPtr) As Integer
End Function
<DllImport("shell32.dll")>
@@ -109,13 +108,13 @@ Public Class DragFileHelper
Private Const MSGFLT_ADD As UInteger = 1
Private Const MAX_PATH As Integer = 260
Private Shared Sub ChangeMessageFilter(ByVal handle As IntPtr)
Private Shared Sub ChangeMessageFilter(handle As IntPtr)
Dim ver As Version = Environment.OSVersion.Version
Dim isVistaOrHigher As Boolean = ver >= New Version(6, 0)
Dim isNt61OrHiger As Boolean = ver >= New Version(6, 1)
If isVistaOrHigher Then
Dim status As CHANGEFILTERSTRUCT = New CHANGEFILTERSTRUCT With {.cbSize = 8}
Dim status As New CHANGEFILTERSTRUCT With {.cbSize = 8}
For Each msg As UInteger In New UInteger() {WM_DROPFILES, WM_COPYGLOBALDATA, WM_COPYDATA}
Dim [error] As Boolean = False
If isNt61OrHiger Then
@@ -129,7 +128,7 @@ Public Class DragFileHelper
End If
End Sub
Private Shared Function TryGetDropInfo(ByVal msg As Integer, ByVal wParam As IntPtr, ByRef dropFilePaths As String(), ByRef dropPoint As POINT) As Boolean
Private Shared Function TryGetDropInfo(msg As Integer, wParam As IntPtr, ByRef dropFilePaths As String(), ByRef dropPoint As POINT) As Boolean
dropFilePaths = Nothing
dropPoint = New POINT()
@@ -141,7 +140,7 @@ Public Class DragFileHelper
For i As UInteger = 0 To fileCount - 1
Dim sb As New StringBuilder(MAX_PATH)
Dim result As UInteger = DragQueryFile(wParam, i, sb, sb.Capacity)
If result > 0 Then dropFilePaths(CInt(i)) = sb.ToString()
If result > 0 Then dropFilePaths(i) = sb.ToString()
Next
DragQueryPoint(wParam, dropPoint)
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*”
<Assembly: AssemblyVersion("2.10.3.0")>
<Assembly: AssemblyFileVersion("2.10.3.0")>
<Assembly: AssemblyVersion("2.10.4.0")>
<Assembly: AssemblyFileVersion("2.10.4.0")>
<Assembly: NeutralResourcesLanguage("")>
+55 -15
View File
@@ -63,9 +63,9 @@ Namespace My.Resources
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Custom() As Byte()
Friend ReadOnly Property CacheCow_Client() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Custom", resourceCulture)
Dim obj As Object = ResourceManager.GetObject("CacheCow.Client", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
@@ -73,9 +73,29 @@ Namespace My.Resources
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Dialogs() As Byte()
Friend ReadOnly Property CacheCow_Client_FileStore() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Dialogs", resourceCulture)
Dim obj As Object = ResourceManager.GetObject("CacheCow.Client.FileStore", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property CacheCow_Common() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("CacheCow.Common", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Custom() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Custom", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
@@ -105,7 +125,7 @@ Namespace My.Resources
'''</summary>
Friend ReadOnly Property Imazen_WebP() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Imazen_WebP", resourceCulture)
Dim obj As Object = ResourceManager.GetObject("Imazen.WebP", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
@@ -120,16 +140,6 @@ Namespace My.Resources
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Json() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Json", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
@@ -160,6 +170,36 @@ Namespace My.Resources
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Newtonsoft_Json() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Newtonsoft.Json", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Ookii_Dialogs_Wpf() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Ookii.Dialogs.Wpf", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property System_Net_Http_Formatting() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("System.Net.Http.Formatting", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
@@ -118,27 +118,30 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="CacheCow.Client" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CacheCow.Client.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CacheCow.Client.FileStore" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CacheCow.Client.FileStore.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CacheCow.Common" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CacheCow.Common.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Custom" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\custom.xaml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Dialogs" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\ookii.dialogs.wpf.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ForgeInstaller" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\forge-installer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Help" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Help.zip;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Imazen_WebP" type="System.Resources.ResXFileRef, System.Windows.Forms">
<data name="Imazen.WebP" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Imazen.WebP.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="JavaWrapper" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\java-wrapper.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Json" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Newtonsoft.Json.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="libwebp64" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\libwebp64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
@@ -148,6 +151,15 @@
<data name="NAudio" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Newtonsoft.Json" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Newtonsoft.Json.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Ookii.Dialogs.Wpf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\ookii.dialogs.wpf.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="System.Net.Http.Formatting" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\System.Net.Http.Formatting.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Transformer" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\transformer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
@@ -99,7 +99,6 @@ Public Class PageComp
End If
TargetVersion = Nothing
If TargetName IsNot Nothing Then
'设置搜索框内容
TextSearchName.Text = TargetName
TargetName = Nothing
End If
@@ -73,13 +73,14 @@
'筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表)
Private Function GetResults() As List(Of CompFile)
Dim Results As List(Of CompFile) = CompFileLoader.Output
If PageType = CompType.Any Then
Select Case PageType
Case CompType.Any
Results = Results.Where(Function(r) r.Type <> CompType.Plugin).ToList
ElseIf PageType = CompType.Shader OrElse PageType = CompType.ResourcePack Then
Results = Results.ToList
Else
Case CompType.Shader, CompType.ResourcePack
'不筛选光影和资源包,否则原版光影会因为是资源包格式而被过滤(#6473)
Case Else
Results = Results.Where(Function(r) r.Type = PageType).ToList
End If
End Select
Return Results
End Function
Private Sub Load_OnFinish()
@@ -358,7 +359,7 @@
Return False
End Function
'获取常规资源默认下载位置
If CachedFolder.ContainsKey(Project.Type) AndAlso Not String.IsNullOrEmpty(CachedFolder(Project.Type)) Then
If CachedFolder.ContainsKey(Project.Type) Then
DefaultFolder = CachedFolder(Project.Type)
Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}")
ElseIf McVersionCurrent IsNot Nothing AndAlso IsVersionSuitable(McVersionCurrent) Then
@@ -424,13 +425,7 @@
If Not Target.Contains("\") Then Return
'构造步骤加载器
Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " "
If Target <> DefaultFolder Then
If CachedFolder.ContainsKey(Project.Type) Then
CachedFolder(Project.Type) = GetPathFromFullPath(Target)
Else
CachedFolder.Add(Project.Type, GetPathFromFullPath(Target))
End If
End If
If Target <> DefaultFolder Then CachedFolder(Project.Type) = GetPathFromFullPath(Target)
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True})
'启动
@@ -570,7 +570,8 @@ pause"
'官方源
Dim PageData As String
Try
PageData = NetGetCodeByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile, New UTF8Encoding(False), 15000, "text/html", True)
PageData = NetRequestByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile,
Encoding:=New UTF8Encoding(False), Timeout:=15000, Accept:="text/html", UseBrowserUserAgent:=True)
Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last)
@@ -733,7 +734,8 @@ Retry:
'官方源
Dim PageData As String
Try
PageData = NetGetCodeByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile, New UTF8Encoding(False), 15000, "text/html", True)
PageData = NetRequestByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile,
Encoding:=New UTF8Encoding(False), Timeout:=15000, Accept:="text/html", UseBrowserUserAgent:=True)
Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last)
@@ -1340,7 +1342,7 @@ Retry:
If Json("data") IsNot Nothing AndAlso Json("data")("MOJMAPS") IsNot Nothing Then
'下载原版 Json 文件
Task.Progress = 0.4
Dim RawJson As JObject = GetJson(NetGetCodeByLoader(DlSourceLauncherOrMetaGet(DlClientListGet(Inherit)), IsJson:=True))
Dim RawJson As JObject = GetJson(NetRequestByLoader(DlSourceLauncherOrMetaGet(DlClientListGet(Inherit)), IsJson:=True))
'[net.minecraft:client:1.17.1-20210706.113038:mappings@txt] 或 @tsrg]
Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).BeforeFirst("@")
Dim Address = McLibGet(OriginalName).Replace(".jar", "-mappings." & Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(1))
@@ -1641,10 +1643,11 @@ Retry:
Public Sub McDownloadForgeRecommendedRefresh()
If IsForgeRecommendedRefreshed Then Return
IsForgeRecommendedRefreshed = True
RunInNewThread(Sub()
RunInNewThread(
Sub()
Try
Log("[Download] 刷新 Forge 推荐版本缓存开始")
Dim Result As String = NetGetCodeByLoader("https://bmclapi2.bangbang93.com/forge/promos")
Dim Result As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/promos")
If Result.Length < 1000 Then Throw New Exception("获取的结果过短(" & Result & ")")
Dim ResultJson As JContainer = GetJson(Result)
'获取所有推荐版本列表
@@ -27,7 +27,6 @@
<local:MyHint Text="必须安装 OptiFabric 才能正常使用 OptiFine!" Margin="0,10,0,0" x:Name="HintOptiFabric" Theme="Red" />
<local:MyHint Text="安装结束后,请在 Mod 下载中搜索 OptiFabric Origins 并下载,否则 OptiFine 会无法使用!" Margin="0,10,0,0" x:Name="HintOptiFabricOld" Theme="Yellow" />
<local:MyHint Text="OptiFine 与一部分 Mod 的兼容性不佳,请谨慎安装。" Margin="0,10,0,0" x:Name="HintModOptiFine" Theme="Yellow" />
<local:MyHint Text="1.20.5+ 没有 OptiFabric,无法使用 OptiFine,如需加载光影请考虑使用其他 Mod" Margin="0,10,0,0" x:Name="HintModOptiFineHigh" Theme="Blue" />
<local:MyCard Title="Forge" Height="40" Margin="0,12,0,0" x:Name="CardForge" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanForge" />
<Grid x:Name="PanForgeInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
@@ -476,11 +476,6 @@
Else
HintModOptiFine.Visibility = Visibility.Collapsed
End If
If SelectedFabric IsNot Nothing AndAlso VersionSortInteger(SelectedMinecraftId, "1.21.4") > 0 Then
HintModOptiFineHigh.Visibility = Visibility.Visible
Else
HintModOptiFineHigh.Visibility = Visibility.Collapsed
End If
'结束
IsReloading = False
End Sub
@@ -676,13 +671,16 @@
If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
If LoadOptiFine Is Nothing OrElse LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……"
If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFine.State, Object).Error.Message
'检查 Fabric 1.20.5+:没有 OptiFabric 故全部不兼容
If SelectedFabric IsNot Nothing AndAlso VersionSortInteger(SelectedMinecraftId, "1.20.4") > 0 Then Return "与 Fabric 不兼容"
'检查 Forge 1.13 - 1.14.3:全部不兼容
If SelectedForge IsNot Nothing AndAlso
VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then
Return "与 Forge 不兼容"
End If
'检查 Fabric 1.20.5+:全部不兼容
If SelectedFabric IsNot Nothing AndAlso
VersionSortInteger(SelectedMinecraftId, "1.20.4") > 0 Then
Return "与 Fabric 不兼容"
End If
'检查 Forge 版本
Dim HasAny As Boolean = False
Dim HasRequiredVersion As Boolean = False
@@ -988,8 +986,11 @@
Private Function LoadFabricGetError() As String
If LoadFabric Is Nothing OrElse LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……"
If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabric.State, Object).Error.Message
'检查 Fabric 1.20.5+:没有 OptiFabric 故全部不兼容
If SelectedOptiFine IsNot Nothing AndAlso VersionSortInteger(SelectedMinecraftId, "1.20.4") > 0 Then Return "与 OptiFine 不兼容"
'检查 OptiFine 1.20.5+:没有 OptiFabric 故全部不兼容
If SelectedOptiFine IsNot Nothing AndAlso
VersionSortInteger(SelectedMinecraftId, "1.20.4") > 0 Then
Return "与 OptiFine 不兼容"
End If
For Each Version As JObject In DlFabricListLoader.Output.Value("game")
If Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") Then
If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
@@ -105,13 +105,15 @@
Dim UnknownFailureCount As Integer = 0
Do While Not MyConverter.IsExited
Try
Dim Result = NetRequestOnce(
"https://login.microsoftonline.com/consumers/oauth2/v2.0/token", "POST",
Dim Result = NetRequestByClient(
"https://login.microsoftonline.com/consumers/oauth2/v2.0/token", HttpMethod.Post,
Content:=
"grant_type=urn:ietf:params:oauth:grant-type:device_code" & "&" &
"client_id=" & OAuthClientId & "&" &
"device_code=" & DeviceCode & "&" &
"scope=XboxLive.signin%20offline_access",
"application/x-www-form-urlencoded", 5000 + UnknownFailureCount * 5000, MakeLog:=False)
ContentType:="application/x-www-form-urlencoded",
Timeout:=5000 + UnknownFailureCount * 5000)
'获取结果
Dim ResultJson As JObject = GetJson(Result)
McLaunchLog($"令牌过期时间:{ResultJson("expires_in")} 秒")
@@ -126,7 +128,7 @@
Finished(New Exception("$登录用时太长啦,重新试试吧!"))
Return
ElseIf ex.Message.Contains("Account security interrupt") Then
Finished(New Exception("$非常抱歉,该账号由于安全问题无法登陆,请前往 Microsoft 账户页获取更多信息。"))
Finished(New Exception("$该账号由于安全问题无法登陆,请前往微软账户页获取更多信息。"))
Return
ElseIf ex.Message.Contains("service abuse") Then
Finished(New Exception("$非常抱歉,该账号已被微软封禁,无法登录。"))
@@ -259,12 +259,13 @@ Retry:
End Sub)
If SelId Is Nothing Then Return
'发送请求
Dim Result As String = NetRequestRetry("https://api.minecraftservices.com/minecraft/profile/capes/active",
If(SelId = 0, "DELETE", "PUT"),
If(SelId = 0, "", New JObject(New JProperty("capeId", SkinData("capes")(SelId - 1)("id"))).ToString(0)),
"application/json", Headers:=New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}})
Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/capes/active",
If(SelId = 0, HttpMethod.Delete, HttpMethod.Put),
Content:=If(SelId = 0, "", New JObject(New JProperty("capeId", SkinData("capes")(SelId - 1)("id"))).ToString(0)),
ContentType:="application/json",
Headers:={{"Authorization", "Bearer " & AccessToken}})
If Result.Contains("""errorMessage""") Then
Hint("更改披风失败:" & GetJson(Result)("errorMessage"), HintType.Critical)
Hint("更改披风失败:" & GetJson(Result)("errorMessage").ToString, HintType.Critical)
Return
Else
Hint("更改披风成功!", HintType.Finish)
@@ -156,7 +156,7 @@ Download:
Dim Version As String = ""
Dim NeedDownload As Boolean = True
Try
Version = NetGetCodeByRequestOnce(VersionAddress, Timeout:=10000)
Version = NetRequestByClientRetry(VersionAddress)
If Version.Length > 1000 Then Throw New Exception($"获取的主页版本过长({Version.Length} 字符)")
Dim CurrentVersion As String = Setup.Get("CacheSavedPageVersion")
If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then
@@ -171,7 +171,7 @@ Download:
End Try
'实际下载
If NeedDownload Then
Dim FileContent As String = NetGetCodeByRequestRetry(Address)
Dim FileContent As String = NetRequestByClientRetry(Address)
Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}")
Setup.Set("CacheSavedPageUrl", Address)
Setup.Set("CacheSavedPageVersion", Version)
@@ -231,7 +231,9 @@ Download:
Try
'修改时应同时修改 PageOtherHelpDetail.Init
Content = HelpArgumentReplace(Content)
If Content.Contains("xmlns") Then Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间
Do While Content.Contains("xmlns")
Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间
Loop
Content = "<StackPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:sys=""clr-namespace:System;assembly=mscorlib"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:local=""clr-namespace:PCL;assembly=Plain Craft Launcher 2"">" & Content & "</StackPanel>"
Log($"[Page] 实例化:加载主页 UI 开始,最终内容长度:{Content.Count}")
PanCustom.Children.Add(GetObjectFromXML(Content))
@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PCL"
mc:Ignorable="d" d:DesignWidth="297.6">
<StackPanel Margin="0,0,0,5">
<StackPanel Margin="0,0,0,5" x:Name="PanMain">
<local:MyHint x:Name="HintChinese" Theme="Red" Text="玩家名如果包含英文、数字、下划线以外的内容,可能会无法进入 Minecraft 1.18 以后的世界!" Margin="0,0,0,15" Visibility="Collapsed" />
<local:MySkin HorizontalAlignment="Center" x:Name="Skin" HasCape="False" Margin="0,0,0,15" />
<local:MyComboBox IsEditable="True" x:Name="ComboName" Height="28" IsTextSearchEnabled="False" HintText="游戏用户名" />
@@ -64,6 +64,7 @@ Public Class PageLoginLegacy
Private Sub ComboLegacy_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged
If Setup.Get("LaunchSkinType") = 0 Then PageLaunchLeft.SkinLegacy.Start(IsForceRestart:=True)
HintChinese.Visibility = If(RegexCheck(ComboName.Text, "^[0-9A-Za-z_]*$"), Visibility.Collapsed, Visibility.Visible)
RunInUi(Sub() PanMain.InvalidateMeasure(), True) '由于 WPF 的 Bug,它不一定会自动更新 HintChinese 的大小(#6627)
End Sub
Private Sub Skin_Click() Handles Skin.Click
If (Setup.Get("UiHiddenPageSetup") OrElse Setup.Get("UiHiddenSetupLaunch")) AndAlso Not PageSetupUI.HiddenForceShow Then
@@ -23,9 +23,11 @@
<local:MyIconButton.ContextMenu>
<ContextMenu Closed="HidePanel" HorizontalOffset="10" VerticalOffset="18">
<local:MyMenuItem Click="BtnSkinEdit_Click" Header="修改皮肤"/>
<local:MyMenuItem Click="BtnSkinSave_Click" Header="保存皮肤"/>
<local:MyMenuItem Click="BtnSkinRefresh_Click" Header="刷新头像"/>
<local:MyMenuItem Click="BtnSkinSave_Click" Header="保存皮肤文件"/>
<Separator />
<local:MyMenuItem Click="BtnSkinCape_Click" Header="修改披风"/>
<Separator />
<local:MyMenuItem Click="BtnSkinRefresh_Click" Header="刷新"/>
</ContextMenu>
</local:MyIconButton.ContextMenu>
</local:MyIconButton>
@@ -107,7 +107,7 @@ Retry:
McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
GoTo Retry
ElseIf Result.Contains("""error""") Then
Hint("更改皮肤失败:" & GetJson(Result)("error"), HintType.Critical)
Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Critical)
Return
End If
'获取新皮肤地址
@@ -30,7 +30,7 @@
</Image.Clip>
</Image>
<local:MyButton Text="赞助作者" Grid.Column="2" Grid.Row="0" Height="35" EventType="打开网页" EventData="https://afdian.com/a/LTCat" />
<local:MyButton Text="查看源代码" Grid.Column="2" Grid.Row="1" Height="35" EventType="打开网页" EventData="https://github.com/Meloong-Git/PCL" />
<local:MyButton Text="查看源代码" Grid.Column="2" Grid.Row="1" Height="35" EventType="打开网页" EventData="https://github.com/Hex-Dragon/PCL2" />
</Grid>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="特别鸣谢">
@@ -104,265 +104,288 @@
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="赞助者">
<StackPanel Margin="25,40,10,20">
<TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 5 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
<WrapPanel Margin="0,0,0,10">
<TextBlock Width="120" Margin="0,1.5" Text="Alliance" />
<TextBlock Width="120" Margin="0,1.5" Text="风之轻语" />
<TextBlock Width="120" Margin="0,1.5" Text="大博文" />
<TextBlock Width="120" Margin="0,1.5" Text="狐狸不吃酸葡萄" />
<TextBlock Width="120" Margin="0,1.5" Text="仰望星空的牧星人" />
<TextBlock Width="120" Margin="0,1.5" Text="某个网友" />
<TextBlock Width="120" Margin="0,1.5" Text="114514" />
<TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 6 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
<WrapPanel Margin="0,0,0,10"> <TextBlock Width="120" Margin="0,1.5" Text="星月" />
<TextBlock Width="120" Margin="0,1.5" Text="Nemo" />
<TextBlock Width="120" Margin="0,1.5" Text="长歌当天" />
<TextBlock Width="120" Margin="0,1.5" Text="飒黎lIlIlI" />
<TextBlock Width="120" Margin="0,1.5" Text="hy" />
<TextBlock Width="120" Margin="0,1.5" Text="SaDhhJe" />
<TextBlock Width="120" Margin="0,1.5" Text="风铃子啊" />
<TextBlock Width="120" Margin="0,1.5" Text="柠娜" />
<TextBlock Width="120" Margin="0,1.5" Text="W丶北辰" />
<TextBlock Width="120" Margin="0,1.5" Text="才KRE" />
<TextBlock Width="120" Margin="0,1.5" Text="Yang_mistakeof" />
<TextBlock Width="120" Margin="0,1.5" Text="close eyes" />
<TextBlock Width="120" Margin="0,1.5" Text="顾顾" />
<TextBlock Width="120" Margin="0,1.5" Text="LTuuxj" />
<TextBlock Width="120" Margin="0,1.5" Text="花吃" />
<TextBlock Width="120" Margin="0,1.5" Text="FICazk" />
<TextBlock Width="120" Margin="0,1.5" Text="屑屑你" />
<TextBlock Width="120" Margin="0,1.5" Text="凉凉" />
<TextBlock Width="120" Margin="0,1.5" Text="WDSJ" />
<TextBlock Width="120" Margin="0,1.5" Text="Tohka" />
<TextBlock Width="120" Margin="0,1.5" Text="lz" />
<TextBlock Width="120" Margin="0,1.5" Text="哦嚯嚯嚯皮筋头" />
<TextBlock Width="120" Margin="0,1.5" Text="陈肖杰" />
<TextBlock Width="120" Margin="0,1.5" Text="MC小满" />
<TextBlock Width="120" Margin="0,1.5" Text="残光" />
<TextBlock Width="120" Margin="0,1.5" Text="玖玖璃" />
<TextBlock Width="120" Margin="0,1.5" Text="水晶OTZ" />
<TextBlock Width="120" Margin="0,1.5" Text="伯克礼" />
<TextBlock Width="120" Margin="0,1.5" Text="白猫海贼船" />
<TextBlock Width="120" Margin="0,1.5" Text="zhang1232" />
<TextBlock Width="120" Margin="0,1.5" Text="Never" />
<TextBlock Width="120" Margin="0,1.5" Text="Fish_pomelo" />
<TextBlock Width="120" Margin="0,1.5" Text="生风" />
<TextBlock Width="120" Margin="0,1.5" Text="富士山下" />
<TextBlock Width="120" Margin="0,1.5" Text="小七" />
<TextBlock Width="120" Margin="0,1.5" Text="发呆的呆毛君" />
<TextBlock Width="120" Margin="0,1.5" Text="天黑时看月亮" />
<TextBlock Width="120" Margin="0,1.5" Text="夜枫" />
<TextBlock Width="120" Margin="0,1.5" Text="_章333_" />
<TextBlock Width="120" Margin="0,1.5" Text="孙杰" />
<TextBlock Width="120" Margin="0,1.5" Text="wby" />
<TextBlock Width="120" Margin="0,1.5" Text="封尾==" />
<TextBlock Width="120" Margin="0,1.5" Text="你与空白皆无名" />
<TextBlock Width="120" Margin="0,1.5" Text="鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="zzxniubi" />
<TextBlock Width="120" Margin="0,1.5" Text="炎燚火淼淼" />
<TextBlock Width="120" Margin="0,1.5" Text="三巿" />
<TextBlock Width="120" Margin="0,1.5" Text="奈落" />
<TextBlock Width="120" Margin="0,1.5" Text="华佗" />
<TextBlock Width="120" Margin="0,1.5" Text="oran9e" />
<TextBlock Width="120" Margin="0,1.5" Text="赤冰雨" />
<TextBlock Width="120" Margin="0,1.5" Text="Urizen" />
<TextBlock Width="120" Margin="0,1.5" Text=":)" />
<TextBlock Width="120" Margin="0,1.5" Text="skyqyzm" />
<TextBlock Width="120" Margin="0,1.5" Text="橘子皮丶" />
<TextBlock Width="120" Margin="0,1.5" Text="额外awa" />
<TextBlock Width="120" Margin="0,1.5" Text="安上月" />
<TextBlock Width="120" Margin="0,1.5" Text="念城南" />
<TextBlock Width="120" Margin="0,1.5" Text="多低山丘陵" />
<TextBlock Width="120" Margin="0,1.5" Text="书童呀" />
<TextBlock Width="120" Margin="0,1.5" Text="sxy192425" />
<TextBlock Width="120" Margin="0,1.5" Text="李好啊" />
<TextBlock Width="120" Margin="0,1.5" Text="MH_Nine" />
<TextBlock Width="120" Margin="0,1.5" Text="周先生" />
<TextBlock Width="120" Margin="0,1.5" Text="原" />
<TextBlock Width="120" Margin="0,1.5" Text="良田满穗" />
<TextBlock Width="120" Margin="0,1.5" Text="柴" />
<TextBlock Width="120" Margin="0,1.5" Text="庭师" />
<TextBlock Width="120" Margin="0,1.5" Text="。,。" />
<TextBlock Width="120" Margin="0,1.5" Text="DHLH" />
<TextBlock Width="120" Margin="0,1.5" Text="Xayj" />
<TextBlock Width="120" Margin="0,1.5" Text="绳网用户#37" />
<TextBlock Width="120" Margin="0,1.5" Text="LLLL" />
<TextBlock Width="120" Margin="0,1.5" Text="深绯红" />
<TextBlock Width="120" Margin="0,1.5" Text="奇伢七星" />
<TextBlock Width="120" Margin="0,1.5" Text="Akapigo" />
<TextBlock Width="120" Margin="0,1.5" Text="Shink_guns" />
<TextBlock Width="120" Margin="0,1.5" Text="Aqua 极&amp;坏." />
<TextBlock Width="120" Margin="0,1.5" Text="大事化小蛋糕" />
<TextBlock Width="120" Margin="0,1.5" Text="Nakiya233" />
<TextBlock Width="120" Margin="0,1.5" Text="花小妖" />
<TextBlock Width="120" Margin="0,1.5" Text="septebr" />
<TextBlock Width="120" Margin="0,1.5" Text="一只马喽" />
<TextBlock Width="120" Margin="0,1.5" Text="下暴雨BWB" />
<TextBlock Width="120" Margin="0,1.5" Text="QAQ" />
<TextBlock Width="240" Margin="0,1.5" Text="sl土豆社区服主B友" />
<TextBlock Width="120" Margin="0,1.5" Text="Wang" />
<TextBlock Width="120" Margin="0,1.5" Text="......" />
<TextBlock Width="120" Margin="0,1.5" Text="ResTmoW" />
<TextBlock Width="120" Margin="0,1.5" Text="bochibochibo" />
<TextBlock Width="120" Margin="0,1.5" Text="铸魂之灵" />
<TextBlock Width="120" Margin="0,1.5" Text="柏柏柏" />
<TextBlock Width="120" Margin="0,1.5" Text="Mart1s" />
<TextBlock Width="120" Margin="0,1.5" Text="KuruM148" />
<TextBlock Width="120" Margin="0,1.5" Text="KaiTouCrow" />
<TextBlock Width="120" Margin="0,1.5" Text="LIE-SHAN" />
<TextBlock Width="120" Margin="0,1.5" Text="慈悲方舟" />
<TextBlock Width="120" Margin="0,1.5" Text="于析" />
<TextBlock Width="120" Margin="0,1.5" Text="陌道" />
<TextBlock Width="120" Margin="0,1.5" Text="摇椅上的猫" />
<TextBlock Width="120" Margin="0,1.5" Text="五个麦卷" />
<TextBlock Width="120" Margin="0,1.5" Text="Miraclepoi" />
<TextBlock Width="120" Margin="0,1.5" Text="XiaoLI" />
<TextBlock Width="120" Margin="0,1.5" Text="啊吧啊吧的肥宅" />
<TextBlock Width="120" Margin="0,1.5" Text="不娶雨婷不改名" />
<TextBlock Width="120" Margin="0,1.5" Text="oppo19" />
<TextBlock Width="120" Margin="0,1.5" Text="博麗靈夢" />
<TextBlock Width="120" Margin="0,1.5" Text="莹 of yours" />
<TextBlock Width="120" Margin="0,1.5" Text="ChinaFZXPVP" />
<TextBlock Width="120" Margin="0,1.5" Text="城之内sama" />
<TextBlock Width="120" Margin="0,1.5" Text="ENXI" />
<TextBlock Width="120" Margin="0,1.5" Text="steve_c418" />
<TextBlock Width="120" Margin="0,1.5" Text="洛长安" />
<TextBlock Width="120" Margin="0,1.5" Text="magic_muggle" />
<TextBlock Width="120" Margin="0,1.5" Text="小猫游六喵" />
<TextBlock Width="120" Margin="0,1.5" Text="JY" />
<TextBlock Width="120" Margin="0,1.5" Text="雪豹起司可颂" />
<TextBlock Width="120" Margin="0,1.5" Text="wlsy" />
<TextBlock Width="120" Margin="0,1.5" Text="齐先生爱溜达" />
<TextBlock Width="120" Margin="0,1.5" Text="是小泠啊" />
<TextBlock Width="120" Margin="0,1.5" Text="xioyiao" />
<TextBlock Width="120" Margin="0,1.5" Text="BunnyMiku" />
<TextBlock Width="120" Margin="0,1.5" Text="dadagga" />
<TextBlock Width="120" Margin="0,1.5" Text="无极之笔" />
<TextBlock Width="120" Margin="0,1.5" Text="xiaoyu" />
<TextBlock Width="120" Margin="0,1.5" Text="王梓杰" />
<TextBlock Width="120" Margin="0,1.5" Text="wjbjjd" />
<TextBlock Width="120" Margin="0,1.5" Text="Candy_Mo" />
<TextBlock Width="120" Margin="0,1.5" Text="lettmin_" />
<TextBlock Width="120" Margin="0,1.5" Text="七九·Alnasl" />
<TextBlock Width="120" Margin="0,1.5" Text="辉" />
<TextBlock Width="120" Margin="0,1.5" Text="何为最优解" />
<TextBlock Width="120" Margin="0,1.5" Text="crazy丶天人" />
<TextBlock Width="120" Margin="0,1.5" Text="XsBlueSky" />
<TextBlock Width="120" Margin="0,1.5" Text="冬将軍" />
<TextBlock Width="120" Margin="0,1.5" Text="tiechui" />
<TextBlock Width="120" Margin="0,1.5" Text="Liu2Shi2Pu2" />
<TextBlock Width="120" Margin="0,1.5" Text="Yu_s" />
<TextBlock Width="120" Margin="0,1.5" Text="刘四妹" />
<TextBlock Width="120" Margin="0,1.5" Text="枝皙" />
<TextBlock Width="120" Margin="0,1.5" Text="CC" />
<TextBlock Width="120" Margin="0,1.5" Text="Slana23" />
<TextBlock Width="120" Margin="0,1.5" Text="MMMy" />
<TextBlock Width="120" Margin="0,1.5" Text="Venuse" />
<TextBlock Width="120" Margin="0,1.5" Text="microjie" />
<TextBlock Width="240" Margin="0,1.5" Text="Miner#Cetyleno~^" />
<TextBlock Width="120" Margin="0,1.5" Text="春江花月夜" />
<TextBlock Width="120" Margin="0,1.5" Text="落南子" />
<TextBlock Width="120" Margin="0,1.5" Text="AL1Su-爱丽丝" />
<TextBlock Width="120" Margin="0,1.5" Text="我木有呆毛" />
<TextBlock Width="120" Margin="0,1.5" Text="乌羽" />
<TextBlock Width="120" Margin="0,1.5" Text="知性de含羞草" />
<TextBlock Width="120" Margin="0,1.5" Text="星の殇" />
<TextBlock Width="120" Margin="0,1.5" Text="IED LTAM" />
<TextBlock Width="120" Margin="0,1.5" Text="格罗夫斯基" />
<TextBlock Width="120" Margin="0,1.5" Text="梦启泉" />
<TextBlock Width="120" Margin="0,1.5" Text="岁月无痕" />
<TextBlock Width="120" Margin="0,1.5" Text="????" />
<TextBlock Width="120" Margin="0,1.5" Text="超级脑壳" />
<TextBlock Width="120" Margin="0,1.5" Text="空梦" />
<TextBlock Width="120" Margin="0,1.5" Text="薛小欣" />
<TextBlock Width="120" Margin="0,1.5" Text="蛋黄豆角" />
<TextBlock Width="120" Margin="0,1.5" Text="芒果茶州" />
<TextBlock Width="120" Margin="0,1.5" Text="癫风院院长" />
<TextBlock Width="120" Margin="0,1.5" Text="三十一" />
<TextBlock Width="120" Margin="0,1.5" Text="美醉了" />
<TextBlock Width="240" Margin="0,1.5" Text="中科院在逃量子计算机" />
<TextBlock Width="120" Margin="0,1.5" Text="." />
<TextBlock Width="120" Margin="0,1.5" Text="枫" />
<TextBlock Width="120" Margin="0,1.5" Text="jjj" />
<TextBlock Width="120" Margin="0,1.5" Text="clilick" />
<TextBlock Width="120" Margin="0,1.5" Text="我很快乐" />
<TextBlock Width="120" Margin="0,1.5" Text="Phoenix tamer" />
<TextBlock Width="120" Margin="0,1.5" Text="Lsp77" />
<TextBlock Width="120" Margin="0,1.5" Text="太阳神" />
<TextBlock Width="120" Margin="0,1.5" Text="ikun0014" />
<TextBlock Width="120" Margin="0,1.5" Text="IncredibleYu" />
<TextBlock Width="120" Margin="0,1.5" Text="在下粉毛控" />
<TextBlock Width="120" Margin="0,1.5" Text="SuperCrazyK" />
<TextBlock Width="120" Margin="0,1.5" Text="阿柔" />
<TextBlock Width="120" Margin="0,1.5" Text="HaKNa" />
<TextBlock Width="120" Margin="0,1.5" Text="胡十一" />
<TextBlock Width="120" Margin="0,1.5" Text="菲利絲" />
<TextBlock Width="120" Margin="0,1.5" Text="迷梦的羽" />
<TextBlock Width="120" Margin="0,1.5" Text="20018" />
<TextBlock Width="120" Margin="0,1.5" Text="波比科普员" />
<TextBlock Width="120" Margin="0,1.5" Text="Xiao_JIA" />
<TextBlock Width="240" Margin="0,1.5" Text="龙腾我是你的头号粉丝" />
<TextBlock Width="120" Margin="0,1.5" Text="keer1563" />
<TextBlock Width="120" Margin="0,1.5" Text="百鬼まル" />
<TextBlock Width="120" Margin="0,1.5" Text="DPSYnt" />
<TextBlock Width="120" Margin="0,1.5" Text="七色彩羽" />
<TextBlock Width="120" Margin="0,1.5" Text="臭氧化碳" />
<TextBlock Width="120" Margin="0,1.5" Text="情来风" />
<TextBlock Width="120" Margin="0,1.5" Text="柒月" />
<TextBlock Width="120" Margin="0,1.5" Text="汪汪队队长" />
<TextBlock Width="120" Margin="0,1.5" Text="迷路的猫" />
<TextBlock Width="120" Margin="0,1.5" Text="ktyxlan_lan" />
<TextBlock Width="120" Margin="0,1.5" Text="琳琅039" />
<TextBlock Width="120" Margin="0,1.5" Text="黑色额度" />
<TextBlock Width="120" Margin="0,1.5" Text="sahaua" />
<TextBlock Width="120" Margin="0,1.5" Text="宦昭" />
<TextBlock Width="120" Margin="0,1.5" Text="镜刹" />
<TextBlock Width="120" Margin="0,1.5" Text="房石诶多" />
<TextBlock Width="120" Margin="0,1.5" Text="熊" />
<TextBlock Width="120" Margin="0,1.5" Text="NQ" />
<TextBlock Width="120" Margin="0,1.5" Text="我志永纯" />
<TextBlock Width="120" Margin="0,1.5" Text="漫城" />
<TextBlock Width="120" Margin="0,1.5" Text="憨憨的小草" />
<TextBlock Width="120" Margin="0,1.5" Text="泽涛" />
<TextBlock Width="120" Margin="0,1.5" Text="星海鹿樱" />
<TextBlock Width="120" Margin="0,1.5" Text="祭°" />
<TextBlock Width="120" Margin="0,1.5" Text="赛冷特呀" />
<TextBlock Width="120" Margin="0,1.5" Text="无妄之灾" />
<TextBlock Width="120" Margin="0,1.5" Text="ZGW2008" />
<TextBlock Width="120" Margin="0,1.5" Text="没事多喝感冒灵" />
<TextBlock Width="120" Margin="0,1.5" Text="一梦筱筱" />
<TextBlock Width="120" Margin="0,1.5" Text="twokness" />
<TextBlock Width="120" Margin="0,1.5" Text="hhy7171" />
<TextBlock Width="120" Margin="0,1.5" Text="子虚" />
<TextBlock Width="120" Margin="0,1.5" Text="猫羽" />
<TextBlock Width="120" Margin="0,1.5" Text="有氧丁真" />
<TextBlock Width="120" Margin="0,1.5" Text="dddr" />
<TextBlock Width="120" Margin="0,1.5" Text="天气热" />
<TextBlock Width="120" Margin="0,1.5" Text="Emmanuel" />
<TextBlock Width="120" Margin="0,1.5" Text="云漫雾影" />
<TextBlock Width="120" Margin="0,1.5" Text="**葵" />
<TextBlock Width="120" Margin="0,1.5" Text="吴同学" />
<TextBlock Width="120" Margin="0,1.5" Text="Anderson521314" />
<TextBlock Width="120" Margin="0,1.5" Text="Alrosa" />
<TextBlock Width="120" Margin="0,1.5" Text="可爱电鳗" />
<TextBlock Width="120" Margin="0,1.5" Text="小野冢小町" />
<TextBlock Width="120" Margin="0,1.5" Text="田坎村西头王二狗" />
<TextBlock Width="120" Margin="0,1.5" Text="令月廿一" />
<TextBlock Width="120" Margin="0,1.5" Text="Mrdandan" />
<TextBlock Width="120" Margin="0,1.5" Text="111" />
<TextBlock Width="120" Margin="0,1.5" Text="27733" />
<TextBlock Width="120" Margin="0,1.5" Text="韦韦神父" />
<TextBlock Width="120" Margin="0,1.5" Text="土豆" />
<TextBlock Width="120" Margin="0,1.5" Text="隔岸流年" />
<TextBlock Width="120" Margin="0,1.5" Text="冥吻" />
<TextBlock Width="120" Margin="0,1.5" Text="向阳" />
<TextBlock Width="120" Margin="0,1.5" Text="轻浮" />
<TextBlock Width="120" Margin="0,1.5" Text="小涵0v0" />
<TextBlock Width="120" Margin="0,1.5" Text="祈愿小狐" />
<TextBlock Width="120" Margin="0,1.5" Text="爱莉爱莉爱" />
<TextBlock Width="120" Margin="0,1.5" Text="Bydold" />
<TextBlock Width="120" Margin="0,1.5" Text="SMRWXH" />
<TextBlock Width="120" Margin="0,1.5" Text="翷月" />
<TextBlock Width="120" Margin="0,1.5" Text="husky" />
<TextBlock Width="120" Margin="0,1.5" Text="Hz_yuki" />
<TextBlock Width="120" Margin="0,1.5" Text="先知" />
<TextBlock Width="120" Margin="0,1.5" Text="2683672592" />
<TextBlock Width="120" Margin="0,1.5" Text="龖龖" />
<TextBlock Width="120" Margin="0,1.5" Text="陨树" />
<TextBlock Width="120" Margin="0,1.5" Text="Gripen" />
<TextBlock Width="120" Margin="0,1.5" Text="棒槌" />
<TextBlock Width="120" Margin="0,1.5" Text="北北ovo" />
<TextBlock Width="120" Margin="0,1.5" Text="TombName" />
<TextBlock Width="240" Margin="0,1.5" Text="莳倾梦のshiqingmeng" />
<TextBlock Width="120" Margin="0,1.5" Text="Bortor" />
<TextBlock Width="120" Margin="0,1.5" Text="OuO6006" />
<TextBlock Width="120" Margin="0,1.5" Text="MKSeKai" />
<TextBlock Width="120" Margin="0,1.5" Text="清尘墨雨" />
<TextBlock Width="120" Margin="0,1.5" Text="墨染柊" />
<TextBlock Width="120" Margin="0,1.5" Text="福福" />
<TextBlock Width="120" Margin="0,1.5" Text="夕尽暮染" />
<TextBlock Width="120" Margin="0,1.5" Text="光年摆渡人" />
<TextBlock Width="120" Margin="0,1.5" Text="梦清韩" />
<TextBlock Width="120" Margin="0,1.5" Text="孤城辞典" />
<TextBlock Width="120" Margin="0,1.5" Text="灰" />
<TextBlock Width="120" Margin="0,1.5" Text="小周周" />
<TextBlock Width="120" Margin="0,1.5" Text="孤星痕" />
<TextBlock Width="120" Margin="0,1.5" Text="月孤" />
<TextBlock Width="120" Margin="0,1.5" Text="团团" />
<TextBlock Width="120" Margin="0,1.5" Text="J_ONE" />
<TextBlock Width="120" Margin="0,1.5" Text="初尘ya" />
<TextBlock Width="120" Margin="0,1.5" Text="MooBHise" />
<TextBlock Width="120" Margin="0,1.5" Text="凌之芬芳" />
<TextBlock Width="120" Margin="0,1.5" Text="土豆回锅土豆" />
<TextBlock Width="120" Margin="0,1.5" Text="Reisen" />
<TextBlock Width="120" Margin="0,1.5" Text="Rong" />
<TextBlock Width="120" Margin="0,1.5" Text="FiZone" />
<TextBlock Width="120" Margin="0,1.5" Text="橡素" />
<TextBlock Width="120" Margin="0,1.5" Text="逆光の思" />
<TextBlock Width="120" Margin="0,1.5" Text="Edifier" />
<TextBlock Width="120" Margin="0,1.5" Text="迭风" />
<TextBlock Width="120" Margin="0,1.5" Text="mumu" />
<TextBlock Width="120" Margin="0,1.5" Text="欧润几" />
<TextBlock Width="120" Margin="0,1.5" Text="SiberianHusky" />
<TextBlock Width="120" Margin="0,1.5" Text="虫" />
<TextBlock Width="120" Margin="0,1.5" Text="闪电" />
<TextBlock Width="120" Margin="0,1.5" Text="Bob_Marcus" />
<TextBlock Width="120" Margin="0,1.5" Text="瘦瘦爱吃呕吼" />
<TextBlock Width="120" Margin="0,1.5" Text="盛夏" />
<TextBlock Width="120" Margin="0,1.5" Text="飞起来的Mine" />
<TextBlock Width="120" Margin="0,1.5" Text="cc" />
<TextBlock Width="120" Margin="0,1.5" Text="简麟" />
<TextBlock Width="120" Margin="0,1.5" Text="郴州火车迷" />
<TextBlock Width="120" Margin="0,1.5" Text="守白" />
<TextBlock Width="120" Margin="0,1.5" Text="天长地忙" />
<TextBlock Width="120" Margin="0,1.5" Text="月无痕" />
<TextBlock Width="120" Margin="0,1.5" Text="HWW" />
<TextBlock Width="120" Margin="0,1.5" Text="樱岛麻衣" />
<TextBlock Width="120" Margin="0,1.5" Text="桌子" />
<TextBlock Width="120" Margin="0,1.5" Text="bushihuankong" />
<TextBlock Width="120" Margin="0,1.5" Text="戏梦simi" />
<TextBlock Width="120" Margin="0,1.5" Text="Metal_Yoshika" />
<TextBlock Width="120" Margin="0,1.5" Text="H+H" />
<TextBlock Width="120" Margin="0,1.5" Text="junhuigege" />
<TextBlock Width="120" Margin="0,1.5" Text="Kallen" />
<TextBlock Width="120" Margin="0,1.5" Text="x" />
<TextBlock Width="120" Margin="0,1.5" Text="随便玩" />
<TextBlock Width="120" Margin="0,1.5" Text="魇夜星渊" />
<TextBlock Width="120" Margin="0,1.5" Text="taomiao13579" />
<TextBlock Width="120" Margin="0,1.5" Text="无敌大鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="忆兀安" />
<TextBlock Width="120" Margin="0,1.5" Text="无梦" />
<TextBlock Width="120" Margin="0,1.5" Text="SlyBlackCat" />
<TextBlock Width="120" Margin="0,1.5" Text="180" />
<TextBlock Width="120" Margin="0,1.5" Text="总督大人" />
<TextBlock Width="120" Margin="0,1.5" Text="sc99" />
<TextBlock Width="120" Margin="0,1.5" Text="Fumi" />
<TextBlock Width="120" Margin="0,1.5" Text="豪放" />
<TextBlock Width="120" Margin="0,1.5" Text="Canqiu" />
<TextBlock Width="120" Margin="0,1.5" Text="初心无尘" />
<TextBlock Width="120" Margin="0,1.5" Text="朱利安" />
<TextBlock Width="120" Margin="0,1.5" Text="白露辰霜" />
<TextBlock Width="240" Margin="0,1.5" Text="点燃心中火的大音乐家" />
<TextBlock Width="120" Margin="0,1.5" Text="度你入魔" />
<TextBlock Width="120" Margin="0,1.5" Text="小宝" />
<TextBlock Width="120" Margin="0,1.5" Text="无" />
<TextBlock Width="120" Margin="0,1.5" Text="青出梦名" />
<TextBlock Width="120" Margin="0,1.5" Text="雾日斋主人" />
<TextBlock Width="120" Margin="0,1.5" Text="鸣纳" />
<TextBlock Width="120" Margin="0,1.5" Text="苏卜辰" />
<TextBlock Width="120" Margin="0,1.5" Text="3827" />
<TextBlock Width="120" Margin="0,1.5" Text="水里游的老鹰" />
<TextBlock Width="120" Margin="0,1.5" Text="雪桜" />
<TextBlock Width="120" Margin="0,1.5" Text="Yukiteru" />
<TextBlock Width="120" Margin="0,1.5" Text="零依" />
<TextBlock Width="120" Margin="0,1.5" Text="玻璃糖罐" />
<TextBlock Width="120" Margin="0,1.5" Text="JFF_2005" />
<TextBlock Width="120" Margin="0,1.5" Text="流星" />
<TextBlock Width="120" Margin="0,1.5" Text="ccc" />
<TextBlock Width="120" Margin="0,1.5" Text="PennyLee2023" />
<TextBlock Width="120" Margin="0,1.5" Text="伯劳" />
<TextBlock Width="120" Margin="0,1.5" Text="Sy5H" />
<TextBlock Width="120" Margin="0,1.5" Text="Fomalhaut" />
<TextBlock Width="120" Margin="0,1.5" Text="PERLICA" />
<TextBlock Width="120" Margin="0,1.5" Text="北冥鱼吃" />
<TextBlock Width="120" Margin="0,1.5" Text="千万别自闭" />
<TextBlock Width="120" Margin="0,1.5" Text="00号玩家" />
<TextBlock Width="120" Margin="0,1.5" Text="亗竹" />
<TextBlock Width="120" Margin="0,1.5" Text="云一梦" />
<TextBlock Width="120" Margin="0,1.5" Text="久念" />
<TextBlock Width="120" Margin="0,1.5" Text="继晷" />
<TextBlock Width="120" Margin="0,1.5" Text="史蒂夫" />
<TextBlock Width="120" Margin="0,1.5" Text="椎罗太难了" />
<TextBlock Width="120" Margin="0,1.5" Text="DiamondSYP" />
<TextBlock Width="120" Margin="0,1.5" Text="木林西" />
<TextBlock Width="120" Margin="0,1.5" Text="雩月" />
<TextBlock Width="120" Margin="0,1.5" Text="6628" />
<TextBlock Width="120" Margin="0,1.5" Text="ZoCc" />
<TextBlock Width="120" Margin="0,1.5" Text="wan_yao" />
<TextBlock Width="120" Margin="0,1.5" Text="White_c" />
<TextBlock Width="120" Margin="0,1.5" Text="尉迟羽晨" />
<TextBlock Width="120" Margin="0,1.5" Text="栀梓" />
<TextBlock Width="120" Margin="0,1.5" Text="小命" />
<TextBlock Width="120" Margin="0,1.5" Text="金" />
<TextBlock Width="120" Margin="0,1.5" Text="倾墨画君颜" />
<TextBlock Width="120" Margin="0,1.5" Text="南宫若兮" />
<TextBlock Width="120" Margin="0,1.5" Text="沐言" />
<TextBlock Width="120" Margin="0,1.5" Text="傻预备" />
<TextBlock Width="120" Margin="0,1.5" Text="蒸木" />
<TextBlock Width="120" Margin="0,1.5" Text="那菈" />
<TextBlock Width="120" Margin="0,1.5" Text="suanqiu" />
<TextBlock Width="120" Margin="0,1.5" Text="人见人爱的熊熊" />
<TextBlock Width="120" Margin="0,1.5" Text="Furan255" />
<TextBlock Width="120" Margin="0,1.5" Text="MachineCrab" />
<TextBlock Width="120" Margin="0,1.5" Text="五只大花狗" />
<TextBlock Width="120" Margin="0,1.5" Text="威尔特" />
<TextBlock Width="120" Margin="0,1.5" Text="StarNCosmos" />
<TextBlock Width="120" Margin="0,1.5" Text="Eason" />
<TextBlock Width="120" Margin="0,1.5" Text="风之幻城" />
<TextBlock Width="120" Margin="0,1.5" Text="王舒晨" />
<TextBlock Width="120" Margin="0,1.5" Text="H" />
<TextBlock Width="120" Margin="0,1.5" Text="咏夕" />
<TextBlock Width="120" Margin="0,1.5" Text="不及君子柒" />
<TextBlock Width="120" Margin="0,1.5" Text="GUAN_SKD" />
<TextBlock Width="120" Margin="0,1.5" Text="雅柏菲卡" />
<TextBlock Width="120" Margin="0,1.5" Text="AtDusk" />
<TextBlock Width="120" Margin="0,1.5" Text="九月想睡觉" />
<TextBlock Width="120" Margin="0,1.5" Text="六七" />
<TextBlock Width="120" Margin="0,1.5" Text="老登" />
<TextBlock Width="120" Margin="0,1.5" Text="wd_xuan" />
<TextBlock Width="120" Margin="0,1.5" Text="Wake" />
<TextBlock Width="120" Margin="0,1.5" Text="Jannik" />
<TextBlock Width="120" Margin="0,1.5" Text="cybone" />
<TextBlock Width="120" Margin="0,1.5" Text="mc12345zhl123" />
<TextBlock Width="120" Margin="0,1.5" Text="解" />
<TextBlock Width="120" Margin="0,1.5" Text="Akights" />
<TextBlock Width="120" Margin="0,1.5" Text="秋刀驴" />
<TextBlock Width="120" Margin="0,1.5" Text="樟涛竹" />
<TextBlock Width="120" Margin="0,1.5" Text="sikuno" />
<TextBlock Width="120" Margin="0,1.5" Text="鬼目" />
<TextBlock Width="120" Margin="0,1.5" Text="拜拜白" />
<TextBlock Width="120" Margin="0,1.5" Text="绮铃kirin" />
<TextBlock Width="120" Margin="0,1.5" Text="洛逍遥" />
<TextBlock Width="120" Margin="0,1.5" Text="文文新闻" />
<TextBlock Width="120" Margin="0,1.5" Text="GM" />
<TextBlock Width="120" Margin="0,1.5" Text="小咪" />
<TextBlock Width="120" Margin="0,1.5" Text="Fuxi Fuji" />
<TextBlock Width="120" Margin="0,1.5" Text="?独爱蝉HIA" />
<TextBlock Width="240" Margin="0,1.5" Text="没有咖啡的猫屎咖啡" />
<TextBlock Width="120" Margin="0,1.5" Text="雪风保佑我" />
<TextBlock Width="120" Margin="0,1.5" Text="zhnj" />
<TextBlock Width="120" Margin="0,1.5" Text="火苟" />
<TextBlock Width="120" Margin="0,1.5" Text="梦尽" />
<TextBlock Width="120" Margin="0,1.5" Text="阿泽free" />
<TextBlock Width="120" Margin="0,1.5" Text="阿乐" />
<TextBlock Width="120" Margin="0,1.5" Text="米线" />
<TextBlock Width="120" Margin="0,1.5" Text="依凡" />
<TextBlock Width="120" Margin="0,1.5" Text="涟燃556" />
<TextBlock Width="120" Margin="0,1.5" Text="夏季" />
<TextBlock Width="120" Margin="0,1.5" Text="Game_ReAi" />
<TextBlock Width="120" Margin="0,1.5" Text="秦屎皇" />
<TextBlock Width="120" Margin="0,1.5" Text="6" />
<TextBlock Width="120" Margin="0,1.5" Text="461863352" />
<TextBlock Width="120" Margin="0,1.5" Text="庭" />
<TextBlock Width="120" Margin="0,1.5" Text="Xing_K" />
<TextBlock Width="120" Margin="0,1.5" Text="yzt" />
<TextBlock Width="120" Margin="0,1.5" Text="nuycn" />
<TextBlock Width="120" Margin="0,1.5" Text="鸡人" />
<TextBlock Width="120" Margin="0,1.5" Text="爱无界i" />
<TextBlock Width="120" Margin="0,1.5" Text="Zik yeung" />
<TextBlock Width="120" Margin="0,1.5" Text="awawa" />
<TextBlock Width="120" Margin="0,1.5" Text="智慧村村长" />
<TextBlock Width="120" Margin="0,1.5" Text="海中燕" />
<TextBlock Width="120" Margin="0,1.5" Text="就叫我好人吧" />
<TextBlock Width="120" Margin="0,1.5" Text="梦的回响" />
<TextBlock Width="120" Margin="0,1.5" Text="。。" />
<TextBlock Width="120" Margin="0,1.5" Text="墨子吉安" />
<TextBlock Width="120" Margin="0,1.5" Text="有风" />
<TextBlock Width="240" Margin="0,1.5" Text="孙嘉昊まごかひろし" />
<TextBlock Width="120" Margin="0,1.5" Text="C" />
<TextBlock Width="120" Margin="0,1.5" Text="Haio" />
<TextBlock Width="120" Margin="0,1.5" Text="陆光" />
<TextBlock Width="120" Margin="0,1.5" Text="chuveiro" />
<TextBlock Width="120" Margin="0,1.5" Text="无名氏34613" />
<TextBlock Width="120" Margin="0,1.5" Text="mr_kevin_x" />
<TextBlock Width="120" Margin="0,1.5" Text="来早点" />
<TextBlock Width="120" Margin="0,1.5" Text="柠果籽" />
<TextBlock Width="120" Margin="0,1.5" Text="cai1" />
<TextBlock Width="120" Margin="0,1.5" Text="小比登T^T" />
<TextBlock Width="120" Margin="0,1.5" Text="hb" />
<TextBlock Width="120" Margin="0,1.5" Text="caizzz" />
<TextBlock Width="120" Margin="0,1.5" Text="yyin" />
<TextBlock Width="120" Margin="0,1.5" Text="無言" />
<TextBlock Width="120" Margin="0,1.5" Text="修" />
<TextBlock Width="120" Margin="0,1.5" Text="改头换面" />
<TextBlock Width="120" Margin="0,1.5" Text="无敌百搭的款式" />
<TextBlock Width="120" Margin="0,1.5" Text="御坂1354号" />
<TextBlock Width="120" Margin="0,1.5" Text="木子" />
<TextBlock Width="120" Margin="0,1.5" Text="萤火焱攸" />
<TextBlock Width="120" Margin="0,1.5" Text="盼盼不是Panda" />
<TextBlock Width="120" Margin="0,1.5" Text="烤肉真香" />
<TextBlock Width="120" Margin="0,1.5" Text="Chr0n0s" />
<TextBlock Width="120" Margin="0,1.5" Text="七" />
<TextBlock Width="120" Margin="0,1.5" Text="H?O" />
<TextBlock Width="120" Margin="0,1.5" Text="瑞霖RLD" />
<TextBlock Width="120" Margin="0,1.5" Text="AAcfun" />
<TextBlock Width="120" Margin="0,1.5" Text="鼬嘁" />
<TextBlock Width="120" Margin="0,1.5" Text="名为冉冉的猫" />
<TextBlock Width="120" Margin="0,1.5" Text="hduqggd55379" />
<TextBlock Width="120" Margin="0,1.5" Text="唠叨的土豆" />
<TextBlock Width="120" Margin="0,1.5" Text="Lonely_Grey" />
<TextBlock Width="120" Margin="0,1.5" Text="Vergilio" />
<TextBlock Width="120" Margin="0,1.5" Text="このdioた" />
<TextBlock Width="120" Margin="0,1.5" Text="没睡醒的肉啊" />
<TextBlock Width="120" Margin="0,1.5" Text="铃鸢" />
<TextBlock Width="120" Margin="0,1.5" Text="lvke" />
<TextBlock Width="120" Margin="0,1.5" Text="V-Merlin" />
<TextBlock Width="120" Margin="0,1.5" Text="美式加冰?" />
<TextBlock Width="120" Margin="0,1.5" Text="半岛弥音" />
<TextBlock Width="120" Margin="0,1.5" Text="clclFL" />
<TextBlock Width="120" Margin="0,1.5" Text="事与愿违" />
<TextBlock Width="120" Margin="0,1.5" Text="SamXU1322" />
<TextBlock Width="120" Margin="0,1.5" Text="OCEANI" />
<TextBlock Width="120" Margin="0,1.5" Text="shenpli" />
<TextBlock Width="120" Margin="0,1.5" Text="咸鱼嫌鱼咸" />
<TextBlock Width="120" Margin="0,1.5" Text="kirsnow" />
<TextBlock Width="120" Margin="0,1.5" Text="白庶" />
<TextBlock Width="120" Margin="0,1.5" Text="pengyihang" />
<TextBlock Width="120" Margin="0,1.5" Text="憨憨剑踏" />
<TextBlock Width="120" Margin="0,1.5" Text="SinceCN" />
<TextBlock Width="120" Margin="0,1.5" Text="ZhuTan12" />
<TextBlock Width="120" Margin="0,1.5" Text="tom" />
<TextBlock Width="120" Margin="0,1.5" Text="洛竹" />
<TextBlock Width="120" Margin="0,1.5" Text="foob" />
<TextBlock Width="120" Margin="0,1.5" Text="Garylu" />
<TextBlock Width="120" Margin="0,1.5" Text="阮绍轩" />
<TextBlock Width="120" Margin="0,1.5" Text="xin822" />
<TextBlock Width="120" Margin="0,1.5" Text="BAIgivele" />
<TextBlock Width="120" Margin="0,1.5" Text="ljc" />
<TextBlock Width="120" Margin="0,1.5" Text="暖笑" />
<TextBlock Width="120" Margin="0,1.5" Text="焦糖流酥" />
<TextBlock Width="120" Margin="0,1.5" Text="绚丽的星河" />
<TextBlock Width="120" Margin="0,1.5" Text="魔导兔" />
<TextBlock Width="120" Margin="0,1.5" Text="吾乃斗笔" />
<TextBlock Width="120" Margin="0,1.5" Text="君殇" />
<TextBlock Width="120" Margin="0,1.5" Text="沙轻" />
<TextBlock Width="120" Margin="0,1.5" Text="邓布利多" />
<TextBlock Width="120" Margin="0,1.5" Text="红薯散养专业户" />
<TextBlock Width="120" Margin="0,1.5" Text="十言" />
<TextBlock Width="120" Margin="0,1.5" Text="vvvghjvvv" />
<TextBlock Width="120" Margin="0,1.5" Text="法斯" />
<TextBlock Width="120" Margin="0,1.5" Text="DASENSUN" />
<TextBlock Width="120" Margin="0,1.5" Text="HTS" />
<TextBlock Width="120" Margin="0,1.5" Text="握不住信新心" />
<TextBlock Width="120" Margin="0,1.5" Text="sycuuj133" />
<TextBlock Width="120" Margin="0,1.5" Text="天杉大将军" />
<TextBlock Width="120" Margin="0,1.5" Text="风见翎" />
<TextBlock Width="120" Margin="0,1.5" Text="江心Rain" />
</WrapPanel>
<Grid Height="35">
<Grid.ColumnDefinitions>
@@ -385,7 +408,7 @@
<TextBlock Margin="0,0,0,2" LineHeight="17" Text="Copyright © 龙腾猫跃 2016. All Rights Reserved.&#13;计算机软件著作权登记号:2020SR0875133&#13;违法违规行为举报投诉邮箱:hexdragon@vip.qq.com&#13;非 MINECRAFT 官方产品。未经 MOJANG 或 MICROSOFT 批准,也不与 MOJANG 或 MICROSOFT 关联。" TextWrapping="Wrap" />
<StackPanel Orientation="Horizontal" Height="35" HorizontalAlignment="Left" Margin="0,12,0,0">
<local:MyButton Text="用户协议与免责声明" Width="170" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" EventType="打开网页" EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW" />
<local:MyButton Text="开源代码" Width="140" Padding="13,0" EventType="打开网页" EventData="https://github.com/Meloong-Git/PCL" />
<local:MyButton Text="开源代码" Width="140" Padding="13,0" EventType="打开网页" EventData="https://github.com/Hex-Dragon/PCL2" />
</StackPanel>
</StackPanel>
</local:MyCard>
@@ -227,7 +227,7 @@
DeleteDirectory(Version.Path)
Hint("版本 " & Version.Name & " 已永久删除!", HintType.Finish)
Else
FileIO.FileSystem.DeleteDirectory(Version.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin)
FileIO.FileSystem.DeleteDirectory(Version.Path, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin)
Hint("版本 " & Version.Name & " 已删除到回收站!", HintType.Finish)
End If
Case 2
@@ -205,7 +205,7 @@
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnSkinSave" Text="保存皮肤" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Row="1" />
<local:MyButton x:Name="BtnSkinCache" Text="刷新缓存" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ToolTip="刷新并重新下载 PCL 当前显示的皮肤" Grid.Row="1" Grid.Column="1" />
<local:MyButton x:Name="BtnSkinCache" Text="刷新" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ToolTip="刷新并重新下载 PCL 当前显示的皮肤" Grid.Row="1" Grid.Column="1" />
</Grid>
</Grid>
<Grid x:Name="PanSkinChange" Margin="0,14,0,2" Height="35" Visibility="Collapsed">
@@ -240,10 +240,10 @@
ToolTip="还原" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Logo="M530 0c287 0 521 229 521 511s-233 511-521 511c-233 0-436-151-500-368a63 63 0 0 1 44-79 65 65 0 0 1 80 43c48 162 200 276 375 276 215 0 390-171 390-383s-174-383-390-383c-103 0-199 39-270 106l21-5a63 63 0 0 1 33 123l-157 42a65 65 0 0 1-90-42l-49-183a65 65 0 1 1 126-33l6 26A524 524 0 0 1 530 0z" LogoScale="0.9" />
</StackPanel>
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Tag="LaunchAdvanceJvm" Grid.Column="1" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,除非有确定把握,否则请不要修改" MaxLength="4000"
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Tag="LaunchAdvanceJvm" Grid.Column="1" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,除非有确定把握,否则请不要修改。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。" MaxLength="4000"
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" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如输入 --demo 则会以试玩模式启动游戏。" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchAdvanceRun" Grid.Column="1" HintText=""
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;可以使用以下替换标记实现相对路径(路径均以 \ 结尾):&#xa; · {path}:PCL 的 exe 文件所在的文件夹&#xa; · {minecraft}:.minecraft 文件夹&#xa; · {verpath}:版本文件夹(.minecraft\versions\版本名\)&#xa; · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹&#xa; · {java}:游戏运行时的 Java 文件夹&#xa;&#xa;除此之外,也支持以下替换标记:&#xa; · {user}:玩家名字&#xa; · {login}:玩家的登录方式&#xa; · {uuid}:玩家的 UUID&#xa; · {name}:游戏版本名&#xa; · {date}、{time}:当前的系统时间&#xa; · {version}:游戏对应的原版版本号&#xa;&#xa;例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
@@ -198,7 +198,7 @@
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:MyCheckBox Grid.Column="0" Text="禁止在下载时复制已存在的文件" Height="22" x:Name="CheckDebugSkipCopy" Tag="SystemDebugSkipCopy" ToolTip="在下载时不直接复制已经存在的文件,而是重新下载每个文件。&#xa;只建议在测试下载速度时开启。" />
<local:MyCheckBox Grid.Column="0" Text="禁止在下载时从其他文件夹复制文件" Height="22" x:Name="CheckDebugSkipCopy" Tag="SystemDebugSkipCopy" ToolTip="在下载时不直接复制其他 MC 文件夹中已经存在的相同文件,而是重新下载文件。&#xa;只建议在测试下载速度时开启。" />
<local:MyCheckBox Grid.Column="1" Text="调试模式" Height="22" x:Name="CheckDebugMode" Tag="SystemDebugMode" ToolTip="显示调试信息与更多错误信息。&#xa;这会导致启动器性能略有下降,若无特殊需要不建议开启。" />
<local:MyCheckBox Grid.Column="2" Text="添加延迟" Height="22" x:Name="CheckDebugDelay" Tag="SystemDebugDelay" ToolTip="在各个环节添加随机的延迟,拖慢加载速度,以测试部分功能是否正常运行。&#xa;这会严重影响启动器运行,若无特殊需要不建议开启。" />
</Grid>
@@ -1,6 +1,4 @@
Imports NAudio.Wave
Public Class PageSetupUI
Public Class PageSetupUI
Public Shadows IsLoaded As Boolean = False
@@ -276,7 +274,7 @@ Public Class PageSetupUI
'顶部栏
Private Sub BtnLogoChange_Click(sender As Object, e As EventArgs) Handles BtnLogoChange.Click
Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.gif;*.webp;*.jpeg)|*.png;*.jpg;*.gif;*.webp;*.jpeg", "选择图片")
Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.jpeg;*.gif;*.webp)|*.png;*.jpg;*.jpeg;*.gif;*.webp", "选择图片")
If FileName = "" Then Return
Try
'拷贝文件
@@ -321,7 +319,7 @@ Refresh:
Return
End If
'没有图片则要求选择
Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.gif;*.webp)|*.png;*.jpg;*.gif;*.webp", "选择图片")
Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpeg;*.jpg;*.gif;*.webp)|*.png;*.jpeg;*.jpg;*.gif;*.webp", "选择图片")
If FileName = "" Then
FrmMain.ImageTitleLogo.Source = Nothing
e.Handled = True
@@ -359,15 +357,9 @@ Refresh:
PanMusicVolume.Visibility = Visibility.Visible
PanMusicDetail.Visibility = Visibility.Visible
BtnMusicClear.Visibility = Visibility.Visible
Dim validMusicCount As Integer = 0
For Each File In EnumerateFiles(Path & "PCL\Musics\")
Try
If {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(File.Extension.ToLower) Then Continue For
validMusicCount += 1
Catch ex As Exception
End Try
Next
CardMusic.Title = "背景音乐(" & validMusicCount & " 首)"
CardMusic.Title = "背景音乐(" &
EnumerateFiles(Path & "PCL\Musics\").Count(Function(f) {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(f.Extension.ToLower)) &
" 首)"
Else
PanMusicVolume.Visibility = Visibility.Collapsed
PanMusicDetail.Visibility = Visibility.Collapsed
@@ -564,8 +564,8 @@ Public Class PageVersionExport
Sub()
Try
Dim ModrinthHashes = Loader.Input.Select(Function(m) m.ModrinthHash)
Dim ModrinthRaw = CType(GetJson(DlModRequest("https://api.modrinth.com/v2/version_files", "POST",
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")), JObject)
Dim ModrinthRaw As JObject = DlModRequest("https://api.modrinth.com/v2/version_files", HttpMethod.Post,
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")
For Each ModFile In Loader.Input
'查找对应的文件
If Not ModrinthRaw.ContainsKey(ModFile.ModrinthHash) Then Continue For
@@ -589,8 +589,8 @@ Public Class PageVersionExport
Try
If ModrinthUploadMode Then Return 'Modrinth 上传模式下,不能从 CurseForge 获取信息
Dim CurseForgeHashes = Loader.Input.Select(Function(m) m.CurseForgeHash)
Dim CurseForgeRaw = CType(CType(GetJson(DlModRequest("https://api.curseforge.com/v1/fingerprints/432/", "POST",
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")), JObject)("data")("exactMatches"), JContainer)
Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432/", HttpMethod.Post,
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches")
For Each ResultJson As JObject In CurseForgeRaw
If Not ResultJson.ContainsKey("file") Then Continue For
Dim File As JObject = ResultJson("file")
@@ -381,8 +381,9 @@ Install:
''' 下载 Mod。
''' </summary>
Private Sub BtnManageDownload_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageDownload.Click, BtnHintDownload.Click
PageComp.TargetVersion = PageVersionLeft.Version '将当前版本设置为筛选器
PageComp.TargetName = SearchBox.Text '将当前搜索框内容设置为筛选器
'预设置当前版本和搜索框内容
PageComp.TargetVersion = PageVersionLeft.Version
PageComp.TargetName = SearchBox.Text
FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadMod)
End Sub
@@ -429,6 +430,11 @@ Install:
If FrmMain.PageRight IsNot Me Then Return
If My.Computer.Keyboard.CtrlKeyDown AndAlso e.Key = Key.A Then ChangeAllSelected(True)
End Sub
Private Sub SearchBox_PreviewKeyDown(sender As Object, e As KeyEventArgs) Handles SearchBox.PreviewKeyDown
'Ctrl + A 会被搜索框捕获,导致无法全选,所以在按下 Ctrl + A 时转移焦点以便捕获
If SearchBox.Text.Any Then Return
If My.Computer.Keyboard.CtrlKeyDown AndAlso e.Key = Key.A Then PanBack.Focus()
End Sub
#End Region
@@ -637,14 +643,14 @@ Install:
Try
For Each Entry As McMod In ModList
If File.Exists(Entry.Path) Then
My.Computer.FileSystem.DeleteFile(Entry.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin)
My.Computer.FileSystem.DeleteFile(Entry.Path, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin)
Else
Log($"[Mod] 未找到更新前的 Mod 文件,跳过对它的删除:{Entry.Path}", LogLevel.Debug)
End If
Next
For Each Entry As KeyValuePair(Of String, String) In FileCopyList
If File.Exists(Entry.Value) Then
My.Computer.FileSystem.DeleteFile(Entry.Value, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin)
My.Computer.FileSystem.DeleteFile(Entry.Value, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin)
Log($"[Mod] 更新后的 Mod 文件已存在,将会把它放入回收站:{Entry.Value}", LogLevel.Debug)
End If
If Directory.Exists(GetPathFromFullPath(Entry.Value)) Then
@@ -733,7 +739,7 @@ Install:
If IsShiftPressed Then
File.Delete(ModEntity.Path)
Else
My.Computer.FileSystem.DeleteFile(ModEntity.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin)
My.Computer.FileSystem.DeleteFile(ModEntity.Path, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin)
End If
Catch ex As OperationCanceledException
Log(ex, "删除 Mod 被主动取消")
@@ -116,12 +116,14 @@
Dim TempName As String = NewName & "_temp"
Dim TempPath As String = PathMcFolder & "versions\" & TempName & "\"
Dim IsCaseChangedOnly As Boolean = NewName.ToLower = OldName.ToLower
'重新加载版本 Json 信息,避免 HMCL 项被合并
'重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储
Dim JsonObject As JObject
Try
JsonObject = GetJson(ReadFile(PageVersionLeft.Version.Path & PageVersionLeft.Version.Name & ".json"))
Dim JsonPath As String = PageVersionLeft.Version.GetJsonPath()
JsonObject = GetJson(ReadFile(JsonPath))
File.Delete(JsonPath)
Catch ex As Exception
Log(ex, "重命名读取 json 时失败")
Log(ex, "在重命名读取 json 时失败")
JsonObject = PageVersionLeft.Version.JsonObject
End Try
'重命名主文件夹
@@ -130,32 +132,24 @@
'清理 ini 缓存
IniClearCache(PageVersionLeft.Version.PathIndie & "options.txt")
IniClearCache(PageVersionLeft.Version.Path & "PCL\Setup.ini")
'重命名 JAR 文件、JSON 文件与 natives 文件夹
If Directory.Exists(NewPath & OldName & "-natives") Then
'重命名 jar 文件与 natives 文件夹
'不能进行遍历重命名,否则在版本名很短的时候容易误伤其他文件(#6443)
If Directory.Exists($"{NewPath}{OldName}-natives") Then
If IsCaseChangedOnly Then
My.Computer.FileSystem.RenameDirectory(NewPath & OldName & "-natives", OldName & "natives" & "_temp")
My.Computer.FileSystem.RenameDirectory(NewPath & OldName & "-natives" & "_temp", NewName & "-natives")
My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives", $"{OldName}natives_temp")
My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives_temp", $"{NewName}-natives")
Else
DeleteDirectory(NewPath & NewName & "-natives")
My.Computer.FileSystem.RenameDirectory(NewPath & OldName & "-natives", NewName & "-natives")
DeleteDirectory($"{NewPath}{NewName}-natives")
My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives", $"{NewName}-natives")
End If
End If
If File.Exists(NewPath & OldName & ".jar") Then
If File.Exists($"{NewPath}{OldName}.jar") Then
If IsCaseChangedOnly Then
My.Computer.FileSystem.RenameFile(NewPath & OldName & ".jar", OldName & "_temp" & ".jar")
My.Computer.FileSystem.RenameFile(NewPath & OldName & "_temp" & ".jar", NewName & ".jar")
My.Computer.FileSystem.RenameFile($"{NewPath}{OldName}.jar", $"{OldName}_temp.jar")
My.Computer.FileSystem.RenameFile($"{NewPath}{OldName}_temp.jar", $"{NewName}.jar")
Else
File.Delete(NewPath & NewName & ".jar")
My.Computer.FileSystem.RenameFile(NewPath & OldName & ".jar", NewName & ".jar")
End If
End If
If File.Exists(NewPath & OldName & ".json") Then
If IsCaseChangedOnly Then
My.Computer.FileSystem.RenameFile(NewPath & OldName & ".json", OldName & "_temp" & ".json")
My.Computer.FileSystem.RenameFile(NewPath & OldName & "_temp" & ".json", NewName & ".json")
Else
File.Delete(NewPath & NewName & ".json")
My.Computer.FileSystem.RenameFile(NewPath & OldName & ".json", NewName & ".json")
File.Delete($"{NewPath}{NewName}.jar")
My.Computer.FileSystem.RenameFile($"{NewPath}{OldName}.jar", $"{NewName}.jar")
End If
End If
'替换版本设置文件中的路径
@@ -166,15 +160,13 @@
If ReadIni(PathMcFolder & "PCL.ini", "Version") = OldName Then
WriteIni(PathMcFolder & "PCL.ini", "Version", NewName)
End If
'更改版本 Json
If File.Exists(NewPath & NewName & ".json") Then
'写入版本 Json
Try
JsonObject("id") = NewName
WriteFile(NewPath & NewName & ".json", JsonObject.ToString)
Catch ex As Exception
Log(ex, "重命名版本 json 失败")
End Try
End If
'刷新与提示
Hint("重命名成功!", HintType.Finish)
PageVersionLeft.Version = New McVersion(NewName).Load()
@@ -192,7 +184,7 @@
'选择 自定义 时修改图片
Try
If ComboDisplayLogo.SelectedItem Is ItemDisplayLogoCustom Then
Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.gif;*.jpeg)|*.png;*.jpg;*.gif;*.jpeg", "选择图片")
Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpeg;*.jpg;*.gif;*.webp)|*.png;*.jpeg;*.jpg;*.gif;*.webp", "选择图片")
If FileName = "" Then
Reload() '还原选项
Return
@@ -209,10 +209,10 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="JVM 参数头部" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.Row="0" Grid.ColumnSpan="2" Tag="VersionAdvanceJvm" Grid.Column="1" MaxLength="4000" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,在没有确定把握的情况下请不要尝试修改。&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置"
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.Row="0" Grid.ColumnSpan="2" Tag="VersionAdvanceJvm" Grid.Column="1" MaxLength="4000" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,在没有确定把握的情况下请不要尝试修改。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置"
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" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如输入 --demo 则会以试玩模式启动游戏。&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3"
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。&#xa;&#xa;在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;可以使用以下替换标记实现相对路径(路径均以 \ 结尾):&#xa; · {path}:PCL 的 exe 文件所在的文件夹&#xa; · {minecraft}:.minecraft 文件夹&#xa; · {verpath}:版本文件夹(.minecraft\versions\版本名\)&#xa; · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹&#xa; · {java}:游戏运行时的 Java 文件夹&#xa;&#xa;除此之外,也支持以下替换标记:&#xa; · {user}:玩家名字&#xa; · {login}:玩家的登录方式&#xa; · {uuid}:玩家的 UUID&#xa; · {name}:游戏版本名&#xa; · {date}、{time}:当前的系统时间&#xa; · {version}:游戏对应的原版版本号&#xa;&#xa;例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
@@ -140,6 +140,21 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="CacheCow.Client, Version=2.13.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Resources\CacheCow.Client.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="CacheCow.Client.FileStore, Version=2.13.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Resources\CacheCow.Client.FileStore.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="CacheCow.Common, Version=2.13.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Resources\CacheCow.Common.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Imazen.WebP, Version=10.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Resources\Imazen.WebP.dll</HintPath>
@@ -149,8 +164,9 @@
<SpecificVersion>False</SpecificVersion>
<Private>False</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Resources\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Ookii.Dialogs.Wpf, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0c15020868fd6249, processorArchitecture=MSIL">
@@ -158,13 +174,20 @@
<HintPath>Resources\Ookii.Dialogs.Wpf.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Management" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Resources\System.Net.Http.Formatting.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
@@ -195,11 +218,14 @@
<Compile Include="Controls\MyIconTextButton.xaml.vb">
<DependentUpon>MyIconTextButton.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Base\ModDragHelper.vb" />
<Compile Include="Modules\Minecraft\ModComp.vb" />
<Compile Include="Modules\Minecraft\ModJava.vb" />
<Compile Include="Modules\Minecraft\ModMod.vb" />
<Compile Include="Modules\Minecraft\ModModpack.vb" />
<Compile Include="Modules\ThirdParty\DragHelper.vb" />
<Compile Include="Pages\PageVersion\MyLocalModItem.xaml.vb">
<DependentUpon>MyLocalModItem.xaml</DependentUpon>
</Compile>
@@ -233,9 +259,6 @@
<Compile Include="Modules\ModDevelop.vb" />
<Compile Include="Modules\Minecraft\ModWatcher.vb" />
<Compile Include="Modules\ModSecret.vb" />
<Compile Include="Modules\Reference\CookieWebClient.vb">
<SubType>Component</SubType>
</Compile>
<Compile Include="Pages\PageDownload\Comp\PageComp.xaml.vb">
<DependentUpon>PageComp.xaml</DependentUpon>
</Compile>
@@ -499,6 +522,7 @@
<DependentUpon>FormMain.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Pages\PageVersion\MyLocalModItem.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -721,6 +745,7 @@
<Import Include="System.IO" />
<Import Include="System.Linq" />
<Import Include="System.Net" />
<Import Include="System.Net.Http" />
<Import Include="System.Text" />
<Import Include="System.Threading" />
<Import Include="System.Xml.Linq" />
@@ -946,6 +971,7 @@
<Resource Include="Images\Heads\MCBBS.png" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<Resource Include="Images\Blocks\NeoForge.png" />
@@ -957,5 +983,18 @@
<None Include="Resources\Imazen.WebP.dll" />
<None Include="Resources\libwebp64.dll" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\CacheCow.Client.FileStore.dll" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\CacheCow.Common.dll" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\CacheCow.Client.dll" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\System.Net.Http.Formatting.dll" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project>
Binary file not shown.
Binary file not shown.
@@ -134,6 +134,10 @@
Text="切换到下载页面" EventType="切换页面" EventData="1|1"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="切换到启动器设置" EventType="切换页面" EventData="3|2"/>
<TextBlock Margin="0,4,0,4"
Text="· 下载版本:切换到 EventData 对应的 Minecraft 下载页面"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="下载 Minecraft 1.12.2" EventType="下载版本" EventData="1.12.2"/>
</StackPanel>
</local:MyCard>
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.