2.11.0
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
<local:MyPageRight
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" x:Class="PageLinkFeedback"
|
||||
PanScroll="PanBack">
|
||||
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
|
||||
<StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
|
||||
<local:MyCard Title="关于" Margin="0,0,0,15">
|
||||
<StackPanel Margin="20,40,18,18">
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
<local:MyCard Title="发送反馈" Margin="0,0,0,15">
|
||||
<StackPanel Margin="20,40,18,18">
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
</StackPanel>
|
||||
</local:MyScrollViewer>
|
||||
</local:MyPageRight>
|
||||
@@ -1,2 +0,0 @@
|
||||
Public Class PageLinkFeedback
|
||||
End Class
|
||||
@@ -1,234 +0,0 @@
|
||||
<local:MyPageRight
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" x:Class="PageLinkHiper"
|
||||
d:DesignWidth="800" d:DesignHeight="800">
|
||||
<Grid>
|
||||
<Grid x:Name="PanLoad">
|
||||
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="CardLoad">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="25" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="20" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="18" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="23" />
|
||||
</Grid.RowDefinitions>
|
||||
<local:MyLoading Grid.Column="1" Grid.Row="1" x:Name="Load" Grid.RowSpan="3" Margin="0,0,0,-30" HorizontalAlignment="Center"
|
||||
Text="" TextError="" TextErrorInherit="False" AutoRun="False" IsHitTestVisible="False" />
|
||||
<TextBlock x:Name="LabLoadTitle" Grid.Column="3" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Center" Text="正在创建联机房间" FontSize="19"
|
||||
Margin="0,0,25,1" Foreground="{Binding Foreground, ElementName=Load}" IsHitTestVisible="False" />
|
||||
<TextBlock x:Name="LabLoadDesc" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" VerticalAlignment="Center" Margin="0,5,10,-5" Text="下载联机模块中……" FontSize="14"
|
||||
LineHeight="19" MaxWidth="400" MaxHeight="220" TextWrapping="Wrap" Foreground="{StaticResource ColorBrushGray3}" IsHitTestVisible="False" />
|
||||
<local:MyIconButton Grid.Column="5" Grid.Row="1" x:Name="BtnLoadCancel" Height="28" Width="28" VerticalAlignment="Top"
|
||||
Theme="Black" Opacity="0.5"
|
||||
ToolTip="取消" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="100"
|
||||
LogoScale="0.72" Logo="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid Height="12" VerticalAlignment="Bottom" Grid.ColumnSpan="100" Grid.RowSpan="100" Margin="0,0,0,-0.6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0*" x:Name="ColumnProgressA" />
|
||||
<ColumnDefinition Width="1*" x:Name="ColumnProgressB" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.Clip>
|
||||
<RectangleGeometry RadiusX="6" RadiusY="6" x:Name="RectProgressClip" />
|
||||
</Grid.Clip>
|
||||
<Rectangle Fill="{Binding Foreground, ElementName=Load}" VerticalAlignment="Bottom" Height="2" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
</Grid>
|
||||
<Grid x:Name="PanContent">
|
||||
<Grid x:Name="PanCert">
|
||||
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25" />
|
||||
<ColumnDefinition Width="Auto" /> <!--Logo-->
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="1*" /> <!--文本区 ↓↓-->
|
||||
<ColumnDefinition Width="Auto" /> <!--按钮 1-->
|
||||
<ColumnDefinition Width="Auto" /> <!--按钮 2-->
|
||||
<ColumnDefinition Width="25" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="21" />
|
||||
<RowDefinition Height="Auto" /> <!--标题栏-->
|
||||
<RowDefinition Height="Auto" /> <!--文本区-->
|
||||
<RowDefinition Height="Auto" /> <!--文本框-->
|
||||
<RowDefinition Height="Auto" /> <!--按钮-->
|
||||
<RowDefinition Height="21" />
|
||||
</Grid.RowDefinitions>
|
||||
<Path Grid.Column="1" Grid.Row="1" Height="25" Width="25"
|
||||
Stretch="Uniform" Fill="{DynamicResource ColorBrush3}"
|
||||
Data="M856.3 291.1c-12-29.6-29.5-56-52.2-78.6-22.6-22.6-49.1-40.2-78.6-52.2-28.5-11.5-58.5-17.4-89.3-17.4s-60.8 5.9-89.3 17.4c-29.6 12-56 29.5-78.6 52.2-22.6 22.6-40.2 49.1-52.2 78.6-11.5 28.5-17.4 58.5-17.4 89.3 0 30.8 5.9 60.8 17.4 89.3 1.5 3.6 3 7.2 4.6 10.7l-238 238c-19 19-30.4 43.4-32.3 68.7-2 26.9 6.9 51.6 25 69.5C191.9 873 214 881 236.9 881c27 0 55.2-11.2 77.1-33l40.4-40.4c12.5-12.5 17.6-30.4 13.2-46.6-3.2-11.7 1.5-25.9 11.8-36.3 10.3-10.3 24.5-15 36.2-11.8 16.3 4.4 34.2-0.7 46.8-13.3l95.1-95.1c25.3 8.9 51.6 13.4 78.6 13.4 30.8 0 60.8-5.9 89.3-17.4 29.6-12 56-29.5 78.6-52.2 22.6-22.6 40.2-49.1 52.2-78.6 11.5-28.5 17.4-58.5 17.4-89.3 0.1-30.7-5.7-60.8-17.3-89.3zM427.2 664.2c-28.7-7.1-60.4 2.5-83 25.1-22.7 22.7-32.2 54.4-25.1 83l-40.3 40.3c-20.7 20.7-51.8 24.5-68 8.4-7.6-7.5-11.3-18.3-10.4-30.4 1-13.4 7.3-26.6 17.8-37l229.2-229.2c6.4 8.4 13.4 16.3 20.9 23.9 12.7 12.7 26.6 23.8 41.6 33.2l-82.7 82.7zM810 450.9c-9.5 23.3-23.3 44.2-41.2 62.1-17.9 17.9-38.7 31.7-62.1 41.2-22.5 9.1-46.2 13.7-70.5 13.7-24.3 0-48-4.6-70.5-13.7-2.5-1.7-5.3-2.8-8.1-3.5-20.1-9.3-38.2-21.9-54-37.7-17.9-17.9-31.7-38.7-41.2-62.1-9.1-22.5-13.7-46.2-13.7-70.5 0-24.3 4.6-48 13.7-70.5 9.5-23.3 23.3-44.2 41.2-62.1 17.9-17.9 38.7-31.7 62.1-41.2 22.5-9.1 46.2-13.7 70.5-13.7s48 4.6 70.5 13.7c23.3 9.5 44.2 23.3 62.1 41.2 17.9 17.9 31.7 38.7 41.2 62.1 9.1 22.5 13.7 46.2 13.7 70.5 0 24.3-4.6 48-13.7 70.5z M551.5 295.7c-22.6 22.6-35.1 52.7-35.1 84.7s12.5 62.1 35.1 84.7c23.4 23.4 54 35 84.7 35 30.7 0 61.4-11.7 84.7-35 22.6-22.6 35.1-52.7 35.1-84.7s-12.5-62.1-35.1-84.7c-46.7-46.7-122.7-46.7-169.4 0z m134.1 134.1c-27.2 27.2-71.5 27.2-98.7 0-13.2-13.2-20.4-30.7-20.4-49.4 0-18.6 7.3-36.2 20.4-49.4 13.6-13.6 31.5-20.4 49.4-20.4s35.7 6.8 49.4 20.4c13.2 13.2 20.4 30.7 20.4 49.4-0.1 18.7-7.3 36.2-20.5 49.4z" />
|
||||
<TextBlock Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="1" x:Name="LabCertTitle"
|
||||
Text="输入索引码" FontSize="20" Foreground="{DynamicResource ColorBrush3}" />
|
||||
<TextBlock Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" Margin="0,10,0,6"
|
||||
Text="你需要获取索引码才能使用 HiPer。
如果实在没有索引码,可以在左侧选择 IOI 方式联机。" x:Name="LabCertDesc"
|
||||
FontSize="14" LineHeight="19" MaxWidth="400" TextWrapping="Wrap" Foreground="{StaticResource ColorBrushGray2}" />
|
||||
<local:MyTextBox x:Name="TextCert" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="3"
|
||||
Margin="0,0,0,12" Width="400" MaxLength="100" Height="28">
|
||||
<local:MyTextBox.ValidateRules>
|
||||
<local:ValidateNullOrWhiteSpace />
|
||||
<local:ValidateRegex Regex="^[^\u4e00-\u9fa5]{6,}$" />
|
||||
</local:MyTextBox.ValidateRules>
|
||||
</local:MyTextBox>
|
||||
<local:MyButton Grid.Column="4" Grid.Row="4" Margin="0,0,15,0" Text="获取索引码" Padding="13,8" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://shimo.im/docs/KrkEVXz1K0frowAJ" />
|
||||
<local:MyButton x:Name="BtnCertDone" Grid.Column="5" Grid.Row="4" Text="确定" ColorType="Highlight" Padding="13,8" IsEnabled="False" />
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
</Grid>
|
||||
<Grid x:Name="PanSelect" Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="480" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="120" />
|
||||
<RowDefinition Height="20" />
|
||||
<RowDefinition Height="120" />
|
||||
<RowDefinition Height="20" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<local:MyCard x:Name="BtnSelectCreate" Grid.Column="1" Grid.Row="1">
|
||||
<Grid Margin="35,0,25,0" IsHitTestVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Path Stretch="Uniform" Fill="{DynamicResource ColorBrush3}" Margin="0,25,0,12"
|
||||
Data="M904.479163 416.014006c-41.499044-0.199995-78.198199 20.799521-99.797701 52.698786-4.499896 6.699846-13.299694 9.09979-20.499527 5.399876L398.590818 280.017139c-6.999839-3.499919-10.39976-11.69973-7.999816-19.199557 6.099859-19.199558 9.399783-39.599088 9.399783-60.7986C399.990785 88.721546 308.092902-1.676371 196.795466 0.023589 87.797977 1.72355 0 90.621502 0 200.018982c0 92.597867 62.898551 170.396075 148.196586 193.195549 6.999839 1.899956 11.799728 8.199811 11.799728 15.399646v253.994148c0 7.199834-4.799889 13.399691-11.599733 15.399646C81.198129 697.007533 31.999263 758.806109 31.999263 832.004423c0 88.597959 71.998341 160.296307 160.5963 159.996314 88.09797-0.299993 159.396328-71.798346 159.396328-159.996314v-1.399968c-0.099998-6.099859 3.399922-11.69973 8.799797-14.399668l425.990187-214.495059c6.999839-3.499919 15.499643-1.499965 20.099537 4.79989 21.799498 29.999309 57.198682 49.598857 97.197761 49.598857 66.898459 0 120.997213-54.69874 119.997235-121.797194-1.099975-65.198498-54.498745-118.097279-119.597245-118.297275zM103.797609 296.216766C78.198199 270.517358 63.998526 236.318146 63.998526 200.018982c0-36.299164 14.199673-70.498376 39.799083-96.197784C129.497017 78.12179 163.696229 64.022115 199.995393 64.022115s70.498376 14.099675 96.197784 39.799083c25.699408 25.699408 39.799083 59.798622 39.799083 96.197784 0 15.499643-2.59994 30.499297-7.499828 44.69897-6.599848 19.199558-17.599595 36.699155-32.399253 51.498814-0.899979 0.899979-1.799959 1.699961-2.59994 2.59994-19.499551 18.399576-43.498998 30.499297-69.498399 35.099192-7.79982 1.399968-15.899634 2.099952-23.999447 2.099951-13.799682 0-27.199373-1.999954-39.999079-5.999862-20.999516-6.399853-40.199074-17.899588-56.198705-33.799221z m181.595816 557.887148c-9.99977 42.299026-48.098892 73.898298-93.397848 73.898298-52.898781 0-95.997788-43.099007-95.997789-95.997789 0-41.699039 26.799383-77.298219 63.998526-90.497915 9.99977-3.599917 20.799521-5.499873 31.999263-5.499873s21.999493 1.899956 31.999263 5.499873c22.699477 7.999816 41.499044 24.399438 52.698786 45.398954 7.199834 13.499689 11.29974 28.799337 11.299739 45.098961 0 7.599825-0.899979 14.999654-2.59994 22.099491z m41.299049-108.597498c-20.799521-32.399254-52.998779-56.698694-90.897906-67.498445-6.899841-1.999954-11.799728-8.199811-11.799728-15.399646V412.314091c0-7.699823 5.499873-14.299671 12.9997-15.699638 42.299026-7.899818 79.898159-29.09933 108.297505-59.098638 4.799889-5.099883 12.499712-6.399853 18.69957-3.199927l377.291308 189.995623c11.69973 5.899864 11.69973 22.699477 0 28.599342l-393.990924 198.395429c-7.299832 3.699915-16.199627 1.199972-20.599525-5.799866zM903.979175 592.009952c-19.699546 0-37.099145-10.299763-47.098915-25.699408-5.599871-8.6998-8.899795-19.09956-8.899795-30.299302 0-9.499781 2.399945-18.499574 6.599848-26.399392C863.980096 492.012255 882.579668 480.012532 903.979175 480.012532c30.899288 0 55.99871 25.099422 55.99871 55.99871s-25.099422 55.99871-55.99871 55.99871z" />
|
||||
<TextBlock Grid.Row="1" Text="创建房间" Margin="0,0,0,25" FontSize="20" Foreground="{DynamicResource ColorBrush3}" HorizontalAlignment="Center" />
|
||||
<TextBlock Grid.RowSpan="2" Grid.Column="2" LineHeight="23" FontSize="14" TextWrapping="Wrap" VerticalAlignment="Center" Margin="0,7,0,0"
|
||||
Text="1、打开游戏,在暂停画面选择【对局域网开放】
2、点击这里,并输入游戏显示的端口号
3、将联机码发送给你的朋友" />
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
<local:MyCard x:Name="BtnSelectJoin" Grid.Column="1" Grid.Row="3">
|
||||
<Grid Margin="35,0,25,0" IsHitTestVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Path Stretch="Uniform" Fill="{DynamicResource ColorBrush3}" Margin="0,25,0,12"
|
||||
Data="M896 64H544c-17.7 0-32 14.3-32 32s14.3 32 32 32h352c35.3 0 64 28.7 64 64v640c0 35.3-28.7 64-64 64H544c-17.7 0-32 14.3-32 32s14.3 32 32 32h352c70.7 0 128-57.3 128-128V192c0-70.7-57.3-128-128-128z M821.3 488.3L458.9 160.7c-41.2-37.2-106.9-8-106.9 47.5V339c0 4.4-3.6 8-8 8H32c-17.7 0-32 14.3-32 32v266c0 17.7 14.3 32 32 32h312c4.4 0 8 3.6 8 8v130.9c0 55.5 65.8 84.7 106.9 47.5l362.4-327.6c14.1-12.8 14.1-34.8 0-47.5zM64 597V427c0-8.8 7.2-16 16-16h304c17.7 0 32-14.3 32-32V244.9c0-13.9 16.4-21.2 26.7-11.9L746 506.1c3.5 3.2 3.5 8.7 0 11.9L442.7 791c-10.3 9.3-26.7 2-26.7-11.9V645c0-17.7-14.3-32-32-32H80c-8.8 0-16-7.2-16-16z" />
|
||||
<TextBlock Grid.Row="1" Text="加入房间" Margin="0,0,0,25" FontSize="20" Foreground="{DynamicResource ColorBrush3}" HorizontalAlignment="Center" />
|
||||
<TextBlock Grid.RowSpan="2" Grid.Column="2" LineHeight="23" FontSize="14" TextWrapping="Wrap" VerticalAlignment="Center" Margin="0,7,10,0" HorizontalAlignment="Center"
|
||||
Text="点击这里,然后输入朋友发送给你的联机码" />
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
<local:MyCard x:Name="BtnSelectReturn" Grid.Column="1" Grid.Row="5" HorizontalAlignment="Center">
|
||||
<StackPanel Orientation="Horizontal" IsHitTestVisible="False" Margin="15,12">
|
||||
<Path Stretch="Uniform" Fill="{DynamicResource ColorBrush3}" Height="13" Margin="0,0,8,0"
|
||||
Data="M268.70922 566.468085h929.588652c36.312057 0 72.624113-29.049645 72.624114-72.624113 0-36.312057-29.049645-72.624113-72.624114-72.624114H305.021277l297.758865-297.758865c29.049645-29.049645 29.049645-72.624113 0-101.673759-29.049645-29.049645-72.624113-29.049645-101.673759 0L72.624113 450.269504c-14.524823 14.524823-21.787234 36.312057-21.787234 58.09929 0 21.787234 0 43.574468 21.787234 58.099291l428.48227 428.48227c29.049645 29.049645 72.624113 29.049645 101.673759 0 29.049645-29.049645 29.049645-72.624113 0-101.673759l-334.070922-326.808511z" />
|
||||
<TextBlock Text="修改索引码" FontSize="14" Foreground="{DynamicResource ColorBrush3}" />
|
||||
<TextBlock Text="(28F…)" x:Name="LabSelectCode" FontSize="12" Foreground="{DynamicResource ColorBrushGray4}" VerticalAlignment="Bottom" Margin="5,0,0,0.5" />
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
</Grid>
|
||||
<Grid x:Name="PanFinish" Visibility="Collapsed" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,-50,0,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,20">
|
||||
<StackPanel Orientation="Horizontal" Margin="3,0">
|
||||
<StackPanel x:Name="BtnFinishQuality" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
|
||||
ToolTip="连接状况" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="100" ToolTipService.VerticalOffset="-35">
|
||||
<Path IsHitTestVisible="False" Height="14" Width="14" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" Margin="12,1,7,0"
|
||||
Data="M512 128c212.064 0 384 171.936 384 384s-173.632 384-384 384C299.936 896 128 724.064 128 512S299.936 128 512 128z m-126.4 575.968c-1.728 40.8 3.52 76.8 36.32 115.2 28.576 8.32 58.816 12.832 90.08 12.832 81.984 0 156.8-30.848 213.408-81.536-77.12 7.2-161.6-5.952-289.216-61.856-11.616 7.52-18.976 12.608-50.592 15.36z m-193.44-202.368c0 123.744 53.536 214.272 135.744 272.16-6.08-25.6-8.352-48.448-4.96-91.68-21.344-17.6-34.944-39.264-34.624-82.08-50.816-42.88-82.88-75.712-96.16-98.4zM544 448c-14.944 0-29.12-3.424-41.728-9.504-10.976 12.96-21.376 26.432-31.2 40.512-4.832 6.912-15.36 23.776-31.616 50.624a95.872 95.872 0 0 1 36.384 106.432c155.52 68.16 302.56 62.048 325.952 11.904 23.36-50.112-35.968-139.776-189.504-228.48A95.68 95.68 0 0 1 544 448z m-160 128a32 32 0 1 0 0 64 32 32 0 0 0 0-64z m-161.92-199.2c-16.576 35.52 16.96 99.68 94.08 163.2a95.936 95.936 0 0 1 59.616-27.648c19.936-35.008 30.72-52.736 42.88-70.08 10.944-15.648 22.528-30.656 38.432-49.44-5.696-12.128-8.96-25.6-9.088-39.872-118.176-30.4-206.88-16.96-225.92 23.84z m415.136-47.84c1.824 7.36 3.296 19.104 2.336 32.416 88.96 48.704 153.76 105.056 192.32 160.704 0-118.656-34.208-176.064-75.52-210.976-49.792-5.92-69.952-4.064-119.136 17.856zM544 320a32 32 0 1 0 0 64 32 32 0 0 0 0-64z m-32-128c-82.016 0-156.8 30.848-213.44 81.6 47.264-4.384 96-0.544 170.304 18.624A95.84 95.84 0 0 1 544 256c21.568 0 41.472 7.104 57.504 19.104 35.968-17.28 62.016-25.824 87.136-29.984A318.528 318.528 0 0 0 512 192z" />
|
||||
<TextBlock x:Name="LabFinishQuality" IsHitTestVisible="False" Text="优秀" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0,12,0" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="|" Opacity="0.3" Margin="0,8.8,0,8" RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock.RenderTransform>
|
||||
<ScaleTransform ScaleX="1" ScaleY="2.75" CenterX="0.5" CenterY="0.5" />
|
||||
</TextBlock.RenderTransform>
|
||||
</TextBlock>
|
||||
<StackPanel x:Name="BtnFinishPing" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
|
||||
ToolTip="与房主的延迟(点击刷新)" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="100" ToolTipService.VerticalOffset="-35">
|
||||
<Path IsHitTestVisible="False" Height="14" Width="14" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" Margin="12,0,7,0"
|
||||
Data="M512 409.6a102.4 102.4 0 0 0-51.2 190.464V1024h102.4v-423.936A102.4 102.4 0 0 0 512 409.6z M512 0a512 512 0 0 0-263.168 950.272l51.2-87.552a409.6 409.6 0 1 1 420.864 0l51.2 87.552A512 512 0 0 0 512 0z M819.2 512a307.2 307.2 0 1 0-464.896 263.168l51.2-88.064a204.8 204.8 0 1 1 209.92 0l51.2 88.064A307.2 307.2 0 0 0 819.2 512z" />
|
||||
<TextBlock x:Name="LabFinishPing" IsHitTestVisible="False" Text="15ms" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0,12,0" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="|" x:Name="LineFinishPing" Opacity="0.3" Margin="0,8.8,0,8" RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock.RenderTransform>
|
||||
<ScaleTransform ScaleX="1" ScaleY="2.75" CenterX="0.5" CenterY="0.5" />
|
||||
</TextBlock.RenderTransform>
|
||||
</TextBlock>
|
||||
<StackPanel x:Name="BtnFinishIp" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
|
||||
ToolTip="服务器 IP 地址(点击复制)" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="100" ToolTipService.VerticalOffset="-35">
|
||||
<Path IsHitTestVisible="False" Height="11" Width="11" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" Margin="12,0,7,0"
|
||||
Data="M277.333333 853.333333H192V170.666667h85.333333z m341.333334-597.333333h-170.666667v256h170.666667a128 128 0 0 0 0-256m0-85.333333a213.333333 213.333333 0 0 1 0 426.666666h-170.666667v256h-85.333333V170.666667z" />
|
||||
<TextBlock x:Name="LabFinishIp" IsHitTestVisible="False" Text="6.0.0.1:12345" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0,12,0" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="|" Opacity="0.3" Margin="0,8.8,0,8" RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock.RenderTransform>
|
||||
<ScaleTransform ScaleX="1" ScaleY="2.75" CenterX="0.5" CenterY="0.5" />
|
||||
</TextBlock.RenderTransform>
|
||||
</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
|
||||
ToolTip="索引码剩余时间" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="100" ToolTipService.VerticalOffset="-35">
|
||||
<Path IsHitTestVisible="False" Height="13" Width="13" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" Margin="12,0,7,0"
|
||||
Data="M832 64H192c-35.2 0-64 28.8-64 64v192c0 14.532 4.918 27.965 13.158 38.739a63.808 63.808 0 0 0 5.94 6.869L293.49 512 147.098 658.392a63.808 63.808 0 0 0-5.94 6.869C132.918 676.035 128 689.468 128 704v192c0 35.2 28.8 64 64 64h640c35.2 0 64-28.8 64-64V704c0-14.532-4.918-27.965-13.158-38.739a63.808 63.808 0 0 0-5.94-6.869L730.51 512l146.392-146.392a63.808 63.808 0 0 0 5.94-6.869C891.082 347.965 896 334.532 896 320V128c0-35.2-28.8-64-64-64z m-32 244.49L640.098 466.392c-12.534 12.534-18.749 29.086-18.659 45.608-0.09 16.522 6.125 33.074 18.659 45.608L800 718.51V864H224V718.51l158.902-160.902c12.534-12.534 18.749-29.086 18.659-45.608 0.09-16.522-6.125-33.074-18.659-45.608L224 302.49V160h576v148.49z M476.33 457.292c15.631 17.517 42.263 57.543 8.75 100.373L297.608 745.137a31.809 31.809 0 0 0-2.275 2.536C290.757 753.211 288 760.299 288 768c0 17.6 14.4 32 32 32h384.001c17.6 0 32-14.4 32-32 0-7.701-2.757-14.789-7.333-20.327a32.004 32.004 0 0 0-2.275-2.536L545.71 564.454c-16.012-18.851-39.722-58.366-5.07-100.241l58.388-57.487c12.445-12.445 12.445-32.81 0-45.255a31.711 31.711 0 0 0-13.806-8.102A31.712 31.712 0 0 0 576 352H449c-1.287 0-2.553 0.086-3.801 0.235-7.385 0.548-14.612 3.621-20.227 9.236-12.445 12.445-12.445 32.81 0 45.255l51.358 50.566z" />
|
||||
<TextBlock x:Name="LabFinishTime" IsHitTestVisible="False" Text="2:21" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0,12,0" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
<local:MyCard Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25" />
|
||||
<ColumnDefinition Width="Auto" /> <!--Logo-->
|
||||
<ColumnDefinition Width="13" />
|
||||
<ColumnDefinition Width="1*" /> <!--文本区 ↓↓-->
|
||||
<ColumnDefinition Width="Auto" /> <!--按钮 1-->
|
||||
<ColumnDefinition Width="Auto" /> <!--按钮 2-->
|
||||
<ColumnDefinition Width="25" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="21" />
|
||||
<RowDefinition Height="Auto" /> <!--标题栏-->
|
||||
<RowDefinition Height="Auto" /> <!--文本区-->
|
||||
<RowDefinition Height="Auto" /> <!--按钮-->
|
||||
<RowDefinition Height="21" />
|
||||
</Grid.RowDefinitions>
|
||||
<Path Grid.Column="1" Grid.Row="1" Height="25" Width="25"
|
||||
Stretch="Uniform" Fill="{DynamicResource ColorBrush3}"
|
||||
Data="M845 547.45h65.54A400.6 400.6 0 0 0 712.7 201.77l-33.22 56.49C781.6 318.32 845 429.13 845 547.45zM347.72 253.92L316 196.58a401.21 401.21 0 0 0-207 350.87h65.54a335.66 335.66 0 0 1 173.18-293.53zM509.79 882.68a334 334 0 0 1-181.3-53.2L293 884.57a401.13 401.13 0 0 0 419.1 8.91L679 836.93a334.94 334.94 0 0 1-169.21 45.75z M821.51 625.1A108.64 108.64 0 0 0 752.2 650l-67.31-38.86a185.44 185.44 0 0 0 11.22-63.7c0-91.55-66.38-167.9-153.54-183.42V289a109.14 109.14 0 1 0-65.57 0v75c-87.16 15.53-153.54 91.87-153.54 183.42a185.46 185.46 0 0 0 11.22 63.7L267.39 650a109.17 109.17 0 1 0 35.81 55l64.47-37.23a186 186 0 0 0 284.23 0L716.38 705a109.13 109.13 0 1 0 105.13-79.9zM198.07 777.85a43.6 43.6 0 1 1 43.61-43.61 43.66 43.66 0 0 1-43.61 43.61z m311.72-636.53a43.61 43.61 0 1 1-43.61 43.61 43.65 43.65 0 0 1 43.61-43.61z m0 526.91a120.78 120.78 0 1 1 120.78-120.78 120.91 120.91 0 0 1-120.78 120.77z m311.72 109.62a43.6 43.6 0 1 1 43.61-43.61 43.65 43.65 0 0 1-43.61 43.61z" />
|
||||
<TextBlock x:Name="LabFinishTitle" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="1"
|
||||
Text="已加入 Herobrine 的房间" FontSize="20" Foreground="{DynamicResource ColorBrush3}" />
|
||||
<TextBlock x:Name="LabFinishDesc" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" Margin="0,10,0,12"
|
||||
Text="描述文本。"
|
||||
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" />
|
||||
<local:MyButton x:Name="BtnFinishExit" Grid.Column="5" Grid.Row="3" Text="退出" Padding="13,8" />
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid x:Name="PanAlways" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="15" Opacity="0.5">
|
||||
</Grid>
|
||||
</Grid>
|
||||
</local:MyPageRight>
|
||||
@@ -1,395 +0,0 @@
|
||||
Public Class PageLinkHiper
|
||||
Public Const RequestVersion As Char = "2"
|
||||
|
||||
'记录的启动情况
|
||||
Public Shared IsServerSide As Boolean
|
||||
Private Shared HostIp As String
|
||||
Private Shared HostPort As Integer
|
||||
|
||||
#Region "初始化"
|
||||
|
||||
'加载器初始化
|
||||
Private Sub LoaderInit() Handles Me.Initialized
|
||||
PageLoaderInit(Load, PanLoad, PanContent, PanAlways, InitLoader, AutoRun:=False)
|
||||
'注册自定义的 OnStateChanged
|
||||
AddHandler InitLoader.OnStateChangedUi, AddressOf OnLoadStateChanged
|
||||
End Sub
|
||||
|
||||
Private IsLoad As Boolean = False
|
||||
Private Sub OnLoaded() Handles Me.Loaded
|
||||
FormMain.EndProgramForce(ProcessReturnValues.Aborted)
|
||||
If IsLoad Then Return
|
||||
IsLoad = True
|
||||
'启动监视线程
|
||||
If Not IsWatcherStarted Then RunInNewThread(AddressOf WatcherThread, "Hiper Watcher")
|
||||
'读取索引码
|
||||
Try
|
||||
Dim Time As String = Setup.Get("LinkHiperCertTime")
|
||||
If Time = "" Then
|
||||
Log("[HiPer] 没有缓存凭证")
|
||||
ElseIf Date.Parse(Time) > Date.Now Then
|
||||
TextCert.Text = Setup.Get("LinkHiperCertLast")
|
||||
Log("[HiPer] 缓存凭证尚未过期:" & Time)
|
||||
CurrentSubpage = Subpages.PanSelect
|
||||
Else
|
||||
Log("[HiPer] 缓存凭证已过期:" & Time)
|
||||
LabCertTitle.Text = "输入索引码"
|
||||
LabCertDesc.Text = "你的 HiPer 索引码已经过期,请输入新的索引码。" & vbCrLf & "如果实在没有索引码,可以在左侧选择 IOI 方式联机。"
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "读取缓存凭证失败")
|
||||
Setup.Set("LinkHiperCertTime", "")
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "加载步骤"
|
||||
|
||||
Public Shared PathHiper As String = PathAppdata & "联机模块\"
|
||||
Public Shared WithEvents InitLoader As New LoaderCombo(Of Integer)("HiPer 初始化", {
|
||||
New LoaderTask(Of Integer, Integer)("网络环境:连通检测", AddressOf InitPingCheck) With {.Block = False, .ProgressWeight = 0.5},
|
||||
New LoaderTask(Of Integer, Integer)("网络环境:IP 检测", AddressOf InitIpCheck) With {.Block = False, .ProgressWeight = 1},
|
||||
New LoaderTask(Of Integer, Integer)("检查网络环境", AddressOf InitCheck) With {.ProgressWeight = 0.5},
|
||||
New LoaderTask(Of Integer, List(Of NetFile))("获取所需文件", AddressOf InitGetFile) With {.ProgressWeight = 4},
|
||||
New LoaderDownload("下载所需文件", New List(Of NetFile)) With {.ProgressWeight = 4},
|
||||
New LoaderTask(Of Integer, Integer)("启动联机模块", AddressOf InitLaunch) With {.ProgressWeight = 7}
|
||||
})
|
||||
|
||||
'检查网络状态
|
||||
Private Shared Sub InitPingCheck(Task As LoaderTask(Of Integer, Integer))
|
||||
End Sub
|
||||
Private Shared Sub InitIpCheck()
|
||||
End Sub
|
||||
Private Shared PingTime As Integer, IpCheckStatus As LoadState = LoadState.Loading, IpIsInChina As Boolean
|
||||
Private Shared Sub InitCheck(Task As LoaderTask(Of Integer, Integer))
|
||||
End Sub
|
||||
|
||||
'获取所需文件
|
||||
Private Shared Sub InitGetFile(Task As LoaderTask(Of Integer, List(Of NetFile)))
|
||||
End Sub
|
||||
Public Class CertOutdatedException
|
||||
Inherits Exception
|
||||
End Class
|
||||
'启动联机模块
|
||||
Private Shared Sub InitLaunch(Task As LoaderTask(Of Integer, Integer))
|
||||
End Sub
|
||||
Private Shared PingNodes As Integer, AllNodes As List(Of String)
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "进程管理"
|
||||
|
||||
Private Shared _HiperState As LoadState = LoadState.Waiting
|
||||
Public Shared Property HiperState As LoadState
|
||||
Get
|
||||
Return _HiperState
|
||||
End Get
|
||||
Set(value As LoadState)
|
||||
_HiperState = value
|
||||
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))
|
||||
End Set
|
||||
End Property
|
||||
Public Shared Sub ModuleStopManually() '关闭联机模块按钮
|
||||
HiperExit(False)
|
||||
End Sub
|
||||
|
||||
Private Shared HiperIp As String = Nothing
|
||||
Private Shared HiperProcessId As Integer = -1, McbProcessId As Integer = -1
|
||||
Private Shared HiperCertTime As Date = Date.Now
|
||||
|
||||
''' <summary>
|
||||
''' 若程序正在运行,则结束程序进程,同时初始化状态数据。返回是否关闭了相关进程。
|
||||
''' </summary>
|
||||
Public Shared Function HiperStop(SleepWhenKilled As Boolean) As Boolean
|
||||
Return False
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 启动程序,并等待初始化完成后退出运行,同时更新 HiperIp。
|
||||
''' 若启动失败,则会直接抛出异常。
|
||||
''' 若程序正在运行,则会先停止其运行。
|
||||
''' </summary>
|
||||
Public Shared Sub HiperStart(Task As LoaderTask(Of Integer, Integer))
|
||||
End Sub
|
||||
|
||||
'Hiper 日志
|
||||
Private Shared Sub HiperLogLine(Content As String, Task As LoaderTask(Of Integer, Integer))
|
||||
End Sub
|
||||
Private Shared PossibleFailReason As String = Nothing
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "监视线程"
|
||||
|
||||
'主 Timer 线程
|
||||
Private IsWatcherStarted As Boolean = False
|
||||
Private Sub WatcherThread()
|
||||
Dim Sec15 As Integer = 0
|
||||
Do While True
|
||||
Try
|
||||
For i = 1 To 5
|
||||
Thread.Sleep(200)
|
||||
If InitLoader.State = LoadState.Loading Then
|
||||
RunInUi(AddressOf UpdateProgress)
|
||||
End If
|
||||
Next
|
||||
Thread.Sleep(1000)
|
||||
Sec15 += 1
|
||||
WatcherTimer1()
|
||||
If Sec15 = 15 Then
|
||||
Sec15 = 0
|
||||
WatcherTimer15()
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "联机模块主时钟出错", LogLevel.Feedback)
|
||||
Thread.Sleep(20000)
|
||||
End Try
|
||||
Loop
|
||||
End Sub
|
||||
|
||||
'每 1 秒执行的 Timer
|
||||
Private Sub WatcherTimer1()
|
||||
If HiperState <> LoadState.Finished Then Return
|
||||
RunInUi(Sub()
|
||||
'索引码剩余时间
|
||||
Dim Span As TimeSpan = HiperCertTime - Date.Now
|
||||
If Span.TotalDays >= 30 Then
|
||||
LabFinishTime.Text = "> 30 天"
|
||||
ElseIf Span.TotalDays >= 4 Then
|
||||
LabFinishTime.Text = Span.Days & " 天"
|
||||
ElseIf Span.TotalDays >= 1 Then
|
||||
LabFinishTime.Text = Span.Days & " 天" & If(Span.Hours > 0, " " & Span.Hours & " 小时", "")
|
||||
ElseIf Span.TotalMinutes >= 10 Then
|
||||
LabFinishTime.Text = Span.Hours & ":" & Span.Minutes.ToString.PadLeft(2, "0") & "'"
|
||||
Else
|
||||
LabFinishTime.Text = Span.Minutes & "'" & Span.Seconds.ToString.PadLeft(2, "0") & """"
|
||||
End If
|
||||
'提示索引码即将到期
|
||||
If Span.TotalSeconds <= 5 * 60 AndAlso Span.TotalSeconds > 5 * 60 - 1 AndAlso Setup.Get("LinkHiperCertWarn") Then
|
||||
MyMsgBox("你的索引码还有不到 5 分钟就要过期了!" & vbCrLf & "你可以在设置中关闭这个提示……", "索引码即将过期", "我知道了……")
|
||||
ShowWindowToTop(Handle)
|
||||
Beep()
|
||||
End If
|
||||
'检查索引码到期
|
||||
If Span.TotalSeconds < 2 Then
|
||||
LabCertTitle.Text = "索引码已过期"
|
||||
LabCertDesc.Text = "你的 HiPer 索引码已经过期,请输入新的索引码。" & vbCrLf & "如果实在没有索引码,可以在左侧选择 IOI 方式联机。"
|
||||
TextCert.Text = ""
|
||||
HiperExit(True)
|
||||
ShowWindowToTop(Handle)
|
||||
Beep()
|
||||
Return
|
||||
End If
|
||||
'网络质量
|
||||
Dim QualityScore As Integer = If(IpIsInChina, 0, -2)
|
||||
QualityScore -= Math.Ceiling((Math.Min(PingTime, 600) + Math.Min(PingNodes, 600)) / 80)
|
||||
Select Case QualityScore
|
||||
Case Is >= -1
|
||||
LabFinishQuality.Text = "优秀"
|
||||
Case Is >= -2
|
||||
LabFinishQuality.Text = "优良"
|
||||
Case Is >= -3
|
||||
LabFinishQuality.Text = "良好"
|
||||
Case Is >= -5
|
||||
LabFinishQuality.Text = "一般"
|
||||
Case Is >= -7
|
||||
LabFinishQuality.Text = "较差"
|
||||
Case Else
|
||||
LabFinishQuality.Text = "很差"
|
||||
End Select
|
||||
'Ping
|
||||
If HostPing <> -1 Then
|
||||
If FrmLinkHiper IsNot Nothing AndAlso FrmLinkHiper.LabFinishPing.IsLoaded Then
|
||||
FrmLinkHiper.LabFinishPing.Text = HostPing & "ms"
|
||||
End If
|
||||
End If
|
||||
End Sub)
|
||||
End Sub
|
||||
'每 15 秒执行的 Timer
|
||||
Private Shared HostPing As Integer = -1
|
||||
Private Sub WatcherTimer15()
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "PanCert | 索引码输入页面"
|
||||
|
||||
'检测输入
|
||||
Private Sub TextCert_ValidateChanged(sender As Object, e As EventArgs) Handles TextCert.ValidateChanged
|
||||
BtnCertDone.IsEnabled = TextCert.ValidateResult = ""
|
||||
End Sub
|
||||
Private Sub TextCert_KeyDown(sender As Object, e As KeyEventArgs) Handles TextCert.KeyDown
|
||||
If e.Key = Key.Enter AndAlso BtnCertDone.IsEnabled Then BtnCertDone_Click() '允许回车确认
|
||||
End Sub
|
||||
|
||||
'确认
|
||||
Private Sub BtnCertDone_Click() Handles BtnCertDone.Click
|
||||
CurrentSubpage = Subpages.PanSelect
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "PanSelect | 种类选择页面"
|
||||
|
||||
'返回
|
||||
Private Sub BtnSelectReturn_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectReturn.MouseLeftButtonUp
|
||||
LabCertTitle.Text = "输入索引码"
|
||||
LabCertDesc.Text = "你需要获取索引码才能使用 HiPer。" & vbCrLf & "如果实在没有索引码,可以在左侧选择 IOI 方式联机。"
|
||||
CurrentSubpage = Subpages.PanCert
|
||||
End Sub
|
||||
|
||||
'创建房间
|
||||
Private Sub BtnSelectCreate_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectCreate.MouseLeftButtonUp
|
||||
End Sub
|
||||
Private Sub RoomCreate(Port As Integer)
|
||||
'记录信息
|
||||
HostIp = Nothing : HostPort = Port
|
||||
IsServerSide = True
|
||||
'启动
|
||||
InitLoader.Start(IsForceRestart:=True)
|
||||
End Sub
|
||||
|
||||
'加入房间
|
||||
Private Sub BtnSelectJoin_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectJoin.MouseLeftButtonUp
|
||||
End Sub
|
||||
Private Sub RoomJoin(Ip As String, Port As Integer)
|
||||
'记录信息
|
||||
HostIp = Ip : HostPort = Port
|
||||
IsServerSide = False
|
||||
'启动
|
||||
InitLoader.Start(IsForceRestart:=True)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "PanLoad | 加载中页面"
|
||||
|
||||
'承接状态切换的 UI 改变
|
||||
Private Sub OnLoadStateChanged(Loader As LoaderBase, NewState As LoadState, OldState As LoadState)
|
||||
End Sub
|
||||
Private Shared LoadStep As String = "准备初始化"
|
||||
Private Shared Sub SetLoadDesc(Intro As String, [Step] As String)
|
||||
Log("[Hiper] 连接步骤:" & Intro)
|
||||
LoadStep = [Step]
|
||||
RunInUiWait(Sub()
|
||||
If FrmLinkHiper Is Nothing OrElse Not FrmLinkHiper.LabLoadDesc.IsLoaded Then Return
|
||||
FrmLinkHiper.LabLoadDesc.Text = Intro
|
||||
FrmLinkHiper.UpdateProgress()
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
'承接重试
|
||||
Private Sub CardLoad_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles CardLoad.MouseLeftButtonUp
|
||||
If Not InitLoader.State = LoadState.Failed Then Return
|
||||
InitLoader.Start(IsForceRestart:=True)
|
||||
End Sub
|
||||
|
||||
'取消加载
|
||||
Private Sub CancelLoad() Handles BtnLoadCancel.Click
|
||||
If InitLoader.State = LoadState.Loading Then
|
||||
CurrentSubpage = Subpages.PanSelect
|
||||
InitLoader.Abort()
|
||||
Else
|
||||
InitLoader.State = LoadState.Waiting
|
||||
End If
|
||||
HiperStop(False)
|
||||
End Sub
|
||||
|
||||
'进度改变
|
||||
Private Sub UpdateProgress(Optional Value As Double = -1)
|
||||
If Value = -1 Then Value = InitLoader.Progress
|
||||
Dim DisplayingProgress As Double = ColumnProgressA.Width.Value
|
||||
If Math.Round(Value - DisplayingProgress, 3) = 0 Then Return
|
||||
If DisplayingProgress > Value Then
|
||||
ColumnProgressA.Width = New GridLength(Value, GridUnitType.Star)
|
||||
ColumnProgressB.Width = New GridLength(1 - Value, GridUnitType.Star)
|
||||
AniStop("Hiper Progress")
|
||||
Else
|
||||
Dim NewProgress As Double = If(Value = 1, 1, (Value - DisplayingProgress) * 0.2 + DisplayingProgress)
|
||||
AniStart({
|
||||
AaGridLengthWidth(ColumnProgressA, NewProgress - ColumnProgressA.Width.Value, 300, Ease:=New AniEaseOutFluent),
|
||||
AaGridLengthWidth(ColumnProgressB, (1 - NewProgress) - ColumnProgressB.Width.Value, 300, Ease:=New AniEaseOutFluent)
|
||||
}, "Hiper Progress")
|
||||
End If
|
||||
End Sub
|
||||
Private Sub CardResized() Handles CardLoad.SizeChanged
|
||||
RectProgressClip.Rect = New Rect(0, 0, CardLoad.ActualWidth, 12)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "PanFinish | 加载完成页面"
|
||||
|
||||
'复制 IP
|
||||
Private Sub BtnFinishIp_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnFinishIp.MouseLeftButtonUp
|
||||
ClipboardSet(LabFinishIp.Text)
|
||||
End Sub
|
||||
|
||||
'退出
|
||||
Private Sub BtnFinishExit_Click(sender As Object, e As EventArgs) Handles BtnFinishExit.Click
|
||||
If IsServerSide AndAlso MyMsgBox("你确定要关闭联机房间吗?", "确认退出", "确定", "取消", IsWarn:=True) = 2 Then Return
|
||||
HiperExit(False)
|
||||
End Sub
|
||||
|
||||
'复制联机码
|
||||
Private Sub BtnFinishCopy_Click(sender As Object, e As EventArgs) Handles BtnFinishCopy.Click
|
||||
End Sub
|
||||
|
||||
'Ping 房主
|
||||
Private Sub BtnFinishPing_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnFinishPing.MouseLeftButtonUp
|
||||
LabFinishPing.Text = "检测中"
|
||||
If TaskPingHost.State = LoadState.Loading Then Return
|
||||
TaskPingHost.Start(True, IsForceRestart:=True)
|
||||
End Sub
|
||||
Private Shared TaskPingHost As New LoaderTask(Of Boolean, Integer)("HiPer Ping Host",
|
||||
Sub(Task As LoaderTask(Of Boolean, Integer))
|
||||
HostPing = -1
|
||||
HostPing = Ping(HostIp, 5000, Task.Input)
|
||||
End Sub)
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "子页面管理"
|
||||
|
||||
Public Enum Subpages
|
||||
PanCert
|
||||
PanSelect
|
||||
PanFinish
|
||||
End Enum
|
||||
Private _CurrentSubpage As Subpages = Subpages.PanCert
|
||||
Public Property CurrentSubpage As Subpages
|
||||
Get
|
||||
Return _CurrentSubpage
|
||||
End Get
|
||||
Set(value As Subpages)
|
||||
If _CurrentSubpage = value Then Return
|
||||
_CurrentSubpage = value
|
||||
Log("[Hiper] 子页面更改为 " & GetStringFromEnum(value))
|
||||
PageOnContentExit()
|
||||
If value = Subpages.PanSelect Then
|
||||
LabSelectCode.Text = "(" & TextCert.Text.Substring(0, Math.Min(TextCert.Text.Length, 3)) & "…)"
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
|
||||
Private Sub PageLinkHiper_OnPageEnter() Handles Me.PageEnter
|
||||
FrmLinkHiper.PanCert.Visibility = If(CurrentSubpage = Subpages.PanCert, Visibility.Visible, Visibility.Collapsed)
|
||||
FrmLinkHiper.PanSelect.Visibility = If(CurrentSubpage = Subpages.PanSelect, Visibility.Visible, Visibility.Collapsed)
|
||||
FrmLinkHiper.PanFinish.Visibility = If(CurrentSubpage = Subpages.PanFinish, Visibility.Visible, Visibility.Collapsed)
|
||||
End Sub
|
||||
|
||||
Private Shared Sub HiperExit(ExitToCertPage As Boolean)
|
||||
Log("[Hiper] 要求退出 Hiper(当前加载器状态为 " & GetStringFromEnum(InitLoader.State) & ")")
|
||||
HiperStop(False)
|
||||
If InitLoader.State = LoadState.Loading Then InitLoader.Abort()
|
||||
If InitLoader.State = LoadState.Failed Then InitLoader.State = LoadState.Waiting
|
||||
RunInUi(Sub()
|
||||
If FrmLinkHiper Is Nothing OrElse Not FrmLinkHiper.IsLoaded Then Return
|
||||
FrmLinkHiper.CurrentSubpage = If(ExitToCertPage, Subpages.PanCert, Subpages.PanSelect)
|
||||
FrmLinkHiper.PageOnContentExit()
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
End Class
|
||||
@@ -1,50 +0,0 @@
|
||||
<local:MyPageRight
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:System="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" x:Class="PageLinkIoi"
|
||||
PanScroll="PanBack">
|
||||
<Grid>
|
||||
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
|
||||
<StackPanel Orientation="Vertical" Margin="25,10">
|
||||
<local:MyCard Margin="0,15,0,0" x:Name="CardUser" Title="已连接的玩家 (0)">
|
||||
<StackPanel Margin="20,37,20,15">
|
||||
<local:MyHint Margin="5,2,5,8" x:Name="LabHint" />
|
||||
<StackPanel x:Name="PanUserList" />
|
||||
<Grid Height="35" Margin="5,8,5,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<local:MyButton x:Name="BtnLeftCreate" Grid.Column="0" MinWidth="140" Text="建立连接" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
|
||||
<local:MyButton x:Name="BtnLeftCopy" Grid.Column="1" MinWidth="140" Text="复制联机码" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
<local:MyCard Margin="0,15" Title="房间列表" x:Name="CardRoom">
|
||||
<StackPanel Margin="20,37,20,15">
|
||||
<StackPanel x:Name="PanRoom">
|
||||
<!--<local:MyListItem Type="Clickable" PaddingRight="60" Height="40" Title="00ll00" Info="已连接,1100 ms" Logo="pack://application:,,,/images/Blocks/Grass.png">
|
||||
<local:MyListItem.Buttons>
|
||||
<x:Array Type="{x:Type local:MyIconButton}">
|
||||
<local:MyIconButton ToolTip="刷新" ToolTipService.Placement="Bottom" ToolTipService.HorizontalOffset="-10" ToolTipService.VerticalOffset="5" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
|
||||
<local:MyIconButton ToolTip="断开" ToolTipService.Placement="Bottom" ToolTipService.HorizontalOffset="-10" ToolTipService.VerticalOffset="5" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Logo="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z" />
|
||||
</x:Array>
|
||||
</local:MyListItem.Buttons>
|
||||
</local:MyListItem>-->
|
||||
</StackPanel>
|
||||
<local:MyListItem x:Name="BtnCreate" Type="Clickable" Title="创建房间" Height="34" PaddingLeft="0"
|
||||
Logo="M512.277 954.412c-118.89 0-230.659-46.078-314.73-129.73S67.12 629.666 67.12 511.222s46.327-229.744 130.398-313.427 195.82-129.73 314.73-129.73 230.659 46.078 314.72 129.73S957.397 392.81 957.397 511.183 911.078 740.96 826.97 824.642s-195.8 129.77-314.692 129.77z m0-822.784c-101.972 0-197.809 39.494-269.865 111.222s-111.7 166.997-111.7 268.373 39.653 196.695 111.67 268.335S410.246 890.78 512.248 890.78s197.809-39.484 269.865-111.222 111.7-166.998 111.67-268.374c-0.03-101.375-39.654-196.665-111.67-268.303S614.22 131.628 512.277 131.628z m222.585 347.8H544.073V288.64c-0.76-17.561-15.613-31.18-33.173-30.419-16.495 0.714-29.704 13.924-30.419 30.419v190.787H289.703c-17.56 0.761-31.179 15.614-30.419 33.174 0.715 16.494 13.924 29.703 30.42 30.418H480.48v190.788c0.761 17.56 15.614 31.179 33.174 30.419 16.494-0.715 29.703-13.925 30.418-30.42V543.02h190.788c17.56 0.762 32.413-12.857 33.173-30.418 0.762-17.561-12.858-32.414-30.419-33.174a31.683 31.683 0 0 0-2.753 0z" />
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
</StackPanel>
|
||||
</local:MyScrollViewer>
|
||||
<local:MyCard Opacity="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40,0" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
|
||||
<local:MyLoading Text="正在加载联机模块" Margin="20,20,20,17" x:Name="Load" ShowProgress="True" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</local:MyCard>
|
||||
<Grid x:Name="PanAlways" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="15" Opacity="0.5">
|
||||
<local:MyTextButton Text="联机服务由 速聚 授权提供" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.the.bb/zh-CN.html" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</local:MyPageRight>
|
||||
@@ -1,411 +0,0 @@
|
||||
Imports System.Net.Sockets
|
||||
|
||||
Public Class PageLinkIoi
|
||||
Public Const RequestVersion As Integer = 4
|
||||
Public Const IoiVersion As Integer = 10 '由于已关闭更新渠道,在提升 IoiVersion 时必须提升 RequestVersion
|
||||
Public Shared PathIoi As String = PathAppdata & "联机模块\IOI 联机模块.exe"
|
||||
|
||||
#Region "进程管理"
|
||||
|
||||
Private Shared IoiId As String, IoiPassword As String
|
||||
Private Shared IoiProcess As Process = Nothing
|
||||
Private Shared IoiState As LoadState = LoadState.Waiting
|
||||
|
||||
''' <summary>
|
||||
''' 若 Ioi 正在运行,则结束 Ioi 进程,同时初始化状态数据。返回是否关闭了对应进程。
|
||||
''' </summary>
|
||||
Public Shared Function IoiStop(SleepWhenKilled As Boolean) As Boolean
|
||||
Return False
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 启动 Ioi,并等待初始化完成后退出运行,同时更新 IoiId 与 IoiPassword。
|
||||
''' 正常初始化返回 True,需要更新返回 False,其余情况抛出异常。
|
||||
''' 若 Ioi 正在运行,则会先停止其运行。
|
||||
''' </summary>
|
||||
Public Shared Function IoiStart() As Boolean
|
||||
Return False
|
||||
End Function
|
||||
|
||||
'Ioi 日志
|
||||
Private Shared Sub IoiLogLine(Content As String)
|
||||
End Sub
|
||||
Private Shared LogLinesCount As Integer = 0
|
||||
Private Shared LastPortsId As String = "" '上一个收到 portssub 的 ID,用于记录端口
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "时钟"
|
||||
|
||||
'UI 线程刷新
|
||||
Private Shared UserListIdentifyCache As String = ""
|
||||
Private Shared RoomListIdentifyCache As String = ""
|
||||
Public Sub RefreshUi()
|
||||
End Sub
|
||||
|
||||
'工作线程刷新
|
||||
Public Sub RefreshWorker()
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "发送请求"
|
||||
|
||||
''' <summary>
|
||||
''' 发送 Portsub 请求并等待获取控制台端口。进度将从 0 变化至 80%。
|
||||
''' </summary>
|
||||
Private Shared Sub SendPortsubRequest(User As LinkUserIoi)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 向控制台发送 Connect 请求。
|
||||
''' </summary>
|
||||
Private Shared Sub SendConnectRequest(User As LinkUserIoi)
|
||||
Dim RawJson As New JObject()
|
||||
RawJson("version") = RequestVersion
|
||||
RawJson("name") = GetPlayerName()
|
||||
RawJson("id") = IoiId
|
||||
RawJson("type") = "connect"
|
||||
User.Send(RawJson)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 向控制台发送 Update 请求。
|
||||
''' </summary>
|
||||
Private Shared Sub SendUpdateRequest(User As LinkUserIoi, Stage As Integer, Optional Unique As Long = -1)
|
||||
If Unique = -1 Then Unique = GetTimeTick()
|
||||
Dim RawJson As New JObject
|
||||
RawJson("name") = GetPlayerName()
|
||||
RawJson("id") = IoiId
|
||||
RawJson("type") = "update"
|
||||
RawJson("stage") = Stage
|
||||
RawJson("unique") = Unique
|
||||
If Stage < 3 Then
|
||||
Dim Rooms As New JArray
|
||||
For Each Room In RoomListForMe
|
||||
Dim RoomObject As New JObject
|
||||
RoomObject("name") = Room.DisplayName
|
||||
RoomObject("port") = Room.Port
|
||||
Rooms.Add(RoomObject)
|
||||
Next
|
||||
RawJson("rooms") = Rooms
|
||||
User.PingPending(Unique) = Date.Now
|
||||
End If
|
||||
User.Send(RawJson)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 尝试发送断开请求,并将其从用户列表中移除。
|
||||
''' </summary>
|
||||
Private Shared Sub SendDisconnectRequest(User As LinkUserIoi, Optional Message As String = Nothing, Optional IsError As Boolean = False)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "左边栏操作"
|
||||
|
||||
'刷新连接
|
||||
Private Shared Sub BtnListRefresh_Click(sender As MyIconButton, e As EventArgs)
|
||||
End Sub
|
||||
'断开连接
|
||||
Private Shared Sub BtnListDisconnect_Click(sender As MyIconButton, e As EventArgs)
|
||||
End Sub
|
||||
'复制联机码
|
||||
Public Shared Sub BtnLeftCopy_Click() Handles BtnLeftCopy.Click
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "玩家名"
|
||||
|
||||
''' <summary>
|
||||
''' 获取当前的玩家名。
|
||||
''' </summary>
|
||||
Public Shared Function GetPlayerName() As String
|
||||
Return ""
|
||||
End Function
|
||||
Private Shared AutogenPlayerName As String = Nothing '并非由玩家自定义,而是自动生成的玩家名
|
||||
''' <summary>
|
||||
''' 检查某个玩家名是否合法。
|
||||
''' </summary>
|
||||
Private Shared Function IsPlayerNameValid(Name As String) As Boolean
|
||||
Return True
|
||||
End Function
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "请求核心"
|
||||
|
||||
''' <summary>
|
||||
''' 启动 Socket 监听核心。
|
||||
''' </summary>
|
||||
Public Shared Sub StartSocketListener()
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "用户核心"
|
||||
|
||||
'用户基类
|
||||
Public MustInherit Class LinkUserBase
|
||||
Implements IDisposable
|
||||
|
||||
'基础数据
|
||||
Public Uuid As Integer = GetUuid()
|
||||
Public Id As String
|
||||
Public DisplayName As String
|
||||
|
||||
'请求管理
|
||||
Public Socket As Socket = Nothing
|
||||
Public Sub Send(Request As JObject)
|
||||
End Sub
|
||||
Public ListenerThread As Thread = Nothing
|
||||
Public Sub StartListener()
|
||||
End Sub
|
||||
Public Sub BindSocket(Socket As Socket)
|
||||
If Me.Socket IsNot Nothing Then Throw New Exception("该用户已经绑定了 Socket")
|
||||
Me.Socket = Socket
|
||||
StartListener()
|
||||
End Sub
|
||||
|
||||
'Ping
|
||||
'0:与 Ping 计算无关,不回应
|
||||
'1:A to B,2:B to A,3:A to B
|
||||
Public PingPending As New Dictionary(Of Long, Date)
|
||||
Public PingRecord As New Queue(Of Integer)
|
||||
|
||||
'心跳包
|
||||
Public LastSend As Date = Date.Now
|
||||
Public LastReceive As Date = Date.Now
|
||||
|
||||
'类型转换
|
||||
Public Sub New(Id As String, DisplayName As String)
|
||||
Me.Id = Id
|
||||
Me.DisplayName = DisplayName
|
||||
Log("[IOI] 无通信包的新用户对象:" & ToString())
|
||||
End Sub
|
||||
Public Sub New(Id As String, DisplayName As String, Socket As Socket)
|
||||
Me.Id = Id
|
||||
Me.DisplayName = DisplayName
|
||||
Me.Socket = Socket
|
||||
Log("[IOI] 新用户对象:" & ToString())
|
||||
StartListener()
|
||||
End Sub
|
||||
Public Overrides Function ToString() As String
|
||||
Return DisplayName & " @ " & Id & " #" & Uuid
|
||||
End Function
|
||||
Public Shared Widening Operator CType(User As LinkUserBase) As String
|
||||
Return User.ToString
|
||||
End Operator
|
||||
|
||||
'释放资源
|
||||
Public IsDisposed As Boolean = False
|
||||
Protected Overridable Sub Dispose(IsDisposing As Boolean)
|
||||
If Socket IsNot Nothing Then Socket.Dispose()
|
||||
If ListenerThread IsNot Nothing AndAlso ListenerThread.IsAlive Then ListenerThread.Interrupt()
|
||||
End Sub
|
||||
Public Sub Dispose() Implements IDisposable.Dispose
|
||||
If Not IsDisposed Then
|
||||
IsDisposed = True
|
||||
Dispose(True)
|
||||
End If
|
||||
GC.SuppressFinalize(Me)
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
'用户对象
|
||||
Public Shared UserList As New Dictionary(Of String, LinkUserIoi)
|
||||
Public Class LinkUserIoi
|
||||
Inherits LinkUserBase
|
||||
Public Sub New(Id As String, DisplayName As String, Socket As Socket)
|
||||
MyBase.New(Id, DisplayName, Socket)
|
||||
End Sub
|
||||
Public Sub New(Id As String, DisplayName As String)
|
||||
MyBase.New(Id, DisplayName)
|
||||
End Sub
|
||||
|
||||
'基础数据
|
||||
Public Ports As New Dictionary(Of Integer, String)
|
||||
Public Rooms As New List(Of RoomEntry)
|
||||
|
||||
'进度与 UI
|
||||
Public Progress As Double = 0
|
||||
Public RelativeThread As Thread = Nothing
|
||||
|
||||
Public Function GetDescription() As String
|
||||
Return If(Progress < 1,
|
||||
"正在连接," & Math.Round(Progress * 100) & "%",
|
||||
"已连接," & If(Not PingRecord.Any(), "检查延迟中", Math.Round(PingRecord.Average) & "ms"))
|
||||
End Function
|
||||
Public Function ToListItem() As MyListItem
|
||||
Dim Item As New MyListItem With {
|
||||
.Title = DisplayName, .Height = 42, .Tag = Me, .Type = MyListItem.CheckType.None,
|
||||
.Logo = "pack://application:,,,/images/Blocks/Grass.png"}
|
||||
'绑定图标按钮
|
||||
Dim BtnRefresh As New MyIconButton With {.Logo = Logo.IconButtonRefresh, .LogoScale = 0.85, .ToolTip = "刷新", .Tag = Me}
|
||||
AddHandler BtnRefresh.Click, AddressOf BtnListRefresh_Click
|
||||
ToolTipService.SetPlacement(BtnRefresh, Primitives.PlacementMode.Bottom)
|
||||
ToolTipService.SetHorizontalOffset(BtnRefresh, -10)
|
||||
ToolTipService.SetVerticalOffset(BtnRefresh, 5)
|
||||
ToolTipService.SetInitialShowDelay(BtnRefresh, 200)
|
||||
Dim BtnClose As New MyIconButton With {.Logo = Logo.IconButtonCross, .LogoScale = 0.85, .ToolTip = "断开", .Tag = Me}
|
||||
AddHandler BtnClose.Click, AddressOf BtnListDisconnect_Click
|
||||
ToolTipService.SetPlacement(BtnClose, Primitives.PlacementMode.Bottom)
|
||||
ToolTipService.SetHorizontalOffset(BtnClose, -10)
|
||||
ToolTipService.SetVerticalOffset(BtnClose, 5)
|
||||
ToolTipService.SetInitialShowDelay(BtnClose, 200)
|
||||
Item.Buttons = {BtnRefresh, BtnClose}
|
||||
'刷新并返回
|
||||
RefreshUi(Item)
|
||||
Return Item
|
||||
End Function
|
||||
Public Sub RefreshUi(RelatedListItem As MyListItem)
|
||||
RelatedListItem.Title = DisplayName
|
||||
RelatedListItem.Info = GetDescription()
|
||||
RelatedListItem.Buttons(0).Visibility = If(Progress = 1, Visibility.Visible, Visibility.Collapsed)
|
||||
End Sub
|
||||
|
||||
'释放
|
||||
Protected Overrides Sub Dispose(IsDisposing As Boolean)
|
||||
Log("[IOI] 用户资源释放(IOI, " & DisplayName & ")")
|
||||
If RelativeThread IsNot Nothing AndAlso RelativeThread.IsAlive Then RelativeThread.Interrupt()
|
||||
UserList.Remove(Id)
|
||||
MyBase.Dispose(IsDisposing)
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
'房间对象
|
||||
Private Shared RoomListForMe As New List(Of RoomEntry)
|
||||
|
||||
Private Function GetRoomList() As List(Of RoomEntry)
|
||||
Dim RoomList As New List(Of RoomEntry)(RoomListForMe)
|
||||
For i = 0 To UserList.Count - 1
|
||||
If i > UserList.Count - 1 Then Exit For
|
||||
RoomList.AddRange(UserList.Values(i).Rooms)
|
||||
Next
|
||||
Return RoomList
|
||||
End Function
|
||||
Public Class RoomEntry
|
||||
|
||||
'基础数据
|
||||
Public Port As Integer
|
||||
Public DisplayName As String
|
||||
Public User As LinkUserIoi = Nothing '若 IsOwner = True,则此项为 Nothing
|
||||
Public IsOwner As Boolean
|
||||
Public ReadOnly Property Ip As String
|
||||
Get
|
||||
If IsOwner Then
|
||||
Return "localhost:" & Port
|
||||
Else
|
||||
Return User.Ports(Port) & ":" & Port
|
||||
End If
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'类型转换
|
||||
Public Sub New(Port As Integer, DisplayName As String, Optional User As LinkUserIoi = Nothing)
|
||||
Me.IsOwner = User Is Nothing
|
||||
Me.User = User
|
||||
Me.DisplayName = DisplayName
|
||||
Me.Port = Port
|
||||
End Sub
|
||||
Public Overrides Function ToString() As String
|
||||
Return DisplayName & " - " & Port & " - " & IsOwner
|
||||
End Function
|
||||
Public Shared Widening Operator CType(Room As RoomEntry) As String
|
||||
Return Room.ToString
|
||||
End Operator
|
||||
Public Shared Function SelectPort(Room As RoomEntry) As Integer
|
||||
Return Room.Port
|
||||
End Function
|
||||
|
||||
'UI
|
||||
Public Function GetDescription() As String
|
||||
If IsOwner Then
|
||||
Return "由我创建,端口 " & Port
|
||||
Else
|
||||
Return "由 " & User.DisplayName & " 创建,端口 " & Port
|
||||
End If
|
||||
End Function
|
||||
Public Function ToListItem() As MyListItem
|
||||
Dim Item As New MyListItem With {
|
||||
.Title = DisplayName, .Height = 42, .Info = GetDescription(), .Tag = Me,
|
||||
.Type = If(IsOwner, MyListItem.CheckType.None, MyListItem.CheckType.Clickable),
|
||||
.Logo = "pack://application:,,,/images/Blocks/" & If(IsOwner, "GrassPath", "Grass") & ".png"}
|
||||
If IsOwner Then
|
||||
'绑定图标按钮
|
||||
Dim BtnEdit As New MyIconButton With {.Logo = Logo.IconButtonEdit, .LogoScale = 1, .ToolTip = "修改名称", .Tag = Me}
|
||||
AddHandler BtnEdit.Click, AddressOf BtnRoomEdit_Click
|
||||
ToolTipService.SetPlacement(BtnEdit, Primitives.PlacementMode.Bottom)
|
||||
ToolTipService.SetHorizontalOffset(BtnEdit, -22)
|
||||
ToolTipService.SetVerticalOffset(BtnEdit, 5)
|
||||
ToolTipService.SetInitialShowDelay(BtnEdit, 200)
|
||||
Dim BtnClose As New MyIconButton With {.Logo = Logo.IconButtonCross, .LogoScale = 0.85, .ToolTip = "关闭", .Tag = Me}
|
||||
AddHandler BtnClose.Click, AddressOf BtnRoomClose_Click
|
||||
ToolTipService.SetPlacement(BtnClose, Primitives.PlacementMode.Bottom)
|
||||
ToolTipService.SetHorizontalOffset(BtnClose, -10)
|
||||
ToolTipService.SetVerticalOffset(BtnClose, 5)
|
||||
ToolTipService.SetInitialShowDelay(BtnClose, 200)
|
||||
Item.Buttons = {BtnEdit, BtnClose}
|
||||
Else
|
||||
'绑定点击事件
|
||||
AddHandler Item.Click, AddressOf BtnRoom_Click
|
||||
End If
|
||||
Return Item
|
||||
End Function
|
||||
Public Sub RefreshUi(RelatedListItem As MyListItem)
|
||||
RelatedListItem.Title = DisplayName
|
||||
RelatedListItem.Info = GetDescription()
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
|
||||
#End Region
|
||||
|
||||
'正向与反向连接
|
||||
Public Shared Sub BtnLeftCreate_Click() Handles BtnLeftCreate.Click
|
||||
End Sub
|
||||
Private Shared Sub SendPortsubBack(User As LinkUserIoi, TargetVersion As Integer)
|
||||
End Sub
|
||||
|
||||
'创建房间
|
||||
Private Sub LinkCreate() Handles BtnCreate.Click
|
||||
End Sub
|
||||
Private Shared Sub SendUpdateRequestToAllUsers()
|
||||
For i = 0 To UserList.Count - 1
|
||||
If i > UserList.Count - 1 Then Exit For
|
||||
Dim User = UserList.Values(i)
|
||||
If User.Progress < 1 Then Continue For
|
||||
Try
|
||||
SendUpdateRequest(User, 1) '不需要使用多线程,发送实际会瞬间完成
|
||||
Catch ex As Exception
|
||||
Log(ex, "发送全局刷新请求失败(" & User.DisplayName & ")")
|
||||
End Try
|
||||
Next
|
||||
End Sub
|
||||
'修改房间名称
|
||||
Private Shared Sub BtnRoomEdit_Click(sender As MyIconButton, e As EventArgs)
|
||||
End Sub
|
||||
'加入房间
|
||||
Private Shared Sub BtnRoom_Click(sender As MyListItem, e As EventArgs)
|
||||
Dim Room As RoomEntry = sender.Tag
|
||||
If MyMsgBox("请在多人游戏页面点击直接连接,输入 " & Room.Ip & " 以进入服务器!", "加入房间", "复制地址", "确定") = 1 Then
|
||||
ClipboardSet(Room.Ip)
|
||||
End If
|
||||
End Sub
|
||||
'关闭房间
|
||||
Private Shared Sub BtnRoomClose_Click(sender As MyIconButton, e As EventArgs)
|
||||
End Sub
|
||||
|
||||
'获取数据包
|
||||
Public Shared Sub ReceiveJson(JsonData As JObject, Optional NewSocket As Socket = Nothing)
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 从用户列表中移除一位用户。提示信息视作该用户主动离开。
|
||||
''' </summary>
|
||||
Public Shared Sub UserRemove(User As LinkUserIoi, ShowLeaveMessage As Boolean)
|
||||
End Sub
|
||||
|
||||
Public Shared Sub ModuleStopManually()
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
@@ -1,44 +0,0 @@
|
||||
<local:MyPageLeft x:Class="PageLinkLeft"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:PCL"
|
||||
mc:Ignorable="d" AnimatedControl="PanItem" MinWidth="150">
|
||||
<StackPanel Orientation="Vertical" x:Name="PanItem" Margin="0,12,0,0">
|
||||
<TextBlock Text="联机方式" Margin="13,6,5,4" Opacity="0.6" FontSize="12" />
|
||||
<local:MyListItem x:Name="ItemHiper" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="1" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="HiPer"
|
||||
LogoScale="0.85" Logo="M554.496 170.496c141.312 0 256 114.688 256 256s-114.688 256-256 256H402.432c-22.016-1.536-39.424-19.968-39.424-42.496a42.391 42.391 0 0 1 42.496-42.496h149.504c94.208 0 170.496-76.288 170.496-170.496S648.704 256 554.496 256h-256C204.288 256 128 332.288 128 426.496c0 38.4 12.8 73.728 33.792 102.4 5.632 7.168 8.704 15.872 8.704 25.6A42.391 42.391 0 0 1 128 596.992c-11.264 0-20.992-4.096-28.672-11.264l-0.512 0.512c-35.328-44.032-56.32-99.328-56.32-159.744 0-141.312 114.688-256 256-256h256z m64 192h3.072c22.016 1.536 39.424 19.968 39.424 42.496a42.391 42.391 0 0 1-42.496 42.496H469.504c-94.208 0-170.496 76.288-170.496 170.496S375.296 788.48 469.504 788.48h256C819.712 788.48 896 712.192 896 617.984c0-38.4-12.8-73.728-33.792-102.4-5.632-7.168-8.704-15.872-8.704-25.6A42.391 42.391 0 0 1 896 447.488c11.264 0 20.992 4.096 28.672 11.264l0.512-0.512c35.328 44.032 56.32 99.328 56.32 159.744 0 141.312-114.688 256-256 256h-256c-141.312 0-256-114.688-256-256s114.688-256 256-256h148.992z">
|
||||
<local:MyListItem.Buttons>
|
||||
<x:Array Type="{x:Type local:MyIconButton}">
|
||||
<local:MyIconButton ToolTip="关闭联机模块" Loaded="BtnHiperStop_Loaded" Click="BtnHiperStop_Click"
|
||||
ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" ToolTipService.VerticalOffset="-2" ToolTipService.InitialShowDelay="200" LogoScale="0.7"
|
||||
Logo="M576 512l277.333333 277.333333-64 64-277.333333-277.333333L234.666667 853.333333 170.666667 789.333333l277.333333-277.333333L170.666667 234.666667 234.666667 170.666667l277.333333 277.333333L789.333333 170.666667 853.333333 234.666667 576 512z" />
|
||||
</x:Array>
|
||||
</local:MyListItem.Buttons>
|
||||
</local:MyListItem>
|
||||
<local:MyListItem x:Name="ItemIoi" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="2" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="IOI"
|
||||
LogoScale="0.85" Logo="M554.496 170.496c141.312 0 256 114.688 256 256s-114.688 256-256 256H402.432c-22.016-1.536-39.424-19.968-39.424-42.496a42.391 42.391 0 0 1 42.496-42.496h149.504c94.208 0 170.496-76.288 170.496-170.496S648.704 256 554.496 256h-256C204.288 256 128 332.288 128 426.496c0 38.4 12.8 73.728 33.792 102.4 5.632 7.168 8.704 15.872 8.704 25.6A42.391 42.391 0 0 1 128 596.992c-11.264 0-20.992-4.096-28.672-11.264l-0.512 0.512c-35.328-44.032-56.32-99.328-56.32-159.744 0-141.312 114.688-256 256-256h256z m64 192h3.072c22.016 1.536 39.424 19.968 39.424 42.496a42.391 42.391 0 0 1-42.496 42.496H469.504c-94.208 0-170.496 76.288-170.496 170.496S375.296 788.48 469.504 788.48h256C819.712 788.48 896 712.192 896 617.984c0-38.4-12.8-73.728-33.792-102.4-5.632-7.168-8.704-15.872-8.704-25.6A42.391 42.391 0 0 1 896 447.488c11.264 0 20.992 4.096 28.672 11.264l0.512-0.512c35.328 44.032 56.32 99.328 56.32 159.744 0 141.312-114.688 256-256 256h-256c-141.312 0-256-114.688-256-256s114.688-256 256-256h148.992z">
|
||||
<local:MyListItem.Buttons>
|
||||
<x:Array Type="{x:Type local:MyIconButton}">
|
||||
<local:MyIconButton ToolTip="关闭联机模块" Loaded="BtnIoiStop_Loaded" Click="BtnIoiStop_Click"
|
||||
ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" ToolTipService.VerticalOffset="-2" ToolTipService.InitialShowDelay="200" LogoScale="0.7"
|
||||
Logo="M576 512l277.333333 277.333333-64 64-277.333333-277.333333L234.666667 853.333333 170.666667 789.333333l277.333333-277.333333L170.666667 234.666667 234.666667 170.666667l277.333333 277.333333L789.333333 170.666667 853.333333 234.666667 576 512z" />
|
||||
</x:Array>
|
||||
</local:MyListItem.Buttons>
|
||||
</local:MyListItem>
|
||||
<TextBlock Text="更多选项" Margin="13,18,5,4" Opacity="0.6" FontSize="12" />
|
||||
<local:MyListItem x:Name="ItemSetup" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="设置"
|
||||
LogoScale="0.85" Logo="M940.4 463.7L773.3 174.2c-17.3-30-49.2-48.4-83.8-48.4H340.2c-34.6 0-66.5 18.5-83.8 48.4L89.2 463.7c-17.3 30-17.3 66.9 0 96.8L256.4 850c17.3 30 49.2 48.4 83.8 48.4h349.2c34.6 0 66.5-18.5 83.8-48.4l167.2-289.5c17.3-29.9 17.3-66.8 0-96.8z m-94.6 96.8L725.9 768.1c-17.3 30-49.2 48.4-83.8 48.4H387.5c-34.6 0-66.5-18.5-83.8-48.4L183.9 560.5c-17.3-30-17.3-66.9 0-96.8l119.8-207.5c17.3-30 49.2-48.4 83.8-48.4h254.6c34.6 0 66.5 18.5 83.8 48.4l119.8 207.5c17.3 30 17.3 66.9 0.1 96.8z M522.3 321.2c-2.5-0.1-5-0.2-7.5-0.2-119.9 0-214 110.3-186.3 235 15.8 70.9 71.5 126.6 142.4 142.4 17.5 3.9 34.7 5.4 51.4 4.7 102.1-3.9 183.6-87.9 183.6-191 0.1-103-81.5-187-183.6-190.9z m68.6 269.1c-18.5 18-43 28.9-68.6 30.7l-6 0.3c-30.2 0.4-58.6-11.4-79.7-33-19.5-20.1-30.7-47-30.9-75-0.3-29.6 11.1-57.4 32-78.3 20.6-20.6 48-32 77.2-32 2.5 0 5 0.1 7.5 0.3 26.7 1.8 51.5 13.2 70.5 32.5 19.6 20 30.8 46.9 31.2 74.9 0.2 30.2-11.5 58.6-33.2 79.6z">
|
||||
<local:MyListItem.Buttons>
|
||||
<x:Array Type="{x:Type local:MyIconButton}">
|
||||
<local:MyIconButton Tag="5" ToolTip="初始化设置" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" Click="Reset" Logo="M530 0c287 0 521 229 521 511s-233 511-521 511c-233 0-436-151-500-368a63 63 0 0 1 44-79 65 65 0 0 1 80 43c48 162 200 276 375 276 215 0 390-171 390-383s-174-383-390-383c-103 0-199 39-270 106l21-5a63 63 0 0 1 33 123l-157 42a65 65 0 0 1-90-42l-49-183a65 65 0 1 1 126-33l6 26A524 524 0 0 1 530 0z" LogoScale="0.9" />
|
||||
</x:Array>
|
||||
</local:MyListItem.Buttons>
|
||||
</local:MyListItem>
|
||||
<local:MyListItem x:Name="ItemHelp" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="5" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="常见问题"
|
||||
LogoScale="0.97" Logo="M520.6 620.3c-11.3-0.6-20.1-4-26.9-10.5-6.6-6.3-8.1-11-10.1-20.8-1.9-9.5-1.5-16.7-1-24.9l0.3-5.3c0.5-9.9 3.5-19.6 8.8-28.1 5.7-9 12.5-17.2 20.8-25.1 8.6-8 17.7-15.7 27-22.9 9.4-7.2 18.7-14.8 27.7-22.7 9-7.9 16.2-15.8 22.1-24.3 6.2-9 9.3-18.8 9.3-29.4 1.2-20.3-6.5-37.7-22.8-51.3-16-13.3-37.4-20-63.5-20-13.7 0-26.3 3.3-37.4 10-10.9 6.5-20.2 14.5-27.7 23.8-7.5 9.2-13.5 19-17.9 29.2-4.5 10.6-6.7 19.4-6.7 26.8 0 9.2-3.3 16-10.1 20.8-6.9 4.8-14.6 7.3-22.8 7.3h-1.3c-9-0.3-17-3.3-24.6-9.2-7.3-5.6-11.1-14.6-11.6-27.5-0.6-11.5 1.9-26.1 7.2-43.5 5.4-17.4 14.8-34.4 28.1-50.5 13.4-16.3 31.2-30.4 52.8-41.8 21.6-11.4 49.2-17.2 81.9-17.2 26.4 0 49.6 3.9 69.1 11.7 19.4 7.7 35.4 18.2 47.5 31.1l1.6 1.7c11.8 12.6 20.3 21.7 29.4 44.4 11.6 28.9 7.1 52.1 5.5 58.5-5.8 22.6-12.6 37.7-22.7 50.4-11.7 14.6-24.9 28.2-39.2 40.4-14 11.7-39.2 33.3-39.2 33.3-13.3 11.4-19.4 22.1-18.6 32.9V587c0.5 8.7-2.4 16.1-8.8 22.8-6.2 6.4-14.8 10-26.2 10.5zM519 766.1c-13 0-23.6-4.2-32.2-12.9-8.7-8.7-13-19-13-31.4 0-12.9 4.2-23.5 12.9-32.2 8.7-8.7 19.2-12.9 32.2-12.9 13 0 23.5 4.2 32.2 12.9s12.9 19.2 12.9 32.2c0 12.4-4.2 22.7-12.9 31.4-8.6 8.6-19.2 12.9-32.1 12.9z M515 928.3c-228.1 0-413.7-185.6-413.7-413.7S286.9 100.9 515 100.9s413.7 185.6 413.7 413.7c0.1 228.1-185.5 413.7-413.7 413.7z m0-747.4c-184 0-333.7 149.7-333.7 333.7S331 848.3 515 848.3s333.7-149.7 333.7-333.7S699 180.9 515 180.9z" />
|
||||
<local:MyListItem x:Name="ItemFeedback" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="6" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="关于与反馈"
|
||||
LogoScale="0.9" Logo="M613.717333 64.426667l3.413334 3.242666 331.861333 331.861334a85.333333 85.333333 0 0 1 3.2 117.269333l-3.2 3.413333L573.162667 896H960a21.333333 21.333333 0 0 1 21.333333 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333333 21.333333H64a21.333333 21.333333 0 0 1-21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h295.338667L74.069333 610.709333a85.333333 85.333333 0 0 1-3.221333-117.269333l3.2-3.413333 422.4-422.357334a85.333333 85.333333 0 0 1 117.269333-3.221333z m-20.629333 99.882666l-21.418667 321.493334a85.333333 85.333333 0 0 1-74.944 79.04l-4.522666 0.426666-321.493334 21.44 295.552 295.530667 422.4-422.378667L593.066667 164.309333z m-86.442667 13.824L184.533333 500.266667l301.994667-20.117334 20.117333-301.994666z" />
|
||||
</StackPanel>
|
||||
</local:MyPageLeft>
|
||||
@@ -1,112 +0,0 @@
|
||||
Public Class PageLinkLeft
|
||||
|
||||
Private IsLoad As Boolean = False
|
||||
Private IsPageSwitched As Boolean = False '如果在 Loaded 前切换到其他页面,会导致触发 Loaded 时再次切换一次
|
||||
Private Sub PageLinkLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
|
||||
If IsLoad Then Return
|
||||
IsLoad = True
|
||||
'切换默认页面
|
||||
If IsPageSwitched Then Return
|
||||
ItemHiper.SetChecked(True, False, False)
|
||||
End Sub
|
||||
Private Sub PageOtherLeft_Unloaded(sender As Object, e As RoutedEventArgs) Handles Me.Unloaded
|
||||
IsPageSwitched = False
|
||||
End Sub
|
||||
|
||||
#Region "页面切换"
|
||||
|
||||
''' <summary>
|
||||
''' 当前页面的编号。
|
||||
''' </summary>
|
||||
Public PageID As FormMain.PageSubType = FormMain.PageSubType.LinkHiper
|
||||
|
||||
''' <summary>
|
||||
''' 勾选事件改变页面。
|
||||
''' </summary>
|
||||
Private Sub PageCheck(sender As MyListItem, e As RouteEventArgs) Handles ItemHiper.Check, ItemIoi.Check, ItemSetup.Check, ItemHelp.Check, ItemFeedback.Check
|
||||
'尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0
|
||||
'若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False)
|
||||
If sender.Tag IsNot Nothing Then PageChange(Val(sender.Tag))
|
||||
End Sub
|
||||
|
||||
Public Function PageGet(Optional ID As FormMain.PageSubType = -1)
|
||||
If ID = -1 Then ID = PageID
|
||||
Select Case ID
|
||||
Case 0, FormMain.PageSubType.LinkHiper
|
||||
If FrmLinkHiper Is Nothing Then FrmLinkHiper = New PageLinkHiper
|
||||
Return FrmLinkHiper
|
||||
Case FormMain.PageSubType.LinkIoi
|
||||
If FrmLinkIoi Is Nothing Then FrmLinkIoi = New PageLinkIoi
|
||||
Return FrmLinkIoi
|
||||
Case FormMain.PageSubType.LinkSetup
|
||||
If FrmSetupLink Is Nothing Then FrmSetupLink = New PageSetupLink
|
||||
Return FrmSetupLink
|
||||
Case FormMain.PageSubType.LinkHelp
|
||||
If FrmLinkHelp Is Nothing Then FrmLinkHelp = PageOtherHelp.GetHelpPage(PathTemp & "Help\启动器\联机.json")
|
||||
Return FrmLinkHelp
|
||||
Case FormMain.PageSubType.LinkFeedback
|
||||
If FrmLinkFeedback Is Nothing Then FrmLinkFeedback = New PageLinkFeedback
|
||||
Return FrmLinkFeedback
|
||||
Case Else
|
||||
Throw New Exception("未知的更多子页面种类:" & ID)
|
||||
End Select
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' 切换现有页面。
|
||||
''' </summary>
|
||||
Public Sub PageChange(ID As FormMain.PageSubType)
|
||||
If PageID = ID Then Return
|
||||
AniControlEnabled += 1
|
||||
IsPageSwitched = True
|
||||
Try
|
||||
PageChangeRun(PageGet(ID))
|
||||
PageID = ID
|
||||
Catch ex As Exception
|
||||
Log(ex, "切换分页面失败(ID " & ID & ")", LogLevel.Feedback)
|
||||
Finally
|
||||
AniControlEnabled -= 1
|
||||
End Try
|
||||
End Sub
|
||||
Private Shared Sub PageChangeRun(Target As MyPageRight)
|
||||
AniStop("FrmMain PageChangeRight") '停止主页面的右页面切换动画,防止它与本动画一起触发多次 PageOnEnter
|
||||
If Target.Parent IsNot Nothing Then Target.SetValue(ContentPresenter.ContentProperty, Nothing)
|
||||
FrmMain.PageRight = Target
|
||||
CType(FrmMain.PanMainRight.Child, MyPageRight).PageOnExit()
|
||||
AniStart({
|
||||
AaCode(Sub()
|
||||
CType(FrmMain.PanMainRight.Child, MyPageRight).PageOnForceExit()
|
||||
FrmMain.PanMainRight.Child = FrmMain.PageRight
|
||||
FrmMain.PageRight.Opacity = 0
|
||||
End Sub, 130),
|
||||
AaCode(Sub()
|
||||
'延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
|
||||
FrmMain.PageRight.Opacity = 1
|
||||
FrmMain.PageRight.PageOnEnter()
|
||||
End Sub, 30, True)
|
||||
}, "PageLeft PageChange")
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
Public Sub Reset(sender As Object, e As EventArgs)
|
||||
If MyMsgBox("是否要初始化联机页的所有设置?该操作不可撤销。", "初始化确认",, "取消", IsWarn:=True) = 1 Then
|
||||
If IsNothing(FrmSetupLink) Then FrmSetupLink = New PageSetupLink
|
||||
FrmSetupLink.Reset()
|
||||
ItemSetup.Checked = True
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub BtnHiperStop_Loaded(sender As Object, e As RoutedEventArgs)
|
||||
sender.Visibility = If(PageLinkHiper.HiperState = LoadState.Finished OrElse PageLinkHiper.HiperState = LoadState.Loading, Visibility.Visible, Visibility.Collapsed)
|
||||
End Sub
|
||||
Private Sub BtnHiperStop_Click(sender As Object, e As EventArgs)
|
||||
PageLinkHiper.ModuleStopManually()
|
||||
End Sub
|
||||
Private Sub BtnIoiStop_Loaded(sender As Object, e As RoutedEventArgs)
|
||||
End Sub
|
||||
Private Sub BtnIoiStop_Click(sender As Object, e As EventArgs)
|
||||
PageLinkIoi.ModuleStopManually()
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
@@ -0,0 +1,202 @@
|
||||
<local:MyPageRight
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" x:Class="PageLinkMain"
|
||||
d:DesignWidth="800" d:DesignHeight="800">
|
||||
<Grid>
|
||||
<Grid x:Name="PanLoad">
|
||||
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="CardLoad" MinWidth="300">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="20" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="20" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="20" />
|
||||
</Grid.RowDefinitions>
|
||||
<local:MyLoading Grid.Column="1" Grid.Row="1" x:Name="Load" Grid.RowSpan="3" Margin="0,-4,0,-29" HorizontalAlignment="Center"
|
||||
Text="" TextError="" TextErrorInherit="False" AutoRun="False" IsHitTestVisible="False" RenderTransformOrigin="0.5,0.5">
|
||||
<local:MyLoading.RenderTransform>
|
||||
<ScaleTransform ScaleX="0.9" ScaleY="0.9" />
|
||||
</local:MyLoading.RenderTransform>
|
||||
</local:MyLoading>
|
||||
<TextBlock x:Name="LabLoadTitle" Grid.Column="3" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Center" Text="正在创建联机房间" FontSize="19"
|
||||
Margin="0,0,25,1" Foreground="{Binding Foreground, ElementName=Load}" IsHitTestVisible="False" />
|
||||
<TextBlock x:Name="LabLoadDesc" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" VerticalAlignment="Center" Margin="0,5,10,-5" Text="下载联机模块中……" FontSize="14"
|
||||
LineHeight="19" MaxWidth="450" MaxHeight="220" TextWrapping="Wrap" Foreground="{StaticResource ColorBrushGray3}" IsHitTestVisible="False" />
|
||||
<local:MyIconButton Grid.Column="5" Grid.Row="1" x:Name="BtnLoadCancel" Height="25" Width="25"
|
||||
VerticalAlignment="Top" Margin="0,-13,-13,0"
|
||||
Theme="Black" Opacity="0.3"
|
||||
ToolTip="取消" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="100"
|
||||
ToolTipService.VerticalOffset="-2" ToolTipService.HorizontalOffset="0"
|
||||
LogoScale="0.72" Logo="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid Height="12" VerticalAlignment="Bottom" Grid.ColumnSpan="100" Grid.RowSpan="100" Margin="0,0,0,-0.6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0*" x:Name="ColumnProgressA" />
|
||||
<ColumnDefinition Width="1*" x:Name="ColumnProgressB" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.Clip>
|
||||
<RectangleGeometry RadiusX="6" RadiusY="6" x:Name="RectProgressClip" />
|
||||
</Grid.Clip>
|
||||
<Rectangle Fill="{Binding Foreground, ElementName=Load}" VerticalAlignment="Bottom" Height="2" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
</Grid>
|
||||
<Grid x:Name="PanContent">
|
||||
<Grid x:Name="PanSelect">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="35" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="10" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<local:MyCard x:Name="PanSelectCreate" Grid.Column="1" Grid.Row="1" CornerRadius="13" VerticalAlignment="Center">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="13" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="22" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="12" />
|
||||
</Grid.RowDefinitions>
|
||||
<Path Grid.Column="1" Grid.Row="1" Height="26" Width="26" Margin="0,-1,0,0"
|
||||
Stretch="Uniform" Fill="{DynamicResource ColorBrush3}"
|
||||
Data="M384 128v192h256a64 64 0 0 1 64 64v256h192V128H384zM320 320V128a64 64 0 0 1 64-64h512a64 64 0 0 1 64 64v512a64 64 0 0 1-64 64h-192v192a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V384a64 64 0 0 1 64-64h192z m320 384H384a64 64 0 0 1-64-64V384H128v512h512v-192z m0-64V384H384v256h256z" />
|
||||
<TextBlock Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="1"
|
||||
Text="创建房间" FontSize="20" Foreground="{DynamicResource ColorBrush3}" />
|
||||
<TextBlock Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" Margin="1,10,30,10"
|
||||
Text="邀请朋友加入你的单人游戏。"
|
||||
FontSize="15" LineHeight="19" MaxWidth="400" TextWrapping="Wrap" Foreground="{StaticResource ColorBrushGray3}" />
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
<local:MyCard x:Name="PanSelectJoin" Grid.Column="1" Grid.Row="3" CornerRadius="13" VerticalAlignment="Center">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="13" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="22" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="12" />
|
||||
</Grid.RowDefinitions>
|
||||
<Path Grid.Column="1" Grid.Row="1" Height="26" Width="26" Margin="0,-1,0,0"
|
||||
Stretch="Uniform" Fill="{DynamicResource ColorBrush3}"
|
||||
Data="m399,355l-92.5,101.6c-13.7,13.7-10.6,36.4,4.6,47,13.7,9.1,30.3,7.6,41-4.5l127.4-138.1c16.7-18.2,18.2-47,0-66.8l-125.9-141.1c-12.1-13.7-34.9-15.2-47,0-12.1,12.1-12.1,31.9,0,44l92.5,98.6H28.8c-16.7,0-28.8,13.7-28.8,28.8s13.7,28.8,28.8,28.8h370.2v1.5ZM625.7,0H224.6c-44,0-78.9,34.9-78.9,78.9v101.6c0,15.2,12.1,27.3,27.3,27.3s27.3-12.1,27.3-27.3v-98.6c0-15.2,12.1-27.3,27.3-27.3h387.5c15.2,0,27.3,12.1,27.3,27.3v493c0,15.2-12.1,27.3-27.3,27.3H229.2c-15.2,0-27.3-12.1-27.3-27.3v-101.6c0-16.7-13.7-28.8-28.8-28.8s-28.8,13.7-28.8,28.8v98.6c0,44,34.9,78.9,78.9,78.9h407.2c44,0,67.9-34.9,67.9-78.9V78.9c-4.6-44-28.4-78.9-72.4-78.9Z" />
|
||||
<TextBlock Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="1"
|
||||
Text="加入房间" FontSize="20" Foreground="{DynamicResource ColorBrush3}" />
|
||||
<TextBlock Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" Margin="1,10,30,10"
|
||||
Text="输入你收到的邀请码,加入朋友的房间。"
|
||||
FontSize="15" LineHeight="19" MaxWidth="400" TextWrapping="Wrap" Foreground="{StaticResource ColorBrushGray3}" />
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
</Grid>
|
||||
<Grid x:Name="PanFinish" Visibility="Collapsed" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="300">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="25" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" CornerRadius="12">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25" />
|
||||
<ColumnDefinition Width="Auto" /> <!--Logo-->
|
||||
<ColumnDefinition Width="13" />
|
||||
<ColumnDefinition Width="1*" /> <!--文本区 ↓↓-->
|
||||
<ColumnDefinition Width="Auto" /> <!--按钮 1-->
|
||||
<ColumnDefinition Width="Auto" /> <!--按钮 2-->
|
||||
<ColumnDefinition Width="25" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="21" />
|
||||
<RowDefinition Height="Auto" /> <!--标题栏-->
|
||||
<RowDefinition Height="Auto" /> <!--文本区-->
|
||||
<RowDefinition Height="Auto" /> <!--按钮-->
|
||||
<RowDefinition Height="21" />
|
||||
</Grid.RowDefinitions>
|
||||
<Path Grid.Column="1" Grid.Row="1" Height="28" Width="28" x:Name="ImgFinishLogo"
|
||||
Stretch="Uniform" Fill="{DynamicResource ColorBrush3}" RenderTransformOrigin="0.5,0.54"
|
||||
Data="M845 547.45h65.54A400.6 400.6 0 0 0 712.7 201.77l-33.22 56.49C781.6 318.32 845 429.13 845 547.45zM347.72 253.92L316 196.58a401.21 401.21 0 0 0-207 350.87h65.54a335.66 335.66 0 0 1 173.18-293.53zM509.79 882.68a334 334 0 0 1-181.3-53.2L293 884.57a401.13 401.13 0 0 0 419.1 8.91L679 836.93a334.94 334.94 0 0 1-169.21 45.75z M821.51 625.1A108.64 108.64 0 0 0 752.2 650l-67.31-38.86a185.44 185.44 0 0 0 11.22-63.7c0-91.55-66.38-167.9-153.54-183.42V289a109.14 109.14 0 1 0-65.57 0v75c-87.16 15.53-153.54 91.87-153.54 183.42a185.46 185.46 0 0 0 11.22 63.7L267.39 650a109.17 109.17 0 1 0 35.81 55l64.47-37.23a186 186 0 0 0 284.23 0L716.38 705a109.13 109.13 0 1 0 105.13-79.9zM198.07 777.85a43.6 43.6 0 1 1 43.61-43.61 43.66 43.66 0 0 1-43.61 43.61z m311.72-636.53a43.61 43.61 0 1 1-43.61 43.61 43.65 43.65 0 0 1 43.61-43.61z m0 526.91a120.78 120.78 0 1 1 120.78-120.78 120.91 120.91 0 0 1-120.78 120.77z m311.72 109.62a43.6 43.6 0 1 1 43.61-43.61 43.65 43.65 0 0 1-43.61 43.61z" />
|
||||
<TextBlock x:Name="LabFinishTitle" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="1" Margin="0,3,0,0"
|
||||
Text="已加入房间" FontSize="20" Foreground="{DynamicResource ColorBrush3}" />
|
||||
<TextBlock x:Name="LabFinishDesc" Grid.Column="3" Grid.ColumnSpan="3" Grid.Row="2" Margin="1,9,10,10"
|
||||
Text="描述文本。"
|
||||
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="BtnFinishExit" Grid.Column="5" Grid.Row="3" Text="退出" Padding="13,8" />
|
||||
</Grid>
|
||||
</local:MyCard>
|
||||
<local:MyCard Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" CornerRadius="8">
|
||||
<StackPanel Orientation="Horizontal" Margin="3,0">
|
||||
<StackPanel x:Name="BtnFinishPing" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
|
||||
ToolTip="延迟" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="50" ToolTipService.VerticalOffset="40" ToolTipService.HorizontalOffset="4">
|
||||
<Path IsHitTestVisible="False" Height="14" Width="14" Stretch="Uniform" Fill="#9C9C9C" Margin="13,0,8,0"
|
||||
Data="M60.9 966.2A60.3 60.3 0 0 1 0.8 906.1v-90.1a60.3 60.3 0 0 1 60.1-60.1 60.3 60.3 0 0 1 60.1 60.1v90.1a60.2 60.2 0 0 1-60.1 60.1z m300.6 0a60.3 60.3 0 0 1-60.1-60.1V665.6a60.3 60.3 0 0 1 60.1-60.1 60.3 60.3 0 0 1 60.1 60.1v240.5a60.2 60.2 0 0 1-60.1 60.1z m300.6 0a60.3 60.3 0 0 1-60.1-60.1V425.1a60.3 60.3 0 0 1 60.1-60.1 60.3 60.3 0 0 1 60.1 60.1v481.0a60.3 60.3 0 0 1-60.1 60.1z m300.6 0a60.3 60.3 0 0 1-60.1-60.1V124.5a60.3 60.3 0 0 1 60.1-60.1 60.3 60.3 0 0 1 60.1 60.1v781.6a60.3 60.3 0 0 1-60.1 60.1z" />
|
||||
<TextBlock x:Name="LabFinishPing" IsHitTestVisible="False" Text="15 ms" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0.5,13,0" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="|" Opacity="0.2" Margin="0,8.8,0,8" RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock.RenderTransform>
|
||||
<ScaleTransform ScaleX="1.5" ScaleY="2.75" CenterX="0.5" CenterY="0.5" />
|
||||
</TextBlock.RenderTransform>
|
||||
</TextBlock>
|
||||
<StackPanel x:Name="BtnFinishPlayer" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
|
||||
ToolTip="房间内人数" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="50" ToolTipService.VerticalOffset="40" ToolTipService.HorizontalOffset="4">
|
||||
<Path IsHitTestVisible="False" Height="18" Width="18" Stretch="Uniform" Fill="{StaticResource ColorBrushGray4}" Margin="13,0,8,0"
|
||||
Data="m843.3,478.4c-.1-3.9-.2-7.7-.2-10.8,0-42.8-11.1-84.4-32-120.2-19.6-33.5-47.1-60.7-79.7-79,15-16.8,23.6-39.2,25-65.2,1.3-24.8-3.7-52.1-14.6-79-20.5-50.8-56-86.3-86.3-86.3s-25.1,4.1-37.5,23.5l-.4.7-.2.8c-4.1,16.6,3.9,33.4,20,41.7l.7.4h.8c34.9,5.6,50.6,38.7,53.5,65.3,3.3,30.7-7.8,67.2-40.1,80.1-7.4,1.1-9.9,7.7-11.5,12.1-.6,1.7-1.2,3.3-1.9,4.3l-.7,1v1.2c-3.4,27.8,19.6,39.8,46.3,53.6,41.4,21.4,93,48.1,93.1,144.9v.3c.3,4.3,0,9.9-.1,15.7-.6,17.9-1.4,40.2,10.3,52.4,5.5,5.7,13,8.6,22.5,8.7.7,0,1.4,0,2.1,0h0c8.1,0,14.7-2.6,19.8-7.9,12.7-13.1,11.9-39.4,11.4-58.6Z M204.7,295.9l.5-1.1v-30.1c0-3.9-2.1-6-3.3-7.1-.1-.1-.2-.2-.3-.3v-1.7l-8.9-9.2-.7-.4c-26.3-13.5-42.6-40.8-42.6-71.3s21.8-67.4,55.5-78.1c17-4.5,28.2-22.1,24.5-38.4v-.6c-.1,0-.4-.5-.4-.5-7.5-15.3-21.4-24.7-36.2-24.7s-5.1.3-7.7.8h-.2c-29.8,7.2-56.6,25.5-75.7,51.4-18.9,25.7-29.3,57.8-29.3,90.4s11.1,64.8,32.2,92.1C45.3,303.9,2.5,376.9,0,458.9v57.5s0,.2,0,.2c1.4,15.3,13.1,30.8,32.8,30.8s32.9-12.7,32.9-33.9v-43.3c0-76.2,45.9-139.2,114.3-157.1,10.5-.5,19.5-6.8,24.7-17.3Z M516,286.5c36.8-31.1,58.5-77.4,58.5-125.4C574.4,70.8,507.4,0,421.7,0s-152.7,70.8-152.7,161.2,20.4,95.1,56.4,125.6c-51.7,19.8-96.1,54.8-129,101.5-35.2,50.2-53.9,109.7-53.9,172v33.8c0,16.9,13.7,30.6,30.6,30.6h496.6c16.9,0,30.6-13.7,30.6-30.6v-33.8c0-61.4-19-120.6-54.9-171.3-32.9-46.4-78.6-82.5-129.5-102.4Zm-94.5-225.3c51.3,0,91.5,43.9,91.5,100s-41.9,100-91.5,100-91.5-43.9-91.5-100,40.2-100,91.5-100Zm218,502H203.8v-3.2c0-127,97.8-230.3,218-230.3s217.7,105.4,217.7,230.3v3.2Z" />
|
||||
<TextBlock x:Name="LabFinishPlayer" IsHitTestVisible="False" Text="2 人" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray1}" Margin="0,0.5,13,0" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="|" x:Name="LineFinishPort" Opacity="0.2" Margin="0,8.8,0,8" RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock.RenderTransform>
|
||||
<ScaleTransform ScaleX="1.5" ScaleY="2.75" CenterX="0.5" CenterY="0.5" />
|
||||
</TextBlock.RenderTransform>
|
||||
</TextBlock>
|
||||
<StackPanel x:Name="BtnFinishPort" Orientation="Horizontal" Background="{StaticResource ColorBrushSemiTransparent}"
|
||||
ToolTip="端口" ToolTipService.Placement="Center" ToolTipService.InitialShowDelay="50" ToolTipService.VerticalOffset="40" ToolTipService.HorizontalOffset="4">
|
||||
<Path IsHitTestVisible="False" Height="16" Width="16" Stretch="Uniform" Fill="{StaticResource ColorBrushGray4}" Margin="13,0,7,0"
|
||||
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" />
|
||||
</StackPanel>
|
||||
<!--<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"
|
||||
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" />
|
||||
</StackPanel>-->
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid x:Name="PanAlways" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="15" Opacity="0.5">
|
||||
</Grid>
|
||||
</Grid>
|
||||
</local:MyPageRight>
|
||||
@@ -0,0 +1,844 @@
|
||||
Public Class PageLinkMain
|
||||
|
||||
'===============================
|
||||
' 状态机与前端页面
|
||||
'===============================
|
||||
|
||||
#Region "状态管理"
|
||||
|
||||
Private Enum States
|
||||
Waiting
|
||||
Loading
|
||||
Failed
|
||||
Finished
|
||||
End Enum
|
||||
Private State As States = States.Waiting
|
||||
|
||||
''' <summary>
|
||||
''' 切换到指定的状态。
|
||||
''' </summary>
|
||||
Private Sub ChangeState(NewState As States)
|
||||
If State = NewState Then Return
|
||||
Dim OldState = State
|
||||
State = NewState
|
||||
Log($"[Link] 主状态由 {GetStringFromEnum(OldState)} 变更为 {GetStringFromEnum(NewState)}")
|
||||
'触发状态切换
|
||||
RunInUi(
|
||||
Sub()
|
||||
Select Case NewState
|
||||
Case States.Waiting
|
||||
SwitchToWaiting(OldState)
|
||||
Case States.Loading
|
||||
SwitchToLoading(OldState)
|
||||
Case States.Failed
|
||||
SwitchToFailed(OldState)
|
||||
Case States.Finished
|
||||
SwitchToFinished(OldState)
|
||||
End Select
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
'让加载器的 成功/失败 事件触发状态切换
|
||||
Private Sub LoaderInit() Handles Me.Initialized
|
||||
PageLoaderInit(Load, PanLoad, PanContent, PanAlways, LinkLoader, AutoRun:=False)
|
||||
AddHandler LinkLoader.OnStateChangedUi,
|
||||
Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState)
|
||||
Select Case NewState
|
||||
Case LoadState.Finished
|
||||
ChangeState(States.Finished)
|
||||
Case LoadState.Failed
|
||||
Telemetry("联机失败", "Exception", FilterUserName(Loader.Error.GetDetail, "*"))
|
||||
ChangeState(States.Failed)
|
||||
End Select
|
||||
End Sub
|
||||
End Sub
|
||||
|
||||
'页面动画兼容
|
||||
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)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "初始页面 (Waiting)"
|
||||
|
||||
'由任意状态切换到 Waiting
|
||||
Private Sub SwitchToWaiting(OldState As States)
|
||||
'加载器与进程状态
|
||||
LinkLoader.Abort()
|
||||
SyncLock LinkLoader.LockState
|
||||
LinkLoader.State = LoadState.Waiting
|
||||
End SyncLock
|
||||
ProcessStop()
|
||||
'页面切换
|
||||
If OldState <> States.Finished Then
|
||||
'从完成页面退出时,PageOnContentExit 结束会触发 PageEnter 事件,这会调用 UpdatePanelVisibility
|
||||
'如果在现在提前调用了,会丢失完成页面的退出动画
|
||||
UpdatePanelVisibility()
|
||||
End If
|
||||
PageOnContentExit()
|
||||
End Sub
|
||||
|
||||
'===============================
|
||||
' 页面 UI
|
||||
'===============================
|
||||
|
||||
'创建
|
||||
Private Sub Create_MouseLeftButtonUp() Handles PanSelectCreate.MouseLeftButtonUp
|
||||
'输入端口号
|
||||
Dim Port As String = MyMsgBoxInput("输入端口", $"在单人游戏的暂停菜单选择 {vbLQ}对局域网开放{vbRQ},然后输入端口数字。{vbCrLf}其实也可以输入其他游戏的端口……",
|
||||
ValidateRules:=New ObjectModel.Collection(Of Validate) From {New ValidateInteger(1024, 65535)},
|
||||
HintText:="端口号")
|
||||
If Port Is Nothing Then Return
|
||||
'基础信息
|
||||
IsServerSide = True
|
||||
ServerPort = Port
|
||||
Dim GenerateRandomCode =
|
||||
Function() As String
|
||||
Dim Result As String = ""
|
||||
For i = 1 To 5
|
||||
Result &= RadixConvert(RandomInteger(0, 35), 10, 36)
|
||||
Next
|
||||
Return Result.Replace("O", "0").Replace("I", "1")
|
||||
End Function
|
||||
NetworkName = $"P{RadixConvert(ServerPort, 10, 16).PadLeft(4, "0"c)}-{GenerateRandomCode()}"
|
||||
NetworkSecret = GenerateRandomCode()
|
||||
Log($"[Link] 尝试创建房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort}")
|
||||
'启动
|
||||
ChangeState(States.Loading)
|
||||
End Sub
|
||||
|
||||
'加入
|
||||
Private LastCode As String = Nothing
|
||||
Private Sub Join_MouseLeftButtonUp() Handles PanSelectJoin.MouseLeftButtonUp
|
||||
'输入邀请码
|
||||
Dim Code As String = MyMsgBoxInput("输入邀请码", "输入房主发给你的邀请码。",
|
||||
HintText:=If(String.IsNullOrEmpty(LastCode), "", "使用上一次的邀请码:" & LastCode))
|
||||
If Not String.IsNullOrEmpty(LastCode) AndAlso Code IsNot Nothing AndAlso Code = "" Then Code = LastCode
|
||||
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
|
||||
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
|
||||
Return
|
||||
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
|
||||
ServerPort = RadixConvert(Code.Substring(1, 4), 16, 10)
|
||||
NetworkName = Code.Substring(0, 11)
|
||||
NetworkSecret = Code.Substring(12, 5)
|
||||
Log($"[Link] 尝试加入房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort}")
|
||||
'启动
|
||||
LastCode = Code
|
||||
ChangeState(States.Loading)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "加载页面 (Loading | Failed)"
|
||||
|
||||
'由 Waiting 或 Failed 状态切换到 Loading
|
||||
Private Sub SwitchToLoading(OldState As States)
|
||||
'清理变量
|
||||
Peers = Nothing
|
||||
FailCount = 0
|
||||
'加载器与进程状态
|
||||
LinkLoader.Start(IsForceRestart:=True)
|
||||
'页面切换会由 Loader 调用 MyPageRight 来触发
|
||||
'UI 更新
|
||||
UpdateProgressBar(0)
|
||||
LabLoadTitle.Text = If(IsServerSide, "创建房间中", "加入房间中")
|
||||
UpdateLoadingPage("正在初始化……", "准备初始化")
|
||||
End Sub
|
||||
|
||||
'由 Loading 状态切换到 Failed
|
||||
Private Sub SwitchToFailed(OldState As States)
|
||||
'加载器与进程状态
|
||||
LinkLoader.Abort()
|
||||
ProcessStop()
|
||||
'UI 更新
|
||||
UpdateProgressBar(1)
|
||||
'显示错误信息
|
||||
LabLoadTitle.Text = FailReason
|
||||
Dim Brief As String = LinkLoader.Error.GetBrief
|
||||
Dim InnerEx As Exception = LinkLoader.Error
|
||||
If InnerEx.Message.StartsWithF("$") Then Brief = InnerEx.Message
|
||||
Do Until InnerEx.InnerException Is Nothing
|
||||
InnerEx = InnerEx.InnerException
|
||||
If InnerEx.Message.StartsWithF("$") Then Brief = InnerEx.Message
|
||||
Loop
|
||||
LabLoadDesc.Text = If(Brief.StartsWithF("$"), Brief.TrimStart("$"), LinkLoader.Error.GetDetail)
|
||||
Log(LinkLoader.Error, LabLoadTitle.Text)
|
||||
End Sub
|
||||
|
||||
'===============================
|
||||
' 页面 UI
|
||||
'===============================
|
||||
|
||||
Private Sub UpdateLoadingPage(Title As String, FailBrief As String)
|
||||
If FailReason = FailBrief & "失败" Then Return
|
||||
FailReason = FailBrief & "失败"
|
||||
Log("[Link] 开始步骤:" & Title)
|
||||
RunInUiWait(
|
||||
Sub()
|
||||
If FrmLinkMain Is Nothing OrElse Not FrmLinkMain.LabLoadDesc.IsLoaded Then Return
|
||||
FrmLinkMain.LabLoadDesc.Text = Title
|
||||
End Sub)
|
||||
End Sub
|
||||
Private FailReason As String = "准备初始化"
|
||||
|
||||
'取消加载
|
||||
Private Sub BtnLoadCancel_Click() Handles BtnLoadCancel.Click
|
||||
ChangeState(States.Waiting)
|
||||
End Sub
|
||||
|
||||
'点击重试
|
||||
Private Sub CardLoad_MouseLeftButtonUp() Handles CardLoad.MouseLeftButtonUp
|
||||
ChangeState(States.Loading)
|
||||
End Sub
|
||||
|
||||
'进度条
|
||||
Private Sub UpdateProgressBar(Optional Value As Double = -1)
|
||||
If Value = -1 Then Value = LinkLoader.Progress
|
||||
Dim DisplayingProgress As Double = ColumnProgressA.Width.Value
|
||||
If Math.Round(Value - DisplayingProgress, 3) = 0 Then Return
|
||||
If DisplayingProgress <= Value Then
|
||||
Dim NewProgress As Double = If(Value = 1, 1, DisplayingProgress +
|
||||
(Value - DisplayingProgress) ^ 2 * 0.5)
|
||||
AniStart({
|
||||
AaGridLengthWidth(ColumnProgressA, NewProgress - ColumnProgressA.Width.Value, 200),
|
||||
AaGridLengthWidth(ColumnProgressB, (1 - NewProgress) - ColumnProgressB.Width.Value, 200)
|
||||
}, "Link Progress")
|
||||
Else
|
||||
ColumnProgressA.Width = New GridLength(Value, GridUnitType.Star)
|
||||
ColumnProgressB.Width = New GridLength(1 - Value, GridUnitType.Star)
|
||||
AniStop("Link Progress")
|
||||
End If
|
||||
End Sub
|
||||
Private Sub CardLoad_SizeChanged() Handles CardLoad.SizeChanged
|
||||
RectProgressClip.Rect = New Rect(0, 0, CardLoad.ActualWidth, 12)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "完成页面 (Finished)"
|
||||
|
||||
'由 Loading 状态切换到 Finished
|
||||
Private Sub SwitchToFinished(OldState As States)
|
||||
'由于只可能从加载器的完成事件触发,不需要管加载器
|
||||
UpdatePanelVisibility() '页面的实际切换会由 Loader 调用 MyPageRight 来触发
|
||||
|
||||
'UI 更新
|
||||
If IsServerSide Then
|
||||
LabFinishTitle.Text = "已创建房间"
|
||||
LabFinishDesc.Text = $"把邀请码发给朋友,让大家加入房间吧!{vbCrLf}邀请码:{NetworkName}-{NetworkSecret}"
|
||||
BtnFinishCopy.Text = "复制邀请码"
|
||||
BtnFinishExit.Text = "关闭"
|
||||
'下边栏
|
||||
BtnFinishPing.ToolTip = "网络延迟"
|
||||
LineFinishPort.Visibility = Visibility.Visible
|
||||
BtnFinishPort.Visibility = Visibility.Visible
|
||||
LabFinishPort.Visibility = Visibility.Visible
|
||||
LabFinishPort.Text = ServerPort
|
||||
Else
|
||||
LabFinishTitle.Text = "已加入房间"
|
||||
LabFinishDesc.Text = $"在多人游戏中选择直接连接,粘贴地址即可加入游戏!{vbCrLf}服务器地址:{ClientAddress}" '"如果提示无效会话,不要退出联机房间,重新启动游戏即可!"
|
||||
BtnFinishCopy.Text = "复制地址"
|
||||
BtnFinishExit.Text = "离开"
|
||||
'下边栏
|
||||
BtnFinishPing.ToolTip = "与房主的延迟"
|
||||
LineFinishPort.Visibility = Visibility.Collapsed
|
||||
BtnFinishPort.Visibility = Visibility.Collapsed
|
||||
LabFinishPort.Visibility = Visibility.Collapsed
|
||||
End If
|
||||
Copy() '复制信息
|
||||
Update() '立即刷新
|
||||
End Sub
|
||||
|
||||
'===============================
|
||||
' 页面 UI
|
||||
'===============================
|
||||
|
||||
'退出
|
||||
Private Sub BtnFinishExit_Click() Handles BtnFinishExit.Click
|
||||
TryExit(True)
|
||||
End Sub
|
||||
''' <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
|
||||
End If
|
||||
ChangeState(States.Waiting)
|
||||
Return False
|
||||
End Function
|
||||
|
||||
'复制
|
||||
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
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
'===============================
|
||||
' 后端
|
||||
'===============================
|
||||
|
||||
''' <summary>
|
||||
''' EasyTier 所在的文件夹路径,以 \ 结尾。
|
||||
''' </summary>
|
||||
Private PathEasyTier As String = PathAppdata & "EasyTier\"
|
||||
''' <summary>
|
||||
''' 当前是服务端还是客户端。
|
||||
''' </summary>
|
||||
Private IsServerSide As Boolean
|
||||
''' <summary>
|
||||
''' 服务端映射前的端口号。
|
||||
''' </summary>
|
||||
Private ServerPort As Integer
|
||||
''' <summary>
|
||||
''' 在客户端映射后的地址。
|
||||
''' 除非已作为客户端启动 EasyTier,否则一直为 Nothing。
|
||||
''' </summary>
|
||||
Private ClientAddress As String = Nothing
|
||||
''' <summary>
|
||||
''' 网络信息。
|
||||
''' </summary>
|
||||
Private NetworkName As String, NetworkSecret As String
|
||||
|
||||
#Region "加载"
|
||||
|
||||
Private WithEvents LinkLoader As New LoaderCombo(Of Integer)("联机", {
|
||||
New LoaderTask(Of Integer, Integer)("获取配置", AddressOf InitConfig) With {.Block = False, .ProgressWeight = 8},
|
||||
New LoaderTask(Of Integer, List(Of NetFile))("准备下载联机模块", AddressOf InitPrepareDownload) With {.ProgressWeight = 2},
|
||||
New LoaderDownload("下载联机模块", New List(Of NetFile)) With {.ProgressWeight = 40},
|
||||
New LoaderTask(Of Integer, Integer)("启动联机模块", AddressOf InitLaunch) With {.ProgressWeight = 50}
|
||||
})
|
||||
|
||||
'1. 获取服务器配置
|
||||
Private Sub InitConfig(Task As LoaderTask(Of Integer, Integer))
|
||||
UpdateLoadingPage("正在联网获取配置……", "联网获取配置")
|
||||
If VersionBranchMain <> "Official" Then
|
||||
Throw New Exception($"$开源版无法联网获取配置。{vbCrLf}你可以在 PCL 官方版的缓存文件夹下查看 ServerConfig 的当前内容, 并在代码中进行相应修改。")
|
||||
End If
|
||||
ServerLoader.WaitForExit(LoaderToSyncProgress:=Task)
|
||||
If ServerConfig Is Nothing Then Throw New Exception("无法从服务器获取配置")
|
||||
If Not String.IsNullOrEmpty(ServerConfig("Link")("DisableReason")) Then '检查是否已禁用联机功能
|
||||
Throw New Exception("$" & ServerConfig("Link")("DisableReason").ToString)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
'2. 获取需要下载的文件
|
||||
Private ServerVersion As Integer
|
||||
Private Sub InitPrepareDownload(Task As LoaderTask(Of Integer, List(Of NetFile)))
|
||||
'获取 CPU 架构
|
||||
UpdateLoadingPage("正在获取 CPU 架构……", "获取 CPU 架构")
|
||||
Dim Architecture As String = GetType(String).Assembly.GetName().ProcessorArchitecture
|
||||
Select Case Architecture
|
||||
Case Reflection.ProcessorArchitecture.X86
|
||||
Architecture = "i686"
|
||||
Case Reflection.ProcessorArchitecture.Amd64
|
||||
Architecture = "x86_64"
|
||||
Case Reflection.ProcessorArchitecture.Arm
|
||||
Architecture = "arm64"
|
||||
Case Else
|
||||
Log($"[Link] CPU 是不支持的 {Architecture} 架构,这可能会导致联机模块无法启动!", LogLevel.Debug)
|
||||
Architecture = "arm64"
|
||||
End Select
|
||||
Log("[Link] CPU 架构:" & Architecture)
|
||||
Telemetry("联机开始")
|
||||
'检查 EasyTier 版本
|
||||
UpdateLoadingPage("正在检查联机模块版本……", "检查联机模块版本")
|
||||
If Not (File.Exists(PathEasyTier & "联机模块 CLI.exe") AndAlso File.Exists(PathEasyTier & "联机模块.exe") AndAlso
|
||||
File.Exists(PathEasyTier & "Packet.dll")) Then
|
||||
Setup.Set("LinkEasyTierVersion", -1)
|
||||
End If
|
||||
Dim LocalVersion As Integer = Setup.Get("LinkEasyTierVersion")
|
||||
ServerVersion = ServerConfig("Link")("EasyTierVersion")
|
||||
Dim RequiredFiles As New List(Of NetFile)
|
||||
Log($"[Link] EasyTier 本地版本:{LocalVersion},需求版本:{ServerVersion}")
|
||||
If LocalVersion < ServerVersion Then
|
||||
RequiredFiles.Add(New NetFile(
|
||||
ServerConfig("Link")("Downloads").Select(Function(UrlEntry) UrlEntry.ToString.Replace("{arch}", Architecture)),
|
||||
PathEasyTier & "EasyTier.zip",
|
||||
New FileChecker(MinSize:=1024 * 1024 * 2)))
|
||||
End If
|
||||
'开始下载
|
||||
UpdateLoadingPage("正在下载联机模块……", "下载联机模块")
|
||||
Task.Output = RequiredFiles
|
||||
End Sub
|
||||
|
||||
'3. 启动联机模块
|
||||
Private Shared HostName As String
|
||||
Private Sub InitLaunch(Task As LoaderTask(Of Integer, Integer))
|
||||
'解压文件
|
||||
UpdateLoadingPage("正在解压联机模块……", "解压联机模块")
|
||||
If File.Exists(PathEasyTier & "EasyTier.zip") Then
|
||||
'解压
|
||||
Dim ExtractPath As String = RequestTaskTempFolder()
|
||||
ExtractFile(PathEasyTier & "EasyTier.zip", ExtractPath,
|
||||
ProgressIncrementHandler:=Sub(Progress) Task.Progress += Progress * 0.06)
|
||||
Dim ExtractedPath As String = New DirectoryInfo(ExtractPath).EnumerateDirectories.FirstOrDefault?.FullName
|
||||
Log("[Link] 联机模块解压时的临时路径:" & ExtractedPath)
|
||||
CopyDirectory(ExtractedPath, PathEasyTier)
|
||||
'重命名
|
||||
File.Delete(PathEasyTier & "联机模块.exe")
|
||||
Rename(PathEasyTier & "easytier-core.exe", PathEasyTier & "联机模块.exe")
|
||||
File.Delete(PathEasyTier & "联机模块 CLI.exe")
|
||||
Rename(PathEasyTier & "easytier-cli.exe", PathEasyTier & "联机模块 CLI.exe")
|
||||
'清理
|
||||
File.Delete(PathEasyTier & "EasyTier.zip")
|
||||
Setup.Set("LinkEasyTierVersion", ServerVersion)
|
||||
End If
|
||||
Task.Progress = 0.1
|
||||
'获取启动参数
|
||||
UpdateLoadingPage("正在启动联机模块……", "启动联机模块")
|
||||
Dim Arguments As String = ServerConfig("Link")("Argument")
|
||||
Arguments += $" --network-name={NetworkName} --network-secret={NetworkSecret}"
|
||||
HostName = If(IsServerSide, "Server-", "Client-") & RadixConvert(Math.Abs(Identify.GetHashCode), 10, 36)
|
||||
If IsServerSide Then
|
||||
Arguments += $" -i 10.114.114.114 --hostname={HostName} --tcp-whitelist={ServerPort} --udp-whitelist={ServerPort}"
|
||||
Else
|
||||
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}"
|
||||
End If
|
||||
For Each Peer As String In ServerConfig("Link")("Peers")
|
||||
Arguments += $" -p=""{Peer}"""
|
||||
Next
|
||||
If Not Setup.Get("LinkShareMode") Then Arguments += " --private-mode true"
|
||||
'启动进程
|
||||
ProcessStart(Arguments)
|
||||
Task.Progress = 0.15
|
||||
'等待连接
|
||||
Dim TimeoutCounter As Integer = 0
|
||||
Do
|
||||
Thread.Sleep(500) '为避免还没启动好先跑 CLI 了,先等半秒
|
||||
'刷新信息
|
||||
CheckCrash()
|
||||
RefreshPeerLoader.WaitForExit(IsForceRestart:=True)
|
||||
'查找目标节点
|
||||
Dim Ping = GetPeerPing()
|
||||
If Ping <> 0 Then
|
||||
Log($"[Link] 已与目标建立连接,当前 Ping 为 {Ping:0.0}ms")
|
||||
Telemetry("联机成功", "Server", IsServerSide, "Ping", Ping)
|
||||
Exit Do '退出循环
|
||||
End If
|
||||
'更新进度
|
||||
Dim LastProgress = Task.Progress
|
||||
Dim PeerCount As Integer = If(Peers Is Nothing, -1, Peers.Count)
|
||||
Select Case PeerCount
|
||||
Case -1 'CLI 无返回
|
||||
Task.Progress = MathClamp(Task.Progress + 0.02, 0.15, 0.25)
|
||||
Case 0 'CLI 有返回,但未连接到任何节点
|
||||
UpdateLoadingPage("正在连接到节点……", "连接节点")
|
||||
Task.Progress = MathClamp(Task.Progress + 0.02, If(IsServerSide, 0.5, 0.3), If(IsServerSide, 0.99, 0.5))
|
||||
Case Else '已连接到节点,但未连接到房主
|
||||
UpdateLoadingPage("正在连接到房主……", "连接房主")
|
||||
Task.Progress = MathClamp(Task.Progress + 0.02, Math.Min(0.45 + PeerCount * 0.05, 0.65), 0.99)
|
||||
End Select
|
||||
'超时判定
|
||||
If LastProgress <> Task.Progress Then
|
||||
TimeoutCounter = 0
|
||||
ElseIf TimeoutCounter < 20 Then
|
||||
TimeoutCounter += 1
|
||||
Else '进度停滞超过 10s
|
||||
Select Case PeerCount
|
||||
Case -1 'CLI 无返回
|
||||
Panic("无法启动联机模块", "近期日志:" & vbCrLf & LogHistory.Join(vbCrLf))
|
||||
Case 0 'CLI 有返回,但未连接到任何节点
|
||||
Panic("无法连接到节点", $"请检查你的网络环境是否良好。")
|
||||
Case Else '已连接到节点,但未连接到房主
|
||||
Panic("无法连接到房主", $"可能的原因:{vbCrLf}- 你或者房主的网络环境不佳{vbCrLf}- 房主已关闭房间{vbCrLf}- 邀请码输错了")
|
||||
End Select
|
||||
End If
|
||||
Loop Until Task.IsAborted
|
||||
If Task.IsAborted Then Throw New ThreadInterruptedException
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "进程与日志"
|
||||
|
||||
''' <summary>
|
||||
''' EasyTier Core 进程。
|
||||
''' </summary>
|
||||
Private Shared ProcessCore As Process
|
||||
Private Shared ProcessOutputHandle As AutoResetEvent, ProcessErrorHandle As AutoResetEvent
|
||||
|
||||
''' <summary>
|
||||
''' 若程序正在运行,则结束程序进程。
|
||||
''' 即使失败也不会抛出异常。
|
||||
''' </summary>
|
||||
Public Shared Sub ProcessStop()
|
||||
Try
|
||||
'关闭未捕获的进程
|
||||
For Each ProcessObject In Process.GetProcesses
|
||||
If ProcessObject.Id = ProcessCore?.Id Then Continue For
|
||||
If ProcessObject.ProcessName <> "联机模块" AndAlso ProcessObject.ProcessName <> "联机模块 CLI" Then Continue For
|
||||
Try
|
||||
Log("[Link] 停止残留的联机模块,PID:" & ProcessObject.Id & ",进程名:" & ProcessObject.ProcessName)
|
||||
ProcessObject.Kill()
|
||||
ProcessObject.Close()
|
||||
Catch exx As Exception
|
||||
Log(exx, $"结束进程失败({ProcessObject.ProcessName},PID {ProcessObject.Id})")
|
||||
End Try
|
||||
Next
|
||||
'关闭由自身启动的进程
|
||||
If ProcessCore IsNot Nothing AndAlso Not ProcessCore.HasExited Then
|
||||
Log("[Link] 停止所启动的联机模块,PID:" & ProcessCore.Id)
|
||||
ProcessCore.Kill()
|
||||
ProcessCore.Close()
|
||||
ProcessCore = Nothing
|
||||
End If
|
||||
'释放资源
|
||||
ProcessOutputHandle?.Dispose()
|
||||
ProcessErrorHandle?.Dispose()
|
||||
Catch ex As Exception
|
||||
Log(ex, "停止联机模块失败")
|
||||
End Try
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 出现意外错误,给出错误信息并结束联机。
|
||||
''' </summary>
|
||||
Private Sub Panic(Brief As String, Detail As String)
|
||||
If State = States.Loading Then
|
||||
FailReason = Brief
|
||||
LinkLoader.Failed(New Exception(Detail))
|
||||
Else
|
||||
MyMsgBox(Detail, "联机出错:" & Brief, IsWarn:=True)
|
||||
ChangeState(States.Waiting)
|
||||
Telemetry("联机失败", "Exception", FilterUserName(Brief & ":" & Detail, "*"))
|
||||
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
|
||||
|
||||
''' <summary>
|
||||
''' 启动进程。
|
||||
''' </summary>
|
||||
Private Sub ProcessStart(Arguments As String)
|
||||
Dim Info = New ProcessStartInfo With {
|
||||
.FileName = PathEasyTier & "联机模块.exe",
|
||||
.Arguments = Arguments,
|
||||
.UseShellExecute = False,
|
||||
.CreateNoWindow = True,
|
||||
.RedirectStandardError = True,
|
||||
.RedirectStandardOutput = True,
|
||||
.StandardOutputEncoding = Encoding.UTF8,
|
||||
.StandardErrorEncoding = Encoding.UTF8
|
||||
}
|
||||
Log("[Link] 正在启动 EasyTier:" & Arguments)
|
||||
ProcessCore = New Process With {.StartInfo = Info}
|
||||
Dim LogLineHandler =
|
||||
Function(sender As Object, e As DataReceivedEventArgs, Handle As AutoResetEvent)
|
||||
Try
|
||||
If e.Data Is Nothing Then
|
||||
Handle.[Set]()
|
||||
Return Nothing
|
||||
End If
|
||||
ProcessLogLine(e.Data)
|
||||
Catch unused As ObjectDisposedException
|
||||
Catch ex As Exception
|
||||
Log(ex, "读取 EasyTier 信息失败")
|
||||
End Try
|
||||
Return Nothing
|
||||
End Function
|
||||
ProcessOutputHandle = New AutoResetEvent(False)
|
||||
AddHandler ProcessCore.OutputDataReceived, Function(sender, e) LogLineHandler(sender, e, ProcessOutputHandle)
|
||||
ProcessErrorHandle = New AutoResetEvent(False)
|
||||
AddHandler ProcessCore.ErrorDataReceived, Function(sender, e) LogLineHandler(sender, e, ProcessErrorHandle)
|
||||
ProcessCore.Start()
|
||||
ProcessCore.BeginOutputReadLine()
|
||||
ProcessCore.BeginErrorReadLine()
|
||||
End Sub
|
||||
Private Sub ProcessLogLine(Line As String)
|
||||
'记录日志
|
||||
Log("[EasyTier] " & Line)
|
||||
LogHistory.Enqueue(Line)
|
||||
If LogHistory.Count >= 10 Then LogHistory.Dequeue()
|
||||
'检查日志内容
|
||||
If Line.ContainsF("new peer connection added", True) Then
|
||||
Log("[Link] 已建立连接:" & If(RegexSeek(Line, "(?<=remote_addr.+?"")[^""}]{3,}"), Line), LogLevel.Debug)
|
||||
Update()
|
||||
ElseIf Line.ContainsF("peer connection removed", True) Then
|
||||
Log("[Link] 已断开连接:" & If(RegexSeek(Line, "(?<=remote_addr.+?"")[^""}]{3,}"), Line), LogLevel.Debug)
|
||||
Update()
|
||||
End If
|
||||
End Sub
|
||||
Private LogHistory As New Queue(Of String)(10)
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "CLI 节点信息获取"
|
||||
|
||||
Private Class Peer
|
||||
''' <summary>
|
||||
''' 该节点的类型。
|
||||
''' </summary>
|
||||
Public ReadOnly Type As Types
|
||||
Public Enum Types
|
||||
''' <summary>
|
||||
''' 客户端。
|
||||
''' </summary>
|
||||
Client
|
||||
''' <summary>
|
||||
''' 服务器。
|
||||
''' </summary>
|
||||
Server
|
||||
''' <summary>
|
||||
''' 公共节点。
|
||||
''' </summary>
|
||||
Misc
|
||||
''' <summary>
|
||||
''' 自己,或者自己的重复(它可能返回多个自己)。
|
||||
''' </summary>
|
||||
Self
|
||||
End Enum
|
||||
''' <summary>
|
||||
''' 与该节点的延迟 (ms)。
|
||||
''' 若是自己则为 0。
|
||||
''' </summary>
|
||||
Public ReadOnly Ping As Double
|
||||
''' <summary>
|
||||
''' 名称。
|
||||
''' </summary>
|
||||
Public ReadOnly Name As String
|
||||
|
||||
''' <summary>
|
||||
''' 从 CLI 给出的信息行分析对应的数据。
|
||||
''' </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))
|
||||
'类别
|
||||
Dim PeerName = Parts(1)
|
||||
If PeerName = HostName Then
|
||||
Type = Types.Self
|
||||
ElseIf PeerName.StartsWithF("Client") Then
|
||||
Type = Types.Client
|
||||
ElseIf Parts(0).StartsWithF("10.114.114.114") Then '只允许这个 IP 作为房主,避免网络被多个房主搞炸的情况
|
||||
Type = Types.Server
|
||||
Else
|
||||
Type = Types.Misc
|
||||
End If
|
||||
'主机名
|
||||
Name = PeerName
|
||||
End Sub
|
||||
Public Overrides Function ToString() As String
|
||||
Return $"{Type} - {Name} - Ping {Ping:0.0}ms"
|
||||
End Function
|
||||
End Class
|
||||
|
||||
''' <summary>
|
||||
''' 当前的节点列表,使用 RefreshPeerLoader 来刷新。
|
||||
''' 若尚未成功获取过则为 Nothing,但保证在加载完成后至少是一个列表。
|
||||
''' </summary>
|
||||
Private Peers As List(Of Peer) = Nothing
|
||||
|
||||
''' <summary>
|
||||
''' 调用 EasyTier CLI 获取已连接节点信息。
|
||||
''' 这会过滤掉尚未完成连接的其他节点以及自己。
|
||||
''' 若在加载完成后连续获取失败 3 次,则会强制断开连接。
|
||||
''' </summary>
|
||||
Private RefreshPeerLoader As New LoaderTask(Of Integer, List(Of Peer))("EasyTier CLI", AddressOf RefreshPeer)
|
||||
Private Sub RefreshPeer()
|
||||
'| ipv4 | hostname | cost | lat(ms) | loss | rx | tx | tunnel | NAT | version |
|
||||
'|-------------------|-----------------------|----------|---------|------|---------|---------|--------|----------------|----------------|
|
||||
'| 10.114.114.1/24 | Client-RJ458A | Local | - | - | - | - | - | Unknown | 2.4.5-4c4d172e |
|
||||
'| | PublicServer_公用服务器 | p2p | 48.40 | 0.0% | 875 B | 1.26 kB | tcp | NoPat | 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 |
|
||||
Try
|
||||
Dim CliResult = StartProcessAndGetOutput(PathEasyTier & "联机模块 CLI.exe", "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)
|
||||
Dim NewPeers As New List(Of Peer)
|
||||
For Each Line In CliResult.Split(vbCrLf.ToCharArray, StringSplitOptions.RemoveEmptyEntries).Skip(2)
|
||||
Try
|
||||
Dim Peer = New Peer(Line)
|
||||
If Peer.Type = Peer.Types.Self Then Continue For '自己
|
||||
NewPeers.Add(Peer)
|
||||
Catch exx As Exception
|
||||
Log(exx, $"错误的信息行({Line})")
|
||||
End Try
|
||||
Next
|
||||
'完成
|
||||
Peers = NewPeers
|
||||
FailCount = 0
|
||||
Catch ex As Exception
|
||||
Log(ex, "获取节点信息失败")
|
||||
If State = States.Finished Then
|
||||
FailCount += 1
|
||||
If FailCount >= 4 Then Panic("获取节点信息失败", ex.Message)
|
||||
End If
|
||||
End Try
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' CLI 调用连续失败的次数。
|
||||
''' </summary>
|
||||
Private FailCount As Integer = 0
|
||||
|
||||
''' <summary>
|
||||
''' 根据当前的节点列表获取 Ping 值。
|
||||
''' 服务端会返回所有节点中最低的 Ping,客户端会返回服务端的 Ping。
|
||||
''' 0 代表尚不可用。
|
||||
''' </summary>
|
||||
Private Function GetPeerPing() As Double
|
||||
If Peers Is Nothing Then Return 0
|
||||
Dim PingTargets As IEnumerable(Of Peer)
|
||||
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
|
||||
Else
|
||||
Return Math.Max(1, PingTargets.Select(Function(p) p.Ping).Min())
|
||||
End If
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' 获取当前房间中的人数,包括自己。
|
||||
''' 0 代表不可用。
|
||||
''' </summary>
|
||||
Private ReadOnly Property PeopleCount As Integer
|
||||
Get
|
||||
If Peers Is Nothing Then Return 0
|
||||
Return Peers.Where(Function(p) p.Type <> Peer.Types.Misc).Count() + 1 '加上自己
|
||||
End Get
|
||||
End Property
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "定时状态更新"
|
||||
|
||||
'启动
|
||||
Private IsTimerStarted As Boolean = False
|
||||
Private Sub StartTimerThread() Handles Me.Loaded
|
||||
If IsTimerStarted Then Return
|
||||
RunInNewThread(
|
||||
Sub()
|
||||
Dim Counter As Integer = 0
|
||||
Do While True
|
||||
Try
|
||||
Thread.Sleep(200)
|
||||
Counter += 200
|
||||
'每 4 秒执行一次
|
||||
If Counter >= 4000 Then
|
||||
Counter = 0
|
||||
Update()
|
||||
End If
|
||||
'每 200ms 更新进度条
|
||||
If State = States.Loading Then RunInUi(AddressOf UpdateProgressBar)
|
||||
Catch ex As Exception
|
||||
Log(ex, "联机模块主时钟出错", LogLevel.Feedback)
|
||||
Thread.Sleep(10000)
|
||||
End Try
|
||||
Loop
|
||||
End Sub, "Link Timer")
|
||||
End Sub
|
||||
|
||||
'每 4 秒或进入页面时更新一次信息
|
||||
Private Sub Update() Handles Me.Loaded
|
||||
If State <> States.Finished Then Return
|
||||
'重新获取信息
|
||||
SyncLock RefreshPeerLoader.LockState
|
||||
If RefreshPeerLoader.State <> LoadState.Loading Then RefreshPeerLoader.Start(IsForceRestart:=True)
|
||||
End SyncLock
|
||||
'更新 Ping 与人数显示
|
||||
If FrmMain.PageCurrent = FormMain.PageType.Link Then
|
||||
RunInUi(
|
||||
Sub()
|
||||
Dim Ping As Double = GetPeerPing()
|
||||
If Ping Mod 500 = 0 OrElse $"{Ping:0.0}" = "1.0" OrElse FailCount > 0 Then
|
||||
LabFinishPing.Text = "连接中"
|
||||
AniStop("Link Logo Rotation")
|
||||
Else
|
||||
LabFinishPing.Text = If(Ping >= 10, $"{Ping:0} ms", $"{Ping:0.0} ms")
|
||||
AniStart(AaRotateTransform(ImgFinishLogo, 500, 5000), "Link Logo Rotation") 'Logo 旋转动画
|
||||
End If
|
||||
LabFinishPlayer.Text = PeopleCount & " 人"
|
||||
End Sub)
|
||||
End If
|
||||
'检查核心状态
|
||||
CheckCrash()
|
||||
'检查节点状态
|
||||
If Not Peers.Any Then
|
||||
Panic("网络连接已断开", "请检查你的网络环境是否正常。")
|
||||
Return
|
||||
End If
|
||||
If Not IsServerSide AndAlso Not Peers.Any(Function(p) p.Type = Peer.Types.Server) Then
|
||||
MyMsgBox("房主已离开房间!", "联机结束")
|
||||
ChangeState(States.Waiting)
|
||||
Return
|
||||
End If
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 检查联机模块是否崩溃。
|
||||
''' </summary>
|
||||
Private Sub CheckCrash()
|
||||
If ProcessCore IsNot Nothing AndAlso Not ProcessCore.HasExited Then Return
|
||||
Panic("联机模块已崩溃", "近期日志:" & vbCrLf & LogHistory.Join(vbCrLf))
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
End Class
|
||||
Reference in New Issue
Block a user