This commit is contained in:
龙腾猫跃
2025-11-01 11:51:54 +08:00
parent a067271995
commit efd480f06c
24 changed files with 1031 additions and 431 deletions
+27 -3
View File
@@ -113,6 +113,17 @@ Public Class FormMain
'3:BUG+ IMP* FEAT- '3:BUG+ IMP* FEAT-
'2:BUG* IMP- '2:BUG* IMP-
'1:BUG- '1:BUG-
If LastVersion < 374 Then 'Snapshot 2.11.1
If LastVersion >= 373 Then
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:使用离线登录也可以直接加入联机房间了"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:会从所有共享节点中自动选择负载最低的进行中继连接"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:若复制了邀请码,则可以直接快速加入房间"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:关闭 PCL 时总是会提示是否退出联机,防止在关闭 PCL 时无意地关闭或退出了房间"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "新增:允许自定义要连接的节点"))
End If
FeatureCount += 9
BugCount += 7
End If
If LastVersion < 373 Then 'Snapshot 2.11.0 If LastVersion < 373 Then 'Snapshot 2.11.0
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:联机功能!")) FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:联机功能!"))
FeatureCount += 7 FeatureCount += 7
@@ -587,9 +598,7 @@ Public Class FormMain
End Sub, "强行停止下载任务") End Sub, "强行停止下载任务")
End If End If
'关闭联机? '关闭联机?
If FrmLinkMain IsNot Nothing Then If FrmLinkMain?.TryExit(Not SendWarning, True) Then Return
If FrmLinkMain.TryExit(SendWarning) Then Return
End If
'关闭 '关闭
RunInUiWait( RunInUiWait(
Sub() Sub()
@@ -765,6 +774,21 @@ Public Class FormMain
Catch ex As Exception Catch ex As Exception
Log(ex, "切回窗口时出错", LogLevel.Feedback) Log(ex, "切回窗口时出错", LogLevel.Feedback)
End Try End Try
'读取剪贴板,自动加入联机房间
If PageLinkMain.LinkState <> PageLinkMain.LinkStates.Waiting Then Return '已启动联机
Dim Code = ClipboardGetText() : If Code Is Nothing Then Return '剪贴板无文本
If Setup.Get("LinkLastAutoJoinInviteCode") = Code Then Return
If PageLinkMain.ValidateCodeFormat(Code) IsNot Nothing Then Return '不是邀请码
Setup.Set("LinkLastAutoJoinInviteCode", Code)
RunInThread(
Sub()
If MyMsgBox("嘿,是否使用复制的邀请码加入房间?", "加入联机房间", "加入", "取消") = 2 Then Return '防止弹窗阻碍主线程,所以必须放在工作线程
RunInUi(
Sub()
PageLinkMain.Join(Code)
ClipboardSet(Nothing, False)
End Sub)
End Sub)
End Sub End Sub
'文件拖放 '文件拖放
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+48 -4
View File
@@ -5,6 +5,7 @@ Imports System.Runtime.CompilerServices
Imports System.Security.Cryptography Imports System.Security.Cryptography
Imports System.Security.Principal Imports System.Security.Principal
Imports System.Text.RegularExpressions Imports System.Text.RegularExpressions
Imports System.Threading.Tasks
Imports System.Xaml Imports System.Xaml
Imports Newtonsoft.Json Imports Newtonsoft.Json
@@ -13,13 +14,13 @@ Public Module ModBase
#Region "声明" #Region "声明"
'下列版本信息由更新器自动修改 '下列版本信息由更新器自动修改
Public Const VersionBaseName As String = "2.11.0" '不含分支前缀的显示用版本名 Public Const VersionBaseName As String = "2.11.1" '不含分支前缀的显示用版本名
Public Const VersionStandardCode As String = "2.11.0." & VersionBranchCode '标准格式的四段式版本号 Public Const VersionStandardCode As String = "2.11.1." & 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 = 372 'Release Public Const VersionCode As Integer = 372 'Release
#Else #Else
Public Const VersionCode As Integer = 373 'Snapshot Public Const VersionCode As Integer = 374 'Snapshot
#End If #End If
'自动生成的版本信息 '自动生成的版本信息
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -1727,6 +1728,7 @@ RetryDir:
''' </summary> ''' </summary>
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)> <Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function StartsWithF(Str As String, Prefix As String, Optional IgnoreCase As Boolean = False) As Boolean Public Function StartsWithF(Str As String, Prefix As String, Optional IgnoreCase As Boolean = False) As Boolean
If Str Is Nothing Then Return False
Return Str.StartsWith(Prefix, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal)) Return Str.StartsWith(Prefix, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal))
End Function End Function
''' <summary> ''' <summary>
@@ -1734,6 +1736,7 @@ RetryDir:
''' </summary> ''' </summary>
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)> <Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function EndsWithF(Str As String, Suffix As String, Optional IgnoreCase As Boolean = False) As Boolean Public Function EndsWithF(Str As String, Suffix As String, Optional IgnoreCase As Boolean = False) As Boolean
If Str Is Nothing Then Return False
Return Str.EndsWith(Suffix, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal)) Return Str.EndsWith(Suffix, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal))
End Function End Function
''' <summary> ''' <summary>
@@ -1741,6 +1744,7 @@ RetryDir:
''' </summary> ''' </summary>
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)> <Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function ContainsF(Str As String, SubStr As String, Optional IgnoreCase As Boolean = False) As Boolean Public Function ContainsF(Str As String, SubStr As String, Optional IgnoreCase As Boolean = False) As Boolean
If Str Is Nothing Then Return False
Return Str.IndexOf(SubStr, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal)) >= 0 Return Str.IndexOf(SubStr, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal)) >= 0
End Function End Function
''' <summary> ''' <summary>
@@ -1777,6 +1781,7 @@ RetryDir:
''' 如果输入有误,返回 0。 ''' 如果输入有误,返回 0。
''' </summary> ''' </summary>
Public Function Val(Str As Object) As Double Public Function Val(Str As Object) As Double
If Str Is Nothing Then Return 0
Try Try
Return If(TypeOf Str Is String AndAlso Str = "&", 0, Conversion.Val(Str)) Return If(TypeOf Str Is String AndAlso Str = "&", 0, Conversion.Val(Str))
Catch Catch
@@ -2147,6 +2152,29 @@ RetryDir:
Return result Return result
End Function End Function
''' <summary>
''' 为 Task 设置超时,在超时时抛出 TimeoutException。
''' </summary>
<Extension> Public Function GetResultWithTimeout(Of T)(TargetTask As Task(Of T), TokenSource As CancellationTokenSource, TimeoutMs As Integer) As T
Dim DelayTask = Task.Delay(TimeoutMs)
If Task.WhenAny(TargetTask, DelayTask).GetAwaiter().GetResult() Is DelayTask Then
TokenSource.Cancel()
Throw New TimeoutException($"任务超时({TimeoutMs} ms)")
End If
Return TargetTask.GetAwaiter().GetResult()
End Function
''' <summary>
''' 为 Task 设置超时,在超时时抛出 TimeoutException。
''' </summary>
<Extension> Public Sub GetResultWithTimeout(TargetTask As Task, TokenSource As CancellationTokenSource, TimeoutMs As Integer)
Dim DelayTask = Task.Delay(TimeoutMs)
If Task.WhenAny(TargetTask, DelayTask).GetAwaiter().GetResult() Is DelayTask Then
TokenSource.Cancel()
Throw New TimeoutException($"任务超时({TimeoutMs} ms)")
End If
TargetTask.GetAwaiter().GetResult()
End Sub
''' <summary> ''' <summary>
''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。 ''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。
''' </summary> ''' </summary>
@@ -2586,7 +2614,7 @@ Retry:
RunInUi( RunInUi(
Sub() Sub()
My.Computer.Clipboard.Clear() My.Computer.Clipboard.Clear()
My.Computer.Clipboard.SetText(Text) If Not String.IsNullOrEmpty(Text) Then My.Computer.Clipboard.SetText(Text)
End Sub) End Sub)
Catch ex As Exception Catch ex As Exception
RetryCount += 1 RetryCount += 1
@@ -2600,6 +2628,21 @@ Retry:
If ShowSuccessHint Then Hint("已成功复制!", HintType.Green) If ShowSuccessHint Then Hint("已成功复制!", HintType.Green)
End Sub) End Sub)
End Sub End Sub
''' <summary>
''' 获取剪贴板文本。将在 UI 线程运行,且不会抛出异常。
''' </summary>
Public Function ClipboardGetText() As String
Dim Result As String = Nothing
RunInUiWait(
Sub()
Try
If My.Computer.Clipboard.ContainsText() Then Result = My.Computer.Clipboard.GetText()
Catch ex As Exception
Log(ex, "获取剪贴板文本失败")
End Try
End Sub)
Return Result
End Function
''' <summary> ''' <summary>
''' 以 Byte() 形式获取程序中的资源。 ''' 以 Byte() 形式获取程序中的资源。
@@ -3079,6 +3122,7 @@ Retry:
Public Sub Telemetry([Event] As String, ParamArray Datas As String()) Public Sub Telemetry([Event] As String, ParamArray Datas As String())
If Not Setup.Get("SystemSystemTelemetry") Then Return '用户关闭了遥测 If Not Setup.Get("SystemSystemTelemetry") Then Return '用户关闭了遥测
If Not ClsBaseUrl.StartsWithF("http") Then Return '开源版没有设置遥测地址 If Not ClsBaseUrl.StartsWithF("http") Then Return '开源版没有设置遥测地址
If VersionBranchName = "Debug" Then Return '开发版本不上传遥测
RunInNewThread( RunInNewThread(
Sub() Sub()
Try Try
@@ -344,12 +344,12 @@
LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted
End Sub End Sub
Public Overrides Sub Failed(ex As Exception) Public Overrides Sub Failed(ex As Exception)
[Error] = ex
SyncLock LockState SyncLock LockState
If IsAborted OrElse State >= LoadState.Finished Then Return If IsAborted OrElse State >= LoadState.Finished Then Return
State = LoadState.Failed State = LoadState.Failed
End SyncLock End SyncLock
Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%", LogLevel.Developer) Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%", LogLevel.Developer)
[Error] = ex
TriggerThreadAbort() TriggerThreadAbort()
End Sub End Sub
Public Overrides Sub Abort() Public Overrides Sub Abort()
@@ -464,11 +464,11 @@
End Sub) End Sub)
End Sub End Sub
Public Overrides Sub Failed(Ex As Exception) Public Overrides Sub Failed(Ex As Exception)
[Error] = Ex '先设置错误再调整状态,防止父加载器获取不到异常
SyncLock LockState SyncLock LockState
If State >= LoadState.Finished Then Return If State >= LoadState.Finished Then Return
State = LoadState.Failed State = LoadState.Failed
End SyncLock End SyncLock
[Error] = Ex
For Each Loader In Loaders For Each Loader In Loaders
Loader.Abort() Loader.Abort()
Next Next
+50 -33
View File
@@ -262,11 +262,11 @@ RequestFinished:
}) })
End If End If
End SyncLock End SyncLock
Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetAwaiter().GetResult() Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
Dim ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult() Dim ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
Dim ResponseBytes As Byte() Dim ResponseBytes As Byte()
Using Stream As New MemoryStream Using Stream As New MemoryStream
ResponseStream.CopyToAsync(Stream, 81920, CancelToken.Token).GetAwaiter().GetResult() ResponseStream.CopyToAsync(Stream, 81920, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
ResponseBytes = Stream.ToArray() ResponseBytes = Stream.ToArray()
End Using End Using
'输出 '输出
@@ -286,7 +286,7 @@ RequestFinished:
Throw Throw
Catch ex As Exception Catch ex As Exception
RecordIPReliability(HostIp, -1) RecordIPReliability(HostIp, -1)
If TypeOf ex Is OperationCanceledException Then 'CancellationToken 超时 If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then 'CancellationToken 超时
Throw New WebException($"连接服务器超时,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout) Throw New WebException($"连接服务器超时,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout)
ElseIf ex.IsNetworkRelated Then ElseIf ex.IsNetworkRelated Then
Throw New WebException($"网络请求失败,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout) Throw New WebException($"网络请求失败,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout)
@@ -992,7 +992,7 @@ StartThread:
HostIp = DNSLookup(HttpRequest, CancelToken) 'DNS 预解析 HostIp = DNSLookup(HttpRequest, CancelToken) 'DNS 预解析
If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New RangeHeaderValue(Th.DownloadStart, Nothing) If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New RangeHeaderValue(Th.DownloadStart, Nothing)
Dim ContentLength As Long = 0 Dim ContentLength As Long = 0
Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetAwaiter().GetResult() Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查 If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查
If State = NetState.Error Then GoTo SourceBreak '快速中断 If State = NetState.Error Then GoTo SourceBreak '快速中断
If ModeDebug AndAlso Response.RequestMessage.RequestUri.ToString <> Th.Source.Url Then Log($"[Download] {LocalName}:重定向至 {Response.RequestMessage.RequestUri}") If ModeDebug AndAlso Response.RequestMessage.RequestUri.ToString <> Th.Source.Url Then Log($"[Download] {LocalName}:重定向至 {Response.RequestMessage.RequestUri}")
@@ -1063,7 +1063,7 @@ NotSupportRange:
ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult() ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
If Setup.Get("SystemDebugDelay") Then Threading.Thread.Sleep(RandomInteger(50, 3000)) If Setup.Get("SystemDebugDelay") Then Threading.Thread.Sleep(RandomInteger(50, 3000))
Dim ResponseBytes As Byte() = New Byte(16384) {} Dim ResponseBytes As Byte() = New Byte(16384) {}
HttpDataCount = ReadWithTimeout(ResponseStream, ResponseBytes, 0, 16384, Timeout) HttpDataCount = ResponseStream.ReadAsync(ResponseBytes, 0, 16384, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
While (IsUnknownSize OrElse Th.DownloadUndone > 0) AndAlso '判断是否下载完成 While (IsUnknownSize OrElse Th.DownloadUndone > 0) AndAlso '判断是否下载完成
HttpDataCount > 0 AndAlso Not IsProgramEnded AndAlso State < NetState.Merge AndAlso (Not Th.Source.IsFailed OrElse Th.Source.SingleThread = Th) HttpDataCount > 0 AndAlso Not IsProgramEnded AndAlso State < NetState.Merge AndAlso (Not Th.Source.IsFailed OrElse Th.Source.SingleThread = Th)
'限速 '限速
@@ -1113,7 +1113,7 @@ NotSupportRange:
'无数据,且已超时 '无数据,且已超时
Throw New TimeoutException("操作超时,无数据。") Throw New TimeoutException("操作超时,无数据。")
End If End If
HttpDataCount = ReadWithTimeout(ResponseStream, ResponseBytes, 0, 16384, Timeout) HttpDataCount = ResponseStream.ReadAsync(ResponseBytes, 0, 16384, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
End While End While
SourceBreak: SourceBreak:
If State = NetState.Error OrElse (Th.Source.IsFailed AndAlso Th.Source.SingleThread <> Th) OrElse (Th.DownloadUndone > 0 AndAlso Not IsUnknownSize) Then If State = NetState.Error OrElse (Th.Source.IsFailed AndAlso Th.Source.SingleThread <> Th) OrElse (Th.DownloadUndone > 0 AndAlso Not IsUnknownSize) Then
@@ -1130,7 +1130,8 @@ SourceBreak:
RecordIPReliability(HostIp, 0.5) RecordIPReliability(HostIp, 0.5)
End If End If
Catch ex As Exception Catch ex As Exception
Log($"[Download] {LocalName}:出错,{If(TypeOf ex Is OperationCanceledException, $"已超时({Timeout}ms)", ex.GetDetail())},IP:{HostIp}") Log($"[Download] {LocalName}:出错,{If(TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException,
$"已超时({Timeout}ms)", ex.GetDetail())},IP:{HostIp}")
RecordIPReliability(HostIp, -0.7) RecordIPReliability(HostIp, -0.7)
SourceFail(Th, ex, False) SourceFail(Th, ex, False)
Finally Finally
@@ -1650,15 +1651,15 @@ Retry:
If State >= LoadState.Finished Then Return If State >= LoadState.Finished Then Return
If ExList Is Nothing OrElse Not ExList.Any() Then ExList = New List(Of Exception) From {New Exception("未知错误!")} If ExList Is Nothing OrElse Not ExList.Any() Then ExList = New List(Of Exception) From {New Exception("未知错误!")}
'寻找有效的错误信息 '寻找有效的错误信息
Dim UsefulExs = ExList.Where(Function(e) TypeOf e IsNot OperationCanceledException AndAlso TypeOf e IsNot ThreadInterruptedException).ToList Dim UsefulExs = ExList.Where(Function(e) TypeOf e IsNot OperationCanceledException AndAlso TypeOf e IsNot TimeoutException AndAlso TypeOf e IsNot ThreadInterruptedException).ToList
[Error] = If(UsefulExs.FirstOrDefault, ExList.FirstOrDefault) [Error] = If(UsefulExs.FirstOrDefault, ExList.FirstOrDefault)
'获取实际失败的文件 '获取实际失败的文件
For Each File In Files For Each File In Files
If File.State <> NetState.Error Then Continue For If File.State <> NetState.Error Then Continue For
If File.Sources.All(Function(s) TypeOf s.Ex Is OperationCanceledException OrElse TypeOf s.Ex Is TimeoutException OrElse TypeOf s.Ex Is ThreadInterruptedException) Then Continue For
Dim Detail As String = Join(File.Sources.Select(Function(s) $"{If(s.Ex Is Nothing, "无错误信息。", s.Ex.GetBrief())}({s.Url})"), vbCrLf) Dim Detail As String = Join(File.Sources.Select(Function(s) $"{If(s.Ex Is Nothing, "无错误信息。", s.Ex.GetBrief())}({s.Url})"), vbCrLf)
[Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf & [Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf &
"各下载源的错误如下:" & vbCrLf & Detail, "各下载源的错误如下:" & vbCrLf & Detail, [Error])
[Error])
'上报 '上报
Telemetry("文件下载失败", Telemetry("文件下载失败",
"FileName", File.LocalName, "FileName", File.LocalName,
@@ -1951,6 +1952,45 @@ Retry:
Return False Return False
End Function End Function
#End Region
#Region "端口"
''' <summary>
''' 随机获取单个可用的端口。
''' </summary>
Public Function FindFreePort() As Integer
Dim Listener As New TcpListener(IPAddress.Loopback, 0)
Listener.Start()
Dim port As Integer = CType(Listener.LocalEndpoint, IPEndPoint).Port
Listener.Stop()
Return port
End Function
''' <summary>
''' 获取当前已被占用的端口列表。
''' </summary>
Public Function GetUsedPorts() As List(Of Integer)
Dim IPProperties = NetworkInformation.IPGlobalProperties.GetIPGlobalProperties()
Dim UsedPorts As New List(Of Integer)
UsedPorts.AddRange(IPProperties.GetActiveTcpListeners().Select(Function(ep) ep.Port))
UsedPorts.AddRange(IPProperties.GetActiveUdpListeners().Select(Function(ep) ep.Port))
UsedPorts.AddRange(IPProperties.GetActiveTcpConnections().Select(Function(conn) conn.LocalEndPoint.Port))
Return UsedPorts.Distinct().ToList()
End Function
''' <summary>
''' 寻找数个连续编号的可用端口。
''' </summary>
Public Function FindFreePorts(ConsecutiveCount As Integer, ParamArray ExtraBlackLists As Integer()) As List(Of Integer)
Dim UsedPorts = GetUsedPorts().Concat(ExtraBlackLists)
For port = 12000 To 65000 - ConsecutiveCount
Dim Range = Enumerable.Range(port, ConsecutiveCount)
If Not Range.Any(Function(p) UsedPorts.Contains(p)) Then Return Range.ToList
Next
Throw New Exception("未能找到可用的端口!")
End Function
#End Region #End Region
''' <summary> ''' <summary>
@@ -1985,27 +2025,4 @@ Retry:
}.Any(Function(k) Detail.ContainsF(k, True)) }.Any(Function(k) Detail.ContainsF(k, True))
End Function End Function
''' <summary>
''' 随机获取一个可用的端口。
''' </summary>
Public Function GetAvailablePort() As Integer
Dim Listener As New TcpListener(IPAddress.Loopback, 0)
Listener.Start()
Dim port As Integer = CType(Listener.LocalEndpoint, IPEndPoint).Port
Listener.Stop()
Return port
End Function
''' <summary>
''' 带有 Timeout 的读取 Stream 方法。
''' </summary>
Private Function ReadWithTimeout(TargetStream As Stream, Buffer() As Byte, Offset As Integer, Count As Integer, ReadTimeoutMs As Integer) As Integer
Dim ReadTask = TargetStream.ReadAsync(Buffer, Offset, Count)
Dim DelayTask = Task.Delay(ReadTimeoutMs)
If Task.WhenAny(ReadTask, DelayTask).GetAwaiter().GetResult() Is DelayTask Then
Throw New TimeoutException($"读取数据超时({ReadTimeoutMs} ms)")
End If
Return ReadTask.GetAwaiter().GetResult()
End Function
End Module End Module
@@ -114,12 +114,7 @@ Public Class ValidateInteger
End Sub End Sub
Public Overrides Function Validate(Str As String) As String Public Overrides Function Validate(Str As String) As String
Dim Valed As Integer Dim Valed As Integer
If Not Integer.TryParse(Str, Valed) Then If Not Integer.TryParse(Str, Valed) Then Return "请输入一个整数!"
Return "请输入一个整数!"
End If
If Not RegexCheck(Str, "^(-?0|-?[1-9]\d*)$") Then
Return "请输入一个不带有前导零的整数!"
End If
If Str.Length > 9 Then Return "请输入一个大小合理的数字!" If Str.Length > 9 Then Return "请输入一个大小合理的数字!"
If Valed > Max Then Return "不可超过 " & Max & "!" If Valed > Max Then Return "不可超过 " & Max & "!"
If Valed < Min Then Return "不可低于 " & Min & "!" If Valed < Min Then Return "不可低于 " & Min & "!"
@@ -73,8 +73,10 @@
Sub(Task As LoaderTask(Of String, List(Of NetFile))) Sub(Task As LoaderTask(Of String, List(Of NetFile)))
Try Try
Dim IndexFile = DlClientAssetIndexGet(Version) Dim IndexFile = DlClientAssetIndexGet(Version)
Dim IndexFileInfo As New FileInfo(IndexFile.LocalPath) If IndexFile Is Nothing Then
If AssetsIndexBehaviour <> AssetsIndexExistsBehaviour.AlwaysDownload AndAlso IndexFile.Check.Check(IndexFile.LocalPath) Is Nothing Then Task.Output = New List(Of NetFile)
Log("[Download] 未找到版本 " & Version.Name & " 的合适的资源索引下载地址,游戏 assets 可能缺失", LogLevel.Debug)
ElseIf AssetsIndexBehaviour <> AssetsIndexExistsBehaviour.AlwaysDownload AndAlso IndexFile.Check.Check(IndexFile.LocalPath) Is Nothing Then
Task.Output = New List(Of NetFile) Task.Output = New List(Of NetFile)
Else Else
Task.Output = New List(Of NetFile) From {IndexFile} Task.Output = New List(Of NetFile) From {IndexFile}
@@ -93,6 +95,11 @@
LoadersAssetsUpdate.Add(New LoaderTask(Of String, List(Of NetFile))("后台分析资源文件索引地址", LoadersAssetsUpdate.Add(New LoaderTask(Of String, List(Of NetFile))("后台分析资源文件索引地址",
Sub(Task As LoaderTask(Of String, List(Of NetFile))) Sub(Task As LoaderTask(Of String, List(Of NetFile)))
Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Version) Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Version)
If BackAssetsFile Is Nothing Then
Log("[Download] 未找到版本 " & Version.Name & " 的合适的资源索引下载地址,游戏 assets 可能缺失", LogLevel.Debug)
Task.Abort()
Throw New ThreadInterruptedException
End If
RealAddress = BackAssetsFile.LocalPath RealAddress = BackAssetsFile.LocalPath
TempAddress = PathTemp & "Cache\" & BackAssetsFile.LocalName TempAddress = PathTemp & "Cache\" & BackAssetsFile.LocalName
BackAssetsFile.LocalPath = TempAddress BackAssetsFile.LocalPath = TempAddress
@@ -141,6 +141,7 @@ Public Class CustomEvent
写入设置 写入设置
修改变量 修改变量
写入变量 写入变量
加入房间
End Enum End Enum
''' <summary> ''' <summary>
@@ -283,6 +284,17 @@ Public Class CustomEvent
WriteReg("CustomEvent" & Args(0), Args(1)) WriteReg("CustomEvent" & Args(0), Args(1))
If Args.Length = 2 Then Hint($"已写入变量:{Args(0)} → {Args(1)}", HintType.Green) If Args.Length = 2 Then Hint($"已写入变量:{Args(0)} → {Args(1)}", HintType.Green)
Case EventType.加入房间
RunInUi(
Sub()
If String.IsNullOrWhiteSpace(Arg) Then
PageLinkMain.Join()
Else
If Not EventSafetyConfirm("即将加入第三方联机房间。") Then Return
PageLinkMain.Join(Arg)
End If
End Sub)
Case Else Case Else
MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败") MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败")
End Select End Select
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*” ' 方法是按如下所示使用“*”
<Assembly: AssemblyVersion("2.11.0.0")> <Assembly: AssemblyVersion("2.11.1.0")>
<Assembly: AssemblyFileVersion("2.11.0.0")> <Assembly: AssemblyFileVersion("2.11.1.0")>
<Assembly: NeutralResourcesLanguage("")> <Assembly: NeutralResourcesLanguage("")>
@@ -34,7 +34,7 @@
<TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" /> <TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" />
<local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" IsEditable="True" MaxDropDownHeight="320"> <local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" IsEditable="True" MaxDropDownHeight="320">
<local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" /> <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
<local:MyComboBoxItem Content="1.21.8" /> <local:MyComboBoxItem Content="1.21.10" />
<local:MyComboBoxItem Content="1.21.1" /> <local:MyComboBoxItem Content="1.21.1" />
<local:MyComboBoxItem Content="1.20.6" /> <local:MyComboBoxItem Content="1.20.6" />
<local:MyComboBoxItem Content="1.20.1" /> <local:MyComboBoxItem Content="1.20.1" />
@@ -99,7 +99,8 @@ Public Module ModDownloadLib
Sub(Task As LoaderTask(Of String, List(Of NetFile))) Sub(Task As LoaderTask(Of String, List(Of NetFile)))
Try Try
Dim Version As New McVersion(VersionFolder) Dim Version As New McVersion(VersionFolder)
Task.Output = New List(Of NetFile) From {DlClientAssetIndexGet(Version)} Dim AssetIndex = DlClientAssetIndexGet(Version)
Task.Output = If(AssetIndex Is Nothing, New List(Of NetFile), New List(Of NetFile) From {AssetIndex})
Catch ex As Exception Catch ex As Exception
Throw New Exception("分析资源文件索引地址失败", ex) Throw New Exception("分析资源文件索引地址失败", ex)
End Try End Try
@@ -104,6 +104,9 @@ Public Class PageLaunchRight
Case 12 Case 12
Log("[Page] 主页预设:PCL GitHub 仪表盘") Log("[Page] 主页预设:PCL GitHub 仪表盘")
Url = "https://ddf.pcl-community.org/Custom.xaml" Url = "https://ddf.pcl-community.org/Custom.xaml"
Case 13
Log("[Page] 主页预设:PCL 更新摘要")
Url = "https://raw.gitcode.com/ENC_Euphony/PCL-AI-Summary-HomePage/raw/master/Custom.xaml"
End Select End Select
End Select End Select
'联网下载 '联网下载
@@ -121,7 +121,7 @@ Retry:
Next Next
Throw New Exception("未知错误(" & Result & ")") Throw New Exception("未知错误(" & Result & ")")
Catch ex As Exception Catch ex As Exception
If TypeOf ex Is OperationCanceledException Then If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then
Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red) Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red)
Else Else
Log(ex, "更改皮肤失败", LogLevel.Hint) Log(ex, "更改皮肤失败", LogLevel.Hint)
@@ -152,7 +152,7 @@
<TextBlock x:Name="LabFinishDesc" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" Margin="1,9,10,10" <TextBlock x:Name="LabFinishDesc" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" Margin="1,9,10,10"
Text="描述文本。" Text="描述文本。"
FontSize="14" LineHeight="19" MaxWidth="400" TextWrapping="Wrap" Foreground="{StaticResource ColorBrushGray2}" /> FontSize="14" LineHeight="19" MaxWidth="400" TextWrapping="Wrap" Foreground="{StaticResource ColorBrushGray2}" />
<local:MyButton x:Name="BtnFinishCopy" Grid.Column="4" Grid.Row="3" Margin="0,0,15,0" Text="复制" Padding="13,8" ColorType="Highlight" /> <local:MyButton x:Name="BtnFinishCopy" Grid.Column="4" Grid.Row="3" Margin="0,0,15,0" Text="复制邀请码" Padding="13,8" ColorType="Highlight" />
<local:MyButton x:Name="BtnFinishExit" Grid.Column="5" Grid.Row="3" Text="退出" Padding="13,8" /> <local:MyButton x:Name="BtnFinishExit" Grid.Column="5" Grid.Row="3" Text="退出" Padding="13,8" />
</Grid> </Grid>
</local:MyCard> </local:MyCard>
@@ -186,12 +186,12 @@
Data="m365,295.3c-15.1-3.6-36.5-1.8-39.6,17.5-1.2,12.4,0,107-.5,119.7.8,16.8-5.2,42.4,16.8,47.1,14.3,3.3,34.5,1.9,38.7-15.4,2.6-1.4.1-142.4,1-148.3-.7-10.9-6.2-17.8-16.4-20.6ZM234.1,311.6c-3.2-16.7-20-18.6-34.4-17.2-9.8.4-17.2,6.2-20,15.4-4.4,47.8-.2,97.3-1.6,144.8,0,16,9.8,26.6,24.6,26.1,14.4,1.4,29.1-2.9,31.7-19,2.2-8.8.8-63.9,1.1-74.1-1-25.3,2.1-50.6-1.5-75.9ZM521.4,300.6c-5.4-6.2-15.9-7.1-24.6-6.4-11.9-1-23,6.6-24.7,18.7-2.2,24.1-2,124-.2,148.1,2.6,19.7,24.1,22.4,40.1,18.4,11.9-2.4,16.6-15.2,16.3-27.1,0-33.6.1-69.3,0-103.1-1.2-15.1,4.2-37-6.9-48.5ZM708.8,194.2c.7-34.5-26.8-63.7-61.5-63.4-22.1-.1-52.4,0-75.6,0-13.4,1.1-8.7-12.1-9.6-20.9-1.6-30.6,7.5-67.2-17.5-90.9-11.7-11.9-27.4-18.4-44.3-18.4-64.8,0-129.7,0-194.5,0-37.7,1.4-76.5-3.1-113.8,2.2-48.1,14.7-46.7,55.3-45.4,97.3,0,8,.1,16.1,0,24.1.2,7-7.3,6.8-12.2,6.6-16,0-32,0-48,0-24.4-.7-51.3-1-68.6,18.4C5.8,161.2,0,176.1,0,194.7c0,0,0,350.9,0,350.9,0,22.9,5.5,41.7,16.8,57.5,19.2,27,45.9,40.7,79.5,40.7,37.4,0,77.4.1,129.9.1,42.5,0,85,0,127.5,0,11.2-1.3,273.6,2.4,278-1.8,46.1-9.1,77.1-46.8,77.1-93.8,0-117.8,0-237.9,0-354.1Zm-71-5.3c7.6.2,9.2,1.9,9.3,9.7,0,0,0,347.3,0,347.3,0,3.2.2,6.5-.3,9.9-2.8,19.3-18.9,32.3-38.5,31.9-4.5.4-508.9-.4-513.5,0-3.2,0-6.5.1-9.9-.4-19-2.9-31.8-17.8-31.8-37.1,0-117.9,0-233.9,0-350.9,0-9,2.3-10.3,10.9-10.3,0,0,131.2,0,131.2,0,1.6,0,3,0,4.5,0,0-1.5,0-2.7,0-4.3,0,0,0-115.7,0-115.7.1-8.3,1.9-10.1,10.3-10.1h280.3c8.3,0,10.1,1.8,10.1,10.3v114.1c0,1.9,0,3.7,0,5.6" /> Data="m365,295.3c-15.1-3.6-36.5-1.8-39.6,17.5-1.2,12.4,0,107-.5,119.7.8,16.8-5.2,42.4,16.8,47.1,14.3,3.3,34.5,1.9,38.7-15.4,2.6-1.4.1-142.4,1-148.3-.7-10.9-6.2-17.8-16.4-20.6ZM234.1,311.6c-3.2-16.7-20-18.6-34.4-17.2-9.8.4-17.2,6.2-20,15.4-4.4,47.8-.2,97.3-1.6,144.8,0,16,9.8,26.6,24.6,26.1,14.4,1.4,29.1-2.9,31.7-19,2.2-8.8.8-63.9,1.1-74.1-1-25.3,2.1-50.6-1.5-75.9ZM521.4,300.6c-5.4-6.2-15.9-7.1-24.6-6.4-11.9-1-23,6.6-24.7,18.7-2.2,24.1-2,124-.2,148.1,2.6,19.7,24.1,22.4,40.1,18.4,11.9-2.4,16.6-15.2,16.3-27.1,0-33.6.1-69.3,0-103.1-1.2-15.1,4.2-37-6.9-48.5ZM708.8,194.2c.7-34.5-26.8-63.7-61.5-63.4-22.1-.1-52.4,0-75.6,0-13.4,1.1-8.7-12.1-9.6-20.9-1.6-30.6,7.5-67.2-17.5-90.9-11.7-11.9-27.4-18.4-44.3-18.4-64.8,0-129.7,0-194.5,0-37.7,1.4-76.5-3.1-113.8,2.2-48.1,14.7-46.7,55.3-45.4,97.3,0,8,.1,16.1,0,24.1.2,7-7.3,6.8-12.2,6.6-16,0-32,0-48,0-24.4-.7-51.3-1-68.6,18.4C5.8,161.2,0,176.1,0,194.7c0,0,0,350.9,0,350.9,0,22.9,5.5,41.7,16.8,57.5,19.2,27,45.9,40.7,79.5,40.7,37.4,0,77.4.1,129.9.1,42.5,0,85,0,127.5,0,11.2-1.3,273.6,2.4,278-1.8,46.1-9.1,77.1-46.8,77.1-93.8,0-117.8,0-237.9,0-354.1Zm-71-5.3c7.6.2,9.2,1.9,9.3,9.7,0,0,0,347.3,0,347.3,0,3.2.2,6.5-.3,9.9-2.8,19.3-18.9,32.3-38.5,31.9-4.5.4-508.9-.4-513.5,0-3.2,0-6.5.1-9.9-.4-19-2.9-31.8-17.8-31.8-37.1,0-117.9,0-233.9,0-350.9,0-9,2.3-10.3,10.9-10.3,0,0,131.2,0,131.2,0,1.6,0,3,0,4.5,0,0-1.5,0-2.7,0-4.3,0,0,0-115.7,0-115.7.1-8.3,1.9-10.1,10.3-10.1h280.3c8.3,0,10.1,1.8,10.1,10.3v114.1c0,1.9,0,3.7,0,5.6" />
<TextBlock x:Name="LabFinishPort" IsHitTestVisible="False" Text="12345" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0.5,13,0" /> <TextBlock x:Name="LabFinishPort" IsHitTestVisible="False" Text="12345" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0.5,13,0" />
</StackPanel> </StackPanel>
<!--<StackPanel x:Name="BtnFinishIp" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}" <StackPanel x:Name="BtnFinishIp" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
ToolTip="服务器 IP ( 点击复制 )" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="50" ToolTipService.VerticalOffset="40" ToolTipService.HorizontalOffset="4"> ToolTip="服务器 IP(点击复制)" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="50" ToolTipService.VerticalOffset="40" ToolTipService.HorizontalOffset="4">
<Path IsHitTestVisible="False" Height="17" Width="17" Stretch="Uniform" Fill="{StaticResource ColorBrushGray4}" Margin="11,0,7,0" <Path IsHitTestVisible="False" Height="17" Width="17" Stretch="Uniform" Fill="{StaticResource ColorBrushGray4}" Margin="11,0,7,0"
Data="m346.4,692.8c-92.5,0-179.5-36-244.9-101.5C36,525.9,0,438.9,0,346.4S36,166.9,101.5,101.5C166.9,36,253.9,0,346.4,0s179.5,36,244.9,101.5c65.4,65.4,101.5,152.4,101.5,244.9s-36,179.5-101.5,244.9c-65.4,65.4-152.4,101.5-244.9,101.5Zm0-645.1c-164.7,0-298.7,134-298.7,298.7s134,298.7,298.7,298.7,298.7-134,298.7-298.7S511.1,47.7,346.4,47.7Zm13.8,473.4c-14.5,0-28.2-9.8-28.2-24.2V207.9c0-14.5,11.8-26.2,26.2-26.2h78.9c57.9,0,105.1,47.1,105.1,105.1s-47.1,105.1-105.1,105.1h-52.6v105.1c0,14.5-9.8,24.2-24.2,24.2Zm24.2-181.7h52.6c29,0,52.6-23.6,52.6-52.6s-20-49.2-46.5-52.3h-.4s-5.3-.4-5.3-.4h-53v105.2Zm-158.8,181.7c-14.5,0-28.2-9.8-28.2-24.2V207.9c0-14.5,11.8-26.2,26.2-26.2s26.2,11.8,26.2,26.2v289c0,14.5-9.8,24.2-24.2,24.2Z" /> Data="m346.4,692.8c-92.5,0-179.5-36-244.9-101.5C36,525.9,0,438.9,0,346.4S36,166.9,101.5,101.5C166.9,36,253.9,0,346.4,0s179.5,36,244.9,101.5c65.4,65.4,101.5,152.4,101.5,244.9s-36,179.5-101.5,244.9c-65.4,65.4-152.4,101.5-244.9,101.5Zm0-645.1c-164.7,0-298.7,134-298.7,298.7s134,298.7,298.7,298.7,298.7-134,298.7-298.7S511.1,47.7,346.4,47.7Zm13.8,473.4c-14.5,0-28.2-9.8-28.2-24.2V207.9c0-14.5,11.8-26.2,26.2-26.2h78.9c57.9,0,105.1,47.1,105.1,105.1s-47.1,105.1-105.1,105.1h-52.6v105.1c0,14.5-9.8,24.2-24.2,24.2Zm24.2-181.7h52.6c29,0,52.6-23.6,52.6-52.6s-20-49.2-46.5-52.3h-.4s-5.3-.4-5.3-.4h-53v105.2Zm-158.8,181.7c-14.5,0-28.2-9.8-28.2-24.2V207.9c0-14.5,11.8-26.2,26.2-26.2s26.2,11.8,26.2,26.2v289c0,14.5-9.8,24.2-24.2,24.2Z" />
<TextBlock x:Name="LabFinishIp" IsHitTestVisible="False" Text="6.0.0.1:12345" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0.5,13,0" /> <TextBlock x:Name="LabFinishIp" IsHitTestVisible="False" Text="6.0.0.1:12345" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0.5,13,0" />
</StackPanel>--> </StackPanel>
</StackPanel> </StackPanel>
</local:MyCard> </local:MyCard>
</Grid> </Grid>
@@ -1,4 +1,6 @@
Public Class PageLinkMain Imports System.Net.Sockets
Public Class PageLinkMain
'=============================== '===============================
' 状态机与前端页面 ' 状态机与前端页面
@@ -6,33 +8,33 @@
#Region "状态管理" #Region "状态管理"
Private Enum States Public Enum LinkStates
Waiting Waiting
Loading Loading
Failed Failed
Finished Finished
End Enum End Enum
Private State As States = States.Waiting Public Shared LinkState As LinkStates = LinkStates.Waiting
''' <summary> ''' <summary>
''' 切换到指定的状态。 ''' 切换到指定的状态。
''' </summary> ''' </summary>
Private Sub ChangeState(NewState As States) Private Sub ChangeState(NewState As LinkStates)
If State = NewState Then Return If LinkState = NewState Then Return
Dim OldState = State Dim OldState = LinkState
State = NewState LinkState = NewState
Log($"[Link] 主状态由 {GetStringFromEnum(OldState)} 变更为 {GetStringFromEnum(NewState)}") Log($"[Link] 主状态由 {GetStringFromEnum(OldState)} 变更为 {GetStringFromEnum(NewState)}")
'触发状态切换 '触发状态切换
RunInUi( RunInUi(
Sub() Sub()
Select Case NewState Select Case NewState
Case States.Waiting Case LinkStates.Waiting
SwitchToWaiting(OldState) SwitchToWaiting(OldState)
Case States.Loading Case LinkStates.Loading
SwitchToLoading(OldState) SwitchToLoading(OldState)
Case States.Failed Case LinkStates.Failed
SwitchToFailed(OldState) SwitchToFailed(OldState)
Case States.Finished Case LinkStates.Finished
SwitchToFinished(OldState) SwitchToFinished(OldState)
End Select End Select
End Sub) End Sub)
@@ -45,18 +47,18 @@
Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState)
Select Case NewState Select Case NewState
Case LoadState.Finished Case LoadState.Finished
ChangeState(States.Finished) ChangeState(LinkStates.Finished)
Case LoadState.Failed Case LoadState.Failed
Telemetry("联机失败", "Exception", FilterUserName(Loader.Error.GetDetail, "*")) Telemetry("联机失败", "Exception", FilterUserName(Loader.Error.GetDetail, "*"))
ChangeState(States.Failed) ChangeState(LinkStates.Failed)
End Select End Select
End Sub End Sub
End Sub End Sub
'页面动画兼容 '页面动画兼容
Private Sub UpdatePanelVisibility() Handles Me.PageEnter Private Sub UpdatePanelVisibility() Handles Me.PageEnter
FrmLinkMain.PanSelect.Visibility = If(State = States.Waiting, Visibility.Visible, Visibility.Collapsed) FrmLinkMain.PanSelect.Visibility = If(LinkState = LinkStates.Waiting, Visibility.Visible, Visibility.Collapsed)
FrmLinkMain.PanFinish.Visibility = If(State = States.Finished, Visibility.Visible, Visibility.Collapsed) FrmLinkMain.PanFinish.Visibility = If(LinkState = LinkStates.Finished, Visibility.Visible, Visibility.Collapsed)
End Sub End Sub
#End Region #End Region
@@ -64,7 +66,7 @@
#Region "初始页面 (Waiting)" #Region "初始页面 (Waiting)"
'由任意状态切换到 Waiting '由任意状态切换到 Waiting
Private Sub SwitchToWaiting(OldState As States) Private Sub SwitchToWaiting(OldState As LinkStates)
'加载器与进程状态 '加载器与进程状态
LinkLoader.Abort() LinkLoader.Abort()
SyncLock LinkLoader.LockState SyncLock LinkLoader.LockState
@@ -72,7 +74,7 @@
End SyncLock End SyncLock
ProcessStop() ProcessStop()
'页面切换 '页面切换
If OldState <> States.Finished Then If OldState <> LinkStates.Finished Then
'从完成页面退出时,PageOnContentExit 结束会触发 PageEnter 事件,这会调用 UpdatePanelVisibility '从完成页面退出时,PageOnContentExit 结束会触发 PageEnter 事件,这会调用 UpdatePanelVisibility
'如果在现在提前调用了,会丢失完成页面的退出动画 '如果在现在提前调用了,会丢失完成页面的退出动画
UpdatePanelVisibility() UpdatePanelVisibility()
@@ -87,7 +89,7 @@
'创建 '创建
Private Sub Create_MouseLeftButtonUp() Handles PanSelectCreate.MouseLeftButtonUp Private Sub Create_MouseLeftButtonUp() Handles PanSelectCreate.MouseLeftButtonUp
'输入端口号 '输入端口号
Dim Port As String = MyMsgBoxInput("输入端口", $"在单人游戏的暂停菜单选择 {vbLQ}对局域网开放{vbRQ},然后输入端口数字。{vbCrLf}其实也可以输入其他游戏的端口……", Dim Port As String = MyMsgBoxInput("输入端口", $"在单人游戏的暂停菜单选择 {vbLQ}对局域网开放{vbRQ},然后输入端口数字。{vbCrLf}甚至可以输入其他游戏的端口……嗯……",
ValidateRules:=New ObjectModel.Collection(Of Validate) From {New ValidateInteger(1024, 65535)}, ValidateRules:=New ObjectModel.Collection(Of Validate) From {New ValidateInteger(1024, 65535)},
HintText:="端口号") HintText:="端口号")
If Port Is Nothing Then Return If Port Is Nothing Then Return
@@ -106,50 +108,31 @@
NetworkSecret = GenerateRandomCode() NetworkSecret = GenerateRandomCode()
Log($"[Link] 尝试创建房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort}") Log($"[Link] 尝试创建房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort}")
'启动 '启动
ChangeState(States.Loading) ChangeState(LinkStates.Loading)
End Sub End Sub
'加入 '加入
Private LastCode As String = Nothing Private Shared LastCode As String = Nothing
Private Sub Join_MouseLeftButtonUp() Handles PanSelectJoin.MouseLeftButtonUp ''' <summary>
'输入邀请码 ''' 输入邀请码,切换到联机页并立即加入房间。
''' </summary>
Public Shared Sub Join() Handles PanSelectJoin.MouseLeftButtonUp
Dim Code As String = MyMsgBoxInput("输入邀请码", "输入房主发给你的邀请码。", Dim Code As String = MyMsgBoxInput("输入邀请码", "输入房主发给你的邀请码。",
HintText:=If(String.IsNullOrEmpty(LastCode), "", "使用上一次的邀请码:" & LastCode)) HintText:=If(String.IsNullOrEmpty(LastCode), "", "使用上一次的邀请码:" & LastCode))
If Not String.IsNullOrEmpty(LastCode) AndAlso Code IsNot Nothing AndAlso Code = "" Then Code = LastCode If Not String.IsNullOrEmpty(LastCode) AndAlso Code IsNot Nothing AndAlso Code = "" Then Code = LastCode
If Code Is Nothing Then Return
Join(Code)
End Sub
Public Sub JoinInternal(Code As String)
If Code Is Nothing Then Return If Code Is Nothing Then Return
'基础格式校验 '基础格式校验
Code = Code.Between("【", "】").Between("[", "]") '从完整消息中提取 Code = Code.Between("【", "】").Between("[", "]") '从完整消息中提取
Code = Code.ToUpper.Replace("O", "0").Replace("I", "1") '输入修正 Code = Code.ToUpper.Replace("O", "0").Replace("I", "1") '输入修正
If Not (Code.Length >= 14 AndAlso Code(0) = "P"c AndAlso Code(5) = "-"c AndAlso Code(11) = "-"c) Then Dim ValidateResult = ValidateCodeFormat(Code)
If Code.StartsWithF("U/") Then 'HMCL If ValidateResult IsNot Nothing Then
Hint("请让房主使用 PCL 创建房间!", HintType.Red) Hint(ValidateResult, HintType.Red)
ElseIf Code.Length = 10 Then 'PCL CE
Hint("请让房主使用非社区版的 PCL 创建房间!", HintType.Red)
ElseIf Code.StartsWithF("P") Then '远古版 PCL
Hint("你的 PCL 版本与房主的 PCL 版本不一致,或输入的邀请码有误!", HintType.Red)
Else
Hint("邀请码有误,请让房主使用 PCL 创建房间!", HintType.Red)
End If
Return Return
End If End If
'离线登录警告
If McLoginLoader.State = LoadState.Finished AndAlso McLoginLoader.Output.Type = "Legacy" AndAlso Not Setup.Get("LinkOfflineHint") Then
Dim Solution As String
If McVersionCurrent IsNot Nothing AndAlso McVersionCurrent.Version.McVersion >= New Version(1, 21, 5) Then
Solution = $"请换用正版登录,或是让房主安装 {vbLQ}更高级联机设置{vbRQ} Mod 并禁用正版验证。"
ElseIf McVersionCurrent IsNot Nothing AndAlso McVersionCurrent.Version.McVersion >= New Version(1, 12, 0) Then
Solution = $"请换用正版登录,或是让房主安装 {vbLQ}自定义局域网联机{vbRQ} Mod 并关闭在线模式。"
Else
Solution = $"请换用正版登录,或是让房主用服务端开服,关闭 online-mode,然后在创建房间时输入服务端的端口号。"
End If
Select Case MyMsgBox($"如果不用正版登录可能会进不了服,显示 {vbLQ}无效会话{vbRQ}。" & vbCrLf & Solution,
"离线登录警告", "继续", "继续且不再提示", "取消", IsWarn:=True)
Case 2
Setup.Set("LinkOfflineHint", True)
Case 3
Return
End Select
End If
'基础信息 '基础信息
IsServerSide = False IsServerSide = False
ServerPort = RadixConvert(Code.Substring(1, 4), 16, 10) ServerPort = RadixConvert(Code.Substring(1, 4), 16, 10)
@@ -158,7 +141,45 @@
Log($"[Link] 尝试加入房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort}") Log($"[Link] 尝试加入房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort}")
'启动 '启动
LastCode = Code LastCode = Code
ChangeState(States.Loading) ChangeState(LinkStates.Loading)
End Sub
Public Shared Function ValidateCodeFormat(Code As String) As String
If Code Is Nothing Then Return "邀请码为空!"
Code = Code.Between("【", "】").Between("[", "]") '从完整消息中提取
Code = Code.ToUpper.Replace("O", "0").Replace("I", "1") '输入修正
If Not (Code.Length >= 14 AndAlso Code(0) = "P"c AndAlso Code(5) = "-"c AndAlso Code(11) = "-"c) Then
If Code.StartsWithF("U/") Then 'HMCL
Return "请让房主使用 PCL 创建房间!"
ElseIf Code.Length = 10 Then 'PCL CE
Return "请让房主使用非社区版的 PCL 创建房间!"
Else
Return "邀请码有误,请让房主使用 PCL 创建房间!"
End If
End If
Return Nothing
End Function
'自动加入
''' <summary>
''' 切换到联机页并立即加入指定房间。
''' </summary>
Public Shared Sub Join(Code As String)
If LinkState <> LinkStates.Waiting Then
Hint("你已经在联机房间中了!", HintType.Red)
ElseIf FrmMain.PageCurrent = FormMain.PageType.Link Then
FrmLinkMain.JoinInternal(Code)
Else
AutoJoinCode = Code
FrmMain.PageChange(FormMain.PageType.Link, FormMain.PageSubType.LinkMain)
End If
End Sub
'在进入页面时自动尝试加入房间
Private Shared AutoJoinCode As String = Nothing
Private Sub PanSelectJoin_Loaded() Handles PanSelectJoin.Loaded
If AutoJoinCode Is Nothing Then Return
If LinkState = LinkStates.Waiting Then JoinInternal(AutoJoinCode)
AutoJoinCode = Nothing
End Sub End Sub
#End Region #End Region
@@ -166,7 +187,7 @@
#Region "加载页面 (Loading | Failed)" #Region "加载页面 (Loading | Failed)"
'由 Waiting 或 Failed 状态切换到 Loading '由 Waiting 或 Failed 状态切换到 Loading
Private Sub SwitchToLoading(OldState As States) Private Sub SwitchToLoading(OldState As LinkStates)
'清理变量 '清理变量
Peers = Nothing Peers = Nothing
FailCount = 0 FailCount = 0
@@ -180,7 +201,7 @@
End Sub End Sub
'由 Loading 状态切换到 Failed '由 Loading 状态切换到 Failed
Private Sub SwitchToFailed(OldState As States) Private Sub SwitchToFailed(OldState As LinkStates)
'加载器与进程状态 '加载器与进程状态
LinkLoader.Abort() LinkLoader.Abort()
ProcessStop() ProcessStop()
@@ -217,12 +238,12 @@
'取消加载 '取消加载
Private Sub BtnLoadCancel_Click() Handles BtnLoadCancel.Click Private Sub BtnLoadCancel_Click() Handles BtnLoadCancel.Click
ChangeState(States.Waiting) ChangeState(LinkStates.Waiting)
End Sub End Sub
'点击重试 '点击重试
Private Sub CardLoad_MouseLeftButtonUp() Handles CardLoad.MouseLeftButtonUp Private Sub CardLoad_MouseLeftButtonUp() Handles CardLoad.MouseLeftButtonUp
ChangeState(States.Loading) ChangeState(LinkStates.Loading)
End Sub End Sub
'进度条 '进度条
@@ -252,7 +273,7 @@
#Region "完成页面 (Finished)" #Region "完成页面 (Finished)"
'由 Loading 状态切换到 Finished '由 Loading 状态切换到 Finished
Private Sub SwitchToFinished(OldState As States) Private Sub SwitchToFinished(OldState As LinkStates)
'由于只可能从加载器的完成事件触发,不需要管加载器 '由于只可能从加载器的完成事件触发,不需要管加载器
UpdatePanelVisibility() '页面的实际切换会由 Loader 调用 MyPageRight 来触发 UpdatePanelVisibility() '页面的实际切换会由 Loader 调用 MyPageRight 来触发
@@ -260,26 +281,27 @@
If IsServerSide Then If IsServerSide Then
LabFinishTitle.Text = "已创建房间" LabFinishTitle.Text = "已创建房间"
LabFinishDesc.Text = $"把邀请码发给朋友,让大家加入房间吧!{vbCrLf}邀请码:{NetworkName}-{NetworkSecret}" LabFinishDesc.Text = $"把邀请码发给朋友,让大家加入房间吧!{vbCrLf}邀请码:{NetworkName}-{NetworkSecret}"
BtnFinishCopy.Text = "复制邀请码"
BtnFinishExit.Text = "关闭" BtnFinishExit.Text = "关闭"
BtnFinishCopy.Visibility = Visibility.Visible
Copy() '立即复制邀请码
'下边栏 '下边栏
BtnFinishPing.ToolTip = "网络延迟"
LineFinishPort.Visibility = Visibility.Visible
BtnFinishPort.Visibility = Visibility.Visible BtnFinishPort.Visibility = Visibility.Visible
LabFinishPort.Visibility = Visibility.Visible LabFinishPort.Visibility = Visibility.Visible
BtnFinishIp.Visibility = Visibility.Collapsed
LabFinishIp.Visibility = Visibility.Collapsed
LabFinishPort.Text = ServerPort LabFinishPort.Text = ServerPort
Else Else
LabFinishTitle.Text = "已加入房间" LabFinishTitle.Text = "已加入房间"
LabFinishDesc.Text = $"在多人游戏中选择直接连接,粘贴地址即可加入游戏!{vbCrLf}服务器地址:{ClientAddress}" '"如果提示无效会话,不要退出联机房间,重新启动游戏即可!" LabFinishDesc.Text = $"在多人游戏页面的最下方就能找到联机房间!{vbCrLf}注意:使用离线登录时不要手动输入 IP!"
BtnFinishCopy.Text = "复制地址"
BtnFinishExit.Text = "离开" BtnFinishExit.Text = "离开"
BtnFinishCopy.Visibility = Visibility.Collapsed
'下边栏 '下边栏
BtnFinishPing.ToolTip = "与房主的延迟"
LineFinishPort.Visibility = Visibility.Collapsed
BtnFinishPort.Visibility = Visibility.Collapsed BtnFinishPort.Visibility = Visibility.Collapsed
LabFinishPort.Visibility = Visibility.Collapsed LabFinishPort.Visibility = Visibility.Collapsed
LabFinishIp.Text = ClientAddress
BtnFinishIp.Visibility = Visibility.Visible
LabFinishIp.Visibility = Visibility.Visible
End If End If
Copy() '复制信息
Update() '立即刷新 Update() '立即刷新
End Sub End Sub
@@ -289,30 +311,37 @@
'退出 '退出
Private Sub BtnFinishExit_Click() Handles BtnFinishExit.Click Private Sub BtnFinishExit_Click() Handles BtnFinishExit.Click
TryExit(True) TryExit(False, False)
End Sub End Sub
''' <summary> ''' <summary>
''' 退出联机。 ''' 退出联机。
''' 返回是否弹出了警告窗口并且玩家选择了取消。 ''' 返回是否弹出了警告窗口并且玩家选择了取消。
''' </summary> ''' </summary>
Public Function TryExit(SendWarning As Boolean) As Boolean Public Function TryExit(Slient As Boolean, Closing As Boolean) As Boolean
If State = States.Waiting OrElse State = States.Failed Then Return False If LinkState = LinkStates.Waiting OrElse LinkState = LinkStates.Failed Then Return False
If IsServerSide AndAlso PeopleCount > 1 Then If Not Slient Then
If MyMsgBox("你确定要关闭联机房间吗?" & vbCrLf & "所有玩家都需要重新输入邀请码才可加入游戏!", "关闭房间", "确定", "取消", IsWarn:=True) = 2 Then Return True If IsServerSide AndAlso PeopleCount > 1 Then
If MyMsgBox("你确定要关闭联机房间吗?" & vbCrLf & "所有玩家都需要重新输入邀请码才可加入游戏!", "退出联机", "确定", "取消", IsWarn:=True) = 2 Then Return True
ElseIf Closing Then
If MyMsgBox(If(IsServerSide, "你确定要关闭联机房间吗?", "你确定要离开联机房间吗?"), "退出联机", "确定", "取消") = 2 Then Return True
End If
End If End If
ChangeState(States.Waiting) ChangeState(LinkStates.Waiting)
Return False Return False
End Function End Function
'复制 '复制邀请码
Private Sub Copy() Handles BtnFinishCopy.Click Private Sub Copy() Handles BtnFinishCopy.Click
If IsServerSide Then Dim CodeText As String = $"在 PCL 启动器中输入邀请码【{NetworkName}-{NetworkSecret}】,即可加入联机房间!"
ClipboardSet($"在 PCL 启动器中输入邀请码【{NetworkName}-{NetworkSecret}】,即可加入联机房间!", False) ClipboardSet(CodeText, False)
Hint("已复制邀请码!", HintType.Green) Setup.Set("LinkLastAutoJoinInviteCode", CodeText)
Else Hint("已复制邀请码!", HintType.Green)
ClipboardSet(ClientAddress, False) End Sub
Hint("已复制服务器地址!", HintType.Green)
End If '复制 IP
Private Sub BtnFinishIp_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnFinishIp.MouseLeftButtonUp
ClipboardSet(ClientAddress, False)
Hint("已复制服务器地址!", HintType.Green)
End Sub End Sub
#End Region #End Region
@@ -334,6 +363,14 @@
''' </summary> ''' </summary>
Private ServerPort As Integer Private ServerPort As Integer
''' <summary> ''' <summary>
''' 客户端映射后的端口号。
''' </summary>
Private ClientPort As Integer
''' <summary>
''' RPC 端口号。
''' </summary>
Private RPCPort As Integer
''' <summary>
''' 在客户端映射后的地址。 ''' 在客户端映射后的地址。
''' 除非已作为客户端启动 EasyTier,否则一直为 Nothing。 ''' 除非已作为客户端启动 EasyTier,否则一直为 Nothing。
''' </summary> ''' </summary>
@@ -414,7 +451,7 @@
'解压 '解压
Dim ExtractPath As String = RequestTaskTempFolder() Dim ExtractPath As String = RequestTaskTempFolder()
ExtractFile(PathEasyTier & "EasyTier.zip", ExtractPath, ExtractFile(PathEasyTier & "EasyTier.zip", ExtractPath,
ProgressIncrementHandler:=Sub(Progress) Task.Progress += Progress * 0.06) ProgressIncrementHandler:=Sub(Progress) Task.Progress += Progress * 0.05)
Dim ExtractedPath As String = New DirectoryInfo(ExtractPath).EnumerateDirectories.FirstOrDefault?.FullName Dim ExtractedPath As String = New DirectoryInfo(ExtractPath).EnumerateDirectories.FirstOrDefault?.FullName
Log("[Link] 联机模块解压时的临时路径:" & ExtractedPath) Log("[Link] 联机模块解压时的临时路径:" & ExtractedPath)
CopyDirectory(ExtractedPath, PathEasyTier) CopyDirectory(ExtractedPath, PathEasyTier)
@@ -427,28 +464,42 @@
File.Delete(PathEasyTier & "EasyTier.zip") File.Delete(PathEasyTier & "EasyTier.zip")
Setup.Set("LinkEasyTierVersion", ServerVersion) Setup.Set("LinkEasyTierVersion", ServerVersion)
End If End If
Task.Progress = 0.1 Task.Progress = 0.07
'获取启动参数 '获取节点列表
Dim Peers As List(Of String)
Dim CustomPeers As String = Setup.Get("LinkCustomPeer")
If String.IsNullOrWhiteSpace(CustomPeers) Then
Peers = GetOnlinePeers()
Else
Peers = CustomPeers.Split(",,".ToCharArray).Select(Function(p) p.Trim).Where(Function(p) Not String.IsNullOrEmpty(p)).ToList()
Log("[Link] 使用自定义节点")
End If
Task.Progress = 0.13
'获取空闲端口
UpdateLoadingPage("正在启动联机模块……", "启动联机模块") UpdateLoadingPage("正在启动联机模块……", "启动联机模块")
Dim FreePorts = FindFreePorts(5, ServerPort)
ClientPort = FreePorts(0)
RPCPort = FreePorts(1)
Dim ListenersPort As Integer = FreePorts(2) '它会占用【当前、当前 +1、当前 +2】共三个端口
'获取启动参数
Dim Arguments As String = ServerConfig("Link")("Argument") Dim Arguments As String = ServerConfig("Link")("Argument")
Arguments += $" --network-name={NetworkName} --network-secret={NetworkSecret}" Arguments += $" --network-name={NetworkName} --network-secret={NetworkSecret} --listeners {ListenersPort} --rpc-portal {RPCPort}"
HostName = If(IsServerSide, "Server-", "Client-") & RadixConvert(Math.Abs(Identify.GetHashCode), 10, 36) HostName = If(IsServerSide, "Server-", "Client-") & RadixConvert(Math.Abs(Identify.GetHashCode), 10, 36)
If IsServerSide Then If IsServerSide Then
Arguments += $" -i 10.114.114.114 --hostname={HostName} --tcp-whitelist={ServerPort} --udp-whitelist={ServerPort}" Arguments += $" -i 10.114.114.114 --hostname={HostName} --tcp-whitelist={ServerPort} --udp-whitelist={ServerPort}"
Else Else
Arguments += $" -d --hostname={HostName} --tcp-whitelist=0 --udp-whitelist=0" Arguments += $" -d --hostname={HostName} --tcp-whitelist=0 --udp-whitelist=0"
'端口转发 '端口转发
Dim Port As Integer = GetAvailablePort() ClientAddress = $"localhost:{ClientPort}"
ClientAddress = $"localhost:{Port}" Arguments += $" --port-forward tcp://[{IPAddress.IPv6Loopback}]:{ClientPort}/10.114.114.114:{ServerPort}"
Arguments += $" --port-forward tcp://[{IPAddress.IPv6Loopback}]:{Port}/10.114.114.114:{ServerPort}" Arguments += $" --port-forward udp://[{IPAddress.IPv6Loopback}]:{ClientPort}/10.114.114.114:{ServerPort}"
Arguments += $" --port-forward udp://[{IPAddress.IPv6Loopback}]:{Port}/10.114.114.114:{ServerPort}" Arguments += $" --port-forward tcp://{IPAddress.Loopback}:{ClientPort}/10.114.114.114:{ServerPort}"
Arguments += $" --port-forward tcp://{IPAddress.Loopback}:{Port}/10.114.114.114:{ServerPort}" Arguments += $" --port-forward udp://{IPAddress.Loopback}:{ClientPort}/10.114.114.114:{ServerPort}"
Arguments += $" --port-forward udp://{IPAddress.Loopback}:{Port}/10.114.114.114:{ServerPort}"
End If End If
For Each Peer As String In ServerConfig("Link")("Peers") For Each Peer As String In Peers
Arguments += $" -p=""{Peer}""" Arguments += $" -p=""{Peer}"""
Next Next
If Not Setup.Get("LinkShareMode") Then Arguments += " --private-mode true" Arguments += " --private-mode true" '老好人模式现在莫得用:If Not Setup.Get("LinkShareMode") Then
'启动进程 '启动进程
ProcessStart(Arguments) ProcessStart(Arguments)
Task.Progress = 0.15 Task.Progress = 0.15
@@ -482,9 +533,9 @@
'超时判定 '超时判定
If LastProgress <> Task.Progress Then If LastProgress <> Task.Progress Then
TimeoutCounter = 0 TimeoutCounter = 0
ElseIf TimeoutCounter < 20 Then ElseIf TimeoutCounter < 30 * 2 Then
TimeoutCounter += 1 TimeoutCounter += 1
Else '进度停滞超过 10s Else '进度停滞超过 30s
Select Case PeerCount Select Case PeerCount
Case -1 'CLI 无返回 Case -1 'CLI 无返回
Panic("无法启动联机模块", "近期日志:" & vbCrLf & LogHistory.Join(vbCrLf)) Panic("无法启动联机模块", "近期日志:" & vbCrLf & LogHistory.Join(vbCrLf))
@@ -497,6 +548,49 @@
Loop Until Task.IsAborted Loop Until Task.IsAborted
If Task.IsAborted Then Throw New ThreadInterruptedException If Task.IsAborted Then Throw New ThreadInterruptedException
End Sub End Sub
''' <summary>
''' 从在线配置和 API 获取节点列表。
''' </summary>
Private Function GetOnlinePeers() As List(Of String)
Dim Peers As List(Of String) = ServerConfig("Link")("Peers").Select(Function(p) p.ToString).ToList()
Try
'从 API 获取节点列表
Dim BlackList As List(Of String) = ServerConfig("Link")("PeersBlackList").Select(Function(p) p.ToString).ToList() '黑名单
Dim CentralNodes As New List(Of String)
Dim RandomNodes As New List(Of Tuple(Of String, Double))
For Each Node As JObject In CType(GetJson(NetRequestByClientRetry("https://uptime.easytier.cn/api/nodes?page=1&per_page=200")), JObject)("data")("items")
'状态检查
If Node("protocol").ToString <> "tcp" Then Continue For
If Node("current_health_status").ToString <> "healthy" Then Continue For
If Not Node("is_active").ToObject(Of Boolean) Then Continue For
If Not Node("is_approved").ToObject(Of Boolean) Then Continue For
Dim Tags = Node("tags").Select(Function(t) t.ToString).ToList
If Not Tags.Contains("国内") Then Continue For
If Tags.Contains("即将下线") Then Continue For
Dim Address As String = Node("address").ToString
If BlackList.Contains(Address) Then Continue For
'添加节点
If Tags.Contains("MC") Then
CentralNodes.Add(Address)
Else
If Not Node("allow_relay").ToObject(Of Boolean) Then Continue For
If Node("usage_percentage").ToObject(Of Double) = 0 Then Continue For '或许节点有问题才导致是 0 负载
RandomNodes.Add(New Tuple(Of String, Double)(
Address,
Node("usage_percentage").ToObject(Of Double) * (103 - Node("health_percentage_24h").ToObject(Of Double)))) '负载,越低越好
End If
Next
RandomNodes = RandomNodes.OrderBy(Function(n) n.Item2).ToList()
Log($"[Link] 获取到 {CentralNodes.Count} 个中心节点,{RandomNodes.Count} 个随机节点")
'选择节点
Dim RandomCount As Integer = ServerConfig("Link")("RandomPeer").ToObject(Of Integer)
If RandomNodes.Count < RandomCount Then Throw New Exception($"可用的随机节点数量不足,需要 {RandomCount} 个,实际 {RandomNodes.Count} 个")
Peers = CentralNodes.Concat(RandomNodes.Take(RandomCount).Select(Function(n) n.Item1)).ToList()
Catch ex As Exception
Log(ex, "获取节点列表失败,联机质量可能受到影响", LogLevel.Hint)
End Try
Return Peers
End Function
#End Region #End Region
@@ -544,26 +638,14 @@
''' 出现意外错误,给出错误信息并结束联机。 ''' 出现意外错误,给出错误信息并结束联机。
''' </summary> ''' </summary>
Private Sub Panic(Brief As String, Detail As String) Private Sub Panic(Brief As String, Detail As String)
If State = States.Loading Then If LinkState = LinkStates.Loading Then
FailReason = Brief FailReason = Brief
LinkLoader.Failed(New Exception(Detail)) LinkLoader.Failed(New Exception(Detail))
Else Else
MyMsgBox(Detail, "联机出错:" & Brief, IsWarn:=True) MyMsgBox(Detail, "联机出错:" & Brief, IsWarn:=True)
ChangeState(States.Waiting) ChangeState(LinkStates.Waiting)
Telemetry("联机失败", "Exception", FilterUserName(Brief & ":" & Detail, "*")) Telemetry("联机失败", "Exception", FilterUserName(Brief & ":" & Detail, "*"))
End If End If
'收集到的 CLI 错误:
'Error: Timeout : deadline has elapsed
'Caused by
' deadline has elapsed
'Error: failed to get peer manager client
'Caused by
' 0: rust tun error failed to connect to server: Url {scheme: "tcp", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("127.0.0.1")), port: Some(15888), path: "", query: None, fragment: None }
' 1: failed to connect to server: Url {scheme: "tcp", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("127.0.0.1")), port: Some(15888), path: "", query: None, fragment: None }
' 2: IO error
' 3: 由于目标计算机积极拒绝, 无法连接。 (os error 10061)
End Sub End Sub
''' <summary> ''' <summary>
@@ -656,32 +738,33 @@
''' 名称。 ''' 名称。
''' </summary> ''' </summary>
Public ReadOnly Name As String Public ReadOnly Name As String
''' <summary>
''' 连接方式。
''' </summary>
Public ReadOnly Cost As String
''' <summary> ''' <summary>
''' 从 CLI 给出的信息行分析对应的数据。 ''' 从 CLI 给出的信息分析对应的数据。
''' </summary> ''' </summary>
Public Sub New(Info As String) Public Sub New(Info As JObject)
'具体每个部分的索引见 GetPeerData()
Dim Parts = Info.Split("|").Select(Function(s) If(s.All(Function(c) c = " "c), s, s.Trim)).Where(Function(s) s <> "").ToList
If Parts.Count <> 10 Then Throw New Exception($"信息列数有误")
'延迟
Ping = If(Parts(3) = "-", 0, Parts(3))
'类别 '类别
Dim PeerName = Parts(1) Dim PeerName = Info("hostname").ToString
If PeerName = HostName Then If PeerName = HostName Then
Type = Types.Self Type = Types.Self
ElseIf PeerName.StartsWithF("Client") Then ElseIf PeerName.StartsWithF("Client") Then
Type = Types.Client Type = Types.Client
ElseIf Parts(0).StartsWithF("10.114.114.114") Then '只允许这个 IP 作为房主,避免网络被多个房主搞炸的情况 ElseIf Info("ipv4") = "10.114.114.114" Then '只允许这个 IP 作为房主,避免网络被多个房主搞炸的情况
Type = Types.Server Type = Types.Server
Else Else
Type = Types.Misc Type = Types.Misc
End If End If
'主机名 '基础信息
Ping = If(Info("lat_ms").ToString = "-", 0, Info("lat_ms").ToString)
Name = PeerName Name = PeerName
Cost = Info("cost")
End Sub End Sub
Public Overrides Function ToString() As String Public Overrides Function ToString() As String
Return $"{Type} - {Name} - Ping {Ping:0.0}ms" Return $"{Type} - {Name} - Ping {Ping:0.0}ms [{Cost}]"
End Function End Function
End Class End Class
@@ -705,12 +788,12 @@
'| 10.114.114.114/24 | Server-J6P6IW | p2p | 5.63 | 0.0% | 1.65 kB | 1.64 kB | udp | PortRestricted | 2.4.5-4c4d172e | '| 10.114.114.114/24 | Server-J6P6IW | p2p | 5.63 | 0.0% | 1.65 kB | 1.64 kB | udp | PortRestricted | 2.4.5-4c4d172e |
'| 10.114.114.114/24 | Server-J6PHIW (连接中) | relay(2) | 1000.00 | 0.0% | 0 B | 0 B | | PortRestricted | 2.4.5-4c4d172e | '| 10.114.114.114/24 | Server-J6PHIW (连接中) | relay(2) | 1000.00 | 0.0% | 0 B | 0 B | | PortRestricted | 2.4.5-4c4d172e |
Try Try
Dim CliResult = StartProcessAndGetOutput(PathEasyTier & "联机模块 CLI.exe", "peer", 2000, Encoding:=Encoding.UTF8, PrintLog:=False) Dim CliResult = StartProcessAndGetOutput(PathEasyTier & "联机模块 CLI.exe", $"-o json -p 127.0.0.1:{RPCPort} peer", 2000, Encoding:=Encoding.UTF8, PrintLog:=False)
'解析 '解析
If Not CliResult.Contains("lat(ms)") Then Throw New Exception("CLI 调用失败:" & vbCrLf & CliResult) If Not CliResult.Contains("lat_ms") Then Throw New Exception("CLI 调用失败:" & vbCrLf & CliResult)
If GetUuid() Mod If(ModeDebug, 4, 30) = 0 Then Log("[EasyTier] CLI 输出抽样:" & vbCrLf & CliResult) If GetUuid() Mod If(ModeDebug, 23, 103) = 0 Then Log("[EasyTier] CLI 输出抽样:" & vbCrLf & CliResult)
Dim NewPeers As New List(Of Peer) Dim NewPeers As New List(Of Peer)
For Each Line In CliResult.Split(vbCrLf.ToCharArray, StringSplitOptions.RemoveEmptyEntries).Skip(2) For Each Line As JObject In CType(GetJson(CliResult), JArray).Skip(1)
Try Try
Dim Peer = New Peer(Line) Dim Peer = New Peer(Line)
If Peer.Type = Peer.Types.Self Then Continue For '自己 If Peer.Type = Peer.Types.Self Then Continue For '自己
@@ -724,7 +807,7 @@
FailCount = 0 FailCount = 0
Catch ex As Exception Catch ex As Exception
Log(ex, "获取节点信息失败") Log(ex, "获取节点信息失败")
If State = States.Finished Then If LinkState = LinkStates.Finished Then
FailCount += 1 FailCount += 1
If FailCount >= 4 Then Panic("获取节点信息失败", ex.Message) If FailCount >= 4 Then Panic("获取节点信息失败", ex.Message)
End If End If
@@ -741,18 +824,26 @@
''' 0 代表尚不可用。 ''' 0 代表尚不可用。
''' </summary> ''' </summary>
Private Function GetPeerPing() As Double Private Function GetPeerPing() As Double
If Peers Is Nothing Then Return 0 Dim Peer = GetTargetPeer()
Dim PingTargets As IEnumerable(Of Peer) If Peer Is Nothing Then Return 0
Return Peer.Ping
End Function
''' <summary>
''' 服务端会返回所有节点中 Ping 的那一个,客户端会返回服务端。
''' 若没有则为 Nothing。
''' </summary>
Private Function GetTargetPeer() As Peer
If Peers Is Nothing Then Return Nothing
Dim Targets As IEnumerable(Of Peer)
If IsServerSide Then If IsServerSide Then
PingTargets = Peers Targets = Peers.Where(Function(p) p.Ping > 0)
Else Else
PingTargets = Peers.Where(Function(p) p.Type = Peer.Types.Server) Targets = Peers.Where(Function(p) p.Type = Peer.Types.Server AndAlso p.Ping > 0)
End If
If Not PingTargets.Any Then
Return 0
Else
Return Math.Max(1, PingTargets.Select(Function(p) p.Ping).Min())
End If End If
If Not Targets.Any Then Return Nothing
'返回 Ping 大于 0 且最低的那个
Dim MinPing = Targets.Min(Function(p) p.Ping)
Return Targets.First(Function(p) p.Ping = MinPing)
End Function End Function
''' <summary> ''' <summary>
@@ -768,7 +859,7 @@
#End Region #End Region
#Region "定时状态更新" #Region "定时任务"
'启动 '启动
Private IsTimerStarted As Boolean = False Private IsTimerStarted As Boolean = False
@@ -781,13 +872,13 @@
Try Try
Thread.Sleep(200) Thread.Sleep(200)
Counter += 200 Counter += 200
'每 4 秒执行一次 '每秒执行一次
If Counter >= 4000 Then If Counter >= 1000 Then
Counter = 0 Counter = 0
Update() Update()
End If End If
'每 200ms 更新进度条 '每 200ms 更新进度条
If State = States.Loading Then RunInUi(AddressOf UpdateProgressBar) If LinkState = LinkStates.Loading Then RunInUi(AddressOf UpdateProgressBar)
Catch ex As Exception Catch ex As Exception
Log(ex, "联机模块主时钟出错", LogLevel.Feedback) Log(ex, "联机模块主时钟出错", LogLevel.Feedback)
Thread.Sleep(10000) Thread.Sleep(10000)
@@ -796,9 +887,10 @@
End Sub, "Link Timer") End Sub, "Link Timer")
End Sub End Sub
'每 4 秒或进入页面时更新一次信息 '每秒或进入页面时触发
Private BroadcastSocket As New Socket(SocketType.Dgram, ProtocolType.Udp)
Private Sub Update() Handles Me.Loaded Private Sub Update() Handles Me.Loaded
If State <> States.Finished Then Return If LinkState <> LinkStates.Finished Then Return
'重新获取信息 '重新获取信息
SyncLock RefreshPeerLoader.LockState SyncLock RefreshPeerLoader.LockState
If RefreshPeerLoader.State <> LoadState.Loading Then RefreshPeerLoader.Start(IsForceRestart:=True) If RefreshPeerLoader.State <> LoadState.Loading Then RefreshPeerLoader.Start(IsForceRestart:=True)
@@ -808,13 +900,25 @@
RunInUi( RunInUi(
Sub() Sub()
Dim Ping As Double = GetPeerPing() Dim Ping As Double = GetPeerPing()
Dim RelayLayer As Integer = If(GetTargetPeer().Cost.RegexSeek("(?<=relay\()\d+") Is Nothing,
0, Val(GetTargetPeer().Cost.RegexSeek("(?<=relay\()\d+")) - 1)
'更新 Ping 显示
If Ping Mod 500 = 0 OrElse $"{Ping:0.0}" = "1.0" OrElse FailCount > 0 Then If Ping Mod 500 = 0 OrElse $"{Ping:0.0}" = "1.0" OrElse FailCount > 0 Then
LabFinishPing.Text = "连接中" LabFinishPing.Text = "连接中"
AniStop("Link Logo Rotation") AniStop("Link Logo Rotation")
Else Else
LabFinishPing.Text = If(Ping >= 10, $"{Ping:0} ms", $"{Ping:0.0} ms") LabFinishPing.Text =
If(RelayLayer > 0, If(RelayLayer > 1, $"中继 {RelayLayer} · ", "中继 · "), "") & '使用中继连接时显示 “中继” 前缀
If(Ping >= 10, $"{Ping:0} ms", $"{Ping:0.0} ms")
AniStart(AaRotateTransform(ImgFinishLogo, 500, 5000), "Link Logo Rotation") 'Logo 旋转动画 AniStart(AaRotateTransform(ImgFinishLogo, 500, 5000), "Link Logo Rotation") 'Logo 旋转动画
End If End If
'更新 Ping 的 Tooltip 显示
Dim Tooltip As String = If(IsServerSide, "网络延迟", "与房主的延迟")
If RelayLayer Then Tooltip &= If(IsServerSide,
$"(你的网络环境较差,正经过 {RelayLayer} 层中继,可能会有点卡)",
$"(你或者房主的网络环境较差,正经过 {RelayLayer} 层中继,可能会有点卡)")
BtnFinishPing.ToolTip = Tooltip
'更新人数显示
LabFinishPlayer.Text = PeopleCount & "  人" LabFinishPlayer.Text = PeopleCount & "  人"
End Sub) End Sub)
End If End If
@@ -827,9 +931,20 @@
End If End If
If Not IsServerSide AndAlso Not Peers.Any(Function(p) p.Type = Peer.Types.Server) Then If Not IsServerSide AndAlso Not Peers.Any(Function(p) p.Type = Peer.Types.Server) Then
MyMsgBox("房主已离开房间!", "联机结束") MyMsgBox("房主已离开房间!", "联机结束")
ChangeState(States.Waiting) ChangeState(LinkStates.Waiting)
Return Return
End If End If
'广播联机房间端口
If Not IsServerSide Then
Try
BroadcastSocket.SendTo(
Encoding.UTF8.GetBytes($"[MOTD]PCL 联机房间[/MOTD][AD]{ClientPort}[/AD]"),
SocketFlags.None,
New IPEndPoint(IPAddress.Loopback, 4445))
Catch ex As Exception
Log(ex, "广播联机房间端口失败")
End Try
End If
End Sub End Sub
''' <summary> ''' <summary>
''' 检查联机模块是否崩溃。 ''' 检查联机模块是否崩溃。
@@ -46,6 +46,7 @@
<RowDefinition Height="45" /> <RowDefinition Height="45" />
<RowDefinition Height="45" /> <RowDefinition Height="45" />
<RowDefinition Height="45" /> <RowDefinition Height="45" />
<RowDefinition Height="45" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="40" /> <ColumnDefinition Width="40" />
@@ -58,11 +59,13 @@
<local:MyButton Text="打开百科" Grid.Row="1" Grid.Column="2" Height="35" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.mcmod.cn" /> <local:MyButton Text="打开百科" Grid.Row="1" Grid.Column="2" Height="35" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.mcmod.cn" />
<local:MyListItem Title="z0z0r4" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 MCIM 社区资源镜像源和帮助库图床!" Grid.Row="2" Grid.Column="1" /> <local:MyListItem Title="z0z0r4" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 MCIM 社区资源镜像源和帮助库图床!" Grid.Row="2" Grid.Column="1" />
<local:MyButton Text="MCIM 主页" Grid.Row="2" Grid.Column="2" Height="35" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/mcmod-info-mirror" /> <local:MyButton Text="MCIM 主页" Grid.Row="2" Grid.Column="2" Height="35" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/mcmod-info-mirror" />
<local:MyListItem Title="00ll00" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 Java Launch Wrapper 和一些重要服务支持!" Grid.Row="3" Grid.Column="1" /> <local:MyListItem Title="EasyTier" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了联机模块!" Grid.Row="3" Grid.Column="1" />
<local:MyListItem Title="Patrick" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="设计并制作了 PCL 图标,让我从做图标的水深火热中得到了解脱……" Grid.Row="4" Grid.Column="1" /> <local:MyButton Text="GitHub 页面" Grid.Row="3" Grid.Column="2" Height="35" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/EasyTier/EasyTier" />
<local:MyListItem Title="Hao_Tian" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="在内测中找出了一大堆没人想得到的诡异 Bug,有非同寻常的 Bug 体质" Grid.Row="5" Grid.Column="1" /> <local:MyListItem Title="00ll00" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 Java Launch Wrapper 和一些重要服务支持!" Grid.Row="4" Grid.Column="1" />
<local:MyListItem Title="Minecraft 中文论坛" Margin="-5,0,15,0" IsHitTestVisible="False" Info="虽然已经关站了,但感谢此前提供了 MCBBS 镜像源……" Grid.Row="6" Grid.Column="1" /> <local:MyListItem Title="Patrick" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="设计并制作了 PCL 图标,让我从做图标的水深火热中得到了解脱……" Grid.Row="5" Grid.Column="1" />
<local:MyListItem Title="PCL 内群的各位" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="感谢内群的沙雕网友们这么久以来对我和 PCL 的支持与鼓励!" Grid.Row="7" Grid.Column="1" /> <local:MyListItem Title="Hao_Tian" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="在内测中找出了一大堆没人想得到的诡异 Bug,有非同寻常的 Bug 体质" Grid.Row="6" Grid.Column="1" />
<local:MyListItem Title="Minecraft 中文论坛" Margin="-5,0,15,0" IsHitTestVisible="False" Info="虽然已经关站了,但感谢此前提供了 MCBBS 镜像源……" Grid.Row="7" Grid.Column="1" />
<local:MyListItem Title="PCL 内群的各位" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="感谢内群的沙雕网友们这么久以来对我和 PCL 的支持与鼓励!" Grid.Row="8" Grid.Column="1" />
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/bangbang93.png" Grid.Row="0" Margin="3"> <Image Source="/Plain Craft Launcher 2;component/Images/Heads/bangbang93.png" Grid.Row="0" Margin="3">
<Image.Clip> <Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" /> <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
@@ -78,27 +81,32 @@
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" /> <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip> </Image.Clip>
</Image> </Image>
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/00ll00.png" Grid.Row="3" Margin="3"> <Image Source="/Plain Craft Launcher 2;component/Images/Heads/EasyTier.png" Grid.Row="3" Margin="3">
<Image.Clip> <Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" /> <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip> </Image.Clip>
</Image> </Image>
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/Patrick.png" Grid.Row="4" Margin="3"> <Image Source="/Plain Craft Launcher 2;component/Images/Heads/00ll00.png" Grid.Row="4" Margin="3">
<Image.Clip> <Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" /> <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip> </Image.Clip>
</Image> </Image>
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/Hao_Tian.jpg" Grid.Row="5" Margin="3"> <Image Source="/Plain Craft Launcher 2;component/Images/Heads/Patrick.png" Grid.Row="5" Margin="3">
<Image.Clip> <Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" /> <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip> </Image.Clip>
</Image> </Image>
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/MCBBS.png" Grid.Row="6" Margin="3"> <Image Source="/Plain Craft Launcher 2;component/Images/Heads/Hao_Tian.jpg" Grid.Row="6" Margin="3">
<Image.Clip> <Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" /> <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip> </Image.Clip>
</Image> </Image>
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/PCL2.png" Grid.Row="7" Margin="3"> <Image Source="/Plain Craft Launcher 2;component/Images/Heads/MCBBS.png" Grid.Row="7" Margin="3">
<Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip>
</Image>
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/PCL2.png" Grid.Row="8" Margin="3">
<Image.Clip> <Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" /> <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip> </Image.Clip>
@@ -107,217 +115,566 @@
</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 年 9 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" /> <TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 10 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
<WrapPanel Margin="0,0,0,10">␍ <TextBlock Width="120" Margin="0,1.5" Text="lecoe" /> <WrapPanel Margin="0,0,0,10">␍ <TextBlock Width="120" Margin="0,1.5" Text="阿瓦达" />
<TextBlock Width="120" Margin="0,1.5" Text="QIUQI" /> <TextBlock Width="120" Margin="0,1.5" Text="不若" />
<TextBlock Width="120" Margin="0,1.5" Text="Aquadtr" /> <TextBlock Width="120" Margin="0,1.5" Text="Albus" />
<TextBlock Width="120" Margin="0,1.5" Text="stb" /> <TextBlock Width="120" Margin="0,1.5" Text="牛马" />
<TextBlock Width="120" Margin="0,1.5" Text="mco" /> <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="Le Play" /> <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="Kamazi_Yuka5201" /> <TextBlock Width="120" Margin="0,1.5" Text="魂夜" />
<TextBlock Width="120" Margin="0,1.5" Text="滚动的拉布拉多" /> <TextBlock Width="120" Margin="0,1.5" Text="apoooooo" />
<TextBlock Width="120" Margin="0,1.5" Text="王牟" /> <TextBlock Width="120" Margin="0,1.5" Text="落户" />
<TextBlock Width="120" Margin="0,1.5" Text="Lazarus" /> <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="Ding" />
<TextBlock Width="120" Margin="0,1.5" Text="lIIIllIIllIIl" /> <TextBlock Width="120" Margin="0,1.5" Text="yi9999" />
<TextBlock Width="120" Margin="0,1.5" Text="Zsol" /> <TextBlock Width="120" Margin="0,1.5" Text="muo" />
<TextBlock Width="120" Margin="0,1.5" Text="榴莲" /> <TextBlock Width="120" Margin="0,1.5" Text="科骏达" />
<TextBlock Width="120" Margin="0,1.5" Text="Night Voyager" /> <TextBlock Width="120" Margin="0,1.5" Text="嫉妒" />
<TextBlock Width="120" Margin="0,1.5" Text="JOHNJIANG" /> <TextBlock Width="120" Margin="0,1.5" Text="阿辉" />
<TextBlock Width="120" Margin="0,1.5" Text="柒月" /> <TextBlock Width="120" Margin="0,1.5" Text="L." />
<TextBlock Width="120" Margin="0,1.5" Text="不温柔先森" /> <TextBlock Width="120" Margin="0,1.5" Text="??????????)?" />
<TextBlock Width="120" Margin="0,1.5" Text="Freewind" /> <TextBlock Width="120" Margin="0,1.5" Text="温雅" />
<TextBlock Width="120" Margin="0,1.5" Text="纯萧子" /> <TextBlock Width="120" Margin="0,1.5" Text="MingChuYa" />
<TextBlock Width="120" Margin="0,1.5" Text="扇" /> <TextBlock Width="120" Margin="0,1.5" Text="S????? . ?" />
<TextBlock Width="120" Margin="0,1.5" Text="Amturester" /> <TextBlock Width="120" Margin="0,1.5" Text="吴傻傻" />
<TextBlock Width="120" Margin="0,1.5" Text="maigm" /> <TextBlock Width="120" Margin="0,1.5" Text="会忘记九月嘛" />
<TextBlock Width="120" Margin="0,1.5" Text="JO23" /> <TextBlock Width="120" Margin="0,1.5" Text="咸鱼猫猫" />
<TextBlock Width="120" Margin="0,1.5" Text="JCNB" /> <TextBlock Width="120" Margin="0,1.5" Text="MCMIAO" />
<TextBlock Width="120" Margin="0,1.5" Text="星尘" /> <TextBlock Width="120" Margin="0,1.5" Text="熠惊" />
<TextBlock Width="120" Margin="0,1.5" Text="姜桐桐233" /> <TextBlock Width="120" Margin="0,1.5" Text="emm" />
<TextBlock Width="120" Margin="0,1.5" Text="AkaneRyoba" /> <TextBlock Width="120" Margin="0,1.5" Text="十月." />
<TextBlock Width="120" Margin="0,1.5" Text="南山必胜客" /> <TextBlock Width="120" Margin="0,1.5" Text="Mark_ShaoYang" />
<TextBlock Width="120" Margin="0,1.5" Text="57" /> <TextBlock Width="120" Margin="0,1.5" Text="左" />
<TextBlock Width="120" Margin="0,1.5" Text="咸菜萝卜煲" /> <TextBlock Width="120" Margin="0,1.5" Text="Crocoldilopolis" />
<TextBlock Width="120" Margin="0,1.5" Text="shawnlong" /> <TextBlock Width="120" Margin="0,1.5" Text="!" />
<TextBlock Width="120" Margin="0,1.5" Text="DDNGSZX1" /> <TextBlock Width="120" Margin="0,1.5" Text="风息" />
<TextBlock Width="120" Margin="0,1.5" Text="KaguraZaka" /> <TextBlock Width="120" Margin="0,1.5" Text="by烟火" />
<TextBlock Width="120" Margin="0,1.5" Text="谶纛" /> <TextBlock Width="120" Margin="0,1.5" Text="优纪" />
<TextBlock Width="120" Margin="0,1.5" Text="666" /> <TextBlock Width="120" Margin="0,1.5" Text="人世间狡诈邪恶" />
<TextBlock Width="120" Margin="0,1.5" Text="betwangzai" /> <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="fjvg" /> <TextBlock Width="120" Margin="0,1.5" Text="山海." />
<TextBlock Width="120" Margin="0,1.5" Text="TH-x" /> <TextBlock Width="120" Margin="0,1.5" Text="巫元dry" />
<TextBlock Width="120" Margin="0,1.5" Text="Q" /> <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="P·咕·D·咕咕·F" /> <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="LAZY" /> <TextBlock Width="120" Margin="0,1.5" Text="墨枫逸尘" />
<TextBlock Width="120" Margin="0,1.5" Text="沙发上的沙发" /> <TextBlock Width="120" Margin="0,1.5" Text="SmileRm" />
<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="SquareBlock" />
<TextBlock Width="120" Margin="0,1.5" Text="超级白给马" /> <TextBlock Width="240" Margin="0,1.5" Text="失去梦想的GGbond" />
<TextBlock Width="120" Margin="0,1.5" Text="fwlqpalzmd" /> <TextBlock Width="120" Margin="0,1.5" Text="Kuni" />
<TextBlock Width="120" Margin="0,1.5" Text="安执妄dying" /> <TextBlock Width="120" Margin="0,1.5" Text="Herr" />
<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="kirito" />
<TextBlock Width="120" Margin="0,1.5" Text="荆槐序" /> <TextBlock Width="120" Margin="0,1.5" Text="Tt" />
<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="trav" />
<TextBlock Width="120" Margin="0,1.5" Text="zz" /> <TextBlock Width="120" Margin="0,1.5" Text="Danielisdoge" />
<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="BRfake" /> <TextBlock Width="120" Margin="0,1.5" Text="懒人碎觉" />
<TextBlock Width="120" Margin="0,1.5" Text="Lucien_Liu" /> <TextBlock Width="120" Margin="0,1.5" Text="神里绫华的狗" />
<TextBlock Width="120" Margin="0,1.5" Text="煎bingo子" /> <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="hakureireimu" /> <TextBlock Width="120" Margin="0,1.5" Text="水波不兴" />
<TextBlock Width="120" Margin="0,1.5" Text="wwxa2019" /> <TextBlock Width="120" Margin="0,1.5" Text="zero" />
<TextBlock Width="120" Margin="0,1.5" Text="TAIGA" /> <TextBlock Width="120" Margin="0,1.5" Text="许愿流星雨" />
<TextBlock Width="120" Margin="0,1.5" Text="墨玉" /> <TextBlock Width="120" Margin="0,1.5" Text="YiHuwuyue" />
<TextBlock Width="120" Margin="0,1.5" Text="Jane" /> <TextBlock Width="120" Margin="0,1.5" Text="CenturionSC" />
<TextBlock Width="120" Margin="0,1.5" Text="雪下丨残影" /> <TextBlock Width="120" Margin="0,1.5" Text="闲鱼下饭" />
<TextBlock Width="120" Margin="0,1.5" Text="未命名3742" /> <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="ATH9" /> <TextBlock Width="120" Margin="0,1.5" Text="Caryee" />
<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="马春明" /> <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="CT" />
<TextBlock Width="120" Margin="0,1.5" Text="sun次方" /> <TextBlock Width="120" Margin="0,1.5" Text="酋长想去欧洲" />
<TextBlock Width="120" Margin="0,1.5" Text="憨憨橙子" /> <TextBlock Width="120" Margin="0,1.5" Text="MOYO_" />
<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="Jcey" />
<TextBlock Width="120" Margin="0,1.5" Text="蓝叶" /> <TextBlock Width="120" Margin="0,1.5" Text="Nefelibata." />
<TextBlock Width="120" Margin="0,1.5" Text="ELUCIDATE" /> <TextBlock Width="120" Margin="0,1.5" Text="领域星" />
<TextBlock Width="120" Margin="0,1.5" Text="兔饼干哈哈" /> <TextBlock Width="120" Margin="0,1.5" Text="cnp" />
<TextBlock Width="120" Margin="0,1.5" Text="Styx誓约" /> <TextBlock Width="120" Margin="0,1.5" Text="扔完炸药掏蜂鸟" />
<TextBlock Width="120" Margin="0,1.5" Text="V" /> <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="wax" />
<TextBlock Width="120" Margin="0,1.5" Text="A" /> <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="剑鱼776" /> <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="Ashlxy" /> <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="fisher426" /> <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="Freezinker" />
<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="NORMAL_MAN36" />
<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="kikimmo" />
<TextBlock Width="120" Margin="0,1.5" Text="山有木兮325" /> <TextBlock Width="120" Margin="0,1.5" Text="镜像折叠" />
<TextBlock Width="120" Margin="0,1.5" Text="37号村民" /> <TextBlock Width="120" Margin="0,1.5" Text="留不住的刹那" />
<TextBlock Width="120" Margin="0,1.5" Text="白承宣" /> <TextBlock Width="120" Margin="0,1.5" Text="." />
<TextBlock Width="240" Margin="0,1.5" Text="某蓝毛借钱不还的贝斯手" /> <TextBlock Width="120" Margin="0,1.5" Text="朱小楠" />
<TextBlock Width="120" Margin="0,1.5" Text="白狼" /> <TextBlock Width="120" Margin="0,1.5" Text="鹤暝柘" />
<TextBlock Width="120" Margin="0,1.5" Text="工蜂" /> <TextBlock Width="120" Margin="0,1.5" Text="莫离" />
<TextBlock Width="120" Margin="0,1.5" Text="封不觉" /> <TextBlock Width="120" Margin="0,1.5" Text="江上tipsy" />
<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="Master" />
<TextBlock Width="120" Margin="0,1.5" Text="好" /> <TextBlock Width="120" Margin="0,1.5" Text="边打铜锣边鬼叫" />
<TextBlock Width="120" Margin="0,1.5" Text="NeonSoda" /> <TextBlock Width="120" Margin="0,1.5" Text="随便就好" />
<TextBlock Width="120" Margin="0,1.5" Text="UNICORN" /> <TextBlock Width="120" Margin="0,1.5" Text="赢于" />
<TextBlock Width="120" Margin="0,1.5" Text="红石beaker" /> <TextBlock Width="120" Margin="0,1.5" Text="夏目心" />
<TextBlock Width="120" Margin="0,1.5" Text="EliasLSK" /> <TextBlock Width="120" Margin="0,1.5" Text="NOBODY112" />
<TextBlock Width="120" Margin="0,1.5" Text="思考人生" /> <TextBlock Width="120" Margin="0,1.5" Text="黑糖" />
<TextBlock Width="120" Margin="0,1.5" Text="L" /> <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="FAMS" /> <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="baka王" /> <TextBlock Width="120" Margin="0,1.5" Text="EasyOrange" />
<TextBlock Width="120" Margin="0,1.5" Text="深海带鱼" /> <TextBlock Width="120" Margin="0,1.5" Text="MATH算珠" />
<TextBlock Width="120" Margin="0,1.5" Text="四戒梨子" /> <TextBlock Width="120" Margin="0,1.5" Text="暮光Ts" />
<TextBlock Width="120" Margin="0,1.5" Text="无限" /> <TextBlock Width="120" Margin="0,1.5" Text="洛秋" />
<TextBlock Width="120" Margin="0,1.5" Text="Xc_AcE" /> <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="Tenno" />
<TextBlock Width="120" Margin="0,1.5" Text="molFish" /> <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="AAALLLAAANNN" /> <TextBlock Width="120" Margin="0,1.5" Text="今晚不熬夜" />
<TextBlock Width="120" Margin="0,1.5" Text="华氏451" /> <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="Rei" />
<TextBlock Width="120" Margin="0,1.5" Text="志摩凛" /> <TextBlock Width="120" Margin="0,1.5" Text="lxh123123123" />
<TextBlock Width="120" Margin="0,1.5" Text="八云蓝LIN" /> <TextBlock Width="120" Margin="0,1.5" Text="瓷" />
<TextBlock Width="120" Margin="0,1.5" Text="LittleBlue" /> <TextBlock Width="120" Margin="0,1.5" Text="yyc我稀饭你" />
<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="Red_橙子" /> <TextBlock Width="120" Margin="0,1.5" Text="Y先生" />
<TextBlock Width="120" Margin="0,1.5" Text="Junmucheng" /> <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="1111111" /> <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="七日 SEVENDAYS" /> <TextBlock Width="120" Margin="0,1.5" Text="鱿倪克" />
<TextBlock Width="120" Margin="0,1.5" Text="Gǔdù" /> <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="ZJD" />
<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="WLan" />
<TextBlock Width="240" Margin="0,1.5" Text="小狗很担心你有没有好好喝水" /> <TextBlock Width="120" Margin="0,1.5" Text="457ssu" />
<TextBlock Width="120" Margin="0,1.5" Text="hjhmeibao" />
<TextBlock Width="120" Margin="0,1.5" Text="网络白字话事人" />
<TextBlock Width="120" Margin="0,1.5" Text="想要点好运" />
<TextBlock Width="120" Margin="0,1.5" Text="Timmy1950" />
<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="HansOffice" />
<TextBlock Width="120" Margin="0,1.5" Text="466某某某" />
<TextBlock Width="120" Margin="0,1.5" Text="zztzzy" />
<TextBlock Width="120" Margin="0,1.5" Text="辉光离子管" />
<TextBlock Width="120" Margin="0,1.5" Text="联开开" />
<TextBlock Width="120" Margin="0,1.5" Text="XIAOSHUAI" />
<TextBlock Width="120" Margin="0,1.5" Text="KMYLS" />
<TextBlock Width="120" Margin="0,1.5" Text="聽音" />
<TextBlock Width="120" Margin="0,1.5" Text="oPzPo" />
<TextBlock Width="120" Margin="0,1.5" Text="dream" />
<TextBlock Width="120" Margin="0,1.5" Text="123" />
<TextBlock Width="120" Margin="0,1.5" Text="Zik yeung" />
<TextBlock Width="120" Margin="0,1.5" Text="wihz" />
<TextBlock Width="120" Margin="0,1.5" Text="九平" />
<TextBlock Width="120" Margin="0,1.5" Text="liu" /> <TextBlock Width="120" Margin="0,1.5" Text="liu" />
<TextBlock Width="120" Margin="0,1.5" Text="PickStars" /> <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="dailiweier" />
<TextBlock Width="120" Margin="0,1.5" Text="korfr" />
<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="XINA-33" />
<TextBlock Width="120" Margin="0,1.5" Text="Temmie" />
<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="LightingPriest" />
<TextBlock Width="120" Margin="0,1.5" Text="sxdxm" />
<TextBlock Width="120" Margin="0,1.5" Text="GYWTT" />
<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="sul" />
<TextBlock Width="120" Margin="0,1.5" Text="静心涵养" />
<TextBlock Width="120" Margin="0,1.5" Text="均就均吧" />
<TextBlock Width="120" Margin="0,1.5" Text="Tuski_Velpro" />
<TextBlock Width="120" Margin="0,1.5" Text="望江寒" />
<TextBlock Width="120" Margin="0,1.5" Text="我该要E了" />
<TextBlock Width="120" Margin="0,1.5" Text="lxx" />
<TextBlock Width="120" Margin="0,1.5" Text="MX丶" />
<TextBlock Width="120" Margin="0,1.5" Text="乘风9527" />
<TextBlock Width="120" Margin="0,1.5" Text="修狗不是狗" />
<TextBlock Width="120" Margin="0,1.5" Text="奇怪的深渊增加了" />
<TextBlock Width="120" Margin="0,1.5" Text="森森1025" />
<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="shengli" />
<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="亡利普贝当" />
<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="LBDLXLZT" />
<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="qiji_SaMa" />
<TextBlock Width="120" Margin="0,1.5" Text="是我小白鸭~" />
<TextBlock Width="120" Margin="0,1.5" Text="Yylinmu" />
<TextBlock Width="120" Margin="0,1.5" Text="zzz" />
<TextBlock Width="120" Margin="0,1.5" Text="遨菡" />
<TextBlock Width="120" Margin="0,1.5" Text="欧欧欧" />
<TextBlock Width="120" Margin="0,1.5" Text="Freezing" />
<TextBlock Width="120" Margin="0,1.5" Text="潜汐" />
<TextBlock Width="120" Margin="0,1.5" Text="waaiu" />
<TextBlock Width="120" Margin="0,1.5" Text="小劫" />
<TextBlock Width="120" Margin="0,1.5" Text="Lemon0904" />
<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="JiuJiu" />
<TextBlock Width="120" Margin="0,1.5" Text="阋yee" />
<TextBlock Width="120" Margin="0,1.5" Text="qsiwsi" />
<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="ZYX" />
<TextBlock Width="120" Margin="0,1.5" Text="玦" />
<TextBlock Width="120" Margin="0,1.5" Text="浬江河" />
<TextBlock Width="120" Margin="0,1.5" Text="ZERO" />
<TextBlock Width="120" Margin="0,1.5" Text="猫猫qwq" />
<TextBlock Width="120" Margin="0,1.5" Text="shark" />
<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="TTT" />
<TextBlock Width="120" Margin="0,1.5" Text="赵云撤" />
<TextBlock Width="120" Margin="0,1.5" Text="岩壑之崩" />
<TextBlock Width="120" Margin="0,1.5" Text="Fox Hound" />
<TextBlock Width="120" Margin="0,1.5" Text="Alon.E." />
<TextBlock Width="120" Margin="0,1.5" Text="湺" />
<TextBlock Width="120" Margin="0,1.5" Text="陳拾憶" />
<TextBlock Width="120" Margin="0,1.5" Text="kwzddz" />
<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="Q7" />
<TextBlock Width="120" Margin="0,1.5" Text="阿卡找你玩" />
<TextBlock Width="120" Margin="0,1.5" Text="月月" />
<TextBlock Width="120" Margin="0,1.5" Text="POCKY" />
<TextBlock Width="120" Margin="0,1.5" Text="橙子饱宝" />
<TextBlock Width="120" Margin="0,1.5" Text="空城风雨" />
<TextBlock Width="120" Margin="0,1.5" Text="Carlmu" />
<TextBlock Width="120" Margin="0,1.5" Text="日雨云曇" />
<TextBlock Width="120" Margin="0,1.5" Text="Caerphilly" />
<TextBlock Width="120" Margin="0,1.5" Text="Andy Wang" />
<TextBlock Width="120" Margin="0,1.5" Text="Kepler" />
<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="夜Ylz" />
<TextBlock Width="120" Margin="0,1.5" Text="不知道唉kk" />
<TextBlock Width="120" Margin="0,1.5" Text="墨染星云间" />
<TextBlock Width="120" Margin="0,1.5" Text="-Trespassin." />
<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="慕可OvO" />
<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="MOMOHAN" />
<TextBlock Width="120" Margin="0,1.5" Text="希瓦大陆_Hitable" />
<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="okufir" />
<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="Kakiko" />
<TextBlock Width="120" Margin="0,1.5" Text="摩卡茉莉" />
<TextBlock Width="120" Margin="0,1.5" Text="长忆安思" />
<TextBlock Width="120" Margin="0,1.5" Text="Solomon" />
<TextBlock Width="120" Margin="0,1.5" Text="博麗靈夢" />
<TextBlock Width="120" Margin="0,1.5" Text="CMMing" />
<TextBlock Width="120" Margin="0,1.5" Text="择日再起床" />
<TextBlock Width="120" Margin="0,1.5" Text="逆黑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="XingLing2333" />
<TextBlock Width="120" Margin="0,1.5" Text="Lesonmol" />
<TextBlock Width="120" Margin="0,1.5" Text="a" />
<TextBlock Width="120" Margin="0,1.5" Text="格拉索夫司机" />
<TextBlock Width="120" Margin="0,1.5" Text="LDG" />
<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="JadePolarise" />
<TextBlock Width="120" Margin="0,1.5" Text="不爱吃饭的Hog" />
<TextBlock Width="120" Margin="0,1.5" Text="莉莉大饺子" />
<TextBlock Width="120" Margin="0,1.5" Text="yu" />
<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="LordyTheQDuck" />
<TextBlock Width="120" Margin="0,1.5" Text="衔纸人" />
<TextBlock Width="120" Margin="0,1.5" Text="粉色妖精小姐?" />
<TextBlock Width="120" Margin="0,1.5" Text="kongfan" />
<TextBlock Width="120" Margin="0,1.5" Text="白杨之下" />
<TextBlock Width="120" Margin="0,1.5" Text="Eme.b" />
<TextBlock Width="120" Margin="0,1.5" Text="熊猫" />
<TextBlock Width="120" Margin="0,1.5" Text="颜5236" />
<TextBlock Width="120" Margin="0,1.5" Text="KK" />
<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="Escape Star" />
<TextBlock Width="120" Margin="0,1.5" Text="LSEN志恒" />
<TextBlock Width="120" Margin="0,1.5" Text="Azqs7109" />
<TextBlock Width="120" Margin="0,1.5" Text="艾雅法拉的狗" />
<TextBlock Width="120" Margin="0,1.5" Text="????????" />
<TextBlock Width="120" Margin="0,1.5" Text="LOWN" />
<TextBlock Width="120" Margin="0,1.5" Text="cuu7878" />
<TextBlock Width="120" Margin="0,1.5" Text="RemixQQ" />
<TextBlock Width="120" Margin="0,1.5" Text="CANYUEX" />
<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="wujijuan" />
<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="qq1967131327" />
<TextBlock Width="120" Margin="0,1.5" Text="sence4910" />
<TextBlock Width="120" Margin="0,1.5" Text="HilkK" />
<TextBlock Width="120" Margin="0,1.5" Text="ZThengao" />
<TextBlock Width="120" Margin="0,1.5" Text="玖镜Sama" />
<TextBlock Width="120" Margin="0,1.5" Text="Glx?" />
<TextBlock Width="120" Margin="0,1.5" Text="派大星" />
<TextBlock Width="120" Margin="0,1.5" Text="河边鸺葵" />
<TextBlock Width="120" Margin="0,1.5" Text="SoftSui" />
<TextBlock Width="120" Margin="0,1.5" Text="徐家胤" />
<TextBlock Width="120" Margin="0,1.5" Text="至夏" />
<TextBlock Width="120" Margin="0,1.5" Text="溯洄SWZM" />
<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="XLMX" />
<TextBlock Width="120" Margin="0,1.5" Text="雲墨丶雪风" />
<TextBlock Width="120" Margin="0,1.5" Text="每天都是上上签" />
<TextBlock Width="120" Margin="0,1.5" Text="Bright" />
<TextBlock Width="120" Margin="0,1.5" Text="UFO君" />
<TextBlock Width="120" Margin="0,1.5" Text="z001" />
<TextBlock Width="120" Margin="0,1.5" Text="琥色" />
<TextBlock Width="120" Margin="0,1.5" Text="MaxQi" />
<TextBlock Width="120" Margin="0,1.5" Text="姜淼淼" />
<TextBlock Width="120" Margin="0,1.5" Text="Chenluoxcly" />
<TextBlock Width="120" Margin="0,1.5" Text="南宫墨白" />
<TextBlock Width="120" Margin="0,1.5" Text="白晓" />
<TextBlock Width="120" Margin="0,1.5" Text="ChengYhy" />
<TextBlock Width="120" Margin="0,1.5" Text="陆壹" />
<TextBlock Width="120" Margin="0,1.5" Text="Agoni" />
<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="imsunxinhao" />
<TextBlock Width="120" Margin="0,1.5" Text="在我嘴里种水稻" />
<TextBlock Width="120" Margin="0,1.5" Text="浮世三千" />
<TextBlock Width="120" Margin="0,1.5" Text="blue sky" />
<TextBlock Width="120" Margin="0,1.5" Text="wujiayi" />
<TextBlock Width="120" Margin="0,1.5" Text="XIAOXI" />
<TextBlock Width="120" Margin="0,1.5" Text="景天鸽" />
<TextBlock Width="120" Margin="0,1.5" Text="24598" />
<TextBlock Width="120" Margin="0,1.5" Text="世谈茶楼" />
<TextBlock Width="120" Margin="0,1.5" Text="jwl" />
<TextBlock Width="120" Margin="0,1.5" Text="Saki" />
<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="neltharion" />
<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="lalailoveyou" />
<TextBlock Width="120" Margin="0,1.5" Text="EternalSinDusk" />
<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="BIOKL" />
<TextBlock Width="120" Margin="0,1.5" Text="你先别急" />
<TextBlock Width="120" Margin="0,1.5" Text="MuMAA" />
<TextBlock Width="240" Margin="0,1.5" Text="擻齺獼豳鏚嬼嬭鼬乸鑽麣覊" />
<TextBlock Width="120" Margin="0,1.5" Text="风眠" />
<TextBlock Width="120" Margin="0,1.5" Text="hgmzyyy" />
<TextBlock Width="120" Margin="0,1.5" Text="Danc1n9" />
<TextBlock Width="120" Margin="0,1.5" Text="doodo" />
<TextBlock Width="120" Margin="0,1.5" Text="FrostNova" />
<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="XU." />
<TextBlock Width="120" Margin="0,1.5" Text="八云源" />
<TextBlock Width="120" Margin="0,1.5" Text="qbn5" />
<TextBlock Width="120" Margin="0,1.5" Text="许诺霓虹" />
<TextBlock Width="120" Margin="0,1.5" Text="X-ran" />
<TextBlock Width="120" Margin="0,1.5" Text="微风" />
<TextBlock Width="120" Margin="0,1.5" Text="阿米诺斯" />
<TextBlock Width="120" Margin="0,1.5" Text="玄纪2006" />
<TextBlock Width="120" Margin="0,1.5" Text="666" />
<TextBlock Width="120" Margin="0,1.5" Text="恋某人-柏然" />
<TextBlock Width="120" Margin="0,1.5" Text="The_Crispy" />
<TextBlock Width="120" Margin="0,1.5" Text="电脑and病毒哥" />
<TextBlock Width="120" Margin="0,1.5" Text="W" />
<TextBlock Width="120" Margin="0,1.5" Text="jys" />
<TextBlock Width="120" Margin="0,1.5" Text="lonelife" />
<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="Jogycjh" />
<TextBlock Width="120" Margin="0,1.5" Text="F" />
<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="YanTY" />
<TextBlock Width="120" Margin="0,1.5" Text="勿念fmj" />
<TextBlock Width="120" Margin="0,1.5" Text="道瑶" />
<TextBlock Width="120" Margin="0,1.5" Text="JerryGo" />
<TextBlock Width="120" Margin="0,1.5" Text="HAJ_IMI" />
<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="Rock god-Morax" />
<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="HPLY" />
<TextBlock Width="120" Margin="0,1.5" Text="淡然a" />
<TextBlock Width="120" Margin="0,1.5" Text="白玉京" />
<TextBlock Width="120" Margin="0,1.5" Text="Ykir" />
<TextBlock Width="120" Margin="0,1.5" Text="三千" />
<TextBlock Width="120" Margin="0,1.5" Text="溪峡" />
<TextBlock Width="120" Margin="0,1.5" Text="avenqyx" />
<TextBlock Width="120" Margin="0,1.5" Text="xxz" />
<TextBlock Width="120" Margin="0,1.5" Text="tytd" />
<TextBlock Width="120" Margin="0,1.5" Text="yezhi" />
<TextBlock Width="120" Margin="0,1.5" Text="落子不悔" />
<TextBlock Width="120" Margin="0,1.5" Text="chenge886" />
<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="晨099" />
<TextBlock Width="120" Margin="0,1.5" Text="Ado" />
<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="Black_Banana_Cat" />
<TextBlock Width="120" Margin="0,1.5" Text="君染" />
<TextBlock Width="120" Margin="0,1.5" Text="XiaoMingPro" />
<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="123" />
<TextBlock Width="120" Margin="0,1.5" Text="Zikyeung" />
<TextBlock Width="120" Margin="0,1.5" Text="zzz_10728701" />
<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="zzzzzjy" />
<TextBlock Width="120" Margin="0,1.5" Text="南有乔树" />
<TextBlock Width="120" Margin="0,1.5" Text="wsaml" />
<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="HurgerLiPy" /> <TextBlock Width="120" Margin="0,1.5" Text="xsh" />
<TextBlock Width="120" Margin="0,1.5" Text="Crishen70400" /> <TextBlock Width="120" Margin="0,1.5" Text="ChatCTL" />
<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="山本樱桃不是df" /> <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="17382073935" /> <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="Lewis" />
<TextBlock Width="120" Margin="0,1.5" Text="熳ai" /> <TextBlock Width="120" Margin="0,1.5" Text="捞猴子的月亮呐" />
<TextBlock Width="120" Margin="0,1.5" Text="Rainbow Stars" /> <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="一只小孽QAQ" /> <TextBlock Width="120" Margin="0,1.5" Text="老乡老乡开开门" />
<TextBlock Width="120" Margin="0,1.5" Text="五度左右" /> <TextBlock Width="120" Margin="0,1.5" Text="dedf" />
<TextBlock Width="120" Margin="0,1.5" Text="咖喱鱼" /> <TextBlock Width="120" Margin="0,1.5" Text="Adminstrator" />
<TextBlock Width="120" Margin="0,1.5" Text="千叶GG" /> <TextBlock Width="120" Margin="0,1.5" Text="木子李" />
<TextBlock Width="120" Margin="0,1.5" Text="泽木_Zemu" /> <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="wuzhi718" />
<TextBlock Width="120" Margin="0,1.5" Text="琳" />
<TextBlock Width="120" Margin="0,1.5" Text="fycn" />
<TextBlock Width="120" Margin="0,1.5" Text="风铃末末?" />
<TextBlock Width="120" Margin="0,1.5" Text="漫游池塘中" />
<TextBlock Width="120" Margin="0,1.5" Text="james" />
<TextBlock Width="120" Margin="0,1.5" Text="jiekun" />
<TextBlock Width="120" Margin="0,1.5" Text="gugugugugu" />
<TextBlock Width="120" Margin="0,1.5" Text="Zomib" />
<TextBlock Width="120" Margin="0,1.5" Text="乱想的名字" />
<TextBlock Width="120" Margin="0,1.5" Text="fish" />
<TextBlock Width="120" Margin="0,1.5" Text="Kfeadow" />
<TextBlock Width="240" Margin="0,1.5" Text="MeltyAcoustAmber" />
<TextBlock Width="120" Margin="0,1.5" Text="Quan_Q" />
<TextBlock Width="120" Margin="0,1.5" Text="旋叶" />
<TextBlock Width="120" Margin="0,1.5" Text="YanXiaXia__" />
<TextBlock Width="120" Margin="0,1.5" Text="崩坏坏sama" />
<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="50MB" />
</WrapPanel> </WrapPanel>
<Grid Height="35"> <Grid Height="35">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -111,8 +111,9 @@
{"LaunchAdvanceGraphicCard", New SetupEntry(True, Source:=SetupSource.Registry)}, {"LaunchAdvanceGraphicCard", New SetupEntry(True, Source:=SetupSource.Registry)},
{"LaunchRamType", New SetupEntry(0)}, {"LaunchRamType", New SetupEntry(0)},
{"LaunchRamCustom", New SetupEntry(15)}, {"LaunchRamCustom", New SetupEntry(15)},
{"LinkOfflineHint", New SetupEntry(False, Source:=SetupSource.Registry)}, {"LinkLastAutoJoinInviteCode", New SetupEntry("", Source:=SetupSource.Registry)},
{"LinkShareMode", New SetupEntry(True, Source:=SetupSource.Registry)}, {"LinkShareMode", New SetupEntry(True, Source:=SetupSource.Registry)},
{"LinkCustomPeer", New SetupEntry("")},
{"LinkEasyTierVersion", New SetupEntry(-1, Source:=SetupSource.Registry)}, {"LinkEasyTierVersion", New SetupEntry(-1, Source:=SetupSource.Registry)},
{"ToolHelpChinese", New SetupEntry(True, Source:=SetupSource.Registry)}, {"ToolHelpChinese", New SetupEntry(True, Source:=SetupSource.Registry)},
{"ToolDownloadThread", New SetupEntry(63, Source:=SetupSource.Registry)}, {"ToolDownloadThread", New SetupEntry(63, Source:=SetupSource.Registry)},
@@ -86,14 +86,14 @@
</local:MyComboBox> </local:MyComboBox>
<local:MyTextBox Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="1" Margin="50,0,0,0" x:Name="TextArgumentWindowWidth" Tag="LaunchArgumentWindowWidth" Width="60" HorizontalContentAlignment="Center" Text="854"> <local:MyTextBox Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="1" Margin="50,0,0,0" x:Name="TextArgumentWindowWidth" Tag="LaunchArgumentWindowWidth" Width="60" HorizontalContentAlignment="Center" Text="854">
<local:MyTextBox.ValidateRules> <local:MyTextBox.ValidateRules>
<local:ValidateInteger Min="1" Max="9999" /> <local:ValidateInteger Min="1" Max="99999" />
</local:MyTextBox.ValidateRules> </local:MyTextBox.ValidateRules>
</local:MyTextBox> </local:MyTextBox>
<TextBlock x:Name="LabArgumentWindowMiddle" Visibility="Collapsed" Grid.Column="2" Text=" × " VerticalAlignment="Center" FontSize="18" /> <TextBlock x:Name="LabArgumentWindowMiddle" Visibility="Collapsed" Grid.Column="2" Text=" × " VerticalAlignment="Center" FontSize="18" />
<local:MyTextBox Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="3" Width="60" HorizontalContentAlignment="Center" x:Name="TextArgumentWindowHeight" Tag="LaunchArgumentWindowHeight" Text="480" <local:MyTextBox Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="3" Width="60" HorizontalContentAlignment="Center" x:Name="TextArgumentWindowHeight" Tag="LaunchArgumentWindowHeight" Text="480"
ToolTip="Forge 1.12.2 等个别版本存在 Bug,会导致高度设定无效" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5"> ToolTip="Forge 1.12.2 等个别版本存在 Bug,会导致高度设定无效" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5">
<local:MyTextBox.ValidateRules> <local:MyTextBox.ValidateRules>
<local:ValidateInteger Min="1" Max="9999" /> <local:ValidateInteger Min="1" Max="99999" />
</local:MyTextBox.ValidateRules> </local:MyTextBox.ValidateRules>
</local:MyTextBox> </local:MyTextBox>
</Grid> </Grid>
@@ -6,11 +6,32 @@
PanScroll="PanBack"> PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack"> <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10"> <StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="联机"> <local:MyCard Margin="0,15" Title="高级设置" IsSwapped="True" CanSwap="True">
<StackPanel Margin="25,40,25,20" Orientation="Vertical"> <Grid Margin="25,40,25,22">
<local:MyCheckBox Text="老好人模式" x:Name="CheckShareMode" Tag="LinkShareMode" Height="22" <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="15" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义节点" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextCustomPeer" Tag="LinkCustomPeer" Grid.Column="1" MaxHeight="28"
ToolTip="覆盖 PCL 所选择的节点,仅连接此处填写的节点。&#xa;如果你自己搭建了 EasyTier 节点,你可以用这个设置让 PCL 连接它。&#xa;&#xa;使用逗号分隔多个节点,例如:&#xa;tcp://public.easytier.cn:11010,tcp://public2.easytier.cn:54321&#xa;&#xa;房主和加入者必须连接到至少一个相同节点,才能互相连上。" />
<local:MyCheckBox Text="老好人模式" x:Name="CheckShareMode" Grid.Row="1" Tag="LinkShareMode" Height="22" Visibility="Collapsed"
ToolTip="启动联机后,用你的网络帮助其他玩家建立连接、降低延迟!&#xa;即使你不开启,开启了这个选项的其他玩家也会帮助你,不过,人人为我,我为人人嘛……" /> ToolTip="启动联机后,用你的网络帮助其他玩家建立连接、降低延迟!&#xa;即使你不开启,开启了这个选项的其他玩家也会帮助你,不过,人人为我,我为人人嘛……" />
</StackPanel> <StackPanel Orientation="Horizontal" Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Left">
<local:MyButton MinWidth="140" Padding="13,5" Margin="0,0,20,0" HorizontalAlignment="Left"
Text=" 光荣地贡献节点!" ColorType="Highlight"
ToolTip="联机功能全靠社区的各位无私贡献的节点才能存在!&#xa;如果你有空闲的服务器,欢迎搭建一个共享节点,人人为我,我为人人嘛……&#xa;&#xa;你可以在 EasyTier 的【搭建共享节点】文档中查看搭建方式,搭建好后点击这里提交。&#xa;PCL 会自动选取节点进行连接。"
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://uptime.easytier.cn/submit" />
<local:MyButton MinWidth="140" Padding="13,5" Margin="0,0,20,0" HorizontalAlignment="Left"
Text="节点状态"
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://uptime.easytier.cn/" />
</StackPanel>
</Grid>
</local:MyCard> </local:MyCard>
</StackPanel> </StackPanel>
</local:MyScrollViewer> </local:MyScrollViewer>
@@ -1,4 +1,4 @@
Class PageSetupLink Public Class PageSetupLink
Private Shadows IsLoaded As Boolean = False Private Shadows IsLoaded As Boolean = False
@@ -18,12 +18,14 @@
End Sub End Sub
Public Sub Reload() Public Sub Reload()
CheckShareMode.Checked = Setup.Get("LinkShareMode") CheckShareMode.Checked = Setup.Get("LinkShareMode")
TextCustomPeer.Text = Setup.Get("LinkCustomPeer")
End Sub End Sub
'初始化 '初始化
Public Sub Reset() Public Sub Reset()
Try Try
Setup.Reset("LinkShareMode") Setup.Reset("LinkShareMode")
Setup.Reset("LinkCustomPeer")
Log("[Setup] 已初始化联机页设置") Log("[Setup] 已初始化联机页设置")
Hint("已初始化联机页设置!", HintType.Green, False) Hint("已初始化联机页设置!", HintType.Green, False)
@@ -35,7 +37,7 @@
End Sub End Sub
'将控件改变路由到设置改变 '将控件改变路由到设置改变
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) 'Handles TextLinkName.ValidatedTextChanged Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextCustomPeer.ValidatedTextChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Text) If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Text)
End Sub End Sub
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckShareMode.Change Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckShareMode.Change
@@ -253,6 +253,7 @@
<local:MyComboBoxItem Content="OpenMCIM 仪表盘(作者:SALTWOOD)" Visibility="Collapsed" /> <local:MyComboBoxItem Content="OpenMCIM 仪表盘(作者:SALTWOOD)" Visibility="Collapsed" />
<local:MyComboBoxItem Content="杂志主页(作者:CreeperIsASpy)" /> <local:MyComboBoxItem Content="杂志主页(作者:CreeperIsASpy)" />
<local:MyComboBoxItem Content="PCL GitHub 仪表盘(作者:Deep-Dark-Forest)" /> <local:MyComboBoxItem Content="PCL GitHub 仪表盘(作者:Deep-Dark-Forest)" />
<local:MyComboBoxItem Content="Minecraft 更新摘要(作者:pynickle,部分由 AI 生成)" />
</local:MyComboBox> </local:MyComboBox>
</Grid> </Grid>
</StackPanel> </StackPanel>
@@ -1,6 +1,4 @@
Imports System.Threading.Tasks Public Class PageSpeedLeft
Public Class PageSpeedLeft
Private Const WatcherInterval As Integer = 300 Private Const WatcherInterval As Integer = 300
'初始化 '初始化
@@ -933,6 +933,8 @@
<ItemGroup> <ItemGroup>
<None Include="Resources\System.Net.Http.Formatting.dll" /> <None Include="Resources\System.Net.Http.Formatting.dll" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<Resource Include="Images\Heads\EasyTier.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project> </Project>
Binary file not shown.