PageLinkHiper.xaml.vb 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. Public Class PageLinkHiper
  2. Public Const RequestVersion As Char = "2"
  3. '记录的启动情况
  4. Public Shared IsServerSide As Boolean
  5. Private Shared HostIp As String
  6. Private Shared HostPort As Integer
  7. #Region "初始化"
  8. '加载器初始化
  9. Private Sub LoaderInit() Handles Me.Initialized
  10. PageLoaderInit(Load, PanLoad, PanContent, PanAlways, InitLoader, AutoRun:=False)
  11. '注册自定义的 OnStateChanged
  12. AddHandler InitLoader.OnStateChangedUi, AddressOf OnLoadStateChanged
  13. End Sub
  14. Private IsLoad As Boolean = False
  15. Private Sub OnLoaded() Handles Me.Loaded
  16. FormMain.EndProgramForce(Result.Aborted)
  17. If IsLoad Then Exit Sub
  18. IsLoad = True
  19. '启动监视线程
  20. If Not IsWatcherStarted Then RunInNewThread(AddressOf WatcherThread, "Hiper Watcher")
  21. '读取索引码
  22. Try
  23. Dim Time As String = Setup.Get("LinkHiperCertTime")
  24. If Time = "" Then
  25. Log("[HiPer] 没有缓存凭证")
  26. ElseIf Date.Parse(Time) > Date.Now Then
  27. TextCert.Text = Setup.Get("LinkHiperCertLast")
  28. Log("[HiPer] 缓存凭证尚未过期:" & Time)
  29. CurrentSubpage = Subpages.PanSelect
  30. Else
  31. Log("[HiPer] 缓存凭证已过期:" & Time)
  32. LabCertTitle.Text = "输入索引码"
  33. LabCertDesc.Text = "你的 HiPer 索引码已经过期,请输入新的索引码。" & vbCrLf & "如果实在没有索引码,可以在左侧选择 IOI 方式联机。"
  34. End If
  35. Catch ex As Exception
  36. Log(ex, "读取缓存凭证失败")
  37. Setup.Set("LinkHiperCertTime", "")
  38. End Try
  39. End Sub
  40. #End Region
  41. #Region "加载步骤"
  42. Public Shared PathHiper As String = PathAppdata & "联机模块\"
  43. Public Shared WithEvents InitLoader As New LoaderCombo(Of Integer)("HiPer 初始化", {
  44. New LoaderTask(Of Integer, Integer)("网络环境:连通检测", AddressOf InitPingCheck) With {.Block = False, .ProgressWeight = 0.5},
  45. New LoaderTask(Of Integer, Integer)("网络环境:IP 检测", AddressOf InitIpCheck) With {.Block = False, .ProgressWeight = 1},
  46. New LoaderTask(Of Integer, Integer)("检查网络环境", AddressOf InitCheck) With {.ProgressWeight = 0.5},
  47. New LoaderTask(Of Integer, List(Of NetFile))("获取所需文件", AddressOf InitGetFile) With {.ProgressWeight = 4},
  48. New LoaderDownload("下载所需文件", New List(Of NetFile)) With {.ProgressWeight = 4},
  49. New LoaderTask(Of Integer, Integer)("启动联机模块", AddressOf InitLaunch) With {.ProgressWeight = 7}
  50. })
  51. '检查网络状态
  52. Private Shared Sub InitPingCheck(Task As LoaderTask(Of Integer, Integer))
  53. End Sub
  54. Private Shared Sub InitIpCheck()
  55. End Sub
  56. Private Shared PingTime As Integer, IpCheckStatus As LoadState = LoadState.Loading, IpIsInChina As Boolean
  57. Private Shared Sub InitCheck(Task As LoaderTask(Of Integer, Integer))
  58. End Sub
  59. '获取所需文件
  60. Private Shared Sub InitGetFile(Task As LoaderTask(Of Integer, List(Of NetFile)))
  61. End Sub
  62. Public Class CertOutdatedException
  63. Inherits Exception
  64. End Class
  65. '启动联机模块
  66. Private Shared Sub InitLaunch(Task As LoaderTask(Of Integer, Integer))
  67. End Sub
  68. Private Shared PingNodes As Integer, AllNodes As List(Of String)
  69. #End Region
  70. #Region "进程管理"
  71. Private Shared _HiperState As LoadState = LoadState.Waiting
  72. Public Shared Property HiperState As LoadState
  73. Get
  74. Return _HiperState
  75. End Get
  76. Set(value As LoadState)
  77. _HiperState = value
  78. RunInUi(Sub() If FrmLinkLeft IsNot Nothing Then CType(FrmLinkLeft.ItemHiper.Buttons(0), MyIconButton).Visibility = If(HiperState = LoadState.Finished OrElse HiperState = LoadState.Loading, Visibility.Visible, Visibility.Collapsed))
  79. End Set
  80. End Property
  81. Public Shared Sub ModuleStopManually() '关闭联机模块按钮
  82. HiperExit(False)
  83. End Sub
  84. Private Shared HiperIp As String = Nothing
  85. Private Shared HiperProcessId As Integer = -1, McbProcessId As Integer = -1
  86. Private Shared HiperCertTime As Date = Date.Now
  87. ''' <summary>
  88. ''' 若程序正在运行,则结束程序进程,同时初始化状态数据。返回是否关闭了相关进程。
  89. ''' </summary>
  90. Public Shared Function HiperStop(SleepWhenKilled As Boolean) As Boolean
  91. Return False
  92. End Function
  93. ''' <summary>
  94. ''' 启动程序,并等待初始化完成后退出运行,同时更新 HiperIp。
  95. ''' 若启动失败,则会直接抛出异常。
  96. ''' 若程序正在运行,则会先停止其运行。
  97. ''' </summary>
  98. Public Shared Sub HiperStart(Task As LoaderTask(Of Integer, Integer))
  99. End Sub
  100. 'Hiper 日志
  101. Private Shared Sub HiperLogLine(Content As String, Task As LoaderTask(Of Integer, Integer))
  102. End Sub
  103. Private Shared PossibleFailReason As String = Nothing
  104. #End Region
  105. #Region "监视线程"
  106. '主 Timer 线程
  107. Private IsWatcherStarted As Boolean = False
  108. Private Sub WatcherThread()
  109. Dim Sec15 As Integer = 0
  110. Do While True
  111. Try
  112. For i = 1 To 5
  113. Thread.Sleep(200)
  114. If InitLoader.State = LoadState.Loading Then
  115. RunInUi(AddressOf UpdateProgress)
  116. End If
  117. Next
  118. Thread.Sleep(1000)
  119. Sec15 += 1
  120. WatcherTimer1()
  121. If Sec15 = 15 Then
  122. Sec15 = 0
  123. WatcherTimer15()
  124. End If
  125. Catch ex As Exception
  126. Log(ex, "联机模块主时钟出错", LogLevel.Feedback)
  127. Thread.Sleep(20000)
  128. End Try
  129. Loop
  130. End Sub
  131. '每 1 秒执行的 Timer
  132. Private Sub WatcherTimer1()
  133. If HiperState <> LoadState.Finished Then Exit Sub
  134. RunInUi(Sub()
  135. '索引码剩余时间
  136. Dim Span As TimeSpan = HiperCertTime - Date.Now
  137. If Span.TotalDays >= 30 Then
  138. LabFinishTime.Text = "> 30 天"
  139. ElseIf Span.TotalDays >= 4 Then
  140. LabFinishTime.Text = Span.Days & " 天"
  141. ElseIf Span.TotalDays >= 1 Then
  142. LabFinishTime.Text = Span.Days & " 天" & If(Span.Hours > 0, " " & Span.Hours & " 小时", "")
  143. ElseIf Span.TotalMinutes >= 10 Then
  144. LabFinishTime.Text = Span.Hours & ":" & Span.Minutes.ToString.PadLeft(2, "0") & "'"
  145. Else
  146. LabFinishTime.Text = Span.Minutes & "'" & Span.Seconds.ToString.PadLeft(2, "0") & """"
  147. End If
  148. '提示索引码即将到期
  149. If Span.TotalSeconds <= 5 * 60 AndAlso Span.TotalSeconds > 5 * 60 - 1 AndAlso Setup.Get("LinkHiperCertWarn") Then
  150. MyMsgBox("你的索引码还有不到 5 分钟就要过期了!" & vbCrLf & "你可以在设置中关闭这个提示……", "索引码即将过期", "我知道了……")
  151. ShowWindowToTop(Handle)
  152. Beep()
  153. End If
  154. '检查索引码到期
  155. If Span.TotalSeconds < 2 Then
  156. LabCertTitle.Text = "索引码已过期"
  157. LabCertDesc.Text = "你的 HiPer 索引码已经过期,请输入新的索引码。" & vbCrLf & "如果实在没有索引码,可以在左侧选择 IOI 方式联机。"
  158. TextCert.Text = ""
  159. HiperExit(True)
  160. ShowWindowToTop(Handle)
  161. Beep()
  162. Exit Sub
  163. End If
  164. '网络质量
  165. Dim QualityScore As Integer = If(IpIsInChina, 0, -2)
  166. QualityScore -= Math.Ceiling((Math.Min(PingTime, 600) + Math.Min(PingNodes, 600)) / 80)
  167. Select Case QualityScore
  168. Case Is >= -1
  169. LabFinishQuality.Text = "优秀"
  170. Case Is >= -2
  171. LabFinishQuality.Text = "优良"
  172. Case Is >= -3
  173. LabFinishQuality.Text = "良好"
  174. Case Is >= -5
  175. LabFinishQuality.Text = "一般"
  176. Case Is >= -7
  177. LabFinishQuality.Text = "较差"
  178. Case Else
  179. LabFinishQuality.Text = "很差"
  180. End Select
  181. 'Ping
  182. If HostPing <> -1 Then
  183. If FrmLinkHiper IsNot Nothing AndAlso FrmLinkHiper.LabFinishPing.IsLoaded Then
  184. FrmLinkHiper.LabFinishPing.Text = HostPing & "ms"
  185. End If
  186. End If
  187. End Sub)
  188. End Sub
  189. '每 15 秒执行的 Timer
  190. Private Shared HostPing As Integer = -1
  191. Private Sub WatcherTimer15()
  192. End Sub
  193. #End Region
  194. #Region "PanCert | 索引码输入页面"
  195. '检测输入
  196. Private Sub TextCert_ValidateChanged(sender As Object, e As EventArgs) Handles TextCert.ValidateChanged
  197. BtnCertDone.IsEnabled = TextCert.ValidateResult = ""
  198. End Sub
  199. Private Sub TextCert_KeyDown(sender As Object, e As KeyEventArgs) Handles TextCert.KeyDown
  200. If e.Key = Key.Enter AndAlso BtnCertDone.IsEnabled Then BtnCertDone_Click() '允许回车确认
  201. End Sub
  202. '确认
  203. Private Sub BtnCertDone_Click() Handles BtnCertDone.Click
  204. CurrentSubpage = Subpages.PanSelect
  205. End Sub
  206. #End Region
  207. #Region "PanSelect | 种类选择页面"
  208. '返回
  209. Private Sub BtnSelectReturn_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectReturn.MouseLeftButtonUp
  210. LabCertTitle.Text = "输入索引码"
  211. LabCertDesc.Text = "你需要获取索引码才能使用 HiPer。" & vbCrLf & "如果实在没有索引码,可以在左侧选择 IOI 方式联机。"
  212. CurrentSubpage = Subpages.PanCert
  213. End Sub
  214. '创建房间
  215. Private Sub BtnSelectCreate_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectCreate.MouseLeftButtonUp
  216. End Sub
  217. Private Sub RoomCreate(Port As Integer)
  218. '记录信息
  219. HostIp = Nothing : HostPort = Port
  220. IsServerSide = True
  221. '启动
  222. InitLoader.Start(IsForceRestart:=True)
  223. End Sub
  224. '加入房间
  225. Private Sub BtnSelectJoin_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectJoin.MouseLeftButtonUp
  226. End Sub
  227. Private Sub RoomJoin(Ip As String, Port As Integer)
  228. '记录信息
  229. HostIp = Ip : HostPort = Port
  230. IsServerSide = False
  231. '启动
  232. InitLoader.Start(IsForceRestart:=True)
  233. End Sub
  234. #End Region
  235. #Region "PanLoad | 加载中页面"
  236. '承接状态切换的 UI 改变
  237. Private Sub OnLoadStateChanged(Loader As LoaderBase, NewState As LoadState, OldState As LoadState)
  238. End Sub
  239. Private Shared LoadStep As String = "准备初始化"
  240. Private Shared Sub SetLoadDesc(Intro As String, [Step] As String)
  241. Log("[Hiper] 连接步骤:" & Intro)
  242. LoadStep = [Step]
  243. RunInUiWait(Sub()
  244. If FrmLinkHiper Is Nothing OrElse Not FrmLinkHiper.LabLoadDesc.IsLoaded Then Exit Sub
  245. FrmLinkHiper.LabLoadDesc.Text = Intro
  246. FrmLinkHiper.UpdateProgress()
  247. End Sub)
  248. End Sub
  249. '承接重试
  250. Private Sub CardLoad_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles CardLoad.MouseLeftButtonUp
  251. If Not InitLoader.State = LoadState.Failed Then Exit Sub
  252. InitLoader.Start(IsForceRestart:=True)
  253. End Sub
  254. '取消加载
  255. Private Sub CancelLoad() Handles BtnLoadCancel.Click
  256. If InitLoader.State = LoadState.Loading Then
  257. CurrentSubpage = Subpages.PanSelect
  258. InitLoader.Abort()
  259. Else
  260. InitLoader.State = LoadState.Waiting
  261. End If
  262. HiperStop(False)
  263. End Sub
  264. '进度改变
  265. Private Sub UpdateProgress(Optional Value As Double = -1)
  266. If Value = -1 Then Value = InitLoader.Progress
  267. Dim DisplayingProgress As Double = ColumnProgressA.Width.Value
  268. If Math.Round(Value - DisplayingProgress, 3) = 0 Then Exit Sub
  269. If DisplayingProgress > Value Then
  270. ColumnProgressA.Width = New GridLength(Value, GridUnitType.Star)
  271. ColumnProgressB.Width = New GridLength(1 - Value, GridUnitType.Star)
  272. AniStop("Hiper Progress")
  273. Else
  274. Dim NewProgress As Double = If(Value = 1, 1, (Value - DisplayingProgress) * 0.2 + DisplayingProgress)
  275. AniStart({
  276. AaGridLengthWidth(ColumnProgressA, NewProgress - ColumnProgressA.Width.Value, 300, Ease:=New AniEaseOutFluent),
  277. AaGridLengthWidth(ColumnProgressB, (1 - NewProgress) - ColumnProgressB.Width.Value, 300, Ease:=New AniEaseOutFluent)
  278. }, "Hiper Progress")
  279. End If
  280. End Sub
  281. Private Sub CardResized() Handles CardLoad.SizeChanged
  282. RectProgressClip.Rect = New Rect(0, 0, CardLoad.ActualWidth, 12)
  283. End Sub
  284. #End Region
  285. #Region "PanFinish | 加载完成页面"
  286. '复制 IP
  287. Private Sub BtnFinishIp_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnFinishIp.MouseLeftButtonUp
  288. ClipboardSet(LabFinishIp.Text)
  289. End Sub
  290. '退出
  291. Private Sub BtnFinishExit_Click(sender As Object, e As EventArgs) Handles BtnFinishExit.Click
  292. If IsServerSide AndAlso MyMsgBox("你确定要关闭联机房间吗?", "确认退出", "确定", "取消", IsWarn:=True) = 2 Then Exit Sub
  293. HiperExit(False)
  294. End Sub
  295. '复制联机码
  296. Private Sub BtnFinishCopy_Click(sender As Object, e As EventArgs) Handles BtnFinishCopy.Click
  297. End Sub
  298. 'Ping 房主
  299. Private Sub BtnFinishPing_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnFinishPing.MouseLeftButtonUp
  300. LabFinishPing.Text = "检测中"
  301. If TaskPingHost.State = LoadState.Loading Then Exit Sub
  302. TaskPingHost.Start(True, IsForceRestart:=True)
  303. End Sub
  304. Private Shared TaskPingHost As New LoaderTask(Of Boolean, Integer)("HiPer Ping Host",
  305. Sub(Task As LoaderTask(Of Boolean, Integer))
  306. HostPing = -1
  307. HostPing = Ping(HostIp, 5000, Task.Input)
  308. End Sub)
  309. #End Region
  310. #Region "子页面管理"
  311. Public Enum Subpages
  312. PanCert
  313. PanSelect
  314. PanFinish
  315. End Enum
  316. Private _CurrentSubpage As Subpages = Subpages.PanCert
  317. Public Property CurrentSubpage As Subpages
  318. Get
  319. Return _CurrentSubpage
  320. End Get
  321. Set(value As Subpages)
  322. If _CurrentSubpage = value Then Exit Property
  323. _CurrentSubpage = value
  324. Log("[Hiper] 子页面更改为 " & GetStringFromEnum(value))
  325. PageOnContentExit()
  326. If value = Subpages.PanSelect Then
  327. LabSelectCode.Text = "(" & TextCert.Text.Substring(0, Math.Min(TextCert.Text.Length, 3)) & "…)"
  328. End If
  329. End Set
  330. End Property
  331. Private Sub PageLinkHiper_OnPageEnter() Handles Me.PageEnter
  332. FrmLinkHiper.PanCert.Visibility = If(CurrentSubpage = Subpages.PanCert, Visibility.Visible, Visibility.Collapsed)
  333. FrmLinkHiper.PanSelect.Visibility = If(CurrentSubpage = Subpages.PanSelect, Visibility.Visible, Visibility.Collapsed)
  334. FrmLinkHiper.PanFinish.Visibility = If(CurrentSubpage = Subpages.PanFinish, Visibility.Visible, Visibility.Collapsed)
  335. End Sub
  336. Private Shared Sub HiperExit(ExitToCertPage As Boolean)
  337. Log("[Hiper] 要求退出 Hiper(当前加载器状态为 " & GetStringFromEnum(InitLoader.State) & ")")
  338. HiperStop(False)
  339. If InitLoader.State = LoadState.Loading Then InitLoader.Abort()
  340. If InitLoader.State = LoadState.Failed Then InitLoader.State = LoadState.Waiting
  341. RunInUi(Sub()
  342. If FrmLinkHiper Is Nothing OrElse Not FrmLinkHiper.IsLoaded Then Exit Sub
  343. FrmLinkHiper.CurrentSubpage = If(ExitToCertPage, Subpages.PanCert, Subpages.PanSelect)
  344. FrmLinkHiper.PageOnContentExit()
  345. End Sub)
  346. End Sub
  347. #End Region
  348. End Class