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"/> <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/> <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
</dependentAssembly> </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> </assemblyBinding>
</runtime> </runtime>
</configuration> </configuration>
+19 -43
View File
@@ -181,53 +181,29 @@ WaitRetry:
End Sub End Sub
'动态 DLL 调用 '动态 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 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 Public Shared Function AssemblyResolve(sender As Object, Args As ResolveEventArgs) As Assembly
If args.Name.StartsWithF("NAudio") Then '缓存
SyncLock AssemblyNAudioLock Static Prefixes As String() = {"NAudio", "Newtonsoft.Json", "Ookii.Dialogs.Wpf", "Imazen.WebP", "CacheCow.Common", "CacheCow.Client.FileStore", "CacheCow.Client", "System.Net.Http.Formatting"}
If AssemblyNAudio Is Nothing Then Static Locks As New Dictionary(Of String, Object)(StringComparer.Ordinal)
Log("[Start] 加载 DLL:NAudio") Static LoadedAssembly As New Dictionary(Of String, Assembly)(StringComparer.Ordinal)
AssemblyNAudio = Assembly.Load(GetResources("NAudio")) '查找对应的 DLL
End If Dim Prefix As String = Prefixes.FirstOrDefault(Function(p) Args.Name.StartsWithF(p))
Return AssemblyNAudio If Prefix Is Nothing Then Return Nothing
End SyncLock '加载 DLL
ElseIf args.Name.StartsWithF("Newtonsoft.Json") Then If Not Locks.ContainsKey(Prefix) Then Locks(Prefix) = New Object()
SyncLock AssemblyJsonLock SyncLock Locks(Prefix)
If AssemblyJson Is Nothing Then If Not LoadedAssembly.ContainsKey(Prefix) Then
Log("[Start] 加载 DLL:Json") Log($"[Start] 加载 DLL:{Prefix}")
AssemblyJson = Assembly.Load(GetResources("Json")) LoadedAssembly(Prefix) = Assembly.Load(GetResources(Prefix))
End If 'WebP 特判
Return AssemblyJson If Prefix = "Imazen.WebP" Then
End SyncLock SetDllDirectory(PathPure.TrimEnd("\"c))
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("\"))
WriteFile(PathPure & "libwebp.dll", GetResources("libwebp64")) WriteFile(PathPure & "libwebp.dll", GetResources("libwebp64"))
End If End If
Return AssemblyImazenWebp
End SyncLock
Else
Return Nothing
End If End If
Return LoadedAssembly(Prefix)
End SyncLock
End Function End Function
'切换窗口 '切换窗口
+33 -35
View File
@@ -83,6 +83,13 @@ Public Class FormMain
'3:BUG+ IMP* FEAT- '3:BUG+ IMP* FEAT-
'2:BUG* IMP- '2:BUG* IMP-
'1:BUG- '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 If LastVersion < 362 Then 'Snapshot 2.10.3
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法安装部分使用老版本 PCL 导出的整合包")) FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法安装部分使用老版本 PCL 导出的整合包"))
End If End If
@@ -204,8 +211,6 @@ Public Class FormMain
End Sub, "UpdateLog Output") End Sub, "UpdateLog Output")
End Sub End Sub
Private ReadOnly Helper As New DragFileHelper()
'窗口加载 '窗口加载
Private IsWindowLoadFinished As Boolean = False Private IsWindowLoadFinished As Boolean = False
Public Sub New() Public Sub New()
@@ -228,7 +233,7 @@ Public Class FormMain
If Not Setup.IsUnset("LaunchArgumentIndie") Then If Not Setup.IsUnset("LaunchArgumentIndie") Then
Log("[Start] 从老 PCL 迁移版本隔离") Log("[Start] 从老 PCL 迁移版本隔离")
Setup.Set("LaunchArgumentIndieV2", Setup.Get("LaunchArgumentIndie")) Setup.Set("LaunchArgumentIndieV2", Setup.Get("LaunchArgumentIndie"))
ElseIf Not Setup.IsUnset("WindowHeight") Then ElseIf Not Setup.IsUnset("LaunchVersionSelect") Then
Log("[Start] 从老 PCL 升级,但此前未调整版本隔离,使用老的版本隔离默认值") Log("[Start] 从老 PCL 升级,但此前未调整版本隔离,使用老的版本隔离默认值")
Setup.Set("LaunchArgumentIndieV2", Setup.GetDefault("LaunchArgumentIndie")) Setup.Set("LaunchArgumentIndieV2", Setup.GetDefault("LaunchArgumentIndie"))
Else Else
@@ -244,36 +249,24 @@ Public Class FormMain
[AddHandler](DragDrop.DragOverEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True) [AddHandler](DragDrop.DragOverEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True)
'加载 UI '加载 UI
InitializeComponent() InitializeComponent()
Opacity = 0 Opacity = 0
'旧代码 '开启管理员权限下的文件拖拽
''开启管理员权限下的文件拖拽,但下列代码也没用(#2531) If IsAdmin() Then
'If IsAdmin() Then Static Helper As New DragHelper
' Log("[Start] PCL 正以管理员权限运行") 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(&H233, 1)
' ChangeWindowMessageFilter(&H4A, 1) ' ChangeWindowMessageFilter(&H4A, 1)
' ChangeWindowMessageFilter(&H49, 1) ' ChangeWindowMessageFilter(&H49, 1)
'End If '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(FrmLaunchLeft.Parent) Then FrmLaunchLeft.SetValue(ContentPresenter.ContentProperty, Nothing)
If Not IsNothing(FrmLaunchRight.Parent) Then FrmLaunchRight.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 Catch ex As Exception
Log(ex, "清理自动更新文件失败") Log(ex, "清理自动更新文件失败")
End Try End Try
End Sub, "Start Loader", ThreadPriority.Lowest) End Sub, "初始化", ThreadPriority.Lowest)
Log("[Start] 第三阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms") Log("[Start] 第三阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
End Sub End Sub
@@ -616,11 +609,12 @@ Public Class FormMain
'按键事件 '按键事件
Private Sub FormMain_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown Private Sub FormMain_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If e.IsRepeat Then Return If e.IsRepeat Then Return
'调用弹窗:回车选择第一个,Esc 选择最后一个 '修复按下 Alt 后误认为弹出系统菜单导致的冻结
If PanMsg.Children.Count > 0 Then 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 If e.Key = Key.Enter Then
CType(PanMsg.Children(0), Object).Btn1_Click() CType(PanMsg.Children(0), Object).Btn1_Click()
Return
ElseIf e.Key = Key.Escape Then ElseIf e.Key = Key.Escape Then
Dim Msg As Object = PanMsg.Children(0) Dim Msg As Object = PanMsg.Children(0)
If TypeOf Msg IsNot MyMsgInput AndAlso TypeOf Msg IsNot MyMsgSelect AndAlso Msg.Btn3.Visibility = Visibility.Visible Then 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 Else
Msg.Btn1_Click() Msg.Btn1_Click()
End If End If
End If
Return Return
End If End If
End If
'==========================
' 在没有弹窗时:继续检查……
'==========================
'按 ESC 返回上一级 '按 ESC 返回上一级
If e.Key = Key.Escape Then TriggerPageBack() If e.Key = Key.Escape Then TriggerPageBack()
'更改隐藏版本可见性 '更改隐藏版本可见性
@@ -666,8 +665,6 @@ Public Class FormMain
FrmLaunchLeft.LaunchButtonClick() FrmLaunchLeft.LaunchButtonClick()
End If End If
End If End If
'修复按下 Alt 后误认为弹出系统菜单导致的冻结
If e.SystemKey = Key.LeftAlt OrElse e.SystemKey = Key.RightAlt Then e.Handled = True
End Sub End Sub
Private Sub FormMain_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseDown Private Sub FormMain_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseDown
'鼠标侧键返回上一级 '鼠标侧键返回上一级
@@ -732,6 +729,7 @@ Public Class FormMain
End Sub End Sub
Private Sub FrmMain_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop Private Sub FrmMain_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop
Try Try
ShowWindowToTop()
If e.Data.GetDataPresent(DataFormats.Text) Then If e.Data.GetDataPresent(DataFormats.Text) Then
'获取文本 '获取文本
Try Try
+29 -13
View File
@@ -13,13 +13,13 @@ Public Module ModBase
#Region "声明" #Region "声明"
'下列版本信息由更新器自动修改 '下列版本信息由更新器自动修改
Public Const VersionBaseName As String = "2.10.3" '不含分支前缀的显示用版本名 Public Const VersionBaseName As String = "2.10.4" '不含分支前缀的显示用版本名
Public Const VersionStandardCode As String = "2.10.3." & VersionBranchCode '标准格式的四段式版本号 Public Const VersionStandardCode As String = "2.10.4." & VersionBranchCode '标准格式的四段式版本号
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换 Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
#If BETA Then #If BETA Then
Public Const VersionCode As Integer = 361 'Release Public Const VersionCode As Integer = 361 'Release
#Else #Else
Public Const VersionCode As Integer = 362 'Snapshot Public Const VersionCode As Integer = 363 'Snapshot
#End If #End If
'自动生成的版本信息 '自动生成的版本信息
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -1551,7 +1551,7 @@ RetryDir:
''' <summary> ''' <summary>
''' 获取 JSON 对象。 ''' 获取 JSON 对象。
''' </summary> ''' </summary>
Public Function GetJson(Data As String) Public Function GetJson(Data As String) As JToken
Try Try
Return JsonConvert.DeserializeObject(Data, New JsonSerializerSettings With {.DateTimeZoneHandling = DateTimeZoneHandling.Local}) Return JsonConvert.DeserializeObject(Data, New JsonSerializerSettings With {.DateTimeZoneHandling = DateTimeZoneHandling.Local})
Catch ex As Exception Catch ex As Exception
@@ -2131,6 +2131,19 @@ RetryDir:
End Function End Function
End Class 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>
''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。 ''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。
''' </summary> ''' </summary>
@@ -2179,10 +2192,10 @@ RetryDir:
End Function End Function
''' <summary> ''' <summary>
''' 判断当前系统语言是否为 zh-CN。 ''' 判断当前系统语言是否为中文。
''' </summary> ''' </summary>
Public Function IsSystemLanguageChinese() As Boolean 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 End Function
Private Uuid As Integer = 1 Private Uuid As Integer = 1
@@ -2225,6 +2238,9 @@ NextElement:
Next i Next i
Return ResultArray Return ResultArray
End Function End Function
<Extension> Public Function Any(Arr As UIElementCollection) As Boolean
Return Arr?.Count > 0
End Function
''' <summary> ''' <summary>
''' 获取格式类似于“11:08:52.037”的当前时间的字符串。 ''' 获取格式类似于“11:08:52.037”的当前时间的字符串。
@@ -2462,7 +2478,7 @@ NextElement:
''' </summary> ''' </summary>
Public Sub RunInThread(Action As Action) Public Sub RunInThread(Action As Action)
If RunInUi() Then If RunInUi() Then
RunInNewThread(Action, "Runtime Invoke " & GetUuid() & "#") RunInNewThread(Action, "Invoke " & GetUuid())
Else Else
Action() Action()
End If End If
@@ -2760,11 +2776,11 @@ Retry:
Using Reader As New XamlXmlReader(Stream) Using Reader As New XamlXmlReader(Stream)
While Reader.Read() While Reader.Read()
For Each BlackListType In {GetType(WebBrowser), GetType(Frame), GetType(MediaElement), GetType(ObjectDataProvider), GetType(XamlReader), GetType(Window), GetType(XmlDataProvider)} 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.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.Value IsNot Nothing AndAlso Reader.Value = BlackListType.Name Then Throw New UnauthorizedAccessException($"基于安全考虑,不允许使用 {BlackListType.Name} 值。")
Next Next
For Each BlackListMember In {"Code", "FactoryMethod", "Static"} 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 Next
End While End While
End Using End Using
@@ -2922,7 +2938,7 @@ Retry:
'处理错误会导致再次调用 Log() 导致无限循环 '处理错误会导致再次调用 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 If ModeDebug Then
SyncLock LogListLock SyncLock LogListLock
LogList.Append(AppendText) LogList.Append(AppendText)
@@ -2986,7 +3002,7 @@ Retry:
Dim ExFull As String = Desc & ":" & GetExceptionDetail(Ex) 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 If ModeDebug Then
SyncLock LogListLock SyncLock LogListLock
LogList.Append(AppendText) LogList.Append(AppendText)
@@ -3048,7 +3064,7 @@ Retry:
If ForceOpenLog OrElse (ShowMsgbox AndAlso MyMsgBox("若你在汇报一个 Bug,请点击 打开文件夹 按钮,并上传 Log(1~5).txt 中包含错误信息的文件。" & vbCrLf & "游戏崩溃一般与启动器无关,请不要因为游戏崩溃而提交反馈。", "反馈提交提醒", "打开文件夹", "不需要") = 1) Then If ForceOpenLog OrElse (ShowMsgbox AndAlso MyMsgBox("若你在汇报一个 Bug,请点击 打开文件夹 按钮,并上传 Log(1~5).txt 中包含错误信息的文件。" & vbCrLf & "游戏崩溃一般与启动器无关,请不要因为游戏崩溃而提交反馈。", "反馈提交提醒", "打开文件夹", "不需要") = 1) Then
OpenExplorer(Path & "PCL\Log1.txt") OpenExplorer(Path & "PCL\Log1.txt")
End If End If
OpenWebsite("https://github.com/Hex-Dragon/PCL2/issues/") OpenWebsite("https://github.com/Meloong-Git/PCL/issues/")
End Sub End Sub
Public Function CanFeedback(ShowHint As Boolean) As Boolean Public Function CanFeedback(ShowHint As Boolean) As Boolean
If False.Equals(PageSetupSystem.IsLauncherNewest) Then If False.Equals(PageSetupSystem.IsLauncherNewest) Then
@@ -339,7 +339,7 @@
[Error] = ex [Error] = ex
State = LoadState.Failed State = LoadState.Failed
End Try End Try
End Sub) With {.Name = Name, .Priority = ThreadPriority} End Sub) With {.Name = "L/" & Name, .Priority = ThreadPriority}
LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted
End Sub End Sub
Public Overrides Sub Abort() Public Overrides Sub Abort()
File diff suppressed because it is too large Load Diff
@@ -1076,7 +1076,7 @@ Retry:
Try Try
'获取工程列表 '获取工程列表
Log("[Comp] 开始从 CurseForge 获取工程列表:" & CurseForgeUrl) Log("[Comp] 开始从 CurseForge 获取工程列表:" & CurseForgeUrl)
Dim RequestResult As JObject = DlModRequest(CurseForgeUrl, IsJson:=True) Dim RequestResult As JObject = DlModRequest(CurseForgeUrl)
Task.Progress += 0.2 Task.Progress += 0.2
Dim ProjectList As New List(Of CompProject) Dim ProjectList As New List(Of CompProject)
For Each JsonEntry As JObject In RequestResult("data") For Each JsonEntry As JObject In RequestResult("data")
@@ -1107,7 +1107,7 @@ Retry:
Sub() Sub()
Try Try
Log("[Comp] 开始从 Modrinth 获取工程列表:" & ModrinthUrl) Log("[Comp] 开始从 Modrinth 获取工程列表:" & ModrinthUrl)
Dim RequestResult As JObject = DlModRequest(ModrinthUrl, IsJson:=True) Dim RequestResult As JObject = DlModRequest(ModrinthUrl)
Task.Progress += 0.2 Task.Progress += 0.2
Dim ProjectList As New List(Of CompProject) Dim ProjectList As New List(Of CompProject)
For Each JsonEntry As JObject In RequestResult("hits") For Each JsonEntry As JObject In RequestResult("hits")
@@ -1396,7 +1396,7 @@ Retry:
'DownloadAddress 'DownloadAddress
Dim Url = Data("downloadUrl").ToString 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}" 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 = HandleCurseForgeDownloadUrls(Url) '对脑残 CurseForge 的下载地址进行多种修正
DownloadUrls.AddRange(DownloadUrls.Select(Function(u) DlSourceModGet(u)).ToList) '添加镜像源,这个写法是为了让镜像源排在后面 DownloadUrls.AddRange(DownloadUrls.Select(Function(u) DlSourceModGet(u)).ToList) '添加镜像源,这个写法是为了让镜像源排在后面
DownloadUrls = DownloadUrls.Distinct.ToList '最终去重 DownloadUrls = DownloadUrls.Distinct.ToList '最终去重
@@ -1492,9 +1492,8 @@ Retry:
Return { Return {
Url.Replace("-service.overwolf.wtf", ".forgecdn.net").Replace("://edge.", "://mediafilez.").Replace("://media.", "://mediafilez."), Url.Replace("-service.overwolf.wtf", ".forgecdn.net").Replace("://edge.", "://mediafilez.").Replace("://media.", "://mediafilez."),
Url.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("-service.overwolf.wtf", ".forgecdn.net"),
Url.Replace("://edge.", "://media."), Url.Replace("://media.", "://edge."),
Url Url
}.Distinct.ToList }.Distinct.ToList
End Function End Function
@@ -1591,27 +1590,40 @@ Retry:
If CompProjectCache.ContainsKey(ProjectId) Then '存在缓存 If CompProjectCache.ContainsKey(ProjectId) Then '存在缓存
TargetProject = CompProjectCache(ProjectId) TargetProject = CompProjectCache(ProjectId)
ElseIf FromCurseForge Then 'CurseForge 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 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 End If
'获取工程对象的文件列表 '获取工程对象的文件列表
If Not CompFilesCache.ContainsKey(ProjectId) Then '有缓存也不能直接返回,这时候前置可能没获取(#5173) If Not CompFilesCache.ContainsKey(ProjectId) Then '有缓存也不能直接返回,这时候前置可能没获取(#5173)
Log("[Comp] 开始获取文件列表:" & ProjectId) Log("[Comp] 开始获取文件列表:" & ProjectId)
Dim ResultJsonArray As JArray Dim ResultJsonArray As JArray = Nothing
If FromCurseForge Then If FromCurseForge Then
'CurseForge '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) '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 使用每个版本最新的文件 '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 '否则使用全部文件 '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 '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 Else
'Modrinth '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 End If
CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)). CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)).
Where(Function(a) a.Available).ToList. Where(Function(a) a.Available).ToList.
@@ -1625,10 +1637,10 @@ Retry:
Log($"[Comp] {ProjectId} 文件列表中还需要获取信息的前置:{Join(UndoneDeps, ",")}") Log($"[Comp] {ProjectId} 文件列表中还需要获取信息的前置:{Join(UndoneDeps, ",")}")
Dim Projects As JArray Dim Projects As JArray
If TargetProject.FromCurseForge Then If TargetProject.FromCurseForge Then
Projects = GetJson(DlModRequest("https://api.curseforge.com/v1/mods", Projects = DlModRequest("https://api.curseforge.com/v1/mods",
"POST", "{""modIds"": [" & Join(UndoneDeps, ",") & "]}", "application/json"))("data") HttpMethod.Post, "{""modIds"": [" & Join(UndoneDeps, ",") & "]}", "application/json")("data")
Else 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 End If
For Each Project In Projects For Each Project In Projects
Dim Unused As New CompProject(Project) '在 New 的时候会添加缓存以便之后读取 Dim Unused As New CompProject(Project) '在 New 的时候会添加缓存以便之后读取
@@ -1018,9 +1018,9 @@ NextStack:
End If End If
Case CrashReason.特定实体导致崩溃 Case CrashReason.特定实体导致崩溃
If Additional.Count = 1 Then If Additional.Count = 1 Then
Results.Add("游戏似乎因为实体 " & Additional.First & " 出现了问题。\n\n你可以创建一个新世界,并生成一个该实体,然后观察游戏的运行情况:\n - 若正常运行,则是该实体导致出错,你或许需要使用一些方式删除此实体。\n - 若仍然出错,问题就可能来自其他原因……\h") Results.Add("游戏似乎因为实体 " & Additional.First & " 出现了问题。\n\n你可以创建一个新世界,并生成一个该实体,然后观察游戏的运行情况。\h")
Else Else
Results.Add("游戏似乎因为世界中的某些实体出现了问题。\n\n你可以创建一个新世界,并生成各种实体,观察游戏的运行情况:\n - 若正常运行,则是某些实体导致出错,你或许需要删除该世界。\n - 若仍然出错,问题就可能来自其他原因……\h") Results.Add("游戏似乎因为世界中的某些实体出现了问题。\n\n你可以创建一个新世界,并生成各种实体,然后观察游戏的运行情况。\h")
End If End If
Case CrashReason.OptiFine与Forge不兼容 Case CrashReason.OptiFine与Forge不兼容
Results.Add("由于 OptiFine 与当前版本的 Forge 不兼容,导致了游戏崩溃。\n\n请前往 OptiFine 官网(https://optifine.net/downloads)查看 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 IsNewClientVersionHinted As Boolean = False
Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult)) Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult))
Dim StartTime As Long = GetTimeTick() 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 Try
Dim Versions As JArray = Json("versions") Dim Versions As JArray = Json("versions")
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")") If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
@@ -235,7 +235,7 @@
''' </summary> ''' </summary>
Public DlClientListBmclapiLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain) Public DlClientListBmclapiLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain)
Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of String, DlClientListResult)) 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 Try
Dim Versions As JArray = Json("versions") Dim Versions As JArray = Json("versions")
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")") If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
@@ -377,7 +377,7 @@
''' </summary> ''' </summary>
Public DlOptiFineListOfficialLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Official", AddressOf DlOptiFineListOfficialMain) Public DlOptiFineListOfficialLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Official", AddressOf DlOptiFineListOfficialMain)
Private Sub DlOptiFineListOfficialMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult)) 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 & ")") If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
Try Try
'获取所有版本信息 '获取所有版本信息
@@ -413,7 +413,7 @@
''' </summary> ''' </summary>
Public DlOptiFineListBmclapiLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Bmclapi", AddressOf DlOptiFineListBmclapiMain) Public DlOptiFineListBmclapiLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Bmclapi", AddressOf DlOptiFineListBmclapiMain)
Private Sub DlOptiFineListBmclapiMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult)) 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 Try
Dim Versions As New List(Of DlOptiFineListEntry) Dim Versions As New List(Of DlOptiFineListEntry)
For Each Token As JObject In Json For Each Token As JObject In Json
@@ -483,7 +483,7 @@
''' </summary> ''' </summary>
Public DlForgeListOfficialLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Official", AddressOf DlForgeListOfficialMain) Public DlForgeListOfficialLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Official", AddressOf DlForgeListOfficialMain)
Private Sub DlForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlForgeListResult)) 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 & ")") 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)") Dim Names As List(Of String) = RegexSearch(Result, "(?<=a href=""index_)[0-9.]+(_pre[0-9]?)?(?=.html)")
@@ -497,7 +497,7 @@
''' </summary> ''' </summary>
Public DlForgeListBmclapiLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Bmclapi", AddressOf DlForgeListBmclapiMain) Public DlForgeListBmclapiLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Bmclapi", AddressOf DlForgeListBmclapiMain)
Private Sub DlForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlForgeListResult)) 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 & ")") If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
'获取所有版本信息 '获取所有版本信息
Dim Names As List(Of String) = RegexSearch(Result, "[0-9.]+(_pre[0-9]?)?") 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))) Public Sub DlForgeVersionOfficialMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
Dim Result As String Dim Result As String
Try 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 Loader.Input.Replace("-", "_") & '兼容 Forge 1.7.10-pre4,#4057
".html", UseBrowserUserAgent:=True) ".html", UseBrowserUserAgent:=True)
Catch ex As Exception Catch ex As Exception
@@ -700,9 +700,8 @@
''' Forge 版本列表,BMCLAPI。 ''' Forge 版本列表,BMCLAPI。
''' </summary> ''' </summary>
Public Sub DlForgeVersionBmclapiMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry))) Public Sub DlForgeVersionBmclapiMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
Dim Json As JArray = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/forge/minecraft/" & Dim Json As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/minecraft/" &
Loader.Input.Replace("-", "_"), '兼容 Forge 1.7.10-pre4,#4057 Loader.Input.Replace("-", "_"))) '兼容 Forge 1.7.10-pre4,#4057
IsJson:=True)
Dim Versions As New List(Of DlForgeVersionEntry) Dim Versions As New List(Of DlForgeVersionEntry)
Try Try
Dim Recommended As String = McDownloadForgeRecommendedGet(Loader.Input) Dim Recommended As String = McDownloadForgeRecommendedGet(Loader.Input)
@@ -836,8 +835,8 @@
Public DlNeoForgeListOfficialLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Official", AddressOf DlNeoForgeListOfficialMain) Public DlNeoForgeListOfficialLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Official", AddressOf DlNeoForgeListOfficialMain)
Private Sub DlNeoForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult)) Private Sub DlNeoForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
'获取版本列表 JSON '获取版本列表 JSON
Dim ResultLatest As String = NetGetCodeByLoader("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge", UseBrowserUserAgent:=True, IsJson:=True) Dim ResultLatest As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge")
Dim ResultLegacy As String = NetGetCodeByLoader("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge", UseBrowserUserAgent:=True, IsJson:=True) 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 & ")") If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
'解析 '解析
Try Try
@@ -854,8 +853,8 @@
Public DlNeoForgeListBmclapiLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Bmclapi", AddressOf DlNeoForgeListBmclapiMain) Public DlNeoForgeListBmclapiLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Bmclapi", AddressOf DlNeoForgeListBmclapiMain)
Public Sub DlNeoForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult)) Public Sub DlNeoForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
'获取版本列表 JSON '获取版本列表 JSON
Dim ResultLatest As String = NetGetCodeByLoader("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/neoforge", 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 = NetGetCodeByLoader("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/forge", UseBrowserUserAgent:=True, IsJson:=True) 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 & ")") If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
'解析 '解析
Try Try
@@ -960,7 +959,7 @@
''' </summary> ''' </summary>
Public DlLiteLoaderListOfficialLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Official", AddressOf DlLiteLoaderListOfficialMain) Public DlLiteLoaderListOfficialLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Official", AddressOf DlLiteLoaderListOfficialMain)
Private Sub DlLiteLoaderListOfficialMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult)) 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 Try
Dim Json As JObject = Result("versions") Dim Json As JObject = Result("versions")
Dim Versions As New List(Of DlLiteLoaderListEntry) Dim Versions As New List(Of DlLiteLoaderListEntry)
@@ -988,7 +987,7 @@
''' </summary> ''' </summary>
Public DlLiteLoaderListBmclapiLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Bmclapi", AddressOf DlLiteLoaderListBmclapiMain) Public DlLiteLoaderListBmclapiLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Bmclapi", AddressOf DlLiteLoaderListBmclapiMain)
Private Sub DlLiteLoaderListBmclapiMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult)) 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 Try
Dim Json As JObject = Result("versions") Dim Json As JObject = Result("versions")
Dim Versions As New List(Of DlLiteLoaderListEntry) Dim Versions As New List(Of DlLiteLoaderListEntry)
@@ -1059,7 +1058,7 @@
''' </summary> ''' </summary>
Public DlFabricListOfficialLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Official", AddressOf DlFabricListOfficialMain) Public DlFabricListOfficialLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Official", AddressOf DlFabricListOfficialMain)
Private Sub DlFabricListOfficialMain(Loader As LoaderTask(Of Integer, DlFabricListResult)) 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 Try
Dim Output = New DlFabricListResult With {.IsOfficial = True, .SourceName = "Fabric 官方源", .Value = Result} 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("获取到的列表缺乏必要项") 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> ''' </summary>
Public DlFabricListBmclapiLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Bmclapi", AddressOf DlFabricListBmclapiMain) Public DlFabricListBmclapiLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Bmclapi", AddressOf DlFabricListBmclapiMain)
Private Sub DlFabricListBmclapiMain(Loader As LoaderTask(Of Integer, DlFabricListResult)) 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 Try
Dim Output = New DlFabricListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Result} 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("获取到的列表缺乏必要项") 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 镜像源请求" #Region "DlMod | Mod 镜像源请求"
''' <summary> ''' <summary>
''' 对可能涉及 Mod 镜像源的请求进行处理,返回字符串或 JObject。 ''' 对可能涉及 Mod 镜像源的请求进行处理,返回 JToken。
''' 调用 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 镜像源的请求进行处理。
''' 调用 NetRequest,会进行重试。 ''' 调用 NetRequest,会进行重试。
''' </summary> ''' </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)) 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, 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) 'Dim McimUrl As String = DlSourceModGet(Url)
'If McimUrl <> Url Then 'If McimUrl <> Url Then
' Select Case Setup.Get("ToolDownloadMod") ' Select Case Setup.Get("ToolDownloadMod")
@@ -1166,7 +1129,7 @@
Dim Exs As String = "" Dim Exs As String = ""
For Each Source In Urls For Each Source In Urls
Try 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 Catch ex As Exception
Exs += ex.Message + vbCrLf Exs += ex.Message + vbCrLf
End Try End Try
@@ -117,7 +117,7 @@
If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败") If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败")
If ModeDebug Then Log("[Java] Java 检查输出:" & PathFolder & "java.exe" & vbCrLf & Output) 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("/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 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" If VersionString.Split(".").Count > 4 Then VersionString = VersionString.Replace(".0.", ".") '#3493,VersionString = "21.0.2.0.2"
@@ -460,10 +460,12 @@ NoUserJava:
''' 将 Java 按照适用性排序。 ''' 将 Java 按照适用性排序。
''' </summary> ''' </summary>
Public Function JavaSorter(Left As JavaEntry, Right As JavaEntry) As Boolean 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 文件夹 '1. 尽量在当前文件夹或当前 Minecraft 文件夹
Dim ProgramPathParent As String, MinecraftPathParent As String = "" Dim ProgramPathParent As String, MinecraftPathParent As String = ""
ProgramPathParent = If(New DirectoryInfo(Path).Parent, New DirectoryInfo(Path)).FullName ProgramPathParent = If(PathInfo.Parent, PathInfo).FullName
If PathMcFolder <> "" Then MinecraftPathParent = If(New DirectoryInfo(PathMcFolder).Parent, New DirectoryInfo(PathMcFolder)).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 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 Not Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Right.PathFolder.StartsWithF(ProgramPathParent) Then Return False
If PathMcFolder <> "" Then If PathMcFolder <> "" Then
@@ -530,7 +532,7 @@ NoUserJava:
If Disk.DriveType = DriveType.Network Then Continue For '跳过网络驱动器(#3705) If Disk.DriveType = DriveType.Network Then Continue For '跳过网络驱动器(#3705)
JavaSearchFolder(Disk.Name, JavaPreList, False) JavaSearchFolder(Disk.Name, JavaPreList, False)
Next Next
'查找 ~/.jdks 文件夹中的 Java '查找 .jdks 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.jdks\", JavaPreList, False) JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.jdks\", JavaPreList, False)
'查找 APPDATA 文件夹中的 Java '查找 APPDATA 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\", JavaPreList, False) JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\", JavaPreList, False)
@@ -680,8 +682,8 @@ Wait:
'若该目录有 Java,则加入结果 '若该目录有 Java,则加入结果
If File.Exists(Path & "javaw.exe") Then Results(Path) = Source If File.Exists(Path & "javaw.exe") Then Results(Path) = Source
'查找其下的所有文件夹 '查找其下的所有文件夹
'不应使用网易的 Java:https://github.com/HMeloong-Git/PCL/issues/1279#issuecomment-2761489121 '不应使用网易的 Java:https://github.com/Meloong-Git/PCL/issues/1279#issuecomment-2761489121
Dim Keywords = {"java", "jdk", "env", "环境", "run", "软件", "jre", "mc", "dragon", Dim Keywords = {"java", "jdk", "env", "环境", "run", "软件", "jre", "mc", "dragon", "bin",
"soft", "cache", "temp", "corretto", "roaming", "users", "craft", "program", "世界", "net", "soft", "cache", "temp", "corretto", "roaming", "users", "craft", "program", "世界", "net",
"游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", "client", "整合", "游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", "client", "整合",
"应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot", "应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot",
@@ -748,7 +750,7 @@ Wait:
Private LastJavaBaseDir As String = Nothing '用于在下载中断或失败时删除未完成下载的 Java 文件夹,防止残留只下了一半但 -version 能跑的 Java Private LastJavaBaseDir As String = Nothing '用于在下载中断或失败时删除未完成下载的 Java 文件夹,防止残留只下了一半但 -version 能跑的 Java
Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile))) Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile)))
Log("[Java] 开始获取 Java 下载信息") 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://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
{"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"} {"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"}
), IsJson:=True) ), IsJson:=True)
@@ -760,7 +762,7 @@ Wait:
Dim Address As String = TargetEntry.Value("manifest")("url") Dim Address As String = TargetEntry.Value("manifest")("url")
Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}") 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 & "\" LastJavaBaseDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\runtime\" & TargetEntry.Key & "\"
Dim Results As New List(Of NetFile) Dim Results As New List(Of NetFile)
For Each File As JProperty In CType(GetJson(ListFileStr), JObject)("files") For Each File As JProperty In CType(GetJson(ListFileStr), JObject)("files")
@@ -684,11 +684,10 @@ LoginFinish:
'发送登录请求 '发送登录请求
Dim RequestData As New JObject( Dim RequestData As New JObject(
New JProperty("accessToken", AccessToken), New JProperty("clientToken", ClientToken), New JProperty("requestUser", True)) New JProperty("accessToken", AccessToken), New JProperty("clientToken", ClientToken), New JProperty("requestUser", True))
NetRequestRetry( NetRequestByClientRetry(
Url:=Data.Input.BaseUrl & "/validate", Data.Input.BaseUrl & "/validate", HttpMethod.Post,
Method:="POST", Content:=RequestData.ToString(Newtonsoft.Json.Formatting.None),
Data:=RequestData.ToString(0), Headers:={{"Accept-Language", "zh-CN"}},
Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh-CN"}},
ContentType:="application/json; charset=utf-8") '没有返回值的 ContentType:="application/json; charset=utf-8") '没有返回值的
'将登录结果输出 '将登录结果输出
Data.Output.AccessToken = AccessToken Data.Output.AccessToken = AccessToken
@@ -701,10 +700,9 @@ LoginFinish:
End Sub End Sub
Private Sub McLoginRequestRefresh(ByRef Data As LoaderTask(Of McLoginServer, McLoginResult), RequestUser As Boolean) Private Sub McLoginRequestRefresh(ByRef Data As LoaderTask(Of McLoginServer, McLoginResult), RequestUser As Boolean)
McLaunchLog("刷新登录开始(Refresh, " & Data.Input.Token & ")") McLaunchLog("刷新登录开始(Refresh, " & Data.Input.Token & ")")
Dim LoginJson As JObject = GetJson(NetRequestRetry( Dim LoginJson As JObject = GetJson(NetRequestByClientRetry(
Url:=Data.Input.BaseUrl & "/refresh", Data.Input.BaseUrl & "/refresh", HttpMethod.Post,
Method:="POST", Content:=New JObject(
Data:=New JObject(
New JProperty("selectedProfile", New JObject( New JProperty("selectedProfile", New JObject(
New JProperty("name", Setup.Get($"Cache{Data.Input.Token}Name")), New JProperty("name", Setup.Get($"Cache{Data.Input.Token}Name")),
New JProperty("id", Setup.Get($"Cache{Data.Input.Token}Uuid")) 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("accessToken", Setup.Get($"Cache{Data.Input.Token}Access")),
New JProperty("requestUser", True) New JProperty("requestUser", True)
).ToString(Newtonsoft.Json.Formatting.None), ).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")) ContentType:="application/json; charset=utf-8"))
'将登录结果输出 '将登录结果输出
If LoginJson("selectedProfile") Is Nothing Then Throw New Exception("选择的角色 " & Setup.Get("Cache" & Data.Input.Token & "Name") & " 无效!") 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("username", Data.Input.UserName),
New JProperty("password", Data.Input.Password), New JProperty("password", Data.Input.Password),
New JProperty("requestUser", True)) New JProperty("requestUser", True))
Dim LoginJson As JObject = GetJson(NetRequestRetry( Dim LoginJson As JObject = GetJson(NetRequestByClientRetry(
Url:=Data.Input.BaseUrl & "/authenticate", Data.Input.BaseUrl & "/authenticate", HttpMethod.Post,
Method:="POST", Content:=RequestData.ToString(Newtonsoft.Json.Formatting.None),
Data:=RequestData.ToString(0), Headers:={{"Accept-Language", "zh-CN"}},
Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh-CN"}},
ContentType:="application/json; charset=utf-8")) ContentType:="application/json; charset=utf-8"))
'检查登录结果 '检查登录结果
If LoginJson("availableProfiles").Count = 0 Then If LoginJson("availableProfiles").Count = 0 Then
@@ -858,8 +855,9 @@ LoginFinish:
'初始请求 '初始请求
Retry: Retry:
McLaunchLog("开始微软登录步骤 1/6(原始登录)") McLaunchLog("开始微软登录步骤 1/6(原始登录)")
Dim PrepareJson As JObject = GetJson(NetRequestRetry("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", "POST", Dim PrepareJson As JObject = GetJson(NetRequestByClientRetry("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", HttpMethod.Post,
$"client_id={OAuthClientId}&tenant=/consumers&scope=XboxLive.signin%20offline_access", "application/x-www-form-urlencoded")) Content:=$"client_id={OAuthClientId}&tenant=/consumers&scope=XboxLive.signin%20offline_access",
Accept:="application/x-www-form-urlencoded"))
McLaunchLog("网页登录地址:" & PrepareJson("verification_uri").ToString) McLaunchLog("网页登录地址:" & PrepareJson("verification_uri").ToString)
'弹窗 '弹窗
@@ -888,9 +886,11 @@ Retry:
Dim Result As String Dim Result As String
Try Try
Result = NetRequestMultiple("https://login.live.com/oauth20_token.srf", "POST", Result = NetRequestByClientMultiple("https://login.live.com/oauth20_token.srf", HttpMethod.Post,
$"client_id={OAuthClientId}&refresh_token={Uri.EscapeDataString(Code)}&grant_type=refresh_token&scope=XboxLive.signin%20offline_access", Content:=$"client_id={OAuthClientId}&refresh_token={Uri.EscapeDataString(Code)}&grant_type=refresh_token&scope=XboxLive.signin%20offline_access",
"application/x-www-form-urlencoded", 2) 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 Catch ex As Exception
If ex.Message.ContainsF("must sign in again", True) OrElse ex.Message.ContainsF("password expired", True) OrElse 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 (ex.Message.Contains("refresh_token") AndAlso ex.Message.Contains("is not valid")) Then '#269
@@ -918,8 +918,8 @@ Retry:
""RelyingParty"": ""http://auth.xboxlive.com"", ""RelyingParty"": ""http://auth.xboxlive.com"",
""TokenType"": ""JWT"" ""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 ResultJson As JObject = GetJson(Result)
Dim XBLToken As String = ResultJson("Token").ToString Dim XBLToken As String = ResultJson("Token").ToString
Return XBLToken Return XBLToken
@@ -940,7 +940,8 @@ Retry:
}" }"
Dim Result As String Dim Result As String
Try 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 Catch ex As Net.WebException
'参考 https://github.com/PrismarineJS/prismarine-auth/blob/master/src/common/Constants.js '参考 https://github.com/PrismarineJS/prismarine-auth/blob/master/src/common/Constants.js
If ex.Message.Contains("2148916227") Then If ex.Message.Contains("2148916227") Then
@@ -971,10 +972,15 @@ Retry:
End If End If
End Try End Try
Try '这个 Try 块仅为了追踪 #6683 而添加
Dim ResultJson As JObject = GetJson(Result) Dim ResultJson As JObject = GetJson(Result)
Dim XSTSToken As String = ResultJson("Token").ToString Dim XSTSToken As String = ResultJson("Token").ToString
Dim UHS As String = ResultJson("DisplayClaims")("xui")(0)("uhs").ToString Dim UHS As String = ResultJson("DisplayClaims")("xui")(0)("uhs").ToString
Return {XSTSToken, UHS} Return {XSTSToken, UHS}
Catch
Log("[Launch] 返回内容:" & vbCrLf & Result)
Throw
End Try
End Function End Function
'微软登录步骤 4:从 {XSTSToken, UHS} 获取 Minecraft AccessToken '微软登录步骤 4:从 {XSTSToken, UHS} 获取 Minecraft AccessToken
Private Function MsLoginStep4(Tokens As String()) As String 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 Request As String = New JObject(New JProperty("identityToken", $"XBL3.0 x={Tokens(1)};{Tokens(0)}")).ToString(0)
Dim Result As String Dim Result As String
Try 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 Catch ex As Net.WebException
Dim Message As String = GetExceptionSummary(ex) Dim Message As String = GetExceptionSummary(ex)
If Message.Contains("(429)") Then If Message.Contains("(429)") Then
@@ -1005,7 +1012,8 @@ Retry:
Private Sub MsLoginStep5(AccessToken As String) Private Sub MsLoginStep5(AccessToken As String)
McLaunchLog("开始微软登录步骤 5/6") 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 Try
Dim ResultJson As JObject = GetJson(Result) Dim ResultJson As JObject = GetJson(Result)
If Not (ResultJson.ContainsKey("items") AndAlso ResultJson("items").Any) Then If Not (ResultJson.ContainsKey("items") AndAlso ResultJson("items").Any) Then
@@ -1026,7 +1034,8 @@ Retry:
Dim Result As String Dim Result As String
Try 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 Catch ex As Net.WebException
Dim Message As String = GetExceptionSummary(ex) Dim Message As String = GetExceptionSummary(ex)
If Message.Contains("(429)") Then If Message.Contains("(429)") Then
@@ -1099,7 +1108,7 @@ Retry:
If Len(Uuid) = 32 Then Return Uuid If Len(Uuid) = 32 Then Return Uuid
'从官网获取 '从官网获取
Try 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 & ")") If GotJson Is Nothing Then Throw New FileNotFoundException("正版玩家档案不存在(" & Name & ")")
Uuid = If(GotJson("id"), "") Uuid = If(GotJson("id"), "")
Catch ex As Exception Catch ex As Exception
@@ -1205,6 +1214,12 @@ Retry:
End If End If
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 If Setup.Get("LoginType") = McLoginType.Nide Then
'至少 Java 8u101 '至少 Java 8u101
@@ -1356,16 +1371,6 @@ Retry:
If McLaunchJavaSelected.VersionCode >= 18 Then If McLaunchJavaSelected.VersionCode >= 18 Then
If Not Arguments.Contains("-Dfile.encoding=") Then Arguments = "-Dfile.encoding=COMPAT " & Arguments If Not Arguments.Contains("-Dfile.encoding=") Then Arguments = "-Dfile.encoding=COMPAT " & Arguments
End If 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 'MJSB
Arguments = Arguments.Replace(" -Dos.name=Windows 10", " -Dos.name=""Windows 10""") Arguments = Arguments.Replace(" -Dos.name=Windows 10", " -Dos.name=""Windows 10""")
'全屏 '全屏
@@ -1374,31 +1379,47 @@ Retry:
For Each Arg In CurrentLaunchOptions.ExtraArgs For Each Arg In CurrentLaunchOptions.ExtraArgs
Arguments += " " & Arg.Trim Arguments += " " & Arg.Trim
Next 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) Dim Server As String = If(String.IsNullOrEmpty(CurrentLaunchOptions.ServerIp), Setup.Get("VersionServerEnter", McVersionCurrent), CurrentLaunchOptions.ServerIp)
If Server.Length > 0 Then If Server.Length > 0 Then
If McVersionCurrent.ReleaseTime > New Date(2023, 4, 4) Then If McVersionCurrent.ReleaseTime > New Date(2023, 4, 4) Then
'QuickPlay 'QuickPlay
Arguments += $" --quickPlayMultiplayer ""{Server}""" FinalArguments += $" --quickPlayMultiplayer ""{Server}"""
Else Else
'老版本 '老版本
If Server.Contains(":") Then If Server.Contains(":") Then
'包含端口号 '包含端口号
Arguments += " --server " & Server.Split(":")(0) & " --port " & Server.Split(":")(1) FinalArguments += $" --server {Server.Split(":")(0)} --port {Server.Split(":")(1)}"
Else Else
'不包含端口号 '不包含端口号
Arguments += " --server " & Server & " --port 25565" FinalArguments += $" --server {Server} --port 25565"
End If End If
If McVersionCurrent.Version.HasOptiFine Then Hint("OptiFine 与自动进入服务器可能不兼容,有概率导致材质丢失甚至游戏崩溃!", HintType.Critical) If McVersionCurrent.Version.HasOptiFine Then Hint("OptiFine 与自动进入服务器可能不兼容,有概率导致材质丢失甚至游戏崩溃!", HintType.Critical)
End If End If
End If End If
'自定义
Dim ArgumentGame As String = Setup.Get("VersionAdvanceGame", Version:=McVersionCurrent)
Arguments += " " & If(ArgumentGame = "", Setup.Get("LaunchAdvanceGame"), ArgumentGame)
'输出 '输出
McLaunchLog("Minecraft 启动参数:") McLaunchLog("Minecraft 启动参数:")
McLaunchLog(Arguments) McLaunchLog(FinalArguments)
McLaunchArgument = Arguments McLaunchArgument = FinalArguments
End Sub End Sub
'Jvm 部分(第一段) 'Jvm 部分(第一段)
@@ -1424,12 +1445,12 @@ Retry:
End If End If
'Authlib-Injector 'Authlib-Injector
If McLoginLoader.Output.Type = "Auth" Then 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, Dim Server As String = If(McLoginLoader.Input.Type = McLoginType.Legacy,
"http://hiperauth.tech/api/yggdrasil-hiper/", 'HiPer 登录 "http://hiperauth.tech/api/yggdrasil-hiper/", 'HiPer 登录
Setup.Get("VersionServerAuthServer", McVersionCurrent)) Setup.Get("VersionServerAuthServer", McVersionCurrent))
Try 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 & DataList.Insert(0, "-javaagent:""" & PathPure & "authlib-injector.jar""=" & Server &
" -Dauthlibinjector.side=client" & " -Dauthlibinjector.side=client" &
" -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response))) " -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response)))
@@ -1494,12 +1515,12 @@ NextVersion:
End If End If
'Authlib-Injector 'Authlib-Injector
If McLoginLoader.Output.Type = "Auth" Then 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, Dim Server As String = If(McLoginLoader.Input.Type = McLoginType.Legacy,
"http://hiperauth.tech/api/yggdrasil-hiper/", 'HiPer 登录 "http://hiperauth.tech/api/yggdrasil-hiper/", 'HiPer 登录
Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent)) Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent))
Try 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 & DataList.Insert(0, "-javaagent:""" & PathPure & "authlib-injector.jar""=" & Server &
" -Dauthlibinjector.side=client" & " -Dauthlibinjector.side=client" &
" -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response))) " -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response)))
@@ -1533,10 +1554,8 @@ NextVersion:
DeDuplicateDataList.Add(CurrentEntry.Trim.Replace("McEmu= ", "McEmu=")) DeDuplicateDataList.Add(CurrentEntry.Trim.Replace("McEmu= ", "McEmu="))
Next Next
'#3511 的清理
DeDuplicateDataList.Remove("-XX:MaxDirectMemorySize=256M")
'去重 '去重
DeDuplicateDataList.Remove("-XX:MaxDirectMemorySize=256M") '#3511 的清理
Dim Result As String = Join(DeDuplicateDataList.Distinct.ToList, " ") Dim Result As String = Join(DeDuplicateDataList.Distinct.ToList, " ")
'添加 MainClass '添加 MainClass
@@ -169,8 +169,8 @@ Public Module ModMinecraft
_McVersionCurrent = value '由于有可能是 Nothing,导致无法初始化,才得这样弄一圈 _McVersionCurrent = value '由于有可能是 Nothing,导致无法初始化,才得这样弄一圈
_McVersionLast = value _McVersionLast = value
If value Is Nothing Then Return If value Is Nothing Then Return
'重置缓存的 Mod 文件夹 '重置缓存的下载文件夹
PageDownloadCompDetail.CachedFolder = Nothing PageDownloadCompDetail.CachedFolder.Clear()
'统一通行证重判 '统一通行证重判
If AniControlEnabled = 0 AndAlso If AniControlEnabled = 0 AndAlso
Setup.Get("VersionServerNide", Version:=value) <> Setup.Get("CacheNideServer") AndAlso Setup.Get("VersionServerNide", Version:=value) <> Setup.Get("CacheNideServer") AndAlso
@@ -440,6 +440,33 @@ VersionSearchFinish:
''' </summary> ''' </summary>
Public ReleaseTime As New Date(1970, 1, 1, 15, 0, 0) 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> ''' <summary>
''' 该版本的 Json 文本。 ''' 该版本的 Json 文本。
''' </summary> ''' </summary>
@@ -452,17 +479,7 @@ VersionSearchFinish:
Return TrimedJson.StartsWithF("{") AndAlso TrimedJson.EndsWithF("}") Return TrimedJson.StartsWithF("{") AndAlso TrimedJson.EndsWithF("}")
End Function End Function
If _JsonText Is Nothing Then If _JsonText Is Nothing Then
Dim JsonPath As String = Path & Name & ".json" Dim JsonPath As String = GetJsonPath()
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
_JsonText = ReadFile(JsonPath) _JsonText = ReadFile(JsonPath)
'如果 ReadFile 失败会返回空字符串;这可能是由于文件被临时占用,故延时后重试 '如果 ReadFile 失败会返回空字符串;这可能是由于文件被临时占用,故延时后重试
If Not FastJsonCheck(_JsonText) Then If Not FastJsonCheck(_JsonText) Then
@@ -540,9 +557,15 @@ Recheck:
'继续循环 '继续循环
If Inherit.InheritVersion = InheritVersion Then Throw New Exception("版本依赖项出现嵌套:" & InheritVersion) If Inherit.InheritVersion = InheritVersion Then Throw New Exception("版本依赖项出现嵌套:" & InheritVersion)
InheritVersion = Inherit.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) Inherit.JsonObject.Merge(_JsonObject)
_JsonObject = Inherit.JsonObject _JsonObject = Inherit.JsonObject
_JsonObject("libraries") = CurrentLib
GoTo Recheck GoTo Recheck
End If End If
Catch ex As Exception Catch ex As Exception
@@ -580,21 +603,19 @@ Recheck:
Get Get
If Not JsonVersionInited Then If Not JsonVersionInited Then
JsonVersionInited = True JsonVersionInited = True
If File.Exists(Path & Name & ".jar") Then
Try 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)) Using JarArchive As New ZipArchive(New FileStream(Path & Name & ".jar", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
Dim VersionJson As ZipArchiveEntry = JarArchive.GetEntry("version.json") 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) Using VersionJsonStream As New StreamReader(VersionJson.Open)
_JsonVersion = GetJson(VersionJsonStream.ReadToEnd) _JsonVersion = GetJson(VersionJsonStream.ReadToEnd)
End Using End Using
End If
End Using End Using
Catch ex As Exception Catch ex As Exception
Log(ex, "从版本 jar 中读取 version.json 失败") Log(ex, $"从版本 jar 中读取 version.json 失败({Path}{Name}.jar)")
End Try End Try
End If End If
End If
Return _JsonVersion Return _JsonVersion
End Get End Get
End Property End Property
@@ -1538,7 +1559,7 @@ OnLoaded:
''' 要求玩家选择一个皮肤文件,并进行相关校验。 ''' 要求玩家选择一个皮肤文件,并进行相关校验。
''' </summary> ''' </summary>
Public Function McSkinSelect() As McSkinInfo 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} If FileName = "" Then Return New McSkinInfo With {.IsVaild = False}
@@ -1589,7 +1610,7 @@ OnLoaded:
Case Else Case Else
Throw New ArgumentException("皮肤地址种类无效:" & If(Type, "null")) Throw New ArgumentException("皮肤地址种类无效:" & If(Type, "null"))
End Select End Select
Dim SkinString = NetGetCodeByRequestRetry(Url & Uuid) Dim SkinString = NetRequestByClientRetry(Url & Uuid)
If SkinString = "" Then Throw New Exception("皮肤返回值为空,可能是未设置自定义皮肤的用户") If SkinString = "" Then Throw New Exception("皮肤返回值为空,可能是未设置自定义皮肤的用户")
'处理皮肤地址 '处理皮肤地址
Dim SkinValue As String Dim SkinValue As String
@@ -1611,7 +1632,7 @@ OnLoaded:
Throw New Exception("用户未设置自定义皮肤") Throw New Exception("用户未设置自定义皮肤")
Else Else
Dim SkinUrl As String = SkinJson("textures")("skin")("url").ToString 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 End If
'保存缓存 '保存缓存
WriteIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", Uuid, SkinValue) WriteIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", Uuid, SkinValue)
@@ -1628,9 +1649,9 @@ OnLoaded:
Dim FileAddress As String = PathTemp & "Cache\Skin\" & GetHash(Address) & ".png" Dim FileAddress As String = PathTemp & "Cache\Skin\" & GetHash(Address) & ".png"
SyncLock McSkinDownloadLock SyncLock McSkinDownloadLock
If Not File.Exists(FileAddress) Then If Not File.Exists(FileAddress) Then
NetDownloadByClient(Address, FileAddress & NetDownloadEnd) NetDownloadByClient(Address, FileAddress & ".PCLDownloading")
File.Delete(FileAddress) File.Delete(FileAddress)
FileSystem.Rename(FileAddress & NetDownloadEnd, FileAddress) FileSystem.Rename(FileAddress & ".PCLDownloading", FileAddress)
Log("[Minecraft] 皮肤下载成功:" & FileAddress) Log("[Minecraft] 皮肤下载成功:" & FileAddress)
End If End If
Return FileAddress Return FileAddress
@@ -1773,10 +1794,10 @@ OnLoaded:
'获取当前支持库列表 '获取当前支持库列表
Log("[Minecraft] 获取支持库列表:" & Version.Name) Log("[Minecraft] 获取支持库列表:" & Version.Name)
McLibListGet = McLibListGetWithJson(Version.JsonObject) Dim Result = McLibListGetWithJson(Version.JsonObject)
If Not IncludeVersionJar Then Return McLibListGet
'需要添加原版 Jar '需要添加原版 Jar
If IncludeVersionJar Then
Dim RealVersion As McVersion Dim RealVersion As McVersion
Dim RequiredJar As String = Version.JsonObject("jar")?.ToString Dim RequiredJar As String = Version.JsonObject("jar")?.ToString
If Version.IsHmclFormatJson OrElse RequiredJar Is Nothing Then If Version.IsHmclFormatJson OrElse RequiredJar Is Nothing Then
@@ -1813,21 +1834,20 @@ OnLoaded:
ClientSHA1 = Nothing ClientSHA1 = Nothing
End If End If
'把所需的原版 Jar 添加进去 '把所需的原版 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 End Function
''' <summary> ''' <summary>
''' 获取 Minecraft 某一版本忽视继承的支持库列表,即结果中没有继承项。 ''' 获取 Minecraft 某一版本忽视继承的支持库列表,即结果中没有继承项。
''' </summary> ''' </summary>
Public Function McLibListGetWithJson(JsonObject As JObject, Optional KeepSameNameDifferentVersionResult As Boolean = False, Optional CustomMcFolder As String = Nothing) As List(Of McLibToken) Public Function McLibListGetWithJson(JsonObject As JObject, Optional KeepSameNameDifferentVersionResult As Boolean = False, Optional CustomMcFolder As String = Nothing) As List(Of McLibToken)
CustomMcFolder = If(CustomMcFolder, PathMcFolder) CustomMcFolder = If(CustomMcFolder, PathMcFolder)
Dim BasicArray As New List(Of McLibToken)
'添加基础 Json 项
Dim AllLibs As JArray = JsonObject("libraries")
'转换为 LibToken '转换为 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) '清理 null 项(BakaXL 会把没有的项序列化为 null,但会被 Newtonsoft 转换为 JValue,导致 Is Nothing = false;这导致了 #409)
For i = Library.Properties.Count - 1 To 0 Step -1 For i = Library.Properties.Count - 1 To 0 Step -1
@@ -1946,8 +1966,7 @@ OnLoaded:
Try Try
Log("[Minecraft] 开始获取统一通行证下载信息") Log("[Minecraft] 开始获取统一通行证下载信息")
'测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/ '测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/
DownloadInfo = GetJson(NetGetCodeByLoader({ DownloadInfo = GetJson(NetRequestByClientRetry("https://auth.mc-user.com:233/" & Setup.Get("VersionServerNide", Version:=Version)))
"https://auth.mc-user.com:233/" & Setup.Get("VersionServerNide", Version:=Version)}, IsJson:=True))
Catch ex As Exception Catch ex As Exception
Log(ex, "获取统一通行证下载信息失败") Log(ex, "获取统一通行证下载信息失败")
End Try End Try
@@ -1969,10 +1988,9 @@ OnLoaded:
'获取下载信息 '获取下载信息
Try Try
Log("[Minecraft] 开始获取 Authlib-Injector 下载信息") Log("[Minecraft] 开始获取 Authlib-Injector 下载信息")
DownloadInfo = GetJson(NetGetCodeByLoader({ DownloadInfo = GetJson(NetRequestByClientRetry(
"https://authlib-injector.yushi.moe/artifact/latest.json", "https://authlib-injector.yushi.moe/artifact/latest.json",
"https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json" BackupUrl:="https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json"))
}, IsJson:=True))
Catch ex As Exception Catch ex As Exception
Log(ex, "获取 Authlib-Injector 下载信息失败") Log(ex, "获取 Authlib-Injector 下载信息失败")
End Try End Try
@@ -2017,12 +2035,16 @@ OnLoaded:
'获取 '获取
For Each Token As McLibToken In Libs 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 If Checker.Check(Token.LocalPath) Is Nothing Then Continue For
'文件不符合,添加下载 '文件不符合,添加下载
Dim Urls As New List(Of String) Dim Urls As New List(Of String)
If Token.Url Is Nothing AndAlso Token.Name = "net.minecraftforge:forge:universal" Then If Token.Url Is Nothing AndAlso Token.Name = "net.minecraftforge:forge:universal" Then '特判修复 Forge 部分 universal 文件缺失 URL(#5455)
'特判修复 Forge 部分 universal 文件缺失 URL(#5455)
Token.Url = "https://maven.minecraftforge.net" & Token.LocalPath.Replace(CustomMcFolder & "libraries", "").Replace("\", "/") Token.Url = "https://maven.minecraftforge.net" & Token.LocalPath.Replace(CustomMcFolder & "libraries", "").Replace("\", "/")
End If End If
If Token.Url IsNot Nothing Then If Token.Url IsNot Nothing Then
@@ -2194,16 +2216,16 @@ OnLoaded:
Dim LocalPath As String Dim LocalPath As String
If Json("map_to_resources") IsNot Nothing AndAlso Json("map_to_resources").ToObject(Of Boolean) Then If Json("map_to_resources") IsNot Nothing AndAlso Json("map_to_resources").ToObject(Of Boolean) Then
'Remap '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 ElseIf Json("virtual") IsNot Nothing AndAlso Json("virtual").ToObject(Of Boolean) Then
'Virtual 'Virtual
LocalPath = PathMcFolder & "assets\virtual\legacy\" & File.Name.Replace("/", "\") LocalPath = $"{PathMcFolder}assets\virtual\legacy\{File.Name}"
Else 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 End If
Result.Add(New McAssetsToken With { Result.Add(New McAssetsToken With {
.LocalPath = LocalPath, .LocalPath = LocalPath.Replace("/", "\"),
.SourcePath = File.Name, .SourcePath = File.Name,
.Hash = File.Value("hash").ToString, .Hash = File.Value("hash").ToString,
.Size = File.Value("size").ToString .Size = File.Value("size").ToString
@@ -1,7 +1,7 @@
Imports System.IO.Compression Imports System.IO.Compression
Public Module ModMod Public Module ModMod
Private Const LocalModCacheVersion As Integer = 7 Private Const LocalModCacheVersion As Integer = 8
Public Class McMod Public Class McMod
@@ -946,8 +946,8 @@ Finished:
Try Try
'步骤 1:获取 Hash 与对应的工程 ID '步骤 1:获取 Hash 与对应的工程 ID
Dim ModrinthHashes = Mods.Select(Function(m) m.ModrinthHash).ToList() Dim ModrinthHashes = Mods.Select(Function(m) m.ModrinthHash).ToList()
Dim ModrinthVersion = CType(GetJson(DlModRequest("https://api.modrinth.com/v2/version_files", "POST", Dim ModrinthVersion As JObject = DlModRequest("https://api.modrinth.com/v2/version_files", HttpMethod.Post,
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")), JObject) $"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")
Log($"[Mod] 从 Modrinth 获取到 {ModrinthVersion.Count} 个本地 Mod 的对应信息") Log($"[Mod] 从 Modrinth 获取到 {ModrinthVersion.Count} 个本地 Mod 的对应信息")
'步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系 '步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系
If ModrinthVersion.Count = 0 Then Return If ModrinthVersion.Count = 0 Then Return
@@ -967,9 +967,8 @@ Finished:
Log($"[Mod] 需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息") Log($"[Mod] 需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息")
'步骤 3:获取工程信息 '步骤 3:获取工程信息
If Not ModrinthMapping.Any() Then Return If Not ModrinthMapping.Any() Then Return
Dim ModrinthProject = CType(GetJson(DlModRequest( Dim ModrinthProject As JArray = DlModRequest(
$"https://api.modrinth.com/v2/projects?ids=[""{ModrinthMapping.Keys.Join(""",""")}""]", $"https://api.modrinth.com/v2/projects?ids=[""{ModrinthMapping.Keys.Join(""",""")}""]")
"GET", "", "application/json")), JArray)
For Each ProjectJson In ModrinthProject For Each ProjectJson In ModrinthProject
Dim Project As New CompProject(ProjectJson) Dim Project As New CompProject(ProjectJson)
For Each Entry In ModrinthMapping(Project.Id) For Each Entry In ModrinthMapping(Project.Id)
@@ -978,9 +977,9 @@ Finished:
Next Next
Log($"[Mod] 已从 Modrinth 获取本地 Mod 信息,继续获取更新信息") Log($"[Mod] 已从 Modrinth 获取本地 Mod 信息,继续获取更新信息")
'步骤 4:获取更新信息 '步骤 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"", $"{{""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 For Each Entry In Mods
If Not ModrinthUpdate.ContainsKey(Entry.ModrinthHash) OrElse Entry.CompFile Is Nothing Then Continue For If Not ModrinthUpdate.ContainsKey(Entry.ModrinthHash) OrElse Entry.CompFile Is Nothing Then Continue For
Dim UpdateFile As New CompFile(ModrinthUpdate(Entry.ModrinthHash), CompType.Mod) Dim UpdateFile As New CompFile(ModrinthUpdate(Entry.ModrinthHash), CompType.Mod)
@@ -1015,8 +1014,8 @@ Finished:
CurseForgeHashes.Add(Entry.CurseForgeHash) CurseForgeHashes.Add(Entry.CurseForgeHash)
If Loader.IsAbortedWithThread(CurrentTaskThread) Then Return If Loader.IsAbortedWithThread(CurrentTaskThread) Then Return
Next Next
Dim CurseForgeRaw = CType(CType(GetJson(DlModRequest("https://api.curseforge.com/v1/fingerprints/432", "POST", Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432", HttpMethod.Post,
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")), JObject)("data")("exactMatches"), JContainer) $"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches")
Log($"[Mod] 从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地 Mod 的对应信息") Log($"[Mod] 从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地 Mod 的对应信息")
'步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系 '步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系
If Not CurseForgeRaw.Any() Then Return If Not CurseForgeRaw.Any() Then Return
@@ -1038,8 +1037,8 @@ Finished:
Log($"[Mod] 需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息") Log($"[Mod] 需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息")
'步骤 3:获取工程信息 '步骤 3:获取工程信息
If Not CurseForgeMapping.Any() Then Return If Not CurseForgeMapping.Any() Then Return
Dim CurseForgeProject = CType(GetJson(DlModRequest("https://api.curseforge.com/v1/mods", "POST", Dim CurseForgeProject = DlModRequest("https://api.curseforge.com/v1/mods", HttpMethod.Post,
$"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")), JObject)("data") $"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")("data")
Dim UpdateFileIds As New Dictionary(Of Integer, List(Of McMod)) 'FileId -> 本地 Mod 文件列表 Dim UpdateFileIds As New Dictionary(Of Integer, List(Of McMod)) 'FileId -> 本地 Mod 文件列表
Dim FileIdToProjectSlug As New Dictionary(Of Integer, String) Dim FileIdToProjectSlug As New Dictionary(Of Integer, String)
For Each ProjectJson In CurseForgeProject For Each ProjectJson In CurseForgeProject
@@ -1079,8 +1078,8 @@ Finished:
Log($"[Mod] 已从 CurseForge 获取本地 Mod 信息,需要获取 {UpdateFileIds.Count} 个用于检查更新的文件信息") Log($"[Mod] 已从 CurseForge 获取本地 Mod 信息,需要获取 {UpdateFileIds.Count} 个用于检查更新的文件信息")
'步骤 4:获取更新文件信息 '步骤 4:获取更新文件信息
If Not UpdateFileIds.Any() Then Return If Not UpdateFileIds.Any() Then Return
Dim CurseForgeFiles = CType(GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", Dim CurseForgeFiles = DlModRequest("https://api.curseforge.com/v1/mods/files", HttpMethod.Post,
$"{{""fileIds"": [{UpdateFileIds.Keys.Join(",")}]}}", "application/json")), JObject)("data") $"{{""fileIds"": [{UpdateFileIds.Keys.Join(",")}]}}", "application/json")("data")
Dim UpdateFiles As New Dictionary(Of McMod, CompFile) Dim UpdateFiles As New Dictionary(Of McMod, CompFile)
For Each FileJson In CurseForgeFiles For Each FileJson In CurseForgeFiles
Dim File As New CompFile(FileJson, CompType.Mod) Dim File As New CompFile(FileJson, CompType.Mod)
@@ -244,7 +244,7 @@ Retry:
'获取 Mod 下载信息 '获取 Mod 下载信息
ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息", ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
Sub(Task As LoaderTask(Of Integer, JArray)) 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 会跳过那一项 '如果文件已被删除,则 API 会跳过那一项
If ModList.Count > Task.Output.Count Then Throw New Exception("整合包中的部分 Mod 版本已被 Mod 作者删除,所以没法继续安装了,请向整合包作者反馈该问题") If ModList.Count > Task.Output.Count Then Throw New Exception("整合包中的部分 Mod 版本已被 Mod 作者删除,所以没法继续安装了,请向整合包作者反馈该问题")
End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s 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 Imports System.Security.Cryptography
Friend Module ModSecret Friend Module ModSecret
@@ -14,7 +13,6 @@ Friend Module ModSecret
'CurseForge API Key 'CurseForge API Key
Public CurseForgeAPIKey As String = If(Environment.GetEnvironmentVariable("PCL_CURSEFORGE_API_KEY"), "") Public CurseForgeAPIKey As String = If(Environment.GetEnvironmentVariable("PCL_CURSEFORGE_API_KEY"), "")
Friend Sub SecretOnApplicationStart() Friend Sub SecretOnApplicationStart()
'提升 UI 线程优先级 '提升 UI 线程优先级
Thread.CurrentThread.Priority = ThreadPriority.Highest Thread.CurrentThread.Priority = ThreadPriority.Highest
@@ -73,7 +71,7 @@ Friend Module ModSecret
#Region "网络鉴权" #Region "网络鉴权"
Friend Function SecretCdnSign(UrlWithMark As String) Friend Function SecretCdnSign(UrlWithMark As String) As String
If Not UrlWithMark.EndsWithF("{CDN}") Then Return UrlWithMark If Not UrlWithMark.EndsWithF("{CDN}") Then Return UrlWithMark
Return UrlWithMark.Replace("{CDN}", "").Replace(" ", "%20") Return UrlWithMark.Replace("{CDN}", "").Replace(" ", "%20")
End Function End Function
@@ -92,7 +90,6 @@ Friend Module ModSecret
If Url.Contains("api.curseforge.com") Then Req.Headers.Add("x-api-key", CurseForgeAPIKey) If Url.Contains("api.curseforge.com") Then Req.Headers.Add("x-api-key", CurseForgeAPIKey)
End Sub End Sub
#End Region #End Region
#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.ComponentModel
Imports System.Runtime.InteropServices Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Windows.Interop Imports System.Windows.Interop
Public Class DragHelper
Public Class DragFileHelper
Public Event DragDrop As EventHandler Public Event DragDrop As EventHandler
@@ -32,22 +31,22 @@ Public Class DragFileHelper
Public Property HwndIntPtrSource As HwndSource Public Property HwndIntPtrSource As HwndSource
Public Sub AddHook() Public Sub AddHook()
Me.RemoveDragHook() RemoveDragHook()
Me.HwndIntPtrSource.AddHook(AddressOf WndProc) HwndIntPtrSource.AddHook(AddressOf WndProc)
Dim handle As IntPtr = Me.HwndIntPtrSource.Handle Dim handle As IntPtr = HwndIntPtrSource.Handle
If IsUserAnAdmin() Then RevokeDragDrop(handle) If IsUserAnAdmin() Then RevokeDragDrop(handle)
DragAcceptFiles(handle, True) DragAcceptFiles(handle, True)
ChangeMessageFilter(handle) ChangeMessageFilter(handle)
End Sub End Sub
Public Sub RemoveDragHook() Public Sub RemoveDragHook()
Me.HwndIntPtrSource.RemoveHook(AddressOf WndProc) HwndIntPtrSource.RemoveHook(AddressOf WndProc)
DragAcceptFiles(Me.HwndIntPtrSource.Handle, False) DragAcceptFiles(HwndIntPtrSource.Handle, False)
End Sub 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 filePaths As String() = Nothing
Dim point As POINT = New POINT() Dim point As New POINT()
If TryGetDropInfo(msg, wParam, filePaths, point) Then If TryGetDropInfo(msg, wParam, filePaths, point) Then
DropPoint = point DropPoint = point
@@ -59,31 +58,31 @@ Public Class DragFileHelper
End Function End Function
<DllImport("user32.dll", SetLastError:=True)> <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 End Function
<DllImport("user32.dll", SetLastError:=True)> <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 End Function
<DllImport("shell32.dll")> <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 End Sub
<DllImport("shell32.dll", CharSet:=CharSet.Unicode)> <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 End Function
<DllImport("shell32.dll")> <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 End Function
<DllImport("shell32.dll")> <DllImport("shell32.dll")>
Private Shared Sub DragFinish(ByVal hDrop As IntPtr) Private Shared Sub DragFinish(hDrop As IntPtr)
End Sub End Sub
<DllImport("ole32.dll")> <DllImport("ole32.dll")>
Private Shared Function RevokeDragDrop(ByVal hWnd As IntPtr) As Integer Private Shared Function RevokeDragDrop(hWnd As IntPtr) As Integer
End Function End Function
<DllImport("shell32.dll")> <DllImport("shell32.dll")>
@@ -109,13 +108,13 @@ Public Class DragFileHelper
Private Const MSGFLT_ADD As UInteger = 1 Private Const MSGFLT_ADD As UInteger = 1
Private Const MAX_PATH As Integer = 260 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 ver As Version = Environment.OSVersion.Version
Dim isVistaOrHigher As Boolean = ver >= New Version(6, 0) Dim isVistaOrHigher As Boolean = ver >= New Version(6, 0)
Dim isNt61OrHiger As Boolean = ver >= New Version(6, 1) Dim isNt61OrHiger As Boolean = ver >= New Version(6, 1)
If isVistaOrHigher Then 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} For Each msg As UInteger In New UInteger() {WM_DROPFILES, WM_COPYGLOBALDATA, WM_COPYDATA}
Dim [error] As Boolean = False Dim [error] As Boolean = False
If isNt61OrHiger Then If isNt61OrHiger Then
@@ -129,7 +128,7 @@ Public Class DragFileHelper
End If End If
End Sub 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 dropFilePaths = Nothing
dropPoint = New POINT() dropPoint = New POINT()
@@ -141,7 +140,7 @@ Public Class DragFileHelper
For i As UInteger = 0 To fileCount - 1 For i As UInteger = 0 To fileCount - 1
Dim sb As New StringBuilder(MAX_PATH) Dim sb As New StringBuilder(MAX_PATH)
Dim result As UInteger = DragQueryFile(wParam, i, sb, sb.Capacity) 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 Next
DragQueryPoint(wParam, dropPoint) DragQueryPoint(wParam, dropPoint)
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*” ' 方法是按如下所示使用“*”
<Assembly: AssemblyVersion("2.10.3.0")> <Assembly: AssemblyVersion("2.10.4.0")>
<Assembly: AssemblyFileVersion("2.10.3.0")> <Assembly: AssemblyFileVersion("2.10.4.0")>
<Assembly: NeutralResourcesLanguage("")> <Assembly: NeutralResourcesLanguage("")>
+55 -15
View File
@@ -63,9 +63,9 @@ Namespace My.Resources
'''<summary> '''<summary>
''' 查找 System.Byte[] 类型的本地化资源。 ''' 查找 System.Byte[] 类型的本地化资源。
'''</summary> '''</summary>
Friend ReadOnly Property Custom() As Byte() Friend ReadOnly Property CacheCow_Client() As Byte()
Get Get
Dim obj As Object = ResourceManager.GetObject("Custom", resourceCulture) Dim obj As Object = ResourceManager.GetObject("CacheCow.Client", resourceCulture)
Return CType(obj,Byte()) Return CType(obj,Byte())
End Get End Get
End Property End Property
@@ -73,9 +73,29 @@ Namespace My.Resources
'''<summary> '''<summary>
''' 查找 System.Byte[] 类型的本地化资源。 ''' 查找 System.Byte[] 类型的本地化资源。
'''</summary> '''</summary>
Friend ReadOnly Property Dialogs() As Byte() Friend ReadOnly Property CacheCow_Client_FileStore() As Byte()
Get 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()) Return CType(obj,Byte())
End Get End Get
End Property End Property
@@ -105,7 +125,7 @@ Namespace My.Resources
'''</summary> '''</summary>
Friend ReadOnly Property Imazen_WebP() As Byte() Friend ReadOnly Property Imazen_WebP() As Byte()
Get Get
Dim obj As Object = ResourceManager.GetObject("Imazen_WebP", resourceCulture) Dim obj As Object = ResourceManager.GetObject("Imazen.WebP", resourceCulture)
Return CType(obj,Byte()) Return CType(obj,Byte())
End Get End Get
End Property End Property
@@ -120,16 +140,6 @@ Namespace My.Resources
End Get End Get
End Property 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> '''<summary>
''' 查找 System.Byte[] 类型的本地化资源。 ''' 查找 System.Byte[] 类型的本地化资源。
'''</summary> '''</summary>
@@ -160,6 +170,36 @@ Namespace My.Resources
End Get End Get
End Property 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> '''<summary>
''' 查找 System.Byte[] 类型的本地化资源。 ''' 查找 System.Byte[] 类型的本地化资源。
'''</summary> '''</summary>
@@ -118,27 +118,30 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <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"> <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> <value>..\resources\custom.xaml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </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"> <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> <value>..\Resources\forge-installer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="Help" type="System.Resources.ResXFileRef, System.Windows.Forms"> <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> <value>..\Resources\Help.zip;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </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> <value>..\Resources\Imazen.WebP.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="JavaWrapper" type="System.Resources.ResXFileRef, System.Windows.Forms"> <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> <value>..\Resources\java-wrapper.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </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"> <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> <value>..\Resources\libwebp64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
@@ -148,6 +151,15 @@
<data name="NAudio" type="System.Resources.ResXFileRef, System.Windows.Forms"> <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> <value>..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </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"> <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> <value>..\Resources\transformer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
@@ -99,7 +99,6 @@ Public Class PageComp
End If End If
TargetVersion = Nothing TargetVersion = Nothing
If TargetName IsNot Nothing Then If TargetName IsNot Nothing Then
'设置搜索框内容
TextSearchName.Text = TargetName TextSearchName.Text = TargetName
TargetName = Nothing TargetName = Nothing
End If End If
@@ -73,13 +73,14 @@
'筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表) '筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表)
Private Function GetResults() As List(Of CompFile) Private Function GetResults() As List(Of CompFile)
Dim Results As List(Of CompFile) = CompFileLoader.Output 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 Results = Results.Where(Function(r) r.Type <> CompType.Plugin).ToList
ElseIf PageType = CompType.Shader OrElse PageType = CompType.ResourcePack Then Case CompType.Shader, CompType.ResourcePack
Results = Results.ToList '不筛选光影和资源包,否则原版光影会因为是资源包格式而被过滤(#6473)
Else Case Else
Results = Results.Where(Function(r) r.Type = PageType).ToList Results = Results.Where(Function(r) r.Type = PageType).ToList
End If End Select
Return Results Return Results
End Function End Function
Private Sub Load_OnFinish() Private Sub Load_OnFinish()
@@ -358,7 +359,7 @@
Return False Return False
End Function 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) DefaultFolder = CachedFolder(Project.Type)
Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}") Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}")
ElseIf McVersionCurrent IsNot Nothing AndAlso IsVersionSuitable(McVersionCurrent) Then ElseIf McVersionCurrent IsNot Nothing AndAlso IsVersionSuitable(McVersionCurrent) Then
@@ -424,13 +425,7 @@
If Not Target.Contains("\") Then Return If Not Target.Contains("\") Then Return
'构造步骤加载器 '构造步骤加载器
Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " " Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " "
If Target <> DefaultFolder Then If Target <> DefaultFolder Then CachedFolder(Project.Type) = GetPathFromFullPath(Target)
If CachedFolder.ContainsKey(Project.Type) Then
CachedFolder(Project.Type) = GetPathFromFullPath(Target)
Else
CachedFolder.Add(Project.Type, GetPathFromFullPath(Target))
End If
End If
Dim Loaders As New List(Of LoaderBase) Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True}) 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 Dim PageData As String
Try 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 Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0)) Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last) Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last)
@@ -733,7 +734,8 @@ Retry:
'官方源 '官方源
Dim PageData As String Dim PageData As String
Try 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 Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0)) Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last) Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last)
@@ -1340,7 +1342,7 @@ Retry:
If Json("data") IsNot Nothing AndAlso Json("data")("MOJMAPS") IsNot Nothing Then If Json("data") IsNot Nothing AndAlso Json("data")("MOJMAPS") IsNot Nothing Then
'下载原版 Json 文件 '下载原版 Json 文件
Task.Progress = 0.4 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] '[net.minecraft:client:1.17.1-20210706.113038:mappings@txt] 或 @tsrg]
Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).BeforeFirst("@") 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)) Dim Address = McLibGet(OriginalName).Replace(".jar", "-mappings." & Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(1))
@@ -1641,10 +1643,11 @@ Retry:
Public Sub McDownloadForgeRecommendedRefresh() Public Sub McDownloadForgeRecommendedRefresh()
If IsForgeRecommendedRefreshed Then Return If IsForgeRecommendedRefreshed Then Return
IsForgeRecommendedRefreshed = True IsForgeRecommendedRefreshed = True
RunInNewThread(Sub() RunInNewThread(
Sub()
Try Try
Log("[Download] 刷新 Forge 推荐版本缓存开始") 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 & ")") If Result.Length < 1000 Then Throw New Exception("获取的结果过短(" & Result & ")")
Dim ResultJson As JContainer = GetJson(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="必须安装 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="安装结束后,请在 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="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"> <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" /> <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"> <Grid x:Name="PanForgeInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
@@ -476,11 +476,6 @@
Else Else
HintModOptiFine.Visibility = Visibility.Collapsed HintModOptiFine.Visibility = Visibility.Collapsed
End If 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 IsReloading = False
End Sub End Sub
@@ -676,13 +671,16 @@
If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容" If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
If LoadOptiFine Is Nothing OrElse LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……" 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 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:全部不兼容 '检查 Forge 1.13 - 1.14.3:全部不兼容
If SelectedForge IsNot Nothing AndAlso If SelectedForge IsNot Nothing AndAlso
VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then
Return "与 Forge 不兼容" Return "与 Forge 不兼容"
End If End If
'检查 Fabric 1.20.5+:全部不兼容
If SelectedFabric IsNot Nothing AndAlso
VersionSortInteger(SelectedMinecraftId, "1.20.4") > 0 Then
Return "与 Fabric 不兼容"
End If
'检查 Forge 版本 '检查 Forge 版本
Dim HasAny As Boolean = False Dim HasAny As Boolean = False
Dim HasRequiredVersion As Boolean = False Dim HasRequiredVersion As Boolean = False
@@ -988,8 +986,11 @@
Private Function LoadFabricGetError() As String Private Function LoadFabricGetError() As String
If LoadFabric Is Nothing OrElse LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……" 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 If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabric.State, Object).Error.Message
'检查 Fabric 1.20.5+:没有 OptiFabric 故全部不兼容 '检查 OptiFine 1.20.5+:没有 OptiFabric 故全部不兼容
If SelectedOptiFine IsNot Nothing AndAlso VersionSortInteger(SelectedMinecraftId, "1.20.4") > 0 Then Return "与 OptiFine 不兼容" 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") 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 Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") Then
If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容" If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
@@ -105,13 +105,15 @@
Dim UnknownFailureCount As Integer = 0 Dim UnknownFailureCount As Integer = 0
Do While Not MyConverter.IsExited Do While Not MyConverter.IsExited
Try Try
Dim Result = NetRequestOnce( Dim Result = NetRequestByClient(
"https://login.microsoftonline.com/consumers/oauth2/v2.0/token", "POST", "https://login.microsoftonline.com/consumers/oauth2/v2.0/token", HttpMethod.Post,
Content:=
"grant_type=urn:ietf:params:oauth:grant-type:device_code" & "&" & "grant_type=urn:ietf:params:oauth:grant-type:device_code" & "&" &
"client_id=" & OAuthClientId & "&" & "client_id=" & OAuthClientId & "&" &
"device_code=" & DeviceCode & "&" & "device_code=" & DeviceCode & "&" &
"scope=XboxLive.signin%20offline_access", "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) Dim ResultJson As JObject = GetJson(Result)
McLaunchLog($"令牌过期时间:{ResultJson("expires_in")} 秒") McLaunchLog($"令牌过期时间:{ResultJson("expires_in")} 秒")
@@ -125,8 +127,8 @@
ElseIf ex.Message.Contains("expired_token") Then ElseIf ex.Message.Contains("expired_token") Then
Finished(New Exception("$登录用时太长啦,重新试试吧!")) Finished(New Exception("$登录用时太长啦,重新试试吧!"))
Return Return
Else If ex.Message.Contains("Account security interrupt") Then ElseIf ex.Message.Contains("Account security interrupt") Then
Finished(New Exception("$非常抱歉,该账号由于安全问题无法登陆,请前往 Microsoft 账户页获取更多信息。")) Finished(New Exception("$该账号由于安全问题无法登陆,请前往微软账户页获取更多信息。"))
Return Return
ElseIf ex.Message.Contains("service abuse") Then ElseIf ex.Message.Contains("service abuse") Then
Finished(New Exception("$非常抱歉,该账号已被微软封禁,无法登录。")) Finished(New Exception("$非常抱歉,该账号已被微软封禁,无法登录。"))
@@ -259,12 +259,13 @@ Retry:
End Sub) End Sub)
If SelId Is Nothing Then Return If SelId Is Nothing Then Return
'发送请求 '发送请求
Dim Result As String = NetRequestRetry("https://api.minecraftservices.com/minecraft/profile/capes/active", Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/capes/active",
If(SelId = 0, "DELETE", "PUT"), If(SelId = 0, HttpMethod.Delete, HttpMethod.Put),
If(SelId = 0, "", New JObject(New JProperty("capeId", SkinData("capes")(SelId - 1)("id"))).ToString(0)), Content:=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}}) ContentType:="application/json",
Headers:={{"Authorization", "Bearer " & AccessToken}})
If Result.Contains("""errorMessage""") Then If Result.Contains("""errorMessage""") Then
Hint("更改披风失败:" & GetJson(Result)("errorMessage"), HintType.Critical) Hint("更改披风失败:" & GetJson(Result)("errorMessage").ToString, HintType.Critical)
Return Return
Else Else
Hint("更改披风成功!", HintType.Finish) Hint("更改披风成功!", HintType.Finish)
@@ -156,7 +156,7 @@ Download:
Dim Version As String = "" Dim Version As String = ""
Dim NeedDownload As Boolean = True Dim NeedDownload As Boolean = True
Try Try
Version = NetGetCodeByRequestOnce(VersionAddress, Timeout:=10000) Version = NetRequestByClientRetry(VersionAddress)
If Version.Length > 1000 Then Throw New Exception($"获取的主页版本过长({Version.Length} 字符)") If Version.Length > 1000 Then Throw New Exception($"获取的主页版本过长({Version.Length} 字符)")
Dim CurrentVersion As String = Setup.Get("CacheSavedPageVersion") Dim CurrentVersion As String = Setup.Get("CacheSavedPageVersion")
If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then
@@ -171,7 +171,7 @@ Download:
End Try End Try
'实际下载 '实际下载
If NeedDownload Then If NeedDownload Then
Dim FileContent As String = NetGetCodeByRequestRetry(Address) Dim FileContent As String = NetRequestByClientRetry(Address)
Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}") Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}")
Setup.Set("CacheSavedPageUrl", Address) Setup.Set("CacheSavedPageUrl", Address)
Setup.Set("CacheSavedPageVersion", Version) Setup.Set("CacheSavedPageVersion", Version)
@@ -231,7 +231,9 @@ Download:
Try Try
'修改时应同时修改 PageOtherHelpDetail.Init '修改时应同时修改 PageOtherHelpDetail.Init
Content = HelpArgumentReplace(Content) 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>" 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}") Log($"[Page] 实例化:加载主页 UI 开始,最终内容长度:{Content.Count}")
PanCustom.Children.Add(GetObjectFromXML(Content)) PanCustom.Children.Add(GetObjectFromXML(Content))
@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PCL" xmlns:local="clr-namespace:PCL"
mc:Ignorable="d" d:DesignWidth="297.6"> 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: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: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="游戏用户名" /> <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 Private Sub ComboLegacy_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged
If Setup.Get("LaunchSkinType") = 0 Then PageLaunchLeft.SkinLegacy.Start(IsForceRestart:=True) 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) 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 End Sub
Private Sub Skin_Click() Handles Skin.Click Private Sub Skin_Click() Handles Skin.Click
If (Setup.Get("UiHiddenPageSetup") OrElse Setup.Get("UiHiddenSetupLaunch")) AndAlso Not PageSetupUI.HiddenForceShow Then If (Setup.Get("UiHiddenPageSetup") OrElse Setup.Get("UiHiddenSetupLaunch")) AndAlso Not PageSetupUI.HiddenForceShow Then
@@ -23,9 +23,11 @@
<local:MyIconButton.ContextMenu> <local:MyIconButton.ContextMenu>
<ContextMenu Closed="HidePanel" HorizontalOffset="10" VerticalOffset="18"> <ContextMenu Closed="HidePanel" HorizontalOffset="10" VerticalOffset="18">
<local:MyMenuItem Click="BtnSkinEdit_Click" Header="修改皮肤"/> <local:MyMenuItem Click="BtnSkinEdit_Click" Header="修改皮肤"/>
<local:MyMenuItem Click="BtnSkinSave_Click" Header="保存皮肤"/> <local:MyMenuItem Click="BtnSkinSave_Click" Header="保存皮肤文件"/>
<local:MyMenuItem Click="BtnSkinRefresh_Click" Header="刷新头像"/> <Separator />
<local:MyMenuItem Click="BtnSkinCape_Click" Header="修改披风"/> <local:MyMenuItem Click="BtnSkinCape_Click" Header="修改披风"/>
<Separator />
<local:MyMenuItem Click="BtnSkinRefresh_Click" Header="刷新"/>
</ContextMenu> </ContextMenu>
</local:MyIconButton.ContextMenu> </local:MyIconButton.ContextMenu>
</local:MyIconButton> </local:MyIconButton>
@@ -107,7 +107,7 @@ Retry:
McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True) McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
GoTo Retry GoTo Retry
ElseIf Result.Contains("""error""") Then ElseIf Result.Contains("""error""") Then
Hint("更改皮肤失败:" & GetJson(Result)("error"), HintType.Critical) Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Critical)
Return Return
End If End If
'获取新皮肤地址 '获取新皮肤地址
@@ -30,7 +30,7 @@
</Image.Clip> </Image.Clip>
</Image> </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="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> </Grid>
</local:MyCard> </local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="特别鸣谢"> <local:MyCard Margin="0,0,0,15" Title="特别鸣谢">
@@ -104,265 +104,288 @@
</local:MyCard> </local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="赞助者"> <local:MyCard Margin="0,0,0,15" Title="赞助者">
<StackPanel Margin="25,40,10,20"> <StackPanel Margin="25,40,10,20">
<TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 5 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" /> <TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 6 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
<WrapPanel Margin="0,0,0,10"> <WrapPanel Margin="0,0,0,10"> <TextBlock Width="120" Margin="0,1.5" Text="星月" />
<TextBlock Width="120" Margin="0,1.5" Text="Alliance" /> <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="长歌当天" />
<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="狐狸不吃酸葡萄" /> <TextBlock Width="120" Margin="0,1.5" Text="hy" />
<TextBlock Width="120" Margin="0,1.5" Text="仰望星空的牧星人" /> <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="114514" /> <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="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="团团" />
<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="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="盛夏" />
<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="120" Margin="0,1.5" Text="461863352" />
<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="Xing_K" />
<TextBlock Width="120" Margin="0,1.5" Text="小宝" /> <TextBlock Width="120" Margin="0,1.5" Text="yzt" />
<TextBlock Width="120" Margin="0,1.5" Text="无" /> <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="鸡人" />
<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="鸣纳" />
<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="Zik yeung" /> <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="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="cai1" />
<TextBlock Width="120" Margin="0,1.5" Text="C" /> <TextBlock Width="120" Margin="0,1.5" Text="小比登T^T" />
<TextBlock Width="120" Margin="0,1.5" Text="Haio" /> <TextBlock Width="120" Margin="0,1.5" Text="hb" />
<TextBlock Width="120" Margin="0,1.5" Text="陆光" /> <TextBlock Width="120" Margin="0,1.5" Text="caizzz" />
<TextBlock Width="120" Margin="0,1.5" Text="chuveiro" /> <TextBlock Width="120" Margin="0,1.5" Text="yyin" />
<TextBlock Width="120" Margin="0,1.5" Text="无名氏34613" /> <TextBlock Width="120" Margin="0,1.5" Text="無言" />
<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="改头换面" />
<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="烤肉真香" />
<TextBlock Width="120" Margin="0,1.5" Text="Chr0n0s" /> <TextBlock Width="120" Margin="0,1.5" Text="ZhuTan12" />
<TextBlock Width="120" Margin="0,1.5" Text="七" /> <TextBlock Width="120" Margin="0,1.5" Text="tom" />
<TextBlock Width="120" Margin="0,1.5" Text="H?O" /> <TextBlock Width="120" Margin="0,1.5" Text="洛竹" />
<TextBlock Width="120" Margin="0,1.5" Text="瑞霖RLD" /> <TextBlock Width="120" Margin="0,1.5" Text="foob" />
<TextBlock Width="120" Margin="0,1.5" Text="AAcfun" /> <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="阮绍轩" />
<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="hduqggd55379" /> <TextBlock Width="120" Margin="0,1.5" Text="BAIgivele" />
<TextBlock Width="120" Margin="0,1.5" Text="唠叨的土豆" /> <TextBlock Width="120" Margin="0,1.5" Text="ljc" />
<TextBlock Width="120" Margin="0,1.5" Text="Lonely_Grey" /> <TextBlock Width="120" Margin="0,1.5" Text="暖笑" />
<TextBlock Width="120" Margin="0,1.5" Text="Vergilio" /> <TextBlock Width="120" Margin="0,1.5" Text="焦糖流酥" />
<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="魔导兔" />
<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="君殇" />
<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="邓布利多" />
<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="事与愿违" /> <TextBlock Width="120" Margin="0,1.5" Text="vvvghjvvv" />
<TextBlock Width="120" Margin="0,1.5" Text="SamXU1322" /> <TextBlock Width="120" Margin="0,1.5" Text="法斯" />
<TextBlock Width="120" Margin="0,1.5" Text="OCEANI" /> <TextBlock Width="120" Margin="0,1.5" Text="DASENSUN" />
<TextBlock Width="120" Margin="0,1.5" Text="shenpli" /> <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="握不住信新心" />
<TextBlock Width="120" Margin="0,1.5" Text="kirsnow" /> <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="pengyihang" /> <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" />
<TextBlock Width="120" Margin="0,1.5" Text="SinceCN" />
</WrapPanel> </WrapPanel>
<Grid Height="35"> <Grid Height="35">
<Grid.ColumnDefinitions> <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" /> <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"> <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="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>
</StackPanel> </StackPanel>
</local:MyCard> </local:MyCard>
@@ -227,7 +227,7 @@
DeleteDirectory(Version.Path) DeleteDirectory(Version.Path)
Hint("版本 " & Version.Name & " 已永久删除!", HintType.Finish) Hint("版本 " & Version.Name & " 已永久删除!", HintType.Finish)
Else 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) Hint("版本 " & Version.Name & " 已删除到回收站!", HintType.Finish)
End If End If
Case 2 Case 2
@@ -205,7 +205,7 @@
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" /> <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions> </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="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> </Grid>
<Grid x:Name="PanSkinChange" Margin="0,14,0,2" Height="35" Visibility="Collapsed"> <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" 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" /> 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> </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" /> Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数尾部" Margin="0,0,25,0" /> <TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数尾部" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="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" /> <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="" <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 文件夹。" /> 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 />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </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="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;这会严重影响启动器运行,若无特殊需要不建议开启。" /> <local:MyCheckBox Grid.Column="2" Text="添加延迟" Height="22" x:Name="CheckDebugDelay" Tag="SystemDebugDelay" ToolTip="在各个环节添加随机的延迟,拖慢加载速度,以测试部分功能是否正常运行。&#xa;这会严重影响启动器运行,若无特殊需要不建议开启。" />
</Grid> </Grid>
@@ -1,6 +1,4 @@
Imports NAudio.Wave Public Class PageSetupUI
Public Class PageSetupUI
Public Shadows IsLoaded As Boolean = False 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 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 If FileName = "" Then Return
Try Try
'拷贝文件 '拷贝文件
@@ -321,7 +319,7 @@ Refresh:
Return Return
End If 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 If FileName = "" Then
FrmMain.ImageTitleLogo.Source = Nothing FrmMain.ImageTitleLogo.Source = Nothing
e.Handled = True e.Handled = True
@@ -359,15 +357,9 @@ Refresh:
PanMusicVolume.Visibility = Visibility.Visible PanMusicVolume.Visibility = Visibility.Visible
PanMusicDetail.Visibility = Visibility.Visible PanMusicDetail.Visibility = Visibility.Visible
BtnMusicClear.Visibility = Visibility.Visible BtnMusicClear.Visibility = Visibility.Visible
Dim validMusicCount As Integer = 0 CardMusic.Title = "背景音乐(" &
For Each File In EnumerateFiles(Path & "PCL\Musics\") EnumerateFiles(Path & "PCL\Musics\").Count(Function(f) {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(f.Extension.ToLower)) &
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 & " 首)"
Else Else
PanMusicVolume.Visibility = Visibility.Collapsed PanMusicVolume.Visibility = Visibility.Collapsed
PanMusicDetail.Visibility = Visibility.Collapsed PanMusicDetail.Visibility = Visibility.Collapsed
@@ -564,8 +564,8 @@ Public Class PageVersionExport
Sub() Sub()
Try Try
Dim ModrinthHashes = Loader.Input.Select(Function(m) m.ModrinthHash) Dim ModrinthHashes = Loader.Input.Select(Function(m) m.ModrinthHash)
Dim ModrinthRaw = CType(GetJson(DlModRequest("https://api.modrinth.com/v2/version_files", "POST", Dim ModrinthRaw As JObject = DlModRequest("https://api.modrinth.com/v2/version_files", HttpMethod.Post,
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")), JObject) $"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")
For Each ModFile In Loader.Input For Each ModFile In Loader.Input
'查找对应的文件 '查找对应的文件
If Not ModrinthRaw.ContainsKey(ModFile.ModrinthHash) Then Continue For If Not ModrinthRaw.ContainsKey(ModFile.ModrinthHash) Then Continue For
@@ -589,8 +589,8 @@ Public Class PageVersionExport
Try Try
If ModrinthUploadMode Then Return 'Modrinth 上传模式下,不能从 CurseForge 获取信息 If ModrinthUploadMode Then Return 'Modrinth 上传模式下,不能从 CurseForge 获取信息
Dim CurseForgeHashes = Loader.Input.Select(Function(m) m.CurseForgeHash) Dim CurseForgeHashes = Loader.Input.Select(Function(m) m.CurseForgeHash)
Dim CurseForgeRaw = CType(CType(GetJson(DlModRequest("https://api.curseforge.com/v1/fingerprints/432/", "POST", Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432/", HttpMethod.Post,
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")), JObject)("data")("exactMatches"), JContainer) $"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches")
For Each ResultJson As JObject In CurseForgeRaw For Each ResultJson As JObject In CurseForgeRaw
If Not ResultJson.ContainsKey("file") Then Continue For If Not ResultJson.ContainsKey("file") Then Continue For
Dim File As JObject = ResultJson("file") Dim File As JObject = ResultJson("file")
@@ -381,8 +381,9 @@ Install:
''' 下载 Mod。 ''' 下载 Mod。
''' </summary> ''' </summary>
Private Sub BtnManageDownload_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageDownload.Click, BtnHintDownload.Click 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) FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadMod)
End Sub End Sub
@@ -429,6 +430,11 @@ Install:
If FrmMain.PageRight IsNot Me Then Return If FrmMain.PageRight IsNot Me Then Return
If My.Computer.Keyboard.CtrlKeyDown AndAlso e.Key = Key.A Then ChangeAllSelected(True) If My.Computer.Keyboard.CtrlKeyDown AndAlso e.Key = Key.A Then ChangeAllSelected(True)
End Sub 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 #End Region
@@ -637,14 +643,14 @@ Install:
Try Try
For Each Entry As McMod In ModList For Each Entry As McMod In ModList
If File.Exists(Entry.Path) Then 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 Else
Log($"[Mod] 未找到更新前的 Mod 文件,跳过对它的删除:{Entry.Path}", LogLevel.Debug) Log($"[Mod] 未找到更新前的 Mod 文件,跳过对它的删除:{Entry.Path}", LogLevel.Debug)
End If End If
Next Next
For Each Entry As KeyValuePair(Of String, String) In FileCopyList For Each Entry As KeyValuePair(Of String, String) In FileCopyList
If File.Exists(Entry.Value) Then 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) Log($"[Mod] 更新后的 Mod 文件已存在,将会把它放入回收站:{Entry.Value}", LogLevel.Debug)
End If End If
If Directory.Exists(GetPathFromFullPath(Entry.Value)) Then If Directory.Exists(GetPathFromFullPath(Entry.Value)) Then
@@ -733,7 +739,7 @@ Install:
If IsShiftPressed Then If IsShiftPressed Then
File.Delete(ModEntity.Path) File.Delete(ModEntity.Path)
Else 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 End If
Catch ex As OperationCanceledException Catch ex As OperationCanceledException
Log(ex, "删除 Mod 被主动取消") Log(ex, "删除 Mod 被主动取消")
@@ -116,12 +116,14 @@
Dim TempName As String = NewName & "_temp" Dim TempName As String = NewName & "_temp"
Dim TempPath As String = PathMcFolder & "versions\" & TempName & "\" Dim TempPath As String = PathMcFolder & "versions\" & TempName & "\"
Dim IsCaseChangedOnly As Boolean = NewName.ToLower = OldName.ToLower Dim IsCaseChangedOnly As Boolean = NewName.ToLower = OldName.ToLower
'重新加载版本 Json 信息,避免 HMCL 项被合并 '重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储
Dim JsonObject As JObject Dim JsonObject As JObject
Try 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 Catch ex As Exception
Log(ex, "重命名读取 json 时失败") Log(ex, "在重命名读取 json 时失败")
JsonObject = PageVersionLeft.Version.JsonObject JsonObject = PageVersionLeft.Version.JsonObject
End Try End Try
'重命名主文件夹 '重命名主文件夹
@@ -130,32 +132,24 @@
'清理 ini 缓存 '清理 ini 缓存
IniClearCache(PageVersionLeft.Version.PathIndie & "options.txt") IniClearCache(PageVersionLeft.Version.PathIndie & "options.txt")
IniClearCache(PageVersionLeft.Version.Path & "PCL\Setup.ini") IniClearCache(PageVersionLeft.Version.Path & "PCL\Setup.ini")
'重命名 JAR 文件、JSON 文件与 natives 文件夹 '重命名 jar 文件与 natives 文件夹
If Directory.Exists(NewPath & OldName & "-natives") Then '不能进行遍历重命名,否则在版本名很短的时候容易误伤其他文件(#6443)
If Directory.Exists($"{NewPath}{OldName}-natives") Then
If IsCaseChangedOnly Then If IsCaseChangedOnly Then
My.Computer.FileSystem.RenameDirectory(NewPath & OldName & "-natives", OldName & "natives" & "_temp") 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_temp", $"{NewName}-natives")
Else Else
DeleteDirectory(NewPath & NewName & "-natives") DeleteDirectory($"{NewPath}{NewName}-natives")
My.Computer.FileSystem.RenameDirectory(NewPath & OldName & "-natives", NewName & "-natives") My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives", $"{NewName}-natives")
End If End If
End If End If
If File.Exists(NewPath & OldName & ".jar") Then If File.Exists($"{NewPath}{OldName}.jar") Then
If IsCaseChangedOnly Then If IsCaseChangedOnly Then
My.Computer.FileSystem.RenameFile(NewPath & OldName & ".jar", OldName & "_temp" & ".jar") 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}_temp.jar", $"{NewName}.jar")
Else Else
File.Delete(NewPath & NewName & ".jar") File.Delete($"{NewPath}{NewName}.jar")
My.Computer.FileSystem.RenameFile(NewPath & OldName & ".jar", 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")
End If End If
End If End If
'替换版本设置文件中的路径 '替换版本设置文件中的路径
@@ -166,15 +160,13 @@
If ReadIni(PathMcFolder & "PCL.ini", "Version") = OldName Then If ReadIni(PathMcFolder & "PCL.ini", "Version") = OldName Then
WriteIni(PathMcFolder & "PCL.ini", "Version", NewName) WriteIni(PathMcFolder & "PCL.ini", "Version", NewName)
End If End If
'更改版本 Json '写入版本 Json
If File.Exists(NewPath & NewName & ".json") Then
Try Try
JsonObject("id") = NewName JsonObject("id") = NewName
WriteFile(NewPath & NewName & ".json", JsonObject.ToString) WriteFile(NewPath & NewName & ".json", JsonObject.ToString)
Catch ex As Exception Catch ex As Exception
Log(ex, "重命名版本 json 失败") Log(ex, "重命名版本 json 失败")
End Try End Try
End If
'刷新与提示 '刷新与提示
Hint("重命名成功!", HintType.Finish) Hint("重命名成功!", HintType.Finish)
PageVersionLeft.Version = New McVersion(NewName).Load() PageVersionLeft.Version = New McVersion(NewName).Load()
@@ -192,7 +184,7 @@
'选择 自定义 时修改图片 '选择 自定义 时修改图片
Try Try
If ComboDisplayLogo.SelectedItem Is ItemDisplayLogoCustom Then 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 If FileName = "" Then
Reload() '还原选项 Reload() '还原选项
Return Return
@@ -209,10 +209,10 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="JVM 参数头部" Margin="0,0,25,0" /> <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" /> Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数尾部" Margin="0,0,25,0" /> <TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数尾部" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#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" /> <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" <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 文件夹。" /> 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> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <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"> <Reference Include="Imazen.WebP, Version=10.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>Resources\Imazen.WebP.dll</HintPath> <HintPath>Resources\Imazen.WebP.dll</HintPath>
@@ -149,8 +164,9 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> <SpecificVersion>False</SpecificVersion>
<HintPath>Resources\Newtonsoft.Json.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="Ookii.Dialogs.Wpf, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0c15020868fd6249, processorArchitecture=MSIL"> <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> <HintPath>Resources\Ookii.Dialogs.Wpf.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" /> <Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" /> <Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Management" /> <Reference Include="System.Management" />
<Reference Include="System.Net.Http" /> <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.Numerics" />
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.ServiceModel" /> <Reference Include="System.ServiceModel" />
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
@@ -195,11 +218,14 @@
<Compile Include="Controls\MyIconTextButton.xaml.vb"> <Compile Include="Controls\MyIconTextButton.xaml.vb">
<DependentUpon>MyIconTextButton.xaml</DependentUpon> <DependentUpon>MyIconTextButton.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Modules\Base\ModDragHelper.vb" />
<Compile Include="Modules\Minecraft\ModComp.vb" /> <Compile Include="Modules\Minecraft\ModComp.vb" />
<Compile Include="Modules\Minecraft\ModJava.vb" /> <Compile Include="Modules\Minecraft\ModJava.vb" />
<Compile Include="Modules\Minecraft\ModMod.vb" /> <Compile Include="Modules\Minecraft\ModMod.vb" />
<Compile Include="Modules\Minecraft\ModModpack.vb" /> <Compile Include="Modules\Minecraft\ModModpack.vb" />
<Compile Include="Modules\ThirdParty\DragHelper.vb" />
<Compile Include="Pages\PageVersion\MyLocalModItem.xaml.vb"> <Compile Include="Pages\PageVersion\MyLocalModItem.xaml.vb">
<DependentUpon>MyLocalModItem.xaml</DependentUpon> <DependentUpon>MyLocalModItem.xaml</DependentUpon>
</Compile> </Compile>
@@ -233,9 +259,6 @@
<Compile Include="Modules\ModDevelop.vb" /> <Compile Include="Modules\ModDevelop.vb" />
<Compile Include="Modules\Minecraft\ModWatcher.vb" /> <Compile Include="Modules\Minecraft\ModWatcher.vb" />
<Compile Include="Modules\ModSecret.vb" /> <Compile Include="Modules\ModSecret.vb" />
<Compile Include="Modules\Reference\CookieWebClient.vb">
<SubType>Component</SubType>
</Compile>
<Compile Include="Pages\PageDownload\Comp\PageComp.xaml.vb"> <Compile Include="Pages\PageDownload\Comp\PageComp.xaml.vb">
<DependentUpon>PageComp.xaml</DependentUpon> <DependentUpon>PageComp.xaml</DependentUpon>
</Compile> </Compile>
@@ -499,6 +522,7 @@
<DependentUpon>FormMain.xaml</DependentUpon> <DependentUpon>FormMain.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Page Include="Pages\PageVersion\MyLocalModItem.xaml"> <Page Include="Pages\PageVersion\MyLocalModItem.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
@@ -721,6 +745,7 @@
<Import Include="System.IO" /> <Import Include="System.IO" />
<Import Include="System.Linq" /> <Import Include="System.Linq" />
<Import Include="System.Net" /> <Import Include="System.Net" />
<Import Include="System.Net.Http" />
<Import Include="System.Text" /> <Import Include="System.Text" />
<Import Include="System.Threading" /> <Import Include="System.Threading" />
<Import Include="System.Xml.Linq" /> <Import Include="System.Xml.Linq" />
@@ -946,6 +971,7 @@
<Resource Include="Images\Heads\MCBBS.png" /> <Resource Include="Images\Heads\MCBBS.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Resource Include="Images\Blocks\NeoForge.png" /> <Resource Include="Images\Blocks\NeoForge.png" />
@@ -957,5 +983,18 @@
<None Include="Resources\Imazen.WebP.dll" /> <None Include="Resources\Imazen.WebP.dll" />
<None Include="Resources\libwebp64.dll" /> <None Include="Resources\libwebp64.dll" />
</ItemGroup> </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" /> <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project> </Project>
Binary file not shown.
Binary file not shown.
@@ -134,6 +134,10 @@
Text="切换到下载页面" EventType="切换页面" EventData="1|1"/> Text="切换到下载页面" EventType="切换页面" EventData="1|1"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35" <local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="切换到启动器设置" EventType="切换页面" EventData="3|2"/> 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> </StackPanel>
</local:MyCard> </local:MyCard>
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.