龙腾猫跃 11 月之前
父节点
当前提交
efd480f06c
共有 24 个文件被更改,包括 1028 次插入 和 428 次删除
  1. 27 3
      Plain Craft Launcher 2/FormMain.xaml.vb
  2. 二进制
      Plain Craft Launcher 2/Images/Heads/EasyTier.png
  3. 48 4
      Plain Craft Launcher 2/Modules/Base/ModBase.vb
  4. 2 2
      Plain Craft Launcher 2/Modules/Base/ModLoader.vb
  5. 50 33
      Plain Craft Launcher 2/Modules/Base/ModNet.vb
  6. 1 6
      Plain Craft Launcher 2/Modules/Base/ModValidate.vb
  7. 9 2
      Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
  8. 12 0
      Plain Craft Launcher 2/Modules/ModEvent.vb
  9. 2 2
      Plain Craft Launcher 2/My Project/AssemblyInfo.vb
  10. 1 1
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml
  11. 2 1
      Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
  12. 3 0
      Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
  13. 1 1
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb
  14. 4 4
      Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml
  15. 255 140
      Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb
  16. 573 216
      Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
  17. 2 1
      Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb
  18. 2 2
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml
  19. 25 4
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml
  20. 4 2
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb
  21. 1 0
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml
  22. 1 3
      Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb
  23. 3 1
      Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj
  24. 二进制
      Plain Craft Launcher 2/Resources/Help.zip

+ 27 - 3
Plain Craft Launcher 2/FormMain.xaml.vb

@@ -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(SendWarning) Then Return
-        End If
+        If FrmLinkMain?.TryExit(Not SendWarning, True) Then Return
         '关闭
         '关闭
         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
 
 
     '文件拖放
     '文件拖放

二进制
Plain Craft Launcher 2/Images/Heads/EasyTier.png


+ 48 - 4
Plain Craft Launcher 2/Modules/Base/ModBase.vb

@@ -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 VersionStandardCode As String = "2.11.0." & VersionBranchCode '标准格式的四段式版本号
+    Public Const VersionBaseName As String = "2.11.1" '不含分支前缀的显示用版本名
+    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

+ 2 - 2
Plain Craft Launcher 2/Modules/Base/ModLoader.vb

@@ -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
Plain Craft Launcher 2/Modules/Base/ModNet.vb

@@ -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,
-                                            [Error])
+                                            "各下载源的错误如下:" & vbCrLf & Detail, [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

+ 1 - 6
Plain Craft Launcher 2/Modules/Base/ModValidate.vb

@@ -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 
-            Return "请输入一个整数!"
-        End If
-        If Not RegexCheck(Str, "^(-?0|-?[1-9]\d*)$") Then 
-            Return "请输入一个不带有前导零的整数!"
-        End If
+        If Not Integer.TryParse(Str, Valed) Then Return "请输入一个整数!"
         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 & "!"

+ 9 - 2
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb

@@ -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 AssetsIndexBehaviour <> AssetsIndexExistsBehaviour.AlwaysDownload AndAlso IndexFile.Check.Check(IndexFile.LocalPath) Is Nothing Then
+                    If IndexFile 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

+ 12 - 0
Plain Craft Launcher 2/Modules/ModEvent.vb

@@ -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

+ 2 - 2
Plain Craft Launcher 2/My Project/AssemblyInfo.vb

@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
 ' 方法是按如下所示使用“*”
 ' 方法是按如下所示使用“*”
 
 
-<Assembly: AssemblyVersion("2.11.0.0")>
-<Assembly: AssemblyFileVersion("2.11.0.0")>
+<Assembly: AssemblyVersion("2.11.1.0")>
+<Assembly: AssemblyFileVersion("2.11.1.0")>
 <Assembly: NeutralResourcesLanguage("")>
 <Assembly: NeutralResourcesLanguage("")>

+ 1 - 1
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml

@@ -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" />

+ 2 - 1
Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb

@@ -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

+ 3 - 0
Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb

@@ -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
         '联网下载
         '联网下载

+ 1 - 1
Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb

@@ -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)

+ 4 - 4
Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml

@@ -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}"
-                                    ToolTip="服务器 IP ( 点击复制 )" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="50" ToolTipService.VerticalOffset="40" ToolTipService.HorizontalOffset="4">
+                        <StackPanel x:Name="BtnFinishIp" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
+                                    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>

+ 255 - 140
Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb

@@ -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)
-        If State = NewState Then Return
-        Dim OldState = State
-        State = NewState
+    Private Sub ChangeState(NewState As LinkStates)
+        If LinkState = NewState Then Return
+        Dim OldState = LinkState
+        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.PanFinish.Visibility = If(State = States.Finished, Visibility.Visible, Visibility.Collapsed)
+        FrmLinkMain.PanSelect.Visibility = If(LinkState = LinkStates.Waiting, 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 Sub Join_MouseLeftButtonUp() Handles PanSelectJoin.MouseLeftButtonUp
-        '输入邀请码
+    Private Shared LastCode As String = Nothing
+    ''' <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
-            If Code.StartsWithF("U/") Then 'HMCL
-                Hint("请让房主使用 PCL 创建房间!", 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
+        Dim ValidateResult = ValidateCodeFormat(Code)
+        If ValidateResult IsNot Nothing Then
+            Hint(ValidateResult, HintType.Red)
             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}" '"如果提示无效会话,不要退出联机房间,重新启动游戏即可!"
-            BtnFinishCopy.Text = "复制地址"
+            LabFinishDesc.Text = $"在多人游戏页面的最下方就能找到联机房间!{vbCrLf}注意:使用离线登录时不要手动输入 IP!"
             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
-        If State = States.Waiting OrElse State = States.Failed Then Return False
-        If IsServerSide AndAlso PeopleCount > 1 Then
-            If MyMsgBox("你确定要关闭联机房间吗?" & vbCrLf & "所有玩家都需要重新输入邀请码才可加入游戏!", "关闭房间", "确定", "取消", IsWarn:=True) = 2 Then Return True
+    Public Function TryExit(Slient As Boolean, Closing As Boolean) As Boolean
+        If LinkState = LinkStates.Waiting OrElse LinkState = LinkStates.Failed Then Return False
+        If Not Slient Then
+            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
-            ClipboardSet($"在 PCL 启动器中输入邀请码【{NetworkName}-{NetworkSecret}】,即可加入联机房间!", False)
-            Hint("已复制邀请码!", HintType.Green)
-        Else
-            ClipboardSet(ClientAddress, False)
-            Hint("已复制服务器地址!", HintType.Green)
-        End If
+        Dim CodeText As String = $"在 PCL 启动器中输入邀请码【{NetworkName}-{NetworkSecret}】,即可加入联机房间!"
+        ClipboardSet(CodeText, False)
+        Setup.Set("LinkLastAutoJoinInviteCode", CodeText)
+        Hint("已复制邀请码!", HintType.Green)
+    End Sub
+
+    '复制 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:{Port}"
-            Arguments += $" --port-forward tcp://[{IPAddress.IPv6Loopback}]:{Port}/10.114.114.114:{ServerPort}"
-            Arguments += $" --port-forward udp://[{IPAddress.IPv6Loopback}]:{Port}/10.114.114.114:{ServerPort}"
-            Arguments += $" --port-forward tcp://{IPAddress.Loopback}:{Port}/10.114.114.114:{ServerPort}"
-            Arguments += $" --port-forward udp://{IPAddress.Loopback}:{Port}/10.114.114.114:{ServerPort}"
+            ClientAddress = $"localhost:{ClientPort}"
+            Arguments += $" --port-forward tcp://[{IPAddress.IPv6Loopback}]:{ClientPort}/10.114.114.114:{ServerPort}"
+            Arguments += $" --port-forward udp://[{IPAddress.IPv6Loopback}]:{ClientPort}/10.114.114.114:{ServerPort}"
+            Arguments += $" --port-forward tcp://{IPAddress.Loopback}:{ClientPort}/10.114.114.114:{ServerPort}"
+            Arguments += $" --port-forward udp://{IPAddress.Loopback}:{ClientPort}/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)
-            '具体每个部分的索引见 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))
+        Public Sub New(Info As JObject)
             '类别
             '类别
-            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 GetUuid() Mod If(ModeDebug, 4, 30) = 0 Then Log("[EasyTier] CLI 输出抽样:" & vbCrLf & CliResult)
+            If Not CliResult.Contains("lat_ms") Then Throw New Exception("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 PingTargets As IEnumerable(Of Peer)
+        Dim Peer = GetTargetPeer()
+        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
-        Else
-            PingTargets = Peers.Where(Function(p) p.Type = Peer.Types.Server)
-        End If
-        If Not PingTargets.Any Then
-            Return 0
+            Targets = Peers.Where(Function(p) p.Ping > 0)
         Else
         Else
-            Return Math.Max(1, PingTargets.Select(Function(p) p.Ping).Min())
+            Targets = Peers.Where(Function(p) p.Type = Peer.Types.Server AndAlso p.Ping > 0)
         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>
     ''' 检查联机模块是否崩溃。
     ''' 检查联机模块是否崩溃。

+ 573 - 216
Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml

@@ -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="Patrick" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="设计并制作了 PCL 图标,让我从做图标的水深火热中得到了解脱……" Grid.Row="4" Grid.Column="1" />
-                    <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="Minecraft 中文论坛" Margin="-5,0,15,0" IsHitTestVisible="False" Info="虽然已经关站了,但感谢此前提供了 MCBBS 镜像源……" Grid.Row="6" 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="EasyTier" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了联机模块!" Grid.Row="3" 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="00ll00" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 Java Launch Wrapper 和一些重要服务支持!" Grid.Row="4" 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="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>
+                            <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
+                        </Image.Clip>
+                    </Image>
+                    <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/Patrick.png" Grid.Row="4" 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/Hao_Tian.jpg" Grid.Row="5" 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/MCBBS.png" Grid.Row="6" Margin="3">
+                    <Image Source="/Plain Craft Launcher 2;component/Images/Heads/MCBBS.png" Grid.Row="7" 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/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" />
-                    <WrapPanel Margin="0,0,0,10">
                        <TextBlock Width="120" Margin="0,1.5" Text="lecoe" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="QIUQI" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Aquadtr" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="stb" />
-                        <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="Le Play" />
-                        <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="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="lIIIllIIllIIl" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Zsol" />
-                        <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="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="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="Amturester" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="maigm" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="JO23" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="JCNB" />
-                        <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="AkaneRyoba" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="南山必胜客" />
-                        <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="shawnlong" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="DDNGSZX1" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="KaguraZaka" />
-                        <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="betwangzai" />
-                        <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="TH-x" />
-                        <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="P·咕·D·咕咕·F" />
-                        <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="240" Margin="0,1.5" Text="月下誓约,予爱以心" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="超级白给马" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="fwlqpalzmd" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="安执妄dying" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="黄开心" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="于是" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="荆槐序" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="三千游魂" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="^ ^" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="zz" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="爱炫鱼的猫" />
+                    <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="阿瓦达" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="不若" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Albus" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="牛马" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="溯" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="他" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="寂静之空" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="断约" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="跑不快的啊走" />
+                        <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="漓九云" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Ding" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="yi9999" />
+                        <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="阿辉" />
+                        <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="MingChuYa" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="S????? . ?" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="吴傻傻" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="会忘记九月嘛" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="咸鱼猫猫" />
+                        <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="emm" />
+                        <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="左" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Crocoldilopolis" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="!" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="风息" />
+                        <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="廾匸" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="称之为翀" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="山海." />
+                        <TextBlock Width="120" Margin="0,1.5" Text="巫元dry" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="墨羽" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="暮秋知岁寒" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="司南" />
+                        <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="SquareBlock" />
+                        <TextBlock Width="240" Margin="0,1.5" Text="失去梦想的GGbond" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Kuni" />
+                        <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="kirito" />
+                        <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="trav" />
+                        <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="翁" />
+                        <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="许愿流星雨" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="YiHuwuyue" />
+                        <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="浪浪天" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="西行寺叶叶子" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="覃丘丘" />
+                        <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="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="CT" />
+                        <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="Jcey" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Nefelibata." />
+                        <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="扔完炸药掏蜂鸟" />
+                        <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="白葉白不白" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="沐晨" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="。" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="哎呀呀" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="龙仔" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="六百六十六" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="剑瘗千秋" />
+                        <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="240" Margin="0,1.5" Text="NORMAL_MAN36" />
+                        <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="镜像折叠" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="留不住的刹那" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="." />
+                        <TextBlock Width="120" Margin="0,1.5" Text="朱小楠" />
+                        <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="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="赢于" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="夏目心" />
+                        <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="皮皮狗我们走" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="卜部美琴" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="商枝" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="嫑喊我" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="流星与朝阳" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="呀呼" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="EasyOrange" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="MATH算珠" />
+                        <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="Tenno" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="酒奇" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="笑叹" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="今晚不熬夜" />
+                        <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="lxh123123123" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="瓷" />
+                        <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="Y先生" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="万兔森罗" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="携酒迎春风" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="消逝" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="昭苏" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="卡卡卡卡啊" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="鱿倪克" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="彺钰" />
+                        <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="WLan" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="457ssu" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="liu" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="贤" />
                         <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="Lucien_Liu" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="煎bingo子" />
+                        <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="hakureireimu" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="wwxa2019" />
-                        <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="Jane" />
-                        <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="ATH9" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="教主" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="落雪有声" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="苏子霄" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="一握砂" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="马春明" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="远力高" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="玉米片" />
-                        <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="准江月" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="蓝叶" />
-                        <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="Styx誓约" />
-                        <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="A" />
-                        <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="Ashlxy" />
-                        <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="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="基围虾" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="山有木兮325" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="37号村民" />
-                        <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="NeonSoda" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="UNICORN" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="红石beaker" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="EliasLSK" />
-                        <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="FAMS" />
-                        <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="深海带鱼" />
-                        <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="@6#" />
-                        <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="AAALLLAAANNN" />
-                        <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="八云蓝LIN" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="LittleBlue" />
-                        <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="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="1111111" />
-                        <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="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="240" Margin="0,1.5" Text="小狗很担心你有没有好好喝水" />
-                        <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="林琴科" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="北雁蘿蔔" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="墨雪竹" />
+                        <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="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="PickStars" />
-                        <TextBlock Width="240" Margin="0,1.5" Text="我真的事仁济啊(恼)" />
+                        <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="Crishen70400" />
-                        <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="17382073935" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="不知道" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="重庆你周哥" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="熳ai" />
-                        <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="一只小孽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="千叶GG" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="泽木_Zemu" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="xsh" />
+                        <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="天绫绫地宁宁" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="无敌百搭的款式" />
+                        <TextBlock Width="240" Margin="0,1.5" Text="没事还有俾斯麦兜底" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Lewis" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="捞猴子的月亮呐" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="活着是为了摆烂" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="浔。" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="周南何" />
+                        <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="Adminstrator" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="木子李" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="文刀木头鱼" />
+                        <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>

+ 2 - 1
Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb

@@ -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)},

+ 2 - 2
Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml

@@ -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>

+ 25 - 4
Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml

@@ -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="联机">
-                <StackPanel Margin="25,40,25,20" Orientation="Vertical">
-                    <local:MyCheckBox Text="老好人模式" x:Name="CheckShareMode" Tag="LinkShareMode" Height="22"
+            <local:MyCard Margin="0,15" Title="高级设置" IsSwapped="True" CanSwap="True">
+                <Grid Margin="25,40,25,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>

+ 4 - 2
Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb

@@ -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

+ 1 - 0
Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml

@@ -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 - 3
Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb

@@ -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
 
 
     '初始化
     '初始化

+ 3 - 1
Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj

@@ -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>

二进制
Plain Craft Launcher 2/Resources/Help.zip