|
@@ -1,204 +1,10 @@
|
|
|
-Imports System.Net
|
|
|
|
|
-Imports System.Net.Sockets
|
|
|
|
|
|
|
+Imports System.Net.Sockets
|
|
|
|
|
|
|
|
Public Class PageLinkIoi
|
|
Public Class PageLinkIoi
|
|
|
Public Const RequestVersion As Integer = 4
|
|
Public Const RequestVersion As Integer = 4
|
|
|
Public Const IoiVersion As Integer = 10 '由于已关闭更新渠道,在提升 IoiVersion 时必须提升 RequestVersion
|
|
Public Const IoiVersion As Integer = 10 '由于已关闭更新渠道,在提升 IoiVersion 时必须提升 RequestVersion
|
|
|
Public Shared PathIoi As String = PathAppdata & "联机模块\IOI 联机模块.exe"
|
|
Public Shared PathIoi As String = PathAppdata & "联机模块\IOI 联机模块.exe"
|
|
|
|
|
|
|
|
-#Region "初始化"
|
|
|
|
|
-
|
|
|
|
|
- '页面初始化
|
|
|
|
|
- Private IsLoad As Boolean = False
|
|
|
|
|
- Private Sub MeLoaded() Handles Me.Loaded
|
|
|
|
|
- FormMain.EndProgramForce(Result.Aborted)
|
|
|
|
|
-
|
|
|
|
|
- '重复加载部分
|
|
|
|
|
- PanBack.ScrollToHome()
|
|
|
|
|
- RefreshUi()
|
|
|
|
|
-
|
|
|
|
|
- '非重复加载部分
|
|
|
|
|
- If IsLoad Then Exit Sub
|
|
|
|
|
- IsLoad = True
|
|
|
|
|
-
|
|
|
|
|
- '更新线程
|
|
|
|
|
- RunInNewThread(Sub()
|
|
|
|
|
- Do While True
|
|
|
|
|
- Thread.Sleep(200)
|
|
|
|
|
- If FrmMain.PageCurrent.Page = FormMain.PageType.Link AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.LinkIoi Then RunInUiWait(Sub() FrmLinkIoi.RefreshUi())
|
|
|
|
|
- RefreshWorker()
|
|
|
|
|
- Loop
|
|
|
|
|
- End Sub, "Link Timer")
|
|
|
|
|
-
|
|
|
|
|
- End Sub
|
|
|
|
|
-
|
|
|
|
|
- '加载器初始化与左边栏处理
|
|
|
|
|
- Private Sub LoaderInit() Handles Me.Initialized
|
|
|
|
|
- PageLoaderInit(Load, PanLoad, PanBack, PanAlways, InitLoader, Sub()
|
|
|
|
|
- End Sub)
|
|
|
|
|
- End Sub
|
|
|
|
|
-
|
|
|
|
|
- '初始化加载器与步骤
|
|
|
|
|
- Public Shared WithEvents InitLoader As New LoaderCombo(Of Integer)("联机模块初始化", {
|
|
|
|
|
- New LoaderTask(Of Integer, Integer)("端口检查", AddressOf InitPortCheck) With {.ProgressWeight = 1},
|
|
|
|
|
- New LoaderTask(Of Integer, Integer)("启动请求核心", AddressOf StartSocketListener) With {.ProgressWeight = 1},
|
|
|
|
|
- New LoaderTask(Of Integer, List(Of NetFile))("初次启动尝试", AddressOf InitFirst) With {.ProgressWeight = 4},
|
|
|
|
|
- New LoaderDownload("下载更新文件", New List(Of NetFile)) With {.ProgressWeight = 6},
|
|
|
|
|
- New LoaderTask(Of List(Of NetFile), Boolean)("二次启动尝试", AddressOf InitSecond) With {.ProgressWeight = 3},
|
|
|
|
|
- New LoaderTask(Of Boolean, Boolean)("创建请求核心房间", AddressOf InitRequest) With {.ProgressWeight = 2}
|
|
|
|
|
- })
|
|
|
|
|
- '判断端口是否被占用
|
|
|
|
|
- Private Shared Sub InitPortCheck()
|
|
|
|
|
- '检查协议
|
|
|
|
|
- If Not Setup.Get("LinkEula") Then
|
|
|
|
|
-Reopen:
|
|
|
|
|
- Select Case MyMsgBox("PCL 的联机服务由速聚授权提供。" & vbCrLf & "在使用前,你需要同意速聚的用户服务协议和隐私政策。", "协议授权", "同意", "拒绝", "查看用户服务协议和隐私政策")
|
|
|
|
|
- Case 1
|
|
|
|
|
- Setup.Set("LinkEula", True)
|
|
|
|
|
- Case 2
|
|
|
|
|
- Throw New Exception("你拒绝了用户服务协议……")
|
|
|
|
|
- Case 3
|
|
|
|
|
- OpenWebsite("https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxMTMyODk3Mg==&action=getalbum&album_id=2585385685407514625&scene=173&from_msgid=2247483720&from_itemidx=1&count=3&nolastread=1#wechat_redirect")
|
|
|
|
|
- GoTo Reopen
|
|
|
|
|
- End Select
|
|
|
|
|
- End If
|
|
|
|
|
- '先掐死
|
|
|
|
|
- IoiStop(True)
|
|
|
|
|
- '检查端口
|
|
|
|
|
- Dim HasConflict As Boolean = False
|
|
|
|
|
- For Each Port In Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()
|
|
|
|
|
- If Port.Port <> 55555 AndAlso Port.Port <> 55557 Then Continue For
|
|
|
|
|
- Log("[IOI] 发现端口 " & Port.Port & " 被占用")
|
|
|
|
|
- HasConflict = True
|
|
|
|
|
- Next
|
|
|
|
|
- If Not HasConflict Then Exit Sub
|
|
|
|
|
- '对应的报错
|
|
|
|
|
- For Each Line As String In ShellAndGetOutput("netstat", "-ano", 30000).Split({vbCrLf}, StringSplitOptions.RemoveEmptyEntries)
|
|
|
|
|
- If Not (Line.Contains("127.0.0.1:55555") OrElse Line.Contains("127.0.0.1:55557")) Then Continue For
|
|
|
|
|
- Dim ProcessName As String
|
|
|
|
|
- Try
|
|
|
|
|
- ProcessName = Process.GetProcessById(Line.Split(" ").Last).ProcessName
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "获取占用端口的进程信息失败,假定进程已结束")
|
|
|
|
|
- Continue For
|
|
|
|
|
- End Try
|
|
|
|
|
- If ProcessName = "联机模块" Then
|
|
|
|
|
- Throw New Exception("由于一个已知问题,请在重启电脑后再尝试使用联机功能")
|
|
|
|
|
- ElseIf ProcessName = "Idle" Then
|
|
|
|
|
- '不知道为啥反正又没占用了
|
|
|
|
|
- Log("[IOI] 未发现占用此端口的程序,继续执行")
|
|
|
|
|
- Else
|
|
|
|
|
- Throw New Exception("端口被程序 " & ProcessName & " 占用,无法启动联机模块,请在任务管理器关闭此程序后再试")
|
|
|
|
|
- End If
|
|
|
|
|
- Next
|
|
|
|
|
- End Sub
|
|
|
|
|
- '下载更新前尝试启动
|
|
|
|
|
- Private Shared Sub InitFirst(Task As LoaderTask(Of Integer, List(Of NetFile)))
|
|
|
|
|
- '初次启动尝试
|
|
|
|
|
- If IoiVersion <> Setup.Get("LinkIoiVersion") Then
|
|
|
|
|
- Log("[IOI] 设置版本强制要求联机模块更新")
|
|
|
|
|
- Setup.Set("LinkIoiVersion", IoiVersion)
|
|
|
|
|
- ElseIf File.Exists(PathIoi) Then
|
|
|
|
|
- Task.Progress = 0.2
|
|
|
|
|
- CheckFirewall()
|
|
|
|
|
- If IoiStart() Then
|
|
|
|
|
- '已完成启动与初始化
|
|
|
|
|
- Task.Output = New List(Of NetFile)
|
|
|
|
|
- Exit Sub
|
|
|
|
|
- Else
|
|
|
|
|
- '需要更新
|
|
|
|
|
- IoiStop(True)
|
|
|
|
|
- File.Delete(PathIoi)
|
|
|
|
|
- GoTo StartDownload
|
|
|
|
|
- End If
|
|
|
|
|
- '如果抛出异常则直接使加载器失败
|
|
|
|
|
- End If
|
|
|
|
|
- '开始下载
|
|
|
|
|
-StartDownload:
|
|
|
|
|
- Task.Progress = 0.8
|
|
|
|
|
- Log("[IOI] 需要下载联机模块")
|
|
|
|
|
- If File.Exists(PathTemp & "联机模块.zip") Then File.Delete(PathTemp & "联机模块.zip")
|
|
|
|
|
- Task.Output = New List(Of NetFile) From {New NetFile(
|
|
|
|
|
- {"https://gitcode.net/to/cato_bin/-/raw/master/ioi_v2_x" & If(Is32BitSystem, 32, 64) & ".zip",
|
|
|
|
|
- "http://mirror.hiper.cn.s2.the.bb/ioi_v2_x" & If(Is32BitSystem, 32, 64) & ".zip",
|
|
|
|
|
- "http://mirror.hiper.cn.s3.the.bb:175/ioi_v2_x" & If(Is32BitSystem, 32, 64) & ".zip",
|
|
|
|
|
- "https://pcl2-server-1253424809.file.myqcloud.com/link/ioi_v2_x" & If(Is32BitSystem, 32, 64) & ".zip{CDN}"},
|
|
|
|
|
- PathTemp & "联机模块.zip")}
|
|
|
|
|
- End Sub
|
|
|
|
|
- '下载更新后尝试启动
|
|
|
|
|
- Private Shared Sub InitSecond(Task As LoaderTask(Of List(Of NetFile), Boolean))
|
|
|
|
|
- '若首次尝试已经成功,则直接跳过
|
|
|
|
|
- If IoiState = LoadState.Finished Then Exit Sub
|
|
|
|
|
- '解压更新包
|
|
|
|
|
- Log("[IOI] 解压联机模块以完成下载")
|
|
|
|
|
- If File.Exists(PathTemp & "ioi.exe") Then File.Delete(PathTemp & "ioi.exe")
|
|
|
|
|
- If File.Exists(PathIoi) Then File.Delete(PathIoi)
|
|
|
|
|
- ExtractFile(PathTemp & "联机模块.zip", PathTemp)
|
|
|
|
|
- File.Delete(PathTemp & "联机模块.zip")
|
|
|
|
|
- CopyFile(PathTemp & "ioi.exe", PathIoi)
|
|
|
|
|
- File.Delete(PathTemp & "ioi.exe")
|
|
|
|
|
- Task.Progress = 0.4
|
|
|
|
|
- '再次尝试启动
|
|
|
|
|
- CheckFirewall()
|
|
|
|
|
- If IoiStart() Then Exit Sub
|
|
|
|
|
- IoiStop(True)
|
|
|
|
|
- Throw New Exception("联机模块初始化失败")
|
|
|
|
|
- End Sub
|
|
|
|
|
- '在 IOI 启动后建立 55557 房间
|
|
|
|
|
- Private Shared Sub InitRequest()
|
|
|
|
|
- Try
|
|
|
|
|
- Dim Result As JObject = GetJson(NetRequestOnce("http://127.0.0.1:55555/api/port?proto=tcp&port=55557" & "&password=" & IoiPassword, "PUT", "", "", 100000))
|
|
|
|
|
- If Result("msg") IsNot Nothing Then Throw New InvalidOperationException(Result("msg").ToString)
|
|
|
|
|
- Catch ex As InvalidOperationException
|
|
|
|
|
- 'API 返回的错误
|
|
|
|
|
- Log("创建请求核心房间失败:" & ex.Message, LogLevel.Msgbox)
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- '常规错误
|
|
|
|
|
- Log(ex, "创建请求核心房间失败", LogLevel.Msgbox)
|
|
|
|
|
- End Try
|
|
|
|
|
- End Sub
|
|
|
|
|
-
|
|
|
|
|
- '检查防火墙权限,并添加对应的权限
|
|
|
|
|
- Private Shared Sub CheckFirewall()
|
|
|
|
|
- Try
|
|
|
|
|
- Log("[IOI] Windows 防火墙:检测开始")
|
|
|
|
|
- If Not PageLinkLeft.FirewallIsBlock(PathIoi) Then Exit Try
|
|
|
|
|
- If PageLinkLeft.FirewallPolicy.CurrentProfile.ExceptionsNotAllowed Then
|
|
|
|
|
- '禁止白名单
|
|
|
|
|
- MyMsgBox("由于 Windows 防火墙阻止了所有传入连接,PCL 无法获取防火墙通行权限。" & vbCrLf &
|
|
|
|
|
- "联机会有很大概率失败,就算连上了,延迟也会变高……" & vbCrLf & vbCrLf &
|
|
|
|
|
- "请先关闭 Windows 防火墙中的 " & vbLQ & "阻止所有传入连接" & vbRQ & " 选项,然后重启 PCL。", "遭到防火墙拦截")
|
|
|
|
|
- ElseIf IsAdmin() Then
|
|
|
|
|
- '有管理员权限
|
|
|
|
|
- Log("[IOI] Windows 防火墙:尝试添加防火墙通行权限")
|
|
|
|
|
- Try
|
|
|
|
|
- PageLinkLeft.FirewallAddAuthorized("Plain Craft Launcher 启动器(IOI 联机模块)", PathIoi)
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "无法将联机模块添加至防火墙白名单,可能导致联机失败", LogLevel.Msgbox)
|
|
|
|
|
- End Try
|
|
|
|
|
- Else
|
|
|
|
|
- '无管理员权限
|
|
|
|
|
- If MyMsgBox("由于你开启了 Windows 防火墙,PCL 需要获取防火墙通行权限。" & vbCrLf & vbCrLf &
|
|
|
|
|
- "若继续,PCL 将尝试以管理员权限重新启动。" & vbCrLf &
|
|
|
|
|
- "若拒绝,联机模块可能会被防火墙拦截,联机会有很大概率失败。", "需要管理员权限", "继续", "拒绝") = 1 Then
|
|
|
|
|
- Log("[IOI] Windows 防火墙:尝试提升权限")
|
|
|
|
|
- If RunAsAdmin("--link ioi") Then
|
|
|
|
|
- FrmMain.EndProgram(False) '已重新运行
|
|
|
|
|
- Else
|
|
|
|
|
- Hint("获取管理员权限失败,请尝试右键 PCL,选择 " & vbLQ & "以管理员身份运行" & vbRQ & ",然后再进入联机页面!", HintType.Critical)
|
|
|
|
|
- End If
|
|
|
|
|
- Else
|
|
|
|
|
- Hint("在没有防火墙权限的情况下尝试联机,很可能会导致联机失败!", HintType.Critical)
|
|
|
|
|
- End If
|
|
|
|
|
- End If
|
|
|
|
|
- Log("[IOI] Windows 防火墙:无防火墙通行权限")
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "无法检测防火墙状态,可能导致联机失败", LogLevel.Msgbox)
|
|
|
|
|
- End Try
|
|
|
|
|
- End Sub
|
|
|
|
|
-
|
|
|
|
|
-#End Region
|
|
|
|
|
-
|
|
|
|
|
#Region "进程管理"
|
|
#Region "进程管理"
|
|
|
|
|
|
|
|
Private Shared IoiId As String, IoiPassword As String
|
|
Private Shared IoiId As String, IoiPassword As String
|
|
@@ -209,38 +15,7 @@ StartDownload:
|
|
|
''' 若 Ioi 正在运行,则结束 Ioi 进程,同时初始化状态数据。返回是否关闭了对应进程。
|
|
''' 若 Ioi 正在运行,则结束 Ioi 进程,同时初始化状态数据。返回是否关闭了对应进程。
|
|
|
''' </summary>
|
|
''' </summary>
|
|
|
Public Shared Function IoiStop(SleepWhenKilled As Boolean) As Boolean
|
|
Public Shared Function IoiStop(SleepWhenKilled As Boolean) As Boolean
|
|
|
- IoiStop = False
|
|
|
|
|
- '发送断开信息
|
|
|
|
|
- Try
|
|
|
|
|
- If IoiProcess IsNot Nothing AndAlso Not IoiProcess.HasExited Then
|
|
|
|
|
- For i = 0 To UserList.Count - 1
|
|
|
|
|
- If i > UserList.Count - 1 Then Exit For
|
|
|
|
|
- Dim User = UserList.Values(i)
|
|
|
|
|
- SendDisconnectRequest(User)
|
|
|
|
|
- Next
|
|
|
|
|
- End If
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "结束 IOI 进程时发送 Disconnect 信息失败")
|
|
|
|
|
- End Try
|
|
|
|
|
- '关闭所有 Ioi 进程
|
|
|
|
|
- For Each ProcessObject In Process.GetProcesses
|
|
|
|
|
- If ProcessObject.ProcessName <> "IOI 联机模块" Then Continue For
|
|
|
|
|
- IoiStop = True
|
|
|
|
|
- Try
|
|
|
|
|
- ProcessObject.Kill()
|
|
|
|
|
- Log("[IOI] 已关闭联机模块:" & ProcessObject.Id)
|
|
|
|
|
- If SleepWhenKilled Then Thread.Sleep(3000) '等待 3 秒确认进程已退出
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "关闭联机模块失败(" & ProcessObject.Id & ")")
|
|
|
|
|
- End Try
|
|
|
|
|
- Next
|
|
|
|
|
- '初始化
|
|
|
|
|
- IoiProcess = Nothing
|
|
|
|
|
- IoiId = Nothing
|
|
|
|
|
- IoiPassword = Nothing
|
|
|
|
|
- IoiState = LoadState.Waiting
|
|
|
|
|
- UserList = New Dictionary(Of String, LinkUserIoi)
|
|
|
|
|
- RoomListForMe = New List(Of RoomEntry)
|
|
|
|
|
|
|
+ Return False
|
|
|
End Function
|
|
End Function
|
|
|
''' <summary>
|
|
''' <summary>
|
|
|
''' 启动 Ioi,并等待初始化完成后退出运行,同时更新 IoiId 与 IoiPassword。
|
|
''' 启动 Ioi,并等待初始化完成后退出运行,同时更新 IoiId 与 IoiPassword。
|
|
@@ -248,130 +23,11 @@ StartDownload:
|
|
|
''' 若 Ioi 正在运行,则会先停止其运行。
|
|
''' 若 Ioi 正在运行,则会先停止其运行。
|
|
|
''' </summary>
|
|
''' </summary>
|
|
|
Public Shared Function IoiStart() As Boolean
|
|
Public Shared Function IoiStart() As Boolean
|
|
|
- IoiStop(True)
|
|
|
|
|
- Log("[IOI] 启动联机模块进程")
|
|
|
|
|
- Dim Info = New ProcessStartInfo With {
|
|
|
|
|
- .FileName = PathIoi,
|
|
|
|
|
- .UseShellExecute = False,
|
|
|
|
|
- .CreateNoWindow = True,
|
|
|
|
|
- .RedirectStandardError = True,
|
|
|
|
|
- .RedirectStandardOutput = True,
|
|
|
|
|
- .WorkingDirectory = PathTemp
|
|
|
|
|
- }
|
|
|
|
|
- IoiProcess = New Process() With {.StartInfo = Info}
|
|
|
|
|
- Using outputWaitHandle As New AutoResetEvent(False)
|
|
|
|
|
- Using errorWaitHandle As New AutoResetEvent(False)
|
|
|
|
|
- AddHandler IoiProcess.OutputDataReceived, Function(sender, e)
|
|
|
|
|
- Try
|
|
|
|
|
- If e.Data Is Nothing Then
|
|
|
|
|
- outputWaitHandle.[Set]()
|
|
|
|
|
- Else
|
|
|
|
|
- IoiLogLine(e.Data)
|
|
|
|
|
- End If
|
|
|
|
|
- Catch ex As ObjectDisposedException
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "读取联机模块信息失败")
|
|
|
|
|
- IoiState = LoadState.Failed
|
|
|
|
|
- End Try
|
|
|
|
|
- Return Nothing
|
|
|
|
|
- End Function
|
|
|
|
|
- AddHandler IoiProcess.ErrorDataReceived, Function(sender, e)
|
|
|
|
|
- Try
|
|
|
|
|
- If e.Data Is Nothing Then
|
|
|
|
|
- errorWaitHandle.[Set]()
|
|
|
|
|
- Else
|
|
|
|
|
- IoiLogLine(e.Data)
|
|
|
|
|
- End If
|
|
|
|
|
- Catch ex As ObjectDisposedException
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "读取联机模块错误信息失败")
|
|
|
|
|
- IoiState = LoadState.Failed
|
|
|
|
|
- End Try
|
|
|
|
|
- Return Nothing
|
|
|
|
|
- End Function
|
|
|
|
|
- IoiProcess.Start()
|
|
|
|
|
- IoiState = LoadState.Loading
|
|
|
|
|
- IoiProcess.BeginOutputReadLine()
|
|
|
|
|
- IoiProcess.BeginErrorReadLine()
|
|
|
|
|
- '等待
|
|
|
|
|
- Do Until IoiProcess.HasExited OrElse IoiState <> LoadState.Loading
|
|
|
|
|
- Thread.Sleep(10)
|
|
|
|
|
- Loop
|
|
|
|
|
- '输出
|
|
|
|
|
- If IoiState = LoadState.Finished Then
|
|
|
|
|
- Log("[IOI] 联机模块启动成功")
|
|
|
|
|
- Return True
|
|
|
|
|
- Else
|
|
|
|
|
- Throw New Exception("联机模块启动失败")
|
|
|
|
|
- End If
|
|
|
|
|
- 'Select Case IoiState
|
|
|
|
|
- ' Case LoadState.Finished
|
|
|
|
|
- ' Log("[IOI] 联机模块启动成功")
|
|
|
|
|
- ' Return True
|
|
|
|
|
- ' Case LoadState.Aborted
|
|
|
|
|
- ' Log("[IOI] 联机模块要求更新")
|
|
|
|
|
- ' Return False
|
|
|
|
|
- ' Case LoadState.Failed
|
|
|
|
|
- ' Log("[IOI] 联机模块启动出现异常")
|
|
|
|
|
- ' Return False
|
|
|
|
|
- ' Case Else 'LoadState.Loading
|
|
|
|
|
- ' Throw New Exception("联机模块启动失败,请检查你的网络连接")
|
|
|
|
|
- 'End Select
|
|
|
|
|
- End Using
|
|
|
|
|
- End Using
|
|
|
|
|
|
|
+ Return False
|
|
|
End Function
|
|
End Function
|
|
|
|
|
|
|
|
'Ioi 日志
|
|
'Ioi 日志
|
|
|
Private Shared Sub IoiLogLine(Content As String)
|
|
Private Shared Sub IoiLogLine(Content As String)
|
|
|
-
|
|
|
|
|
- '初始化
|
|
|
|
|
- If Content.Contains(" > http://127.0.0.1:55555/") Then Exit Sub
|
|
|
|
|
- If Content.Contains("All done") Then
|
|
|
|
|
- If IoiId IsNot Nothing AndAlso IoiPassword IsNot Nothing Then
|
|
|
|
|
- IoiState = LoadState.Finished
|
|
|
|
|
- Else
|
|
|
|
|
- Log("[IOI] 联机模块汇报初始化完成,但未提供账户信息")
|
|
|
|
|
- IoiState = LoadState.Failed
|
|
|
|
|
- End If
|
|
|
|
|
- Exit Sub
|
|
|
|
|
- End If
|
|
|
|
|
- If Content.Contains("Password :: ") Then
|
|
|
|
|
- IoiPassword = Content.Split({"Password :: "}, StringSplitOptions.None)(1)
|
|
|
|
|
- Exit Sub '为保证安全不记录密码到 Log
|
|
|
|
|
- End If
|
|
|
|
|
-
|
|
|
|
|
- '初始化
|
|
|
|
|
- If Content.Contains("ID :: ") Then IoiId = Content.Split({"ID :: "}, StringSplitOptions.None)(1)
|
|
|
|
|
- If Content.Contains("Initialization failed") OrElse Content.Contains("The version is ") Then IoiState = LoadState.Aborted
|
|
|
|
|
-
|
|
|
|
|
- '系统回应
|
|
|
|
|
- If Content.Contains("'portssub' from ") Then LastPortsId = Content.Split(" ").Last
|
|
|
|
|
- If Content.Contains("Listening tcp ") Then
|
|
|
|
|
- If UserList.ContainsKey(LastPortsId) Then
|
|
|
|
|
- UserList(LastPortsId).Ports(Content.Split(" ").Last) = RegexSeek(Content, "(?<=Listening tcp )[^:]+")
|
|
|
|
|
- Else
|
|
|
|
|
- Log("[IOI] 未在列表中的用户出现意料外的连接信息")
|
|
|
|
|
- NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & LastPortsId & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
|
|
|
- End If
|
|
|
|
|
- End If
|
|
|
|
|
-
|
|
|
|
|
- '断开连接
|
|
|
|
|
- If Content.Contains("Closed tcp connection from ") AndAlso Content.Contains(":55557") Then
|
|
|
|
|
- For i = 0 To UserList.Count - 1
|
|
|
|
|
- Dim User = UserList.Values(i)
|
|
|
|
|
- If Not Content.Contains(User.Ports(55557)) OrElse User.IsDisposed Then Continue For
|
|
|
|
|
- Log("[IOI] 检测到 55557 端口断开(" & User.DisplayName & ")")
|
|
|
|
|
- UserRemove(User, True)
|
|
|
|
|
- Exit For
|
|
|
|
|
- Next
|
|
|
|
|
- End If
|
|
|
|
|
-
|
|
|
|
|
- '写入日志
|
|
|
|
|
- If Not Content.Contains("read /dev/stdin: The handle is invalid.") AndAlso LogLinesCount < If(ModeDebug, 10000, 1000) Then
|
|
|
|
|
- LogLinesCount += 1
|
|
|
|
|
- Log("[IOI] " & Content)
|
|
|
|
|
- End If
|
|
|
|
|
-
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
Private Shared LogLinesCount As Integer = 0
|
|
Private Shared LogLinesCount As Integer = 0
|
|
|
Private Shared LastPortsId As String = "" '上一个收到 portssub 的 ID,用于记录端口
|
|
Private Shared LastPortsId As String = "" '上一个收到 portssub 的 ID,用于记录端口
|
|
@@ -384,94 +40,10 @@ StartDownload:
|
|
|
Private Shared UserListIdentifyCache As String = ""
|
|
Private Shared UserListIdentifyCache As String = ""
|
|
|
Private Shared RoomListIdentifyCache As String = ""
|
|
Private Shared RoomListIdentifyCache As String = ""
|
|
|
Public Sub RefreshUi()
|
|
Public Sub RefreshUi()
|
|
|
- Try
|
|
|
|
|
- '确认用户列表缓存
|
|
|
|
|
- Dim UserListIdentify As String = Join(UserList, vbCrLf)
|
|
|
|
|
- If UserListIdentify <> UserListIdentifyCache Then
|
|
|
|
|
- UserListIdentifyCache = UserListIdentify
|
|
|
|
|
- '刷新列表项
|
|
|
|
|
- PanUserList.Children.Clear()
|
|
|
|
|
- For i = 0 To UserList.Count - 1
|
|
|
|
|
- If i > UserList.Count - 1 Then Exit For
|
|
|
|
|
- PanUserList.Children.Add(UserList.Values(i).ToListItem)
|
|
|
|
|
- Next
|
|
|
|
|
- '刷新列表标题
|
|
|
|
|
- CardUser.Title = "已连接的玩家 (" & PanUserList.Children.Count & ")"
|
|
|
|
|
- End If
|
|
|
|
|
- '刷新用户列表项
|
|
|
|
|
- For Each UserItem As MyListItem In PanUserList.Children
|
|
|
|
|
- CType(UserItem.Tag, LinkUserIoi).RefreshUi(UserItem)
|
|
|
|
|
- Next
|
|
|
|
|
- '确认房间列表缓存
|
|
|
|
|
- Dim RoomListIdentify As String = Join(GetRoomList(), vbCrLf)
|
|
|
|
|
- If RoomListIdentify <> RoomListIdentifyCache Then
|
|
|
|
|
- RoomListIdentifyCache = RoomListIdentify
|
|
|
|
|
- '刷新列表项
|
|
|
|
|
- PanRoom.Children.Clear()
|
|
|
|
|
- For Each Room In GetRoomList()
|
|
|
|
|
- PanRoom.Children.Add(Room.ToListItem)
|
|
|
|
|
- Next
|
|
|
|
|
- End If
|
|
|
|
|
- '刷新房间列表项
|
|
|
|
|
- For Each RoomItem As MyListItem In PanRoom.Children
|
|
|
|
|
- CType(RoomItem.Tag, RoomEntry).RefreshUi(RoomItem)
|
|
|
|
|
- Next
|
|
|
|
|
- '刷新操作提示
|
|
|
|
|
- If UserList.Count = 0 Then
|
|
|
|
|
- If RoomListForMe.Count = 0 Then
|
|
|
|
|
- LabHint.Text = "若想创建房间,请点击创建房间按钮,并按说明进行操作。" & vbCrLf & "若想加入他人的房间,请点击建立连接,然后输入对方的联机码。"
|
|
|
|
|
- Else
|
|
|
|
|
- LabHint.Text = "若想让其他人加入你的房间,请点击复制联机码,然后让你的朋友输入你的联机码以建立连接。"
|
|
|
|
|
- End If
|
|
|
|
|
- Else
|
|
|
|
|
- If GetRoomList.Count = 0 Then
|
|
|
|
|
- LabHint.Text = "若想创建房间,请点击创建房间按钮,然后输入对局域网开放后 MC 显示的端口号,或本地服务端的端口号。"
|
|
|
|
|
- ElseIf RoomListForMe.Count = 0 Then
|
|
|
|
|
- '已有连接,本人没有房间,对方有房间
|
|
|
|
|
- LabHint.Text = "若想加入某个房间,直接点击该房间即可获取说明。"
|
|
|
|
|
- Else
|
|
|
|
|
- '已有连接,且本人有房间
|
|
|
|
|
- LabHint.Text = "指向你所创建的房间,能在右侧找到修改房间名称、关闭房间等选项。" &
|
|
|
|
|
- If(RoomListForMe.Count <> GetRoomList.Count, vbCrLf & "若想加入其他人的房间,直接点击该房间即可获取说明。", "")
|
|
|
|
|
- End If
|
|
|
|
|
- End If
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "联机模块 UI 时钟运行失败", LogLevel.Feedback)
|
|
|
|
|
- End Try
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
'工作线程刷新
|
|
'工作线程刷新
|
|
|
Public Sub RefreshWorker()
|
|
Public Sub RefreshWorker()
|
|
|
- Try
|
|
|
|
|
- '检测退出
|
|
|
|
|
- If InitLoader.State = LoadState.Finished AndAlso IoiProcess.HasExited Then
|
|
|
|
|
- Log("[IOI] 联机模块出现异常!", LogLevel.Hint)
|
|
|
|
|
- ModuleStopManually()
|
|
|
|
|
- End If
|
|
|
|
|
- '检测用户
|
|
|
|
|
- For i = 0 To UserList.Values.Count - 1
|
|
|
|
|
- If i > UserList.Values.Count - 1 Then Exit For
|
|
|
|
|
- Dim User = UserList.Values(i)
|
|
|
|
|
- If User.Progress < 1 Then Continue For '跳过连接中的用户
|
|
|
|
|
- '发送心跳包
|
|
|
|
|
- If Date.Now - User.LastSend > New TimeSpan(0, 0, RandomInteger(50, 30)) Then
|
|
|
|
|
- RunInNewThread(Sub()
|
|
|
|
|
- Try
|
|
|
|
|
- SendUpdateRequest(User, 1)
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "心跳包发送失败(" & User.DisplayName & ")", LogLevel.Normal)
|
|
|
|
|
- End Try
|
|
|
|
|
- End Sub, "Link Heartbeat " & User.Id)
|
|
|
|
|
- End If
|
|
|
|
|
- '检测被动离线
|
|
|
|
|
- If Date.Now - User.LastReceive > New TimeSpan(0, 2, 0) Then
|
|
|
|
|
- SendDisconnectRequest(User)
|
|
|
|
|
- Hint("与 " & User.DisplayName & " 的连接已中断!", HintType.Critical)
|
|
|
|
|
- End If
|
|
|
|
|
- Next
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "联机模块工作时钟运行失败", LogLevel.Feedback)
|
|
|
|
|
- End Try
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
#End Region
|
|
#End Region
|
|
@@ -482,65 +54,6 @@ StartDownload:
|
|
|
''' 发送 Portsub 请求并等待获取控制台端口。进度将从 0 变化至 80%。
|
|
''' 发送 Portsub 请求并等待获取控制台端口。进度将从 0 变化至 80%。
|
|
|
''' </summary>
|
|
''' </summary>
|
|
|
Private Shared Sub SendPortsubRequest(User As LinkUserIoi)
|
|
Private Shared Sub SendPortsubRequest(User As LinkUserIoi)
|
|
|
- Log("[IOI] 尝试建立连接:" & User.Id)
|
|
|
|
|
- '向对方发送 portsub 请求
|
|
|
|
|
- Dim Retry As Integer = 0
|
|
|
|
|
-RetryLink:
|
|
|
|
|
- Dim Result As JObject = GetJson(NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "PUT", "", "", 100000))
|
|
|
|
|
- '失败与重试
|
|
|
|
|
- If Result("msg") IsNot Nothing Then
|
|
|
|
|
- Dim ErrorMessage As String = Result("msg").ToString
|
|
|
|
|
- Select Case ErrorMessage
|
|
|
|
|
- Case "failed to find any peer in table"
|
|
|
|
|
- Retry += 1
|
|
|
|
|
- ErrorMessage = "我方网络环境不佳,连接失败。" '初始化对等机列表超时
|
|
|
|
|
- Log("[IOI] 尝试建立连接结果:未找到对等机,第 " & Retry & " 级重试")
|
|
|
|
|
- Case "routing: not found"
|
|
|
|
|
- Retry += 4
|
|
|
|
|
- ErrorMessage = "我方或对方网络环境不佳,或对方已关闭联机模块,未找到路由。" '未知情况
|
|
|
|
|
- Log("[IOI] 尝试建立连接结果:无法连接到路由,第 " & Retry & " 级重试")
|
|
|
|
|
- Case "you are already connected to specified host"
|
|
|
|
|
- If User.IsDisposed Then Throw New ThreadInterruptedException("用户对象已被释放")
|
|
|
|
|
- Log("[IOI] 尝试建立连接结果:已与对方连接")
|
|
|
|
|
- GoTo Done
|
|
|
|
|
- 'Retry += 1
|
|
|
|
|
- 'NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 100000)
|
|
|
|
|
- 'ErrorMessage = "已与对方连接。" '双向连接偶尔导致
|
|
|
|
|
- 'Log("[IOI] 已与对方连接,尝试中断现有连接,第 " & Retry & " 级重试")
|
|
|
|
|
- Case "dial backoff"
|
|
|
|
|
- Retry += 20
|
|
|
|
|
- ErrorMessage = "对方网络环境不佳,或对方已关闭联机模块。请尝试让对方主动连接你,而不是你去连接对方。" 'NAT2 连 NAT4 导致
|
|
|
|
|
- Log("[IOI] 尝试建立连接结果:NAT 异常,第 " & Retry & " 级重试")
|
|
|
|
|
- Case Else
|
|
|
|
|
- If ErrorMessage.Contains("all dials failed") Then
|
|
|
|
|
- Retry += 8
|
|
|
|
|
- ErrorMessage = "我方或对方网络环境不佳,或对方已关闭联机模块,连接失败。" '网络不佳,或对方已关闭模块
|
|
|
|
|
- Log("[IOI] 尝试建立连接结果:连接失败,第 " & Retry & " 级重试")
|
|
|
|
|
- Else
|
|
|
|
|
- Retry += 8
|
|
|
|
|
- Log("[IOI] 尝试建立连接结果:未知错误(" & ErrorMessage & "),第 " & Retry & " 级重试")
|
|
|
|
|
- End If
|
|
|
|
|
- End Select
|
|
|
|
|
- If User.IsDisposed Then Throw New ThreadInterruptedException("用户对象已被释放")
|
|
|
|
|
- If Retry <= 64 Then
|
|
|
|
|
- User.Progress = Retry * 0.01 + 0.05
|
|
|
|
|
- Thread.Sleep(3000)
|
|
|
|
|
- GoTo RetryLink
|
|
|
|
|
- Else
|
|
|
|
|
- Throw New InvalidOperationException(ErrorMessage)
|
|
|
|
|
- End If
|
|
|
|
|
- End If
|
|
|
|
|
- Log("[IOI] 尝试建立连接结果:成功")
|
|
|
|
|
- '等待获取对方端口
|
|
|
|
|
-Done:
|
|
|
|
|
- Dim WaitCount As Integer = 0
|
|
|
|
|
- Do Until User.Ports.ContainsKey(55555) AndAlso User.Ports.ContainsKey(55557)
|
|
|
|
|
- WaitCount += 1
|
|
|
|
|
- User.Progress = 0.7 + WaitCount / 200 * 0.1 '70% ~ 80%
|
|
|
|
|
- If WaitCount = 100 Then Throw New Exception("连接超时,请尝试重新连接(未收到端口回报)!")
|
|
|
|
|
- Thread.Sleep(150)
|
|
|
|
|
- Loop
|
|
|
|
|
- User.Progress = 0.8
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
''' <summary>
|
|
''' <summary>
|
|
@@ -584,20 +97,6 @@ Done:
|
|
|
''' 尝试发送断开请求,并将其从用户列表中移除。
|
|
''' 尝试发送断开请求,并将其从用户列表中移除。
|
|
|
''' </summary>
|
|
''' </summary>
|
|
|
Private Shared Sub SendDisconnectRequest(User As LinkUserIoi, Optional Message As String = Nothing, Optional IsError As Boolean = False)
|
|
Private Shared Sub SendDisconnectRequest(User As LinkUserIoi, Optional Message As String = Nothing, Optional IsError As Boolean = False)
|
|
|
- Dim RawJson As New JObject()
|
|
|
|
|
- RawJson("id") = IoiId
|
|
|
|
|
- RawJson("type") = "disconnect"
|
|
|
|
|
- If Message IsNot Nothing Then
|
|
|
|
|
- RawJson("message") = Message
|
|
|
|
|
- RawJson("isError") = IsError
|
|
|
|
|
- End If
|
|
|
|
|
- Try
|
|
|
|
|
- User.Send(RawJson)
|
|
|
|
|
- Thread.Sleep(50)
|
|
|
|
|
- Catch
|
|
|
|
|
- End Try
|
|
|
|
|
- NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
|
|
|
- User.Dispose()
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
#End Region
|
|
#End Region
|
|
@@ -606,29 +105,9 @@ Done:
|
|
|
|
|
|
|
|
'刷新连接
|
|
'刷新连接
|
|
|
Private Shared Sub BtnListRefresh_Click(sender As MyIconButton, e As EventArgs)
|
|
Private Shared Sub BtnListRefresh_Click(sender As MyIconButton, e As EventArgs)
|
|
|
- Dim User As LinkUserIoi = sender.Tag
|
|
|
|
|
- User.PingRecord.Clear()
|
|
|
|
|
- FrmLinkIoi.RefreshUi()
|
|
|
|
|
- RunInThread(Sub()
|
|
|
|
|
- Try
|
|
|
|
|
- SendUpdateRequest(User, 1)
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- If InitLoader.State = LoadState.Finished Then Log(ex, "刷新与 " & User.DisplayName & " 的连接失败", LogLevel.Hint)
|
|
|
|
|
- End Try
|
|
|
|
|
- End Sub)
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
'断开连接
|
|
'断开连接
|
|
|
Private Shared Sub BtnListDisconnect_Click(sender As MyIconButton, e As EventArgs)
|
|
Private Shared Sub BtnListDisconnect_Click(sender As MyIconButton, e As EventArgs)
|
|
|
- Dim User As LinkUserIoi = sender.Tag
|
|
|
|
|
- sender.IsEnabled = False
|
|
|
|
|
- RunInThread(Sub()
|
|
|
|
|
- If User.Progress < 1 AndAlso User.RelativeThread IsNot Nothing AndAlso User.RelativeThread.IsAlive Then
|
|
|
|
|
- NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
|
|
|
- User.Dispose()
|
|
|
|
|
- Else
|
|
|
|
|
- SendDisconnectRequest(User, GetPlayerName() & " 主动断开了连接!")
|
|
|
|
|
- End If
|
|
|
|
|
- End Sub)
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
'复制联机码
|
|
'复制联机码
|
|
|
Public Shared Sub BtnLeftCopy_Click() Handles BtnLeftCopy.Click
|
|
Public Shared Sub BtnLeftCopy_Click() Handles BtnLeftCopy.Click
|
|
@@ -680,46 +159,10 @@ Done:
|
|
|
|
|
|
|
|
#Region "请求核心"
|
|
#Region "请求核心"
|
|
|
|
|
|
|
|
- Private Shared Listener As Socket = Nothing
|
|
|
|
|
''' <summary>
|
|
''' <summary>
|
|
|
''' 启动 Socket 监听核心。
|
|
''' 启动 Socket 监听核心。
|
|
|
''' </summary>
|
|
''' </summary>
|
|
|
Public Shared Sub StartSocketListener()
|
|
Public Shared Sub StartSocketListener()
|
|
|
- If Listener IsNot Nothing Then Exit Sub '已经启动过了
|
|
|
|
|
- Listener = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) With {.ReceiveTimeout = 1000000000, .SendTimeout = 1000000000}
|
|
|
|
|
- Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True)
|
|
|
|
|
- Try
|
|
|
|
|
- Listener.Bind(New IPEndPoint(IPAddress.Any, 55557))
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "初次启动 Socket 监听核心失败,开始重试")
|
|
|
|
|
- Thread.Sleep(1000)
|
|
|
|
|
- Listener.Bind(New IPEndPoint(IPAddress.Any, 55557))
|
|
|
|
|
- End Try
|
|
|
|
|
- Listener.Listen(100)
|
|
|
|
|
- Log("[IOI] 已启动 Socket 监听核心")
|
|
|
|
|
- RunInNewThread(Sub()
|
|
|
|
|
- While True
|
|
|
|
|
- Try
|
|
|
|
|
- '获取新的 Socket
|
|
|
|
|
- Dim bytes(1024) As Byte
|
|
|
|
|
- Dim ClientSocket As Socket = Listener.Accept()
|
|
|
|
|
- '获取初始输入信息
|
|
|
|
|
- Dim RequestInput As String = Encoding.UTF8.GetString(bytes, 0, ClientSocket.Receive(bytes))
|
|
|
|
|
- If Not RequestInput.StartsWith("PCL - ") Then Exit Sub
|
|
|
|
|
- Dim RawData As String
|
|
|
|
|
- Try
|
|
|
|
|
- RawData = SecretDecrypt(WebUtility.UrlDecode(RequestInput.Substring(6)))
|
|
|
|
|
- Log("[IOI] 接收到新的 Socket:" & RawData)
|
|
|
|
|
- PageLinkIoi.ReceiveJson(GetJson(RawData), ClientSocket)
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "新的 Socket 处理出错(内容:" & RequestInput & ")")
|
|
|
|
|
- End Try
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- Log(ex, "Socket 监听出错")
|
|
|
|
|
- Thread.Sleep(3000) '防止死循环出错
|
|
|
|
|
- End Try
|
|
|
|
|
- End While
|
|
|
|
|
- End Sub, "Socket Listener")
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
#End Region
|
|
#End Region
|
|
@@ -738,40 +181,9 @@ Done:
|
|
|
'请求管理
|
|
'请求管理
|
|
|
Public Socket As Socket = Nothing
|
|
Public Socket As Socket = Nothing
|
|
|
Public Sub Send(Request As JObject)
|
|
Public Sub Send(Request As JObject)
|
|
|
- If Socket Is Nothing Then Throw New Exception("该用户尚未绑定 Socket")
|
|
|
|
|
- Dim Data As String = Request.ToString(Newtonsoft.Json.Formatting.None)
|
|
|
|
|
- If ModeDebug Then Log("[IOI] 发送联机数据包(" & DisplayName & "):" & Data)
|
|
|
|
|
- Data = "PCL - " & WebUtility.UrlEncode(SecretEncrypt(Data))
|
|
|
|
|
- Me.LastSend = Date.Now
|
|
|
|
|
- Socket.Send(Encoding.UTF8.GetBytes(Data))
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
Public ListenerThread As Thread = Nothing
|
|
Public ListenerThread As Thread = Nothing
|
|
|
Public Sub StartListener()
|
|
Public Sub StartListener()
|
|
|
- If ListenerThread IsNot Nothing Then Exit Sub
|
|
|
|
|
- '启动监听
|
|
|
|
|
- ListenerThread = RunInNewThread(Sub()
|
|
|
|
|
- Try
|
|
|
|
|
- Dim bytes(1024) As Byte
|
|
|
|
|
- While PageLinkIoi.UserList.ContainsValue(Me)
|
|
|
|
|
- Dim RequestInput As String = Encoding.UTF8.GetString(bytes, 0, Socket.Receive(bytes))
|
|
|
|
|
- If Not RequestInput.StartsWith("PCL - ") Then Exit Sub
|
|
|
|
|
- Dim RawData As String = SecretDecrypt(WebUtility.UrlDecode(RequestInput.Substring(6)))
|
|
|
|
|
- If ModeDebug Then Log("[IOI] 接收联机数据包(" & DisplayName & "):" & RawData)
|
|
|
|
|
- PageLinkIoi.ReceiveJson(GetJson(RawData)) '调用去实际的联机模块
|
|
|
|
|
- End While
|
|
|
|
|
- Catch ex As ThreadInterruptedException
|
|
|
|
|
- Log("[IOI] 用户监听已中断(" & DisplayName & ")")
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- If IsDisposed Then Exit Sub
|
|
|
|
|
- If ex.GetType.Equals(GetType(SocketException)) AndAlso CType(ex, SocketException).SocketErrorCode = 10053 Then
|
|
|
|
|
- Log("[IOI] 客户端已关闭(" & DisplayName & ")")
|
|
|
|
|
- PageLinkIoi.UserRemove(CType(Me, PageLinkIoi.LinkUserIoi), True)
|
|
|
|
|
- Exit Sub
|
|
|
|
|
- End If
|
|
|
|
|
- Log(ex, "用户监听出错(" & DisplayName & ")")
|
|
|
|
|
- PageLinkIoi.UserRemove(CType(Me, PageLinkIoi.LinkUserIoi), True)
|
|
|
|
|
- End Try
|
|
|
|
|
- End Sub, "Link Listener " & DisplayName)
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
Public Sub BindSocket(Socket As Socket)
|
|
Public Sub BindSocket(Socket As Socket)
|
|
|
If Me.Socket IsNot Nothing Then Throw New Exception("该用户已经绑定了 Socket")
|
|
If Me.Socket IsNot Nothing Then Throw New Exception("该用户已经绑定了 Socket")
|
|
@@ -975,135 +387,12 @@ Done:
|
|
|
|
|
|
|
|
'正向与反向连接
|
|
'正向与反向连接
|
|
|
Public Shared Sub BtnLeftCreate_Click() Handles BtnLeftCreate.Click
|
|
Public Shared Sub BtnLeftCreate_Click() Handles BtnLeftCreate.Click
|
|
|
- ''获取信息
|
|
|
|
|
- 'Dim Code As String = MyMsgBoxInput("", New ObjectModel.Collection(Of Validate) From {New ValidateLength(9, 99999)}, "", "输入对方的联机码", "确定", "取消")
|
|
|
|
|
- 'If Code Is Nothing Then Exit Sub
|
|
|
|
|
- ''检查
|
|
|
|
|
- 'If Code.StartsWith("P") AndAlso Code.Length < 48 Then
|
|
|
|
|
- ' Hint("你输入的可能是 HiPer 的联机码,请在左侧的联机方式中选择 HiPer!", HintType.Critical) : Exit Sub
|
|
|
|
|
- 'End If
|
|
|
|
|
- 'Dim Id As String, DisplayName As String
|
|
|
|
|
- 'Try '解密失败检查
|
|
|
|
|
- ' Id = "12D3" & Code.Substring(0, 48)
|
|
|
|
|
- ' DisplayName = SecretDecrypt(Code.Substring(48))
|
|
|
|
|
- 'Catch
|
|
|
|
|
- ' Hint("你输入的联机码有误!", HintType.Critical)
|
|
|
|
|
- ' Exit Sub
|
|
|
|
|
- 'End Try
|
|
|
|
|
- 'If Id = IoiId Then '自我连接检查
|
|
|
|
|
- ' Hint("我连我自己?搁这卡 Bug 呢?", HintType.Critical)
|
|
|
|
|
- ' Exit Sub
|
|
|
|
|
- 'End If
|
|
|
|
|
- ''开始
|
|
|
|
|
- 'Dim User As New LinkUserIoi(Id, DisplayName)
|
|
|
|
|
- 'User.RelativeThread = RunInNewThread(Sub()
|
|
|
|
|
- ' Dim WaitCount As Integer = 0
|
|
|
|
|
- ' Try
|
|
|
|
|
- ' '加入列表
|
|
|
|
|
- ' If UserList.ContainsKey(Id) Then
|
|
|
|
|
- ' Hint(UserList(Id).DisplayName & " 已在列表中,无需再次连接!")
|
|
|
|
|
- ' Exit Sub
|
|
|
|
|
- ' Else
|
|
|
|
|
- ' UserList.Add(Id, User)
|
|
|
|
|
- ' End If
|
|
|
|
|
- ' '发送 portsub 请求(0% -> 80%)
|
|
|
|
|
- ' SendPortsubRequest(User)
|
|
|
|
|
- ' '构建 Socket(81% -> 82%)
|
|
|
|
|
- ' Dim ClientSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) With {.ReceiveTimeout = 1000000000, .SendTimeout = 1000000000}
|
|
|
|
|
- ' ClientSocket.Connect(New IPEndPoint(IPAddress.Parse(User.Ports(55557)), 55557))
|
|
|
|
|
- ' User.BindSocket(ClientSocket)
|
|
|
|
|
- ' User.Progress = 0.82
|
|
|
|
|
- ' '发送 connect 请求(83% -> 85%)
|
|
|
|
|
- ' SendConnectRequest(User)
|
|
|
|
|
- ' User.Progress = 0.85
|
|
|
|
|
- ' '等待对方向自己请求
|
|
|
|
|
- ' Log("[IOI] 加入成功,等待反向请求")
|
|
|
|
|
- ' Do While User.Progress < 0.9999
|
|
|
|
|
- ' User.Progress += 0.0002
|
|
|
|
|
- ' If User.Progress > 0.98 AndAlso User.Progress < 0.9999 Then Throw New Exception("对方未回应连接请求!")
|
|
|
|
|
- ' Thread.Sleep(100)
|
|
|
|
|
- ' Loop
|
|
|
|
|
- ' Hint("已连接到 " & User.DisplayName & "!", HintType.Finish)
|
|
|
|
|
- ' Catch ex As ThreadInterruptedException
|
|
|
|
|
- ' Log("[IOI] 已中断主动发起的连接(" & User.DisplayName & ")")
|
|
|
|
|
- ' Catch ex As InvalidOperationException
|
|
|
|
|
- ' 'API 返回的错误
|
|
|
|
|
- ' NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
|
|
|
- ' User.Dispose()
|
|
|
|
|
- ' If InitLoader.State = LoadState.Finished Then Log("与 " & DisplayName & " 建立连接失败:" & ex.Message, LogLevel.Msgbox)
|
|
|
|
|
- ' Catch ex As Exception
|
|
|
|
|
- ' '常规错误
|
|
|
|
|
- ' NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
|
|
|
- ' User.Dispose()
|
|
|
|
|
- ' If ex.InnerException IsNot Nothing AndAlso TypeOf ex.InnerException Is ThreadInterruptedException Then Exit Sub
|
|
|
|
|
- ' If InitLoader.State = LoadState.Finished Then Log(ex, "与 " & DisplayName & " 建立连接失败", LogLevel.Msgbox)
|
|
|
|
|
- ' End Try
|
|
|
|
|
- ' End Sub, "Link Create " & DisplayName)
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
Private Shared Sub SendPortsubBack(User As LinkUserIoi, TargetVersion As Integer)
|
|
Private Shared Sub SendPortsubBack(User As LinkUserIoi, TargetVersion As Integer)
|
|
|
- Try
|
|
|
|
|
- SendPortsubRequest(User)
|
|
|
|
|
- User.Progress = 0.9
|
|
|
|
|
- If TargetVersion > RequestVersion Then
|
|
|
|
|
- SendDisconnectRequest(User, "无法连接到 " & GetPlayerName() & ":对方的 PCL 版本过低!", True)
|
|
|
|
|
- Throw New InvalidOperationException("你的 PCL 版本过低!")
|
|
|
|
|
- ElseIf TargetVersion < RequestVersion Then
|
|
|
|
|
- SendDisconnectRequest(User, "无法连接到 " & GetPlayerName() & ":你的 PCL 版本过低!", True)
|
|
|
|
|
- Throw New InvalidOperationException("对方的 PCL 版本过低!")
|
|
|
|
|
- Else
|
|
|
|
|
- SendUpdateRequest(User, 1)
|
|
|
|
|
- User.Progress = 1
|
|
|
|
|
- Hint(User.DisplayName & " 已与你建立连接!")
|
|
|
|
|
- End If
|
|
|
|
|
- Catch ex As ThreadInterruptedException
|
|
|
|
|
- Log("[IOI] 已中断被动建立的连接(" & User.DisplayName & ")")
|
|
|
|
|
- Catch ex As InvalidOperationException
|
|
|
|
|
- 'API 返回的错误
|
|
|
|
|
- NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
|
|
|
- User.Dispose()
|
|
|
|
|
- If InitLoader.State = LoadState.Finished Then Log("与 " & User.DisplayName & " 建立连接失败:" & ex.Message, LogLevel.Hint)
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- '常规错误
|
|
|
|
|
- NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
|
|
|
- User.Dispose()
|
|
|
|
|
- If InitLoader.State = LoadState.Finished Then Log(ex, "与 " & User.DisplayName & " 建立连接失败", LogLevel.Hint)
|
|
|
|
|
- End Try
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
'创建房间
|
|
'创建房间
|
|
|
Private Sub LinkCreate() Handles BtnCreate.Click
|
|
Private Sub LinkCreate() Handles BtnCreate.Click
|
|
|
- 'If MyMsgBox("请先进入 MC 并暂停游戏,在暂停页面选择对局域网开放,然后在下一个窗口输入 MC 显示的端口号。" & vbCrLf & "若使用服务端开服,则直接在下一个窗口输入服务器配置中的端口号即可。", "提示", "继续", "取消") = 2 Then Exit Sub
|
|
|
|
|
- ''获取端口号
|
|
|
|
|
- 'Dim Port As String = MyMsgBoxInput("", New ObjectModel.Collection(Of Validate) From {
|
|
|
|
|
- ' New ValidateInteger(0, 65535),
|
|
|
|
|
- ' New ValidateExceptSame({"55555", "55557"}, "端口不能为 %!"),
|
|
|
|
|
- ' New ValidateExceptSame(RoomListForMe.Select(AddressOf RoomEntry.SelectPort), "端口 % 已创建过房间,请在删除该房间后继续!")
|
|
|
|
|
- ' }, "", "输入端口号", "确定", "取消")
|
|
|
|
|
- 'If Port Is Nothing Then Exit Sub
|
|
|
|
|
- ''获取显示名称
|
|
|
|
|
- 'Dim DisplayName As String = MyMsgBoxInput(GetPlayerName() & " 的房间 - " & Port, New ObjectModel.Collection(Of Validate) From {
|
|
|
|
|
- ' New ValidateNullOrWhiteSpace(), New ValidateLength(1, 40), New ValidateFilter()
|
|
|
|
|
- ' }, "", "输入房间名(建议包含游戏版本等信息)", "确定", "取消")
|
|
|
|
|
- 'If DisplayName Is Nothing Then Exit Sub
|
|
|
|
|
- 'DisplayName = DisplayName.Trim
|
|
|
|
|
- ''开始
|
|
|
|
|
- 'RunInThread(Sub()
|
|
|
|
|
- ' Try
|
|
|
|
|
- ' '请求
|
|
|
|
|
- ' Dim Result As JObject = GetJson(NetRequestOnce("http://127.0.0.1:55555/api/port?proto=tcp&port=" & Port & "&password=" & IoiPassword, "PUT", "", "", 100000))
|
|
|
|
|
- ' If Result("msg") IsNot Nothing Then Throw New InvalidOperationException(Result("msg").ToString)
|
|
|
|
|
- ' '成功
|
|
|
|
|
- ' RoomListForMe.Add(New RoomEntry(Port, DisplayName))
|
|
|
|
|
- ' Hint("房间 " & DisplayName & " 已创建!", HintType.Finish)
|
|
|
|
|
- ' SendUpdateRequestToAllUsers()
|
|
|
|
|
- ' Catch ex As InvalidOperationException
|
|
|
|
|
- ' 'API 返回的错误
|
|
|
|
|
- ' Log("创建房间失败:" & ex.Message, LogLevel.Msgbox)
|
|
|
|
|
- ' Catch ex As Exception
|
|
|
|
|
- ' '常规错误
|
|
|
|
|
- ' Log(ex, "创建房间失败", LogLevel.Msgbox)
|
|
|
|
|
- ' End Try
|
|
|
|
|
- ' End Sub)
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
Private Shared Sub SendUpdateRequestToAllUsers()
|
|
Private Shared Sub SendUpdateRequestToAllUsers()
|
|
|
For i = 0 To UserList.Count - 1
|
|
For i = 0 To UserList.Count - 1
|
|
@@ -1119,18 +408,6 @@ Done:
|
|
|
End Sub
|
|
End Sub
|
|
|
'修改房间名称
|
|
'修改房间名称
|
|
|
Private Shared Sub BtnRoomEdit_Click(sender As MyIconButton, e As EventArgs)
|
|
Private Shared Sub BtnRoomEdit_Click(sender As MyIconButton, e As EventArgs)
|
|
|
- 'Dim Room As RoomEntry = sender.Tag
|
|
|
|
|
- ''获取房间名
|
|
|
|
|
- 'Dim DisplayName As String = MyMsgBoxInput(Room.DisplayName, New ObjectModel.Collection(Of Validate) From {
|
|
|
|
|
- ' New ValidateNullOrWhiteSpace(),
|
|
|
|
|
- ' New ValidateLength(1, 40)
|
|
|
|
|
- ' }, "", "输入房间名(建议包含游戏版本等信息)", "确定", "取消")
|
|
|
|
|
- 'If DisplayName Is Nothing Then Exit Sub
|
|
|
|
|
- 'DisplayName = DisplayName.Trim
|
|
|
|
|
- ''修改
|
|
|
|
|
- 'Room.DisplayName = DisplayName
|
|
|
|
|
- 'FrmLinkIoi.RefreshUi()
|
|
|
|
|
- 'SendUpdateRequestToAllUsers()
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
'加入房间
|
|
'加入房间
|
|
|
Private Shared Sub BtnRoom_Click(sender As MyListItem, e As EventArgs)
|
|
Private Shared Sub BtnRoom_Click(sender As MyListItem, e As EventArgs)
|
|
@@ -1141,25 +418,6 @@ Done:
|
|
|
End Sub
|
|
End Sub
|
|
|
'关闭房间
|
|
'关闭房间
|
|
|
Private Shared Sub BtnRoomClose_Click(sender As MyIconButton, e As EventArgs)
|
|
Private Shared Sub BtnRoomClose_Click(sender As MyIconButton, e As EventArgs)
|
|
|
- Dim Room As RoomEntry = sender.Tag
|
|
|
|
|
- RunInThread(Sub()
|
|
|
|
|
- Try
|
|
|
|
|
- '远程移除
|
|
|
|
|
- Dim Result As JObject = GetJson(NetRequestOnce("http://127.0.0.1:55555/api/port?proto=tcp&port=" & Room.Port & "&password=" & IoiPassword, "DELETE", "", "", 100000))
|
|
|
|
|
- If Result("msg") IsNot Nothing Then Throw New InvalidOperationException(Result("msg").ToString)
|
|
|
|
|
- '本地移除
|
|
|
|
|
- RoomListForMe.Remove(Room)
|
|
|
|
|
- '成功
|
|
|
|
|
- RunInUi(Sub() FrmLinkIoi.RefreshUi())
|
|
|
|
|
- SendUpdateRequestToAllUsers()
|
|
|
|
|
- Catch ex As InvalidOperationException
|
|
|
|
|
- 'API 返回的错误
|
|
|
|
|
- If InitLoader.State = LoadState.Finished Then Log("移除房间失败:" & ex.Message, LogLevel.Msgbox)
|
|
|
|
|
- Catch ex As Exception
|
|
|
|
|
- '常规错误
|
|
|
|
|
- If InitLoader.State = LoadState.Finished Then Log(ex, "移除房间失败", LogLevel.Msgbox)
|
|
|
|
|
- End Try
|
|
|
|
|
- End Sub)
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
'获取数据包
|
|
'获取数据包
|
|
@@ -1238,21 +496,9 @@ Done:
|
|
|
''' 从用户列表中移除一位用户。提示信息视作该用户主动离开。
|
|
''' 从用户列表中移除一位用户。提示信息视作该用户主动离开。
|
|
|
''' </summary>
|
|
''' </summary>
|
|
|
Public Shared Sub UserRemove(User As LinkUserIoi, ShowLeaveMessage As Boolean)
|
|
Public Shared Sub UserRemove(User As LinkUserIoi, ShowLeaveMessage As Boolean)
|
|
|
- If Not UserList.ContainsKey(User.Id) Then Exit Sub
|
|
|
|
|
- If ShowLeaveMessage Then Hint(User.DisplayName & " 已离开!")
|
|
|
|
|
- NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
|
|
|
- User.Dispose()
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
- '关闭联机模块按钮
|
|
|
|
|
- Private Shared Sub ModuleStateChanged(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) Handles InitLoader.OnStateChangedUi
|
|
|
|
|
- If FrmLinkLeft IsNot Nothing Then CType(FrmLinkLeft.ItemIoi.Buttons(0), MyIconButton).Visibility = If(NewState = LoadState.Finished, Visibility.Visible, Visibility.Collapsed)
|
|
|
|
|
- End Sub
|
|
|
|
|
Public Shared Sub ModuleStopManually()
|
|
Public Shared Sub ModuleStopManually()
|
|
|
- IoiStop(False)
|
|
|
|
|
- InitLoader.Error = New Exception("联机模块已关闭,点击以重新启动")
|
|
|
|
|
- InitLoader.State = LoadState.Failed
|
|
|
|
|
- IoiState = LoadState.Failed
|
|
|
|
|
End Sub
|
|
End Sub
|
|
|
|
|
|
|
|
End Class
|
|
End Class
|