2.6.14
This commit is contained in:
@@ -277,7 +277,7 @@
|
|||||||
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
|
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
|
||||||
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
|
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
|
||||||
<Setter Property="UndoLimit" Value="15" />
|
<Setter Property="UndoLimit" Value="15" />
|
||||||
<Setter Property="MaxLength" Value="10000" />
|
<Setter Property="MaxLength" Value="1000" />
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrushBg0}" />
|
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrushBg0}" />
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
|
|||||||
@@ -47,9 +47,12 @@ Public Class Application
|
|||||||
Environment.Exit((My.Computer.Info.AvailablePhysicalMemory - Ram) / 1024) '返回清理的内存量(K)
|
Environment.Exit((My.Computer.Info.AvailablePhysicalMemory - Ram) / 1024) '返回清理的内存量(K)
|
||||||
End If
|
End If
|
||||||
#If DEBUG Then
|
#If DEBUG Then
|
||||||
ElseIf e.Args(0) = "--make" Then
|
|
||||||
'制作更新包
|
'制作更新包
|
||||||
UpdateMake(e.Args(1))
|
ElseIf e.Args(0) = "--edit1" Then
|
||||||
|
ExeEdit(e.Args(1), True)
|
||||||
|
Environment.Exit(Result.Cancel)
|
||||||
|
ElseIf e.Args(0) = "--edit2" Then
|
||||||
|
ExeEdit(e.Args(1), False)
|
||||||
Environment.Exit(Result.Cancel)
|
Environment.Exit(Result.Cancel)
|
||||||
#End If
|
#End If
|
||||||
End If
|
End If
|
||||||
@@ -112,13 +115,11 @@ Public Class Application
|
|||||||
Setup.Load("SystemDebugMode")
|
Setup.Load("SystemDebugMode")
|
||||||
Setup.Load("SystemDebugAnim")
|
Setup.Load("SystemDebugAnim")
|
||||||
Setup.Load("ToolDownloadThread")
|
Setup.Load("ToolDownloadThread")
|
||||||
|
Setup.Load("ToolDownloadCert")
|
||||||
'网络配置初始化
|
'网络配置初始化
|
||||||
ServicePointManager.Expect100Continue = True
|
ServicePointManager.Expect100Continue = True
|
||||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
|
||||||
ServicePointManager.DefaultConnectionLimit = 1024
|
ServicePointManager.DefaultConnectionLimit = 1024
|
||||||
'ServicePointManager.ServerCertificateValidationCallback = New Security.RemoteCertificateValidationCallback(Function() As Boolean
|
|
||||||
' Return True
|
|
||||||
' End Function)
|
|
||||||
'计时
|
'计时
|
||||||
Log("[Start] 第一阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
|
Log("[Start] 第一阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
|
||||||
ApplicationStartTick = GetTimeTick()
|
ApplicationStartTick = GetTimeTick()
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ Public Class MyResizer
|
|||||||
|
|
||||||
Private Declare Function GetMonitorInfo Lib "user32" (hMonitor As IntPtr, lpmi As MONITORINFO) As Boolean
|
Private Declare Function GetMonitorInfo Lib "user32" (hMonitor As IntPtr, lpmi As MONITORINFO) As Boolean
|
||||||
|
|
||||||
Friend Declare Function MonitorFromWindow Lib "User32" (handle As IntPtr, flags As Integer) As IntPtr
|
Private Declare Function MonitorFromWindow Lib "User32" (handle As IntPtr, flags As Integer) As IntPtr
|
||||||
|
|
||||||
Private Sub connectMouseHandlers(element As UIElement)
|
Private Sub connectMouseHandlers(element As UIElement)
|
||||||
AddHandler element.MouseLeftButtonDown, AddressOf Me.element_MouseLeftButtonDown
|
AddHandler element.MouseLeftButtonDown, AddressOf Me.element_MouseLeftButtonDown
|
||||||
|
|||||||
@@ -134,7 +134,7 @@
|
|||||||
<Grid x:Name="PanTitleInner" Visibility="Collapsed" Margin="-16,0,0,0" Opacity="0" HorizontalAlignment="Left" Width="{Binding ActualWidth, ElementName=PanTitle, Mode=OneWay}">
|
<Grid x:Name="PanTitleInner" Visibility="Collapsed" Margin="-16,0,0,0" Opacity="0" HorizontalAlignment="Left" Width="{Binding ActualWidth, ElementName=PanTitle, Mode=OneWay}">
|
||||||
<local:MyIconButton HorizontalAlignment="Left" Theme="White" x:Name="BtnTitleInner" Margin="12,0,0,0" Height="28" Width="28"
|
<local:MyIconButton HorizontalAlignment="Left" Theme="White" x:Name="BtnTitleInner" Margin="12,0,0,0" Height="28" Width="28"
|
||||||
LogoScale="0.87" Logo="M1097.162313 584.707482 250.272424 584.707482 562.833701 896.95123C591.749274 925.859979 591.749274 972.659975 562.833701 1001.568724 533.91812 1030.477473 487.058315 1030.477473 458.142742 1001.568724L21.580946 565.451235C6.757449 550.631234-0.361728 531.131238 0.028357 511.679985L0.028357 511.631236 0.028357 511.582486C-0.361728 492.13124 6.757449 472.582488 21.580946 457.762487L458.142742 21.644997C487.058315-7.215002 533.91812-7.215002 562.833701 21.644997 591.749274 50.553746 591.749274 97.4025 562.833701 126.262499L250.272424 438.55499 1097.162313 438.55499C1137.585605 438.55499 1170.304578 471.266238 1170.304578 511.631236 1170.304578 551.947483 1137.585605 584.707482 1097.162313 584.707482L1097.162313 584.707482Z" />
|
LogoScale="0.87" Logo="M1097.162313 584.707482 250.272424 584.707482 562.833701 896.95123C591.749274 925.859979 591.749274 972.659975 562.833701 1001.568724 533.91812 1030.477473 487.058315 1030.477473 458.142742 1001.568724L21.580946 565.451235C6.757449 550.631234-0.361728 531.131238 0.028357 511.679985L0.028357 511.631236 0.028357 511.582486C-0.361728 492.13124 6.757449 472.582488 21.580946 457.762487L458.142742 21.644997C487.058315-7.215002 533.91812-7.215002 562.833701 21.644997 591.749274 50.553746 591.749274 97.4025 562.833701 126.262499L250.272424 438.55499 1097.162313 438.55499C1137.585605 438.55499 1170.304578 471.266238 1170.304578 511.631236 1170.304578 551.947483 1137.585605 584.707482 1097.162313 584.707482L1097.162313 584.707482Z" />
|
||||||
<TextBlock SnapsToDevicePixels="False" IsHitTestVisible="False" Name="LabTitleInner" VerticalAlignment="Center" Margin="47,1,0,0" HorizontalAlignment="Left" Foreground="{DynamicResource ColorBrush8}" FontSize="15" />
|
<TextBlock SnapsToDevicePixels="False" IsHitTestVisible="False" Name="LabTitleInner" VerticalAlignment="Center" Margin="47,1,60,0" HorizontalAlignment="Left" Foreground="{DynamicResource ColorBrush8}" FontSize="15" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid x:Name="PanLeft" Grid.Row="1" HorizontalAlignment="Left" SnapsToDevicePixels="True">
|
<Grid x:Name="PanLeft" Grid.Row="1" HorizontalAlignment="Left" SnapsToDevicePixels="True">
|
||||||
|
|||||||
@@ -129,6 +129,12 @@ Public Class FormMain
|
|||||||
'3:BUG+ IMP* FEAT-
|
'3:BUG+ IMP* FEAT-
|
||||||
'2:BUG* IMP-
|
'2:BUG* IMP-
|
||||||
'1:BUG-
|
'1:BUG-
|
||||||
|
If LastVersion < 314 Then 'Snapshot 2.6.14
|
||||||
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化 MC 下载,尝试解决各种导致 MC 下载失败的问题"))
|
||||||
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "由于 MCBBS 关站,移除其相关内容"))
|
||||||
|
FeatureCount += 17
|
||||||
|
BugCount += 16
|
||||||
|
End If
|
||||||
If LastVersion < 312 Then 'Snapshot 2.6.13
|
If LastVersion < 312 Then 'Snapshot 2.6.13
|
||||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法启动 Forge 1.18.3+ 的 Bug"))
|
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法启动 Forge 1.18.3+ 的 Bug"))
|
||||||
FeatureCount += 6
|
FeatureCount += 6
|
||||||
@@ -906,7 +912,7 @@ Public Class FormMain
|
|||||||
Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!")
|
Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!")
|
||||||
ElseIf Not (PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionMod) Then
|
ElseIf Not (PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionMod) Then
|
||||||
'未处于 Mod 管理页面
|
'未处于 Mod 管理页面
|
||||||
If MyMsgBox($"是否要将这些文件作为 Mod 安装到 {TargetVersion.Name}?", "Mod 安装确认", "确定", "取消") = 1 Then GoTo Install
|
If MyMsgBox($"是否要将这{If(FilePathList.Count = 1, "个", "些")}文件作为 Mod 安装到 {TargetVersion.Name}?", "Mod 安装确认", "确定", "取消") = 1 Then GoTo Install
|
||||||
Else
|
Else
|
||||||
'处于 Mod 管理页面
|
'处于 Mod 管理页面
|
||||||
Install:
|
Install:
|
||||||
@@ -994,7 +1000,6 @@ Install:
|
|||||||
Left -= 10000
|
Left -= 10000
|
||||||
ShowInTaskbar = False
|
ShowInTaskbar = False
|
||||||
Visibility = Visibility.Hidden
|
Visibility = Visibility.Hidden
|
||||||
'SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) Or WS_EX_TOOLWINDOW)
|
|
||||||
Log("[System] 窗口已隐藏,位置:(" & Left & "," & Top & ")")
|
Log("[System] 窗口已隐藏,位置:(" & Left & "," & Top & ")")
|
||||||
Else
|
Else
|
||||||
'取消隐藏
|
'取消隐藏
|
||||||
@@ -1017,16 +1022,9 @@ Install:
|
|||||||
Topmost = False
|
Topmost = False
|
||||||
SetForegroundWindow(Handle)
|
SetForegroundWindow(Handle)
|
||||||
Focus()
|
Focus()
|
||||||
'ShowWindow(Handle, 1) 'SW_RESTORE
|
|
||||||
'SetWindowPos(Handle, 0, 0, 0, 0, 0, 3) 'InsertAfter: TOP, NOMOVE & NOSIZE
|
|
||||||
'SetFocus(Handle)
|
|
||||||
Log("[System] 窗口已置顶,位置:(" & Left & ", " & Top & "), " & Width & " x " & Height)
|
Log("[System] 窗口已置顶,位置:(" & Left & ", " & Top & "), " & Width & " x " & Height)
|
||||||
End Sub)
|
End Sub)
|
||||||
End Sub
|
End Sub
|
||||||
'Private Declare Function SetFocus Lib "user32" (hWnd As IntPtr) As IntPtr
|
|
||||||
'Private Declare Function SetWindowPos Lib "user32" (hWnd As IntPtr, hWndInsertAfter As IntPtr, x As Integer, y As Integer, cx As Integer, cy As Integer, flags As UInteger) As Boolean
|
|
||||||
'Private Declare Function AttachThreadInput Lib "user32" (attachFrom As IntPtr, attachTo As IntPtr, isAttach As Boolean) As Boolean
|
|
||||||
'Private Declare Function SendMessage Lib "user32" (hWnd As IntPtr, msg As UInteger, wParam As Long, lParam As Long) As IntPtr
|
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
|
|
||||||
@@ -1573,7 +1571,11 @@ Install:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public Sub BackToTop() Handles BtnExtraBack.Click
|
Public Sub BackToTop() Handles BtnExtraBack.Click
|
||||||
Dim RealScroll As MyScrollViewer = BtnExtraBack_GetRealChild()
|
Dim RealScroll As MyScrollViewer = BtnExtraBack_GetRealChild()
|
||||||
|
If RealScroll IsNot Nothing Then
|
||||||
RealScroll.PerformVerticalOffsetDelta(-RealScroll.VerticalOffset)
|
RealScroll.PerformVerticalOffsetDelta(-RealScroll.VerticalOffset)
|
||||||
|
Else
|
||||||
|
Log("[UI] 无法返回顶部,未找到合适的 RealScroll", LogLevel.Hint)
|
||||||
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Private Function BtnExtraBack_ShowCheck() As Boolean
|
Private Function BtnExtraBack_ShowCheck() As Boolean
|
||||||
Dim RealScroll As MyScrollViewer = BtnExtraBack_GetRealChild()
|
Dim RealScroll As MyScrollViewer = BtnExtraBack_GetRealChild()
|
||||||
@@ -1581,9 +1583,7 @@ Install:
|
|||||||
End Function
|
End Function
|
||||||
Private Function BtnExtraBack_GetRealChild() As MyScrollViewer
|
Private Function BtnExtraBack_GetRealChild() As MyScrollViewer
|
||||||
If PanMainRight.Child Is Nothing OrElse TypeOf PanMainRight.Child IsNot MyPageRight Then Return Nothing
|
If PanMainRight.Child Is Nothing OrElse TypeOf PanMainRight.Child IsNot MyPageRight Then Return Nothing
|
||||||
Dim Scroll = CType(PanMainRight.Child, MyPageRight).PanScroll
|
Return CType(PanMainRight.Child, MyPageRight).PanScroll
|
||||||
If Scroll Is Nothing OrElse Scroll.Visibility <> Visibility.Visible Then Return Nothing
|
|
||||||
Return Scroll
|
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 715 B |
@@ -11,12 +11,12 @@ Public Module ModBase
|
|||||||
#Region "声明"
|
#Region "声明"
|
||||||
|
|
||||||
'下列版本信息由更新器自动修改
|
'下列版本信息由更新器自动修改
|
||||||
Public Const VersionBaseName As String = "2.6.13" '不含分支前缀的显示用版本名
|
Public Const VersionBaseName As String = "2.6.14" '不含分支前缀的显示用版本名
|
||||||
Public Const VersionStandardCode As String = "2.6.13." & VersionBranchCode '标准格式的四段式版本号
|
Public Const VersionStandardCode As String = "2.6.14." & VersionBranchCode '标准格式的四段式版本号
|
||||||
#If BETA Then
|
#If BETA Then
|
||||||
Public Const VersionCode As Integer = 313 'Release
|
Public Const VersionCode As Integer = 313 'Release
|
||||||
#Else
|
#Else
|
||||||
Public Const VersionCode As Integer = 312 'Snapshot
|
Public Const VersionCode As Integer = 314 'Snapshot
|
||||||
#End If
|
#End If
|
||||||
'自动生成的版本信息
|
'自动生成的版本信息
|
||||||
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
||||||
@@ -158,9 +158,13 @@ Public Module ModBase
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public Const IconButtonUser As String = "M660.338 528.065c63.61-46.825 105.131-121.964 105.131-206.83 0-141.7-115.29-256.987-256.997-256.987-141.706 0-256.998 115.288-256.998 256.987 0 85.901 42.52 161.887 107.456 208.562-152.1 59.92-260.185 207.961-260.185 381.077 0 21.276 17.253 38.53 38.53 38.53 21.278 0 38.53-17.254 38.53-38.53 0-183.426 149.232-332.671 332.667-332.671 1.589 0 3.113-0.207 4.694-0.244 0.8 0.056 1.553 0.244 2.362 0.244 183.434 0 332.664 149.245 332.664 332.671 0 21.276 17.255 38.53 38.533 38.53 21.277 0 38.53-17.254 38.53-38.53 0-174.885-110.354-324.13-264.917-382.809z m-331.803-206.83c0-99.22 80.72-179.927 179.935-179.927s179.937 80.708 179.937 179.927c0 99.203-80.721 179.91-179.937 179.91s-179.935-80.708-179.935-179.91z"
|
Public Const IconButtonUser As String = "M660.338 528.065c63.61-46.825 105.131-121.964 105.131-206.83 0-141.7-115.29-256.987-256.997-256.987-141.706 0-256.998 115.288-256.998 256.987 0 85.901 42.52 161.887 107.456 208.562-152.1 59.92-260.185 207.961-260.185 381.077 0 21.276 17.253 38.53 38.53 38.53 21.278 0 38.53-17.254 38.53-38.53 0-183.426 149.232-332.671 332.667-332.671 1.589 0 3.113-0.207 4.694-0.244 0.8 0.056 1.553 0.244 2.362 0.244 183.434 0 332.664 149.245 332.664 332.671 0 21.276 17.255 38.53 38.533 38.53 21.277 0 38.53-17.254 38.53-38.53 0-174.885-110.354-324.13-264.917-382.809z m-331.803-206.83c0-99.22 80.72-179.927 179.935-179.927s179.937 80.708 179.937 179.927c0 99.203-80.721 179.91-179.937 179.91s-179.935-80.708-179.935-179.91z"
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 图标按钮,微软,0.9x
|
''' 图标按钮,盾牌,1x
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Const IconButtonMs As String = "M0,0h5v5h-5ZM6,0h5v5h-5v-5ZM0,6h5v5h-5v-5ZM6,6h5v5h-5v-5Z"
|
Public Const IconButtonShield As String = "M511.488256 95.184408c35.310345 22.516742 95.184408 55.78011 167.34033 84.437781 75.738131 29.681159 148.405797 40.93953 191.392304 45.033483v353.615193c0 73.691154-50.662669 164.781609-136.123938 244.101949C649.65917 901.181409 558.568716 942.12094 512 942.12094c-46.568716 0-137.65917-40.93953-222.096952-119.748126C204.441779 742.54073 153.77911 651.450275 153.77911 577.247376v-353.103448c42.474763-4.093953 116.165917-15.352324 191.904048-45.545227 75.226387-30.192904 133.565217-63.456272 165.805098-83.414293M512 0c-4.093953 0-8.187906 1.535232-11.258371 3.582209l-14.84058 10.234882c-1.023488 0.511744-67.550225 47.592204-170.410794 88.531735-100.813593 39.916042-198.556722 41.963018-199.58021 41.963018l-25.075462 0.511744c-10.746627 0.511744-18.934533 8.187906-18.934533 18.422789v414.000999c0 216.97951 286.064968 446.24088 440.09995 446.24088s440.09995-229.261369 440.09995-445.729136V163.758121c0-10.234883-8.69965-18.422789-18.934533-18.422789l-24.563718-0.511744c-1.023488 0-98.766617-2.046977-199.58021-41.963018-103.372314-40.93953-170.410795-88.01999-170.922538-88.531734L523.258371 3.582209c-3.070465-2.558721-7.164418-3.582209-11.258371-3.582209z M743.308346 410.930535l-260.477761 260.477761c-15.864068 15.864068-41.963018 15.864068-57.827087 0l-144.823588-144.823588c-15.864068-15.864068-15.864068-41.963018 0-57.827087 8.187906-8.187906 18.422789-11.770115 29.169415-11.770115 10.234883 0 20.981509 4.093953 29.169416 11.770115l115.654173 115.654173L685.993003 352.591704c15.864068-15.864068 41.963018-15.864068 57.827087 0 15.352324 16.375812 15.352324 42.474763-0.511744 58.338831z"
|
||||||
|
''' <summary>
|
||||||
|
''' 图标按钮,离线,0.85x
|
||||||
|
''' </summary>
|
||||||
|
Public Const IconButtonOffline As String = "M533.293176 788.841412a60.235294 60.235294 0 1 1 85.202824 85.202823l-42.616471 42.586353c-129.355294 129.385412-339.124706 129.385412-468.510117 0-129.385412-129.385412-129.385412-339.124706 0-468.510117l42.586353-42.616471a60.235294 60.235294 0 1 1 85.202823 85.202824l-42.61647 42.586352a210.823529 210.823529 0 1 0 298.164706 298.164706l42.586352-42.61647z m255.548236-255.548236l42.61647-42.586352a210.823529 210.823529 0 1 0-298.164706-298.164706l-42.586352 42.61647a60.235294 60.235294 0 1 1-85.202824-85.202823l42.616471-42.586353c129.355294-129.385412 339.124706-129.385412 468.510117 0 129.385412 129.385412 129.385412 339.124706 0 468.510117l-42.586353 42.616471a60.235294 60.235294 0 1 1-85.202823-85.202824zM192.542118 192.542118a60.235294 60.235294 0 0 1 85.202823 0l553.712941 553.712941a60.235294 60.235294 0 0 1-85.202823 85.202823L192.542118 277.744941a60.235294 60.235294 0 0 1 0-85.202823z"
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 图标,音符,1x
|
''' 图标,音符,1x
|
||||||
''' </summary>
|
''' </summary>
|
||||||
@@ -1980,9 +1984,10 @@ NextElement:
|
|||||||
Log("[System] 执行外部命令并等待返回结果:" & FileName & " " & Arguments)
|
Log("[System] 执行外部命令并等待返回结果:" & FileName & " " & Arguments)
|
||||||
Using Program As New Process() With {.StartInfo = Info}
|
Using Program As New Process() With {.StartInfo = Info}
|
||||||
Program.Start()
|
Program.Start()
|
||||||
|
Dim Result As String = Program.StandardOutput.ReadToEnd & Program.StandardError.ReadToEnd
|
||||||
Program.WaitForExit(Timeout)
|
Program.WaitForExit(Timeout)
|
||||||
If Not Program.HasExited Then Program.Kill()
|
If Not Program.HasExited Then Program.Kill()
|
||||||
Return Program.StandardOutput.ReadToEnd & Program.StandardError.ReadToEnd
|
Return Result
|
||||||
End Using
|
End Using
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
@@ -2111,6 +2116,7 @@ NextElement:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public Sub OpenWebsite(Url As String)
|
Public Sub OpenWebsite(Url As String)
|
||||||
Try
|
Try
|
||||||
|
If Not Url.ToLower.StartsWith("http") Then Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!")
|
||||||
Log("[System] 正在打开网页:" & Url)
|
Log("[System] 正在打开网页:" & Url)
|
||||||
Process.Start(Url)
|
Process.Start(Url)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
|
|||||||
@@ -192,7 +192,6 @@ RequestFinished:
|
|||||||
If Url.StartsWith("https", StringComparison.OrdinalIgnoreCase) Then Request.ProtocolVersion = HttpVersion.Version11
|
If Url.StartsWith("https", StringComparison.OrdinalIgnoreCase) Then Request.ProtocolVersion = HttpVersion.Version11
|
||||||
Request.Timeout = Timeout
|
Request.Timeout = Timeout
|
||||||
Request.Accept = Accept
|
Request.Accept = Accept
|
||||||
Request.KeepAlive = False
|
|
||||||
SecretHeadersSign(Url, Request)
|
SecretHeadersSign(Url, Request)
|
||||||
Using res As HttpWebResponse = Request.GetResponse()
|
Using res As HttpWebResponse = Request.GetResponse()
|
||||||
Using HttpStream As Stream = res.GetResponseStream()
|
Using HttpStream As Stream = res.GetResponseStream()
|
||||||
@@ -393,7 +392,6 @@ RequestFinished:
|
|||||||
End If
|
End If
|
||||||
Req.ContentType = ContentType
|
Req.ContentType = ContentType
|
||||||
Req.Timeout = Timeout
|
Req.Timeout = Timeout
|
||||||
Req.KeepAlive = False
|
|
||||||
SecretHeadersSign(Url, Req)
|
SecretHeadersSign(Url, Req)
|
||||||
If Url.StartsWith("https", StringComparison.OrdinalIgnoreCase) Then Req.ProtocolVersion = HttpVersion.Version11
|
If Url.StartsWith("https", StringComparison.OrdinalIgnoreCase) Then Req.ProtocolVersion = HttpVersion.Version11
|
||||||
If Method = "POST" OrElse Method = "PUT" Then
|
If Method = "POST" OrElse Method = "PUT" Then
|
||||||
@@ -965,13 +963,12 @@ Capture:
|
|||||||
'是否禁用多线程,以及规定碎片大小
|
'是否禁用多线程,以及规定碎片大小
|
||||||
Dim TargetUrl As String = GetSource().Url
|
Dim TargetUrl As String = GetSource().Url
|
||||||
If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("gitcode.net") OrElse TargetUrl.Contains("github.com") Then Return False
|
If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("gitcode.net") OrElse TargetUrl.Contains("github.com") Then Return False
|
||||||
Dim RealFilePieceLimit = If(TargetUrl.Contains("download.mcbbs.net"), FilePieceLimit * 5, FilePieceLimit)
|
|
||||||
'寻找最大碎片
|
'寻找最大碎片
|
||||||
Dim FilePieceMax As NetThread = Threads
|
Dim FilePieceMax As NetThread = Threads
|
||||||
For Each Thread As NetThread In Threads
|
For Each Thread As NetThread In Threads
|
||||||
If Thread.DownloadUndone > FilePieceMax.DownloadUndone Then FilePieceMax = Thread
|
If Thread.DownloadUndone > FilePieceMax.DownloadUndone Then FilePieceMax = Thread
|
||||||
Next
|
Next
|
||||||
If FilePieceMax Is Nothing OrElse FilePieceMax.DownloadUndone < RealFilePieceLimit Then Return False
|
If FilePieceMax Is Nothing OrElse FilePieceMax.DownloadUndone < FilePieceLimit Then Return False
|
||||||
StartPosition = FilePieceMax.DownloadEnd - FilePieceMax.DownloadUndone * 0.4
|
StartPosition = FilePieceMax.DownloadEnd - FilePieceMax.DownloadUndone * 0.4
|
||||||
StartSource = GetSource()
|
StartSource = GetSource()
|
||||||
|
|
||||||
@@ -1021,7 +1018,7 @@ StartThread:
|
|||||||
Dim HttpRequest As HttpWebRequest
|
Dim HttpRequest As HttpWebRequest
|
||||||
Dim ResultStream As Stream = Nothing
|
Dim ResultStream As Stream = Nothing
|
||||||
'部分下载源真的特别慢,并且只需要一个请求,例如 Ping 为 20s,如果增长太慢,就会造成类似 2.5s 5s 7.5s 10s 12.5s... 的极大延迟
|
'部分下载源真的特别慢,并且只需要一个请求,例如 Ping 为 20s,如果增长太慢,就会造成类似 2.5s 5s 7.5s 10s 12.5s... 的极大延迟
|
||||||
'延迟过长会导致某些特别慢的链接迟迟不被掐死,即使 MCBBS 源在 10s 下也会出现类似情况
|
'延迟过长会导致某些特别慢的链接迟迟不被掐死
|
||||||
Dim Timeout As Integer = Math.Min(Math.Max(ConnectAverage, 6000) * (1 + Info.Source.FailCount), 30000)
|
Dim Timeout As Integer = Math.Min(Math.Max(ConnectAverage, 6000) * (1 + Info.Source.FailCount), 30000)
|
||||||
Info.State = NetState.Connect
|
Info.State = NetState.Connect
|
||||||
Try
|
Try
|
||||||
@@ -1206,7 +1203,9 @@ SourceBreak:
|
|||||||
'End SyncLock
|
'End SyncLock
|
||||||
Info.Source.Ex = ex
|
Info.Source.Ex = ex
|
||||||
'根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传)
|
'根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传)
|
||||||
If ex.Message.Contains("该下载源不支持") OrElse ex.Message.Contains("未能解析") OrElse ex.Message.Contains("(404)") OrElse ex.Message.Contains("(403)") OrElse ex.Message.Contains("(502)") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse
|
'BMCLAPI 的部分源在高频率请求下会返回 403,所以不应因此禁用下载源
|
||||||
|
If ex.Message.Contains("该下载源不支持") OrElse ex.Message.Contains("未能解析") OrElse ex.Message.Contains("(404)") OrElse
|
||||||
|
ex.Message.Contains("(502)") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse ex.Message.Contains("获取到的片大小不一致") OrElse
|
||||||
(Info.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 40) AndAlso DownloadDone < 1) OrElse
|
(Info.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 40) AndAlso DownloadDone < 1) OrElse
|
||||||
Info.Source.FailCount > NetTaskThreadLimit Then
|
Info.Source.FailCount > NetTaskThreadLimit Then
|
||||||
Dim IsThisFail As Boolean = False
|
Dim IsThisFail As Boolean = False
|
||||||
@@ -1225,7 +1224,7 @@ Wrong:
|
|||||||
'本线程引发下载源被禁用
|
'本线程引发下载源被禁用
|
||||||
If IsThisFail Then
|
If IsThisFail Then
|
||||||
Log("[Download] " & LocalName & " " & Uuid & "#:下载源被禁用(" & Info.Source.Id & "):" & Info.Source.Url)
|
Log("[Download] " & LocalName & " " & Uuid & "#:下载源被禁用(" & Info.Source.Id & "):" & Info.Source.Url)
|
||||||
Log(ex, "下载源 " & Info.Source.Id & " 已被禁用", If(ex.Message.Contains("不支持断点续传") OrElse ex.Message.Contains("404") OrElse ex.Message.Contains("416"), LogLevel.Developer, LogLevel.Debug))
|
Log(ex, "下载源 " & Info.Source.Id & " 已被禁用", If(ex.Message.Contains("不支持断点续传") OrElse ex.Message.Contains("(404)") OrElse ex.Message.Contains("(416)"), LogLevel.Developer, LogLevel.Debug))
|
||||||
If IsSourceFailed() Then
|
If IsSourceFailed() Then
|
||||||
'没有可用源
|
'没有可用源
|
||||||
Log("[Download] 文件 " & LocalName & " 已无可用下载源")
|
Log("[Download] 文件 " & LocalName & " 已无可用下载源")
|
||||||
@@ -1475,7 +1474,7 @@ Retry:
|
|||||||
End Get
|
End Get
|
||||||
Set(value As Integer)
|
Set(value As Integer)
|
||||||
_FailCount = value
|
_FailCount = value
|
||||||
If State = LoadState.Loading AndAlso value >= Math.Min(2000, Math.Max(FileRemain * 5.5, NetTaskThreadLimit * 5.5 + 3)) Then
|
If State = LoadState.Loading AndAlso value >= Math.Min(10000, Math.Max(FileRemain * 5.5, NetTaskThreadLimit * 5.5 + 3)) Then
|
||||||
Log("[Download] 由于同加载器中失败次数过多引发强制失败:连续失败了 " & value & " 次", LogLevel.Debug)
|
Log("[Download] 由于同加载器中失败次数过多引发强制失败:连续失败了 " & value & " 次", LogLevel.Debug)
|
||||||
On Error Resume Next
|
On Error Resume Next
|
||||||
Dim ExList As New List(Of Exception)
|
Dim ExList As New List(Of Exception)
|
||||||
@@ -1846,7 +1845,8 @@ Retry:
|
|||||||
Private Sub StartManager()
|
Private Sub StartManager()
|
||||||
If IsManagerStarted Then Exit Sub
|
If IsManagerStarted Then Exit Sub
|
||||||
IsManagerStarted = True
|
IsManagerStarted = True
|
||||||
RunInNewThread(Sub()
|
RunInNewThread(
|
||||||
|
Sub()
|
||||||
Try
|
Try
|
||||||
Dim LastLoopTime As Long
|
Dim LastLoopTime As Long
|
||||||
While True
|
While True
|
||||||
@@ -1898,12 +1898,12 @@ Retry:
|
|||||||
NewThreadCount -= 1
|
NewThreadCount -= 1
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
|
'等待 40 ms:BMCLAPI 部分时候有 20QPS 的限制
|
||||||
|
Thread.Sleep(40)
|
||||||
Loop While NewThreadCount > 0 AndAlso IsSuccess
|
Loop While NewThreadCount > 0 AndAlso IsSuccess
|
||||||
End If
|
End If
|
||||||
'等待直至 120 ms
|
'等待 40 ms
|
||||||
Do While GetTimeTick() - LastLoopTime < 120
|
Thread.Sleep(40)
|
||||||
Thread.Sleep(10)
|
|
||||||
Loop
|
|
||||||
End While
|
End While
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Log(ex, "下载管理启动线程 1 出错", LogLevel.Assert)
|
Log(ex, "下载管理启动线程 1 出错", LogLevel.Assert)
|
||||||
|
|||||||
@@ -59,7 +59,6 @@
|
|||||||
Entry.WikiId = i
|
Entry.WikiId = i
|
||||||
If SplitedLine.Count >= 2 Then
|
If SplitedLine.Count >= 2 Then
|
||||||
Entry.ChineseName = SplitedLine(1)
|
Entry.ChineseName = SplitedLine(1)
|
||||||
Entry.MCBBS = If(SplitedLine.Count >= 3, SplitedLine(2), Nothing)
|
|
||||||
If Entry.ChineseName.Contains("*") Then '处理 *
|
If Entry.ChineseName.Contains("*") Then '处理 *
|
||||||
Entry.ChineseName = Entry.ChineseName.Replace("*", " (" &
|
Entry.ChineseName = Entry.ChineseName.Replace("*", " (" &
|
||||||
String.Join(" ", If(Entry.CurseForgeSlug, Entry.ModrinthSlug).Split("-").Select(Function(w) w.Substring(0, 1).ToUpper & w.Substring(1, w.Length - 1))) & ")")
|
String.Join(" ", If(Entry.CurseForgeSlug, Entry.ModrinthSlug).Split("-").Select(Function(w) w.Substring(0, 1).ToUpper & w.Substring(1, w.Length - 1))) & ")")
|
||||||
@@ -82,10 +81,6 @@
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public ChineseName As String = ""
|
Public ChineseName As String = ""
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' MCBBS 发布帖编号(例如 195107)。若为 Nothing 则没有发布帖。
|
|
||||||
''' </summary>
|
|
||||||
Public MCBBS As Integer?
|
|
||||||
''' <summary>
|
|
||||||
''' CurseForge Slug(例如 advanced-solar-panels)。
|
''' CurseForge Slug(例如 advanced-solar-panels)。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public CurseForgeSlug As String = Nothing
|
Public CurseForgeSlug As String = Nothing
|
||||||
@@ -95,7 +90,7 @@
|
|||||||
Public ModrinthSlug As String = Nothing
|
Public ModrinthSlug As String = Nothing
|
||||||
|
|
||||||
Public Overrides Function ToString() As String
|
Public Overrides Function ToString() As String
|
||||||
Return If(CurseForgeSlug, "") & "&" & If(ModrinthSlug, "") & "|" & WikiId & "|" & ChineseName & If(MCBBS Is Nothing, "", "|" & MCBBS)
|
Return If(CurseForgeSlug, "") & "&" & If(ModrinthSlug, "") & "|" & WikiId & "|" & ChineseName
|
||||||
End Function
|
End Function
|
||||||
End Class
|
End Class
|
||||||
|
|
||||||
@@ -200,14 +195,6 @@
|
|||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' MCBBS 的帖子 ID。若为 0 则没有。
|
|
||||||
''' </summary>
|
|
||||||
Public ReadOnly Property MCBBS As Integer
|
|
||||||
Get
|
|
||||||
Return If(DatabaseEntry Is Nothing, 0, If(DatabaseEntry.MCBBS, 0))
|
|
||||||
End Get
|
|
||||||
End Property
|
|
||||||
''' <summary>
|
|
||||||
''' 翻译后的中文名。若数据库没有则等同于 RawName。
|
''' 翻译后的中文名。若数据库没有则等同于 RawName。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public ReadOnly Property TranslatedName As String
|
Public ReadOnly Property TranslatedName As String
|
||||||
@@ -884,10 +871,10 @@ NoSubtitle:
|
|||||||
Dim SearchResult As String = ""
|
Dim SearchResult As String = ""
|
||||||
For i = 0 To Math.Min(4, SearchResults.Count - 1) '就算全是准确的,也最多只要 5 个
|
For i = 0 To Math.Min(4, SearchResults.Count - 1) '就算全是准确的,也最多只要 5 个
|
||||||
If Not SearchResults(i).AbsoluteRight AndAlso i >= Math.Min(2, SearchResults.Count - 1) Then Exit For '把 3 个结果拼合以提高准确度
|
If Not SearchResults(i).AbsoluteRight AndAlso i >= Math.Min(2, SearchResults.Count - 1) Then Exit For '把 3 个结果拼合以提高准确度
|
||||||
If SearchResults(i).Item.CurseForgeSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.CurseForgeSlug.Replace("-", " ") & " "
|
If SearchResults(i).Item.CurseForgeSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.CurseForgeSlug.Replace("-", " ").Replace("/", " ") & " "
|
||||||
If SearchResults(i).Item.ModrinthSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.ModrinthSlug.Replace("-", " ") & " "
|
If SearchResults(i).Item.ModrinthSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.ModrinthSlug.Replace("-", " ").Replace("/", " ") & " "
|
||||||
SearchResult += SearchResults(i).Item.ChineseName.Split(" (").Last.TrimEnd(") ").Split(" - ").First.
|
SearchResult += SearchResults(i).Item.ChineseName.Split(" (").Last.TrimEnd(") ").Split(" - ").First.
|
||||||
Replace(":", "").Replace("(", "").Replace(")", "").ToLower & " "
|
Replace(":", "").Replace("(", "").Replace(")", "").ToLower.Replace("/", " ") & " "
|
||||||
Next
|
Next
|
||||||
Log("[Comp] 中文搜索原始关键词:" & SearchResult, LogLevel.Developer)
|
Log("[Comp] 中文搜索原始关键词:" & SearchResult, LogLevel.Developer)
|
||||||
'去除常见连接词
|
'去除常见连接词
|
||||||
@@ -911,9 +898,8 @@ NoSubtitle:
|
|||||||
For Each Keyword In AllPossibleKeywords.Split(" ")
|
For Each Keyword In AllPossibleKeywords.Split(" ")
|
||||||
Keyword = Keyword.Trim("["c, "]"c)
|
Keyword = Keyword.Trim("["c, "]"c)
|
||||||
If Keyword = "" Then Continue For
|
If Keyword = "" Then Continue For
|
||||||
If {"forge", "fabric", "for", "mod",
|
If {"forge", "fabric", "for", "mod", "quilt"}.Contains(Keyword) Then '#208
|
||||||
"forge/fabric", "fabric/forge", "fabric/quilt", "quilt/fabric"}.Contains(Keyword) Then '#208
|
Log("[Comp] 已跳过搜索关键词:" & Keyword, LogLevel.Developer)
|
||||||
Log("[Comp] 已跳过搜索关键词:" & Keyword)
|
|
||||||
Continue For
|
Continue For
|
||||||
End If
|
End If
|
||||||
RightKeywords.Add(Keyword)
|
RightKeywords.Add(Keyword)
|
||||||
@@ -927,7 +913,7 @@ NoSubtitle:
|
|||||||
'例外项:OptiForge、OptiFabric(拆词后因为包含 Forge/Fabric 导致无法搜到实际的 Mod)
|
'例外项:OptiForge、OptiFabric(拆词后因为包含 Forge/Fabric 导致无法搜到实际的 Mod)
|
||||||
If RawFilter.Replace(" ", "").ToLower.Contains("optiforge") Then Task.Input.SearchText = "optiforge"
|
If RawFilter.Replace(" ", "").ToLower.Contains("optiforge") Then Task.Input.SearchText = "optiforge"
|
||||||
If RawFilter.Replace(" ", "").ToLower.Contains("optifabric") Then Task.Input.SearchText = "optifabric"
|
If RawFilter.Replace(" ", "").ToLower.Contains("optifabric") Then Task.Input.SearchText = "optifabric"
|
||||||
Log("[Comp] 工程列表搜索最终文本:" & Task.Input.SearchText, LogLevel.Developer)
|
Log("[Comp] 工程列表搜索最终文本:" & Task.Input.SearchText, LogLevel.Debug)
|
||||||
Task.Progress = 0.1
|
Task.Progress = 0.1
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
|
|||||||
@@ -583,7 +583,8 @@ Done:
|
|||||||
If LogMc IsNot Nothing Then
|
If LogMc IsNot Nothing Then
|
||||||
'常规信息
|
'常规信息
|
||||||
If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf))
|
If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf))
|
||||||
If LogMc.Contains("A potential solution has been determined:") OrElse LogMc.Contains("确定了一种可能的解决方法,这样做可能会解决你的问题:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)((\t)+ - [^\n]+\n)+"), If(RegexSeek(LogMc, "(?<=确定了一种可能的解决方法,这样做可能会解决你的问题:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf))
|
If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf))
|
||||||
|
If LogMc.Contains("确定了一种可能的解决方法,这样做可能会解决你的问题:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=确定了一种可能的解决方法,这样做可能会解决你的问题:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf))
|
||||||
End If
|
End If
|
||||||
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -221,9 +221,7 @@
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public DlClientListBmclapiLoader As New LoaderTask(Of Integer, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain)
|
Public DlClientListBmclapiLoader As New LoaderTask(Of Integer, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain)
|
||||||
Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of Integer, DlClientListResult))
|
Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of Integer, DlClientListResult))
|
||||||
Dim Json As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json",
|
Dim Json As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json", IsJson:=True)
|
||||||
BackupUrl:="https://download.mcbbs.net/mc/game/version_manifest.json",
|
|
||||||
IsJson:=True)
|
|
||||||
Try
|
Try
|
||||||
Dim Versions As JArray = Json("versions")
|
Dim Versions As JArray = Json("versions")
|
||||||
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
|
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
|
||||||
@@ -384,8 +382,7 @@
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public DlOptiFineListBmclapiLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Bmclapi", AddressOf DlOptiFineListBmclapiMain)
|
Public DlOptiFineListBmclapiLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Bmclapi", AddressOf DlOptiFineListBmclapiMain)
|
||||||
Private Sub DlOptiFineListBmclapiMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
|
Private Sub DlOptiFineListBmclapiMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
|
||||||
Dim Json As JArray = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/optifine/versionList",
|
Dim Json As JArray = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/optifine/versionList", IsJson:=True)
|
||||||
BackupUrl:="https://download.mcbbs.net/optifine/versionList", IsJson:=True)
|
|
||||||
Try
|
Try
|
||||||
Dim Versions As New List(Of DlOptiFineListEntry)
|
Dim Versions As New List(Of DlOptiFineListEntry)
|
||||||
For Each Token As JObject In Json
|
For Each Token As JObject In Json
|
||||||
@@ -469,8 +466,7 @@
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public DlForgeListBmclapiLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Bmclapi", AddressOf DlForgeListBmclapiMain)
|
Public DlForgeListBmclapiLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Bmclapi", AddressOf DlForgeListBmclapiMain)
|
||||||
Private Sub DlForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
|
Private Sub DlForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
|
||||||
Dim Result As String = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/forge/minecraft", Encoding.Default,
|
Dim Result As String = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/forge/minecraft", Encoding.Default)
|
||||||
BackupUrl:="https://download.mcbbs.net/forge/minecraft")
|
|
||||||
If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
|
If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
|
||||||
'获取所有版本信息
|
'获取所有版本信息
|
||||||
Dim Names As List(Of String) = RegexSearch(Result, "[0-9.]+(_pre[0-9]?)?")
|
Dim Names As List(Of String) = RegexSearch(Result, "[0-9.]+(_pre[0-9]?)?")
|
||||||
@@ -664,8 +660,7 @@
|
|||||||
''' Forge 版本列表,BMCLAPI。
|
''' Forge 版本列表,BMCLAPI。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Sub DlForgeVersionBmclapiMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
|
Public Sub DlForgeVersionBmclapiMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
|
||||||
Dim Json As JArray = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/forge/minecraft/" & Loader.Input,
|
Dim Json As JArray = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/forge/minecraft/" & Loader.Input, IsJson:=True)
|
||||||
BackupUrl:="https://download.mcbbs.net/forge/minecraft/" & Loader.Input, IsJson:=True)
|
|
||||||
Dim Versions As New List(Of DlForgeVersionEntry)
|
Dim Versions As New List(Of DlForgeVersionEntry)
|
||||||
Try
|
Try
|
||||||
Dim Recommended As String = McDownloadForgeRecommendedGet(Loader.Input)
|
Dim Recommended As String = McDownloadForgeRecommendedGet(Loader.Input)
|
||||||
@@ -827,8 +822,7 @@
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public DlLiteLoaderListBmclapiLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Bmclapi", AddressOf DlLiteLoaderListBmclapiMain)
|
Public DlLiteLoaderListBmclapiLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Bmclapi", AddressOf DlLiteLoaderListBmclapiMain)
|
||||||
Private Sub DlLiteLoaderListBmclapiMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
|
Private Sub DlLiteLoaderListBmclapiMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
|
||||||
Dim Result As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json",
|
Dim Result As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json", IsJson:=True)
|
||||||
BackupUrl:="https://download.mcbbs.net/maven/com/mumfrey/liteloader/versions.json", IsJson:=True)
|
|
||||||
Try
|
Try
|
||||||
Dim Json As JObject = Result("versions")
|
Dim Json As JObject = Result("versions")
|
||||||
Dim Versions As New List(Of DlLiteLoaderListEntry)
|
Dim Versions As New List(Of DlLiteLoaderListEntry)
|
||||||
@@ -914,8 +908,7 @@
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public DlFabricListBmclapiLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Bmclapi", AddressOf DlFabricListBmclapiMain)
|
Public DlFabricListBmclapiLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Bmclapi", AddressOf DlFabricListBmclapiMain)
|
||||||
Private Sub DlFabricListBmclapiMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
|
Private Sub DlFabricListBmclapiMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
|
||||||
Dim Result As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/fabric-meta/v2/versions",
|
Dim Result As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/fabric-meta/v2/versions", IsJson:=True)
|
||||||
BackupUrl:="https://download.mcbbs.net/fabric-meta/v2/versions", IsJson:=True)
|
|
||||||
Try
|
Try
|
||||||
Dim Output = New DlFabricListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Result}
|
Dim Output = New DlFabricListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Result}
|
||||||
If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
|
If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
|
||||||
@@ -943,26 +936,25 @@
|
|||||||
|
|
||||||
Public Function DlSourceResourceGet(MojangBase As String) As String()
|
Public Function DlSourceResourceGet(MojangBase As String) As String()
|
||||||
MojangBase = MojangBase.Replace("http://resources.download.minecraft.net", "https://resources.download.minecraft.net")
|
MojangBase = MojangBase.Replace("http://resources.download.minecraft.net", "https://resources.download.minecraft.net")
|
||||||
Return {MojangBase.Replace("https://piston-data.mojang.com", "https://download.mcbbs.net/assets").Replace("https://piston-meta.mojang.com", "https://download.mcbbs.net/assets").Replace("https://resources.download.minecraft.net", "https://download.mcbbs.net/assets"),
|
Return {
|
||||||
MojangBase,
|
MojangBase.Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/assets").Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/assets").Replace("https://resources.download.minecraft.net", "https://bmclapi2.bangbang93.com/assets"),
|
||||||
MojangBase.Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/assets").Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/assets").Replace("https://resources.download.minecraft.net", "https://bmclapi2.bangbang93.com/assets")
|
MojangBase
|
||||||
}
|
}
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
Public Function DlSourceLibraryGet(MojangBase As String) As String()
|
Public Function DlSourceLibraryGet(MojangBase As String) As String()
|
||||||
Return {MojangBase.Replace("https://piston-data.mojang.com", "https://download.mcbbs.net/maven").Replace("https://piston-meta.mojang.com", "https://download.mcbbs.net/maven").Replace("https://libraries.minecraft.net", "https://download.mcbbs.net/maven"),
|
Return {
|
||||||
MojangBase.Replace("https://piston-data.mojang.com", "https://download.mcbbs.net/libraries").Replace("https://piston-meta.mojang.com", "https://download.mcbbs.net/libraries").Replace("https://libraries.minecraft.net", "https://download.mcbbs.net/libraries"),
|
|
||||||
MojangBase,
|
|
||||||
MojangBase.Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/maven").Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/maven").Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/maven"),
|
MojangBase.Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/maven").Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/maven").Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/maven"),
|
||||||
MojangBase.Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/libraries").Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/libraries").Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
|
MojangBase.Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/libraries").Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/libraries").Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries"),
|
||||||
|
MojangBase
|
||||||
}
|
}
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
Public Function DlSourceLauncherOrMetaGet(MojangBase As String) As String()
|
Public Function DlSourceLauncherOrMetaGet(MojangBase As String) As String()
|
||||||
If MojangBase Is Nothing Then Throw New Exception("无对应的 json 下载地址")
|
If MojangBase Is Nothing Then Throw New Exception("无对应的 json 下载地址")
|
||||||
Return {MojangBase.Replace("https://piston-data.mojang.com", "https://download.mcbbs.net").Replace("https://piston-meta.mojang.com", "https://download.mcbbs.net").Replace("https://launcher.mojang.com", "https://download.mcbbs.net").Replace("https://launchermeta.mojang.com", "https://download.mcbbs.net"),
|
Return {
|
||||||
MojangBase,
|
MojangBase.Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com").Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com").Replace("https://launcher.mojang.com", "https://bmclapi2.bangbang93.com").Replace("https://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com"),
|
||||||
MojangBase.Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com").Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com").Replace("https://launcher.mojang.com", "https://bmclapi2.bangbang93.com").Replace("https://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com")
|
MojangBase
|
||||||
}
|
}
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
|
|||||||
@@ -727,8 +727,7 @@ Wait:
|
|||||||
Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile)))
|
Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile)))
|
||||||
Log("[Java] 开始获取 Java 下载信息")
|
Log("[Java] 开始获取 Java 下载信息")
|
||||||
Dim IndexFileStr As String = NetGetCodeByDownload(
|
Dim IndexFileStr As String = NetGetCodeByDownload(
|
||||||
{"https://download.mcbbs.net/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json",
|
{"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json",
|
||||||
"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json",
|
|
||||||
"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
|
"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
|
||||||
IsJson:=True)
|
IsJson:=True)
|
||||||
'获取下载地址
|
'获取下载地址
|
||||||
@@ -740,8 +739,7 @@ Wait:
|
|||||||
Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}")
|
Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}")
|
||||||
'获取文件列表
|
'获取文件列表
|
||||||
Dim ListFileStr As String = NetGetCodeByDownload(
|
Dim ListFileStr As String = NetGetCodeByDownload(
|
||||||
{Address.Replace("piston-meta.mojang.com", "download.mcbbs.net"),
|
{Address.Replace("piston-meta.mojang.com", "bmclapi2.bangbang93.com"),
|
||||||
Address.Replace("piston-meta.mojang.com", "bmclapi2.bangbang93.com"),
|
|
||||||
Address},
|
Address},
|
||||||
IsJson:=True)
|
IsJson:=True)
|
||||||
Dim BaseDir As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\runtime\" & TargetEntry.Key & "\"
|
Dim BaseDir As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\runtime\" & TargetEntry.Key & "\"
|
||||||
@@ -753,8 +751,7 @@ Wait:
|
|||||||
If Checker.Check(BaseDir & File.Name) Is Nothing Then Continue For '跳过已存在的文件
|
If Checker.Check(BaseDir & File.Name) Is Nothing Then Continue For '跳过已存在的文件
|
||||||
Dim Url As String = Info("url")
|
Dim Url As String = Info("url")
|
||||||
Results.Add(New NetFile(
|
Results.Add(New NetFile(
|
||||||
{Url.Replace("piston-data.mojang.com", "download.mcbbs.net"),
|
{Url.Replace("piston-data.mojang.com", "bmclapi2.bangbang93.com"),
|
||||||
Url.Replace("piston-data.mojang.com", "bmclapi2.bangbang93.com"),
|
|
||||||
Url},
|
Url},
|
||||||
BaseDir & File.Name, Checker))
|
BaseDir & File.Name, Checker))
|
||||||
Next
|
Next
|
||||||
|
|||||||
@@ -1911,9 +1911,9 @@ IgnoreCustomSkin:
|
|||||||
|
|
||||||
'获取自定义命令
|
'获取自定义命令
|
||||||
Dim CustomCommandGlobal As String = Setup.Get("LaunchAdvanceRun")
|
Dim CustomCommandGlobal As String = Setup.Get("LaunchAdvanceRun")
|
||||||
If CustomCommandGlobal <> "" Then CustomCommandGlobal = ArgumentReplace(CustomCommandGlobal)
|
If CustomCommandGlobal <> "" Then CustomCommandGlobal = ArgumentReplace(CustomCommandGlobal, True)
|
||||||
Dim CustomCommandVersion As String = Setup.Get("VersionAdvanceRun", Version:=McVersionCurrent)
|
Dim CustomCommandVersion As String = Setup.Get("VersionAdvanceRun", Version:=McVersionCurrent)
|
||||||
If CustomCommandVersion <> "" Then CustomCommandVersion = ArgumentReplace(CustomCommandVersion)
|
If CustomCommandVersion <> "" Then CustomCommandVersion = ArgumentReplace(CustomCommandVersion, True)
|
||||||
|
|
||||||
'输出 bat
|
'输出 bat
|
||||||
Try
|
Try
|
||||||
@@ -2072,7 +2072,7 @@ IgnoreCustomSkin:
|
|||||||
'获取窗口标题
|
'获取窗口标题
|
||||||
Dim WindowTitle As String = Setup.Get("VersionArgumentTitle", Version:=McVersionCurrent)
|
Dim WindowTitle As String = Setup.Get("VersionArgumentTitle", Version:=McVersionCurrent)
|
||||||
If WindowTitle = "" Then WindowTitle = Setup.Get("LaunchArgumentTitle")
|
If WindowTitle = "" Then WindowTitle = Setup.Get("LaunchArgumentTitle")
|
||||||
WindowTitle = ArgumentReplace(WindowTitle)
|
WindowTitle = ArgumentReplace(WindowTitle, False)
|
||||||
|
|
||||||
'初始化等待
|
'初始化等待
|
||||||
Dim Watcher As New Watcher(Loader, McVersionCurrent, WindowTitle)
|
Dim Watcher As New Watcher(Loader, McVersionCurrent, WindowTitle)
|
||||||
@@ -2124,7 +2124,7 @@ IgnoreCustomSkin:
|
|||||||
''' <summary>
|
''' <summary>
|
||||||
''' 在启动结束时,对 PCL 约定的替换标记进行处理。
|
''' 在启动结束时,对 PCL 约定的替换标记进行处理。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Function ArgumentReplace(Raw As String) As String
|
Private Function ArgumentReplace(Raw As String, ReplaceTimeAndDate As Boolean) As String
|
||||||
If Raw Is Nothing Then Return Nothing
|
If Raw Is Nothing Then Return Nothing
|
||||||
'路径替换
|
'路径替换
|
||||||
Raw = Raw.Replace("{minecraft}", PathMcFolder)
|
Raw = Raw.Replace("{minecraft}", PathMcFolder)
|
||||||
@@ -2134,6 +2134,10 @@ IgnoreCustomSkin:
|
|||||||
'普通替换
|
'普通替换
|
||||||
Raw = Raw.Replace("{user}", McLoginLoader.Output.Name)
|
Raw = Raw.Replace("{user}", McLoginLoader.Output.Name)
|
||||||
Raw = Raw.Replace("{uuid}", McLoginLoader.Output.Uuid)
|
Raw = Raw.Replace("{uuid}", McLoginLoader.Output.Uuid)
|
||||||
|
If ReplaceTimeAndDate Then '设置窗口标题时需要动态替换日期和时间
|
||||||
|
Raw = Raw.Replace("{date}", Date.Now.ToString("yyyy/M/d"))
|
||||||
|
Raw = Raw.Replace("{time}", Date.Now.ToString("HH:mm:ss"))
|
||||||
|
End If
|
||||||
Select Case McLoginLoader.Input.Type
|
Select Case McLoginLoader.Input.Type
|
||||||
Case McLoginType.Legacy
|
Case McLoginType.Legacy
|
||||||
If PageLinkHiper.HiperState = LoadState.Finished Then
|
If PageLinkHiper.HiperState = LoadState.Finished Then
|
||||||
|
|||||||
@@ -42,15 +42,19 @@
|
|||||||
#Region "读取默认(Original)文件夹,即当前、官启文件夹,可能没有结果"
|
#Region "读取默认(Original)文件夹,即当前、官启文件夹,可能没有结果"
|
||||||
|
|
||||||
'扫描当前文件夹
|
'扫描当前文件夹
|
||||||
If CheckPermission(Path) AndAlso Directory.Exists(Path & "versions\") Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Path = Path, .Type = McFolderType.Original})
|
Try
|
||||||
|
If Directory.Exists(Path & "versions\") Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Path = Path, .Type = McFolderType.Original})
|
||||||
For Each Folder As DirectoryInfo In New DirectoryInfo(Path).GetDirectories
|
For Each Folder As DirectoryInfo In New DirectoryInfo(Path).GetDirectories
|
||||||
If CheckPermission(Folder.FullName) AndAlso Directory.Exists(Folder.FullName & "versions\") OrElse Folder.Name = ".minecraft" Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Path = Folder.FullName & "\", .Type = McFolderType.Original})
|
If Directory.Exists(Folder.FullName & "versions\") OrElse Folder.Name = ".minecraft" Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Path = Folder.FullName & "\", .Type = McFolderType.Original})
|
||||||
Next
|
Next
|
||||||
|
Catch ex As Exception
|
||||||
|
Log(ex, "扫描 PCL 所在文件夹中是否有 MC 文件夹失败")
|
||||||
|
End Try
|
||||||
|
|
||||||
'扫描官启文件夹
|
'扫描官启文件夹
|
||||||
Dim MojangPath As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\"
|
Dim MojangPath As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\"
|
||||||
If (CacheMcFolderList.Count = 0 OrElse MojangPath <> CacheMcFolderList(0).Path) AndAlso '当前文件夹不是官启文件夹
|
If (Not CacheMcFolderList.Any OrElse MojangPath <> CacheMcFolderList(0).Path) AndAlso '当前文件夹不是官启文件夹
|
||||||
CheckPermission(MojangPath) AndAlso Directory.Exists(MojangPath & "versions\") Then '具有权限且存在 versions 文件夹
|
Directory.Exists(MojangPath & "versions\") Then '具有权限且存在 versions 文件夹
|
||||||
CacheMcFolderList.Add(New McFolder With {.Name = "官方启动器文件夹", .Path = MojangPath, .Type = McFolderType.Original})
|
CacheMcFolderList.Add(New McFolder With {.Name = "官方启动器文件夹", .Path = MojangPath, .Type = McFolderType.Original})
|
||||||
End If
|
End If
|
||||||
|
|
||||||
@@ -406,7 +410,7 @@
|
|||||||
End If
|
End If
|
||||||
'无法获取
|
'无法获取
|
||||||
_Version.McName = "Unknown"
|
_Version.McName = "Unknown"
|
||||||
Info = "PCL 无法识别该版本,请向作者反馈此问题"
|
Info = "PCL 无法识别该版本的 MC 版本号"
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Log(ex, "识别 Minecraft 版本时出错")
|
Log(ex, "识别 Minecraft 版本时出错")
|
||||||
_Version.McName = "Unknown"
|
_Version.McName = "Unknown"
|
||||||
@@ -1915,7 +1919,7 @@ NextVersion:
|
|||||||
'获取下载信息
|
'获取下载信息
|
||||||
Try
|
Try
|
||||||
Log("[Minecraft] 开始获取 Authlib-Injector 下载信息")
|
Log("[Minecraft] 开始获取 Authlib-Injector 下载信息")
|
||||||
DownloadInfo = GetJson(NetGetCodeByDownload({"https://download.mcbbs.net/mirrors/authlib-injector/artifact/latest.json", "https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json"}, IsJson:=True))
|
DownloadInfo = GetJson(NetGetCodeByDownload({"https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json"}, IsJson:=True))
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Log(ex, "获取 Authlib-Injector 下载信息失败")
|
Log(ex, "获取 Authlib-Injector 下载信息失败")
|
||||||
End Try
|
End Try
|
||||||
@@ -1926,9 +1930,7 @@ NextVersion:
|
|||||||
'开始下载
|
'开始下载
|
||||||
Dim DownloadAddress As String = DownloadInfo("download_url")
|
Dim DownloadAddress As String = DownloadInfo("download_url")
|
||||||
Log("[Minecraft] Authlib-Injector 需要更新:" & DownloadAddress, LogLevel.Developer)
|
Log("[Minecraft] Authlib-Injector 需要更新:" & DownloadAddress, LogLevel.Developer)
|
||||||
Result.Add(New NetFile({
|
Result.Add(New NetFile({DownloadAddress}, TargetFile, New FileChecker(Hash:=DownloadInfo("checksums")("sha256").ToString)))
|
||||||
DownloadAddress.Replace("bmclapi2.bangbang93.com", "download.mcbbs.net"), DownloadAddress
|
|
||||||
}, TargetFile, New FileChecker(Hash:=DownloadInfo("checksums")("sha256").ToString)))
|
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
@@ -1958,7 +1960,7 @@ NextVersion:
|
|||||||
'获取 Url 的真实地址
|
'获取 Url 的真实地址
|
||||||
Urls.Add(Token.Url)
|
Urls.Add(Token.Url)
|
||||||
If Token.Url.Contains("launcher.mojang.com/v1/objects") Then Urls = DlSourceLauncherOrMetaGet(Token.Url).ToList() 'Mappings
|
If Token.Url.Contains("launcher.mojang.com/v1/objects") Then Urls = DlSourceLauncherOrMetaGet(Token.Url).ToList() 'Mappings
|
||||||
If Token.Url.Contains("maven") Then Urls.Insert(0, Token.Url.Replace(Mid(Token.Url, 1, Token.Url.IndexOf("maven")), "https://download.mcbbs.net/").Replace("maven.fabricmc.net", "maven").Replace("maven.minecraftforge.net", "maven"))
|
If Token.Url.Contains("maven") Then Urls.Insert(0, Token.Url.Replace(Mid(Token.Url, 1, Token.Url.IndexOf("maven")), "https://bmclapi2.bangbang93.com/").Replace("maven.fabricmc.net", "maven").Replace("maven.minecraftforge.net", "maven"))
|
||||||
End If
|
End If
|
||||||
If Token.LocalPath.Contains("transformer-discovery-service") Then
|
If Token.LocalPath.Contains("transformer-discovery-service") Then
|
||||||
'Transformer 文件释放
|
'Transformer 文件释放
|
||||||
@@ -1970,7 +1972,6 @@ NextVersion:
|
|||||||
Dim OptiFineBase As String = Token.LocalPath.Replace(If(Token.IsJumpLoader, JumpLoaderFolder, CustomMcFolder) & "libraries\optifine\OptiFine\", "").Split("_")(0) & "/" & GetFileNameFromPath(Token.LocalPath).Replace("-", "_")
|
Dim OptiFineBase As String = Token.LocalPath.Replace(If(Token.IsJumpLoader, JumpLoaderFolder, CustomMcFolder) & "libraries\optifine\OptiFine\", "").Split("_")(0) & "/" & GetFileNameFromPath(Token.LocalPath).Replace("-", "_")
|
||||||
OptiFineBase = "/maven/com/optifine/" & OptiFineBase
|
OptiFineBase = "/maven/com/optifine/" & OptiFineBase
|
||||||
If OptiFineBase.Contains("_pre") Then OptiFineBase = OptiFineBase.Replace("com/optifine/", "com/optifine/preview_")
|
If OptiFineBase.Contains("_pre") Then OptiFineBase = OptiFineBase.Replace("com/optifine/", "com/optifine/preview_")
|
||||||
Urls.Add("https://download.mcbbs.net" & OptiFineBase)
|
|
||||||
Urls.Add("https://bmclapi2.bangbang93.com" & OptiFineBase)
|
Urls.Add("https://bmclapi2.bangbang93.com" & OptiFineBase)
|
||||||
ElseIf Urls.Count <= 2 Then
|
ElseIf Urls.Count <= 2 Then
|
||||||
'普通文件
|
'普通文件
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ Public Module ModMod
|
|||||||
Public Sub New(Path As String)
|
Public Sub New(Path As String)
|
||||||
Me.Path = If(Path, "")
|
Me.Path = If(Path, "")
|
||||||
End Sub
|
End Sub
|
||||||
|
''' <summary>
|
||||||
|
''' Mod 的完整路径,去除最后的 .disabled 和 .old。
|
||||||
|
''' </summary>
|
||||||
|
Public ReadOnly Property RawPath As String
|
||||||
|
Get
|
||||||
|
Return GetPathFromFullPath(Path) & RawFileName
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' Mod 的完整文件名。
|
''' Mod 的完整文件名。
|
||||||
@@ -768,6 +776,18 @@ VersionFindFail:
|
|||||||
End Property
|
End Property
|
||||||
Private _ModrinthHash As String
|
Private _ModrinthHash As String
|
||||||
|
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
#Region "API"
|
||||||
|
|
||||||
|
Public Overrides Function ToString() As String
|
||||||
|
Return $"{State} - {Path}"
|
||||||
|
End Function
|
||||||
|
Public Overrides Function Equals(obj As Object) As Boolean
|
||||||
|
Dim target = TryCast(obj, McMod)
|
||||||
|
Return target IsNot Nothing AndAlso Path = target.Path
|
||||||
|
End Function
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
@@ -844,6 +864,17 @@ VersionFindFail:
|
|||||||
'加载 McMod 对象
|
'加载 McMod 对象
|
||||||
Dim ModEntry As New McMod(ModFile.FullName)
|
Dim ModEntry As New McMod(ModFile.FullName)
|
||||||
ModEntry.Load()
|
ModEntry.Load()
|
||||||
|
Dim DumpMod As McMod = ModList.FirstOrDefault(Function(m) m.RawFileName = ModEntry.RawFileName)
|
||||||
|
If DumpMod IsNot Nothing Then
|
||||||
|
Dim DisabledMod As McMod = If(DumpMod.State = McMod.McModState.Disabled, DumpMod, ModEntry)
|
||||||
|
Log($"[Mod] 重复的 Mod 文件:{DumpMod.FileName} 与 {ModEntry.FileName},已忽略 {DisabledMod.FileName}", LogLevel.Debug)
|
||||||
|
If DisabledMod Is ModEntry Then
|
||||||
|
Continue For
|
||||||
|
Else
|
||||||
|
ModList.Remove(DisabledMod)
|
||||||
|
ModUpdateList.Remove(DisabledMod)
|
||||||
|
End If
|
||||||
|
End If
|
||||||
ModList.Add(ModEntry)
|
ModList.Add(ModEntry)
|
||||||
'读取 Comp 缓存
|
'读取 Comp 缓存
|
||||||
If ModEntry.State = McMod.McModState.Unavaliable Then Continue For
|
If ModEntry.State = McMod.McModState.Unavaliable Then Continue For
|
||||||
@@ -860,7 +891,8 @@ VersionFindFail:
|
|||||||
Log($"[Mod] 共有 {ModList.Count} 个 Mod,其中 {ModUpdateList.Where(Function(m) m.Comp Is Nothing).Count} 个需要联网获取信息,{ModUpdateList.Where(Function(m) m.Comp IsNot Nothing).Count} 个需要更新信息")
|
Log($"[Mod] 共有 {ModList.Count} 个 Mod,其中 {ModUpdateList.Where(Function(m) m.Comp Is Nothing).Count} 个需要联网获取信息,{ModUpdateList.Where(Function(m) m.Comp IsNot Nothing).Count} 个需要更新信息")
|
||||||
|
|
||||||
'排序
|
'排序
|
||||||
ModList = Sort(ModList, Function(Left As McMod, Right As McMod) As Boolean
|
ModList = Sort(ModList,
|
||||||
|
Function(Left As McMod, Right As McMod) As Boolean
|
||||||
If (Left.State = McMod.McModState.Unavaliable) <> (Right.State = McMod.McModState.Unavaliable) Then
|
If (Left.State = McMod.McModState.Unavaliable) <> (Right.State = McMod.McModState.Unavaliable) Then
|
||||||
Return Left.State = McMod.McModState.Unavaliable
|
Return Left.State = McMod.McModState.Unavaliable
|
||||||
Else
|
Else
|
||||||
|
|||||||
@@ -96,7 +96,7 @@
|
|||||||
'设置窗口标题
|
'设置窗口标题
|
||||||
For i = 1 To 3
|
For i = 1 To 3
|
||||||
If IsWindowFinished AndAlso IsWindowAppeared AndAlso WindowTitle <> "" AndAlso State = MinecraftState.Running AndAlso Not GameProcess.HasExited Then
|
If IsWindowFinished AndAlso IsWindowAppeared AndAlso WindowTitle <> "" AndAlso State = MinecraftState.Running AndAlso Not GameProcess.HasExited Then
|
||||||
Dim RealTitle As String = WindowTitle.Replace("{time}", Date.Now.ToShortTimeString)
|
Dim RealTitle As String = WindowTitle.Replace("{date}", Date.Now.ToString("yyyy/M/d")).Replace("{time}", Date.Now.ToString("HH:mm:ss"))
|
||||||
SetWindowText(WindowHandle, RealTitle.ToCharArray)
|
SetWindowText(WindowHandle, RealTitle.ToCharArray)
|
||||||
End If
|
End If
|
||||||
Thread.Sleep(64)
|
Thread.Sleep(64)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
For Each File In EnumerateFiles(Path & "PCL\Musics\")
|
For Each File In EnumerateFiles(Path & "PCL\Musics\")
|
||||||
'文件夹可能会被加入 .ini 文件夹配置文件、一些乱七八糟的 .jpg 文件啥的
|
'文件夹可能会被加入 .ini 文件夹配置文件、一些乱七八糟的 .jpg 文件啥的
|
||||||
Dim Ext As String = File.Extension.ToLower
|
Dim Ext As String = File.Extension.ToLower
|
||||||
If {"ini", "jpg", "txt", "cfg", "lrc", "db", "png"}.Contains(Ext) Then Continue For
|
If {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(Ext) Then Continue For
|
||||||
MusicAllList.Add(File.FullName)
|
MusicAllList.Add(File.FullName)
|
||||||
Next
|
Next
|
||||||
End If
|
End If
|
||||||
|
|||||||
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
|
|||||||
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
||||||
' 方法是按如下所示使用“*”
|
' 方法是按如下所示使用“*”
|
||||||
|
|
||||||
<Assembly: AssemblyVersion("2.6.13.0")>
|
<Assembly: AssemblyVersion("2.6.14.0")>
|
||||||
<Assembly: AssemblyFileVersion("2.6.13.0")>
|
<Assembly: AssemblyFileVersion("2.6.14.0")>
|
||||||
<Assembly: NeutralResourcesLanguage("")>
|
<Assembly: NeutralResourcesLanguage("")>
|
||||||
|
|||||||
@@ -519,10 +519,8 @@ Public Module ModDownloadLib
|
|||||||
Dim Sources As New List(Of String)
|
Dim Sources As New List(Of String)
|
||||||
'BMCLAPI 源
|
'BMCLAPI 源
|
||||||
If DownloadInfo.IsPreview Then
|
If DownloadInfo.IsPreview Then
|
||||||
Sources.Add("https://download.mcbbs.net/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
|
|
||||||
Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
|
Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
|
||||||
Else
|
Else
|
||||||
Sources.Add("https://download.mcbbs.net/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
|
|
||||||
Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
|
Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
|
||||||
End If
|
End If
|
||||||
'官方源
|
'官方源
|
||||||
@@ -686,10 +684,8 @@ Retry:
|
|||||||
Dim Sources As New List(Of String)
|
Dim Sources As New List(Of String)
|
||||||
'BMCLAPI 源
|
'BMCLAPI 源
|
||||||
If DownloadInfo.IsPreview Then
|
If DownloadInfo.IsPreview Then
|
||||||
Sources.Add("https://download.mcbbs.net/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
|
|
||||||
Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
|
Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
|
||||||
Else
|
Else
|
||||||
Sources.Add("https://download.mcbbs.net/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
|
|
||||||
Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
|
Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
|
||||||
End If
|
End If
|
||||||
'官方源
|
'官方源
|
||||||
@@ -852,22 +848,11 @@ Retry:
|
|||||||
Case "1.6.2"
|
Case "1.6.2"
|
||||||
Address.Add("https://dl.liteloader.com/redist/1.6.2/liteloader-installer-1.6.2-04.jar")
|
Address.Add("https://dl.liteloader.com/redist/1.6.2/liteloader-installer-1.6.2-04.jar")
|
||||||
Case "1.5.2"
|
Case "1.5.2"
|
||||||
'Address.AddRange({"https://download.mcbbs.net/maven/com/mumfrey/liteloader/1.5.2/liteloader-1.5.2.jar",
|
|
||||||
' "https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/1.5.2/liteloader-1.5.2.jar"})
|
|
||||||
Address.Add("https://dl.liteloader.com/redist/1.5.2/liteloader-installer-1.5.2-01.jar")
|
Address.Add("https://dl.liteloader.com/redist/1.5.2/liteloader-installer-1.5.2-01.jar")
|
||||||
Case Else
|
Case Else
|
||||||
Throw New NotSupportedException("未知的 Minecraft 版本(" & DownloadInfo.Inherit & ")")
|
Throw New NotSupportedException("未知的 Minecraft 版本(" & DownloadInfo.Inherit & ")")
|
||||||
End Select
|
End Select
|
||||||
Else
|
Else
|
||||||
'BMCLAPI 源下载的是安装后的 Jar,而不是 Installer,故无法使用
|
|
||||||
''BMCLAPI 源
|
|
||||||
'If DownloadInfo.IsPreview Then
|
|
||||||
' Address.AddRange({"https://download.mcbbs.net/maven/com/mumfrey/liteloader/" & DownloadInfo.Inherit & "-SNAPSHOT/liteloader-" & DownloadInfo.Inherit & "-SNAPSHOT.jar",
|
|
||||||
' "https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/" & DownloadInfo.Inherit & "-SNAPSHOT/liteloader-" & DownloadInfo.Inherit & "-SNAPSHOT.jar"})
|
|
||||||
'Else
|
|
||||||
' Address.AddRange({"https://download.mcbbs.net/maven/com/mumfrey/liteloader/" & DownloadInfo.Inherit & "/liteloader-" & DownloadInfo.Inherit & ".jar",
|
|
||||||
' "https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/" & DownloadInfo.Inherit & "/liteloader-" & DownloadInfo.Inherit & ".jar"})
|
|
||||||
'End If
|
|
||||||
'官方源
|
'官方源
|
||||||
Address.Add("http://jenkins.liteloader.com/job/LiteLoaderInstaller%20" & DownloadInfo.Inherit & "/lastSuccessfulBuild/artifact/" & If(DownloadInfo.Inherit = "1.8", "ant/dist/", "build/libs/") & DownloadInfo.FileName)
|
Address.Add("http://jenkins.liteloader.com/job/LiteLoaderInstaller%20" & DownloadInfo.Inherit & "/lastSuccessfulBuild/artifact/" & If(DownloadInfo.Inherit = "1.8", "ant/dist/", "build/libs/") & DownloadInfo.FileName)
|
||||||
End If
|
End If
|
||||||
@@ -1100,7 +1085,6 @@ Retry:
|
|||||||
Sub(Task As LoaderTask(Of DlForgeVersionEntry, List(Of NetFile)))
|
Sub(Task As LoaderTask(Of DlForgeVersionEntry, List(Of NetFile)))
|
||||||
Dim Files As New List(Of NetFile)
|
Dim Files As New List(Of NetFile)
|
||||||
Files.Add(New NetFile({
|
Files.Add(New NetFile({
|
||||||
"https://download.mcbbs.net/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
|
|
||||||
"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
|
"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
|
||||||
"https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
|
"https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
|
||||||
}, Target, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash)))
|
}, Target, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash)))
|
||||||
@@ -1123,7 +1107,7 @@ Retry:
|
|||||||
|
|
||||||
Private Sub ForgeInjector(Target As String, Task As LoaderTask(Of Boolean, Boolean), McFolder As String, UseJavaWrapper As Boolean)
|
Private Sub ForgeInjector(Target As String, Task As LoaderTask(Of Boolean, Boolean), McFolder As String, UseJavaWrapper As Boolean)
|
||||||
'选择 Java
|
'选择 Java
|
||||||
Dim Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 0))
|
Dim Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 60))
|
||||||
If Java Is Nothing Then
|
If Java Is Nothing Then
|
||||||
If Not JavaDownloadConfirm("Java 8 或更高版本") Then Throw New Exception("由于未找到 Java,已取消安装。")
|
If Not JavaDownloadConfirm("Java 8 或更高版本") Then Throw New Exception("由于未找到 Java,已取消安装。")
|
||||||
'开始自动下载
|
'开始自动下载
|
||||||
@@ -1133,7 +1117,7 @@ Retry:
|
|||||||
Thread.Sleep(10)
|
Thread.Sleep(10)
|
||||||
Loop
|
Loop
|
||||||
'检查下载结果
|
'检查下载结果
|
||||||
Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 0))
|
Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 60))
|
||||||
If Task.IsAborted Then Exit Sub
|
If Task.IsAborted Then Exit Sub
|
||||||
If Java Is Nothing Then Throw New Exception("由于未找到 Java,已取消安装。")
|
If Java Is Nothing Then Throw New Exception("由于未找到 Java,已取消安装。")
|
||||||
End If
|
End If
|
||||||
@@ -1160,7 +1144,8 @@ Retry:
|
|||||||
Dim LastResults As New Queue(Of String)
|
Dim LastResults As New Queue(Of String)
|
||||||
Using outputWaitHandle As New AutoResetEvent(False)
|
Using outputWaitHandle As New AutoResetEvent(False)
|
||||||
Using errorWaitHandle As New AutoResetEvent(False)
|
Using errorWaitHandle As New AutoResetEvent(False)
|
||||||
AddHandler process.OutputDataReceived, Function(sender, e)
|
AddHandler process.OutputDataReceived,
|
||||||
|
Function(sender, e)
|
||||||
Try
|
Try
|
||||||
If e.Data Is Nothing Then
|
If e.Data Is Nothing Then
|
||||||
outputWaitHandle.[Set]()
|
outputWaitHandle.[Set]()
|
||||||
@@ -1182,7 +1167,8 @@ Retry:
|
|||||||
End Try
|
End Try
|
||||||
Return Nothing
|
Return Nothing
|
||||||
End Function
|
End Function
|
||||||
AddHandler process.ErrorDataReceived, Function(sender, e)
|
AddHandler process.ErrorDataReceived,
|
||||||
|
Function(sender, e)
|
||||||
Try
|
Try
|
||||||
If e.Data Is Nothing Then
|
If e.Data Is Nothing Then
|
||||||
errorWaitHandle.[Set]()
|
errorWaitHandle.[Set]()
|
||||||
@@ -1321,8 +1307,7 @@ Retry:
|
|||||||
'添加主文件
|
'添加主文件
|
||||||
Dim Files As New List(Of NetFile) From {New NetFile({
|
Dim Files As New List(Of NetFile) From {New NetFile({
|
||||||
"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
|
"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
|
||||||
"https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
|
"https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
|
||||||
"https://download.mcbbs.net/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
|
|
||||||
}, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash))}
|
}, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash))}
|
||||||
Task.Output = Files
|
Task.Output = Files
|
||||||
End Sub) With {.ProgressWeight = 0.5, .Show = False})
|
End Sub) With {.ProgressWeight = 0.5, .Show = False})
|
||||||
@@ -1650,7 +1635,7 @@ Retry:
|
|||||||
RunInNewThread(Sub()
|
RunInNewThread(Sub()
|
||||||
Try
|
Try
|
||||||
Log("[Download] 刷新 Forge 推荐版本缓存开始")
|
Log("[Download] 刷新 Forge 推荐版本缓存开始")
|
||||||
Dim Result As String = NetGetCodeByDownload({"https://bmclapi2.bangbang93.com/forge/promos", "https://download.mcbbs.net/forge/promos"})
|
Dim Result As String = NetGetCodeByDownload("https://bmclapi2.bangbang93.com/forge/promos")
|
||||||
If Result.Length < 1000 Then Throw New Exception("获取的结果过短(" & Result & ")")
|
If Result.Length < 1000 Then Throw New Exception("获取的结果过短(" & Result & ")")
|
||||||
Dim ResultJson As JContainer = GetJson(Result)
|
Dim ResultJson As JContainer = GetJson(Result)
|
||||||
'获取所有推荐版本列表
|
'获取所有推荐版本列表
|
||||||
@@ -1721,7 +1706,6 @@ Retry:
|
|||||||
'下载
|
'下载
|
||||||
'BMCLAPI 不支持 Fabric Installer 下载
|
'BMCLAPI 不支持 Fabric Installer 下载
|
||||||
Dim Address As New List(Of String)
|
Dim Address As New List(Of String)
|
||||||
'Address.Add(Url.Replace("maven.fabricmc.net", "download.mcbbs.net/maven"))
|
|
||||||
Address.Add(Url)
|
Address.Add(Url)
|
||||||
Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile) From {New NetFile(Address.ToArray, Target, New FileChecker(MinSize:=1024 * 64))}) With {.ProgressWeight = 15})
|
Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile) From {New NetFile(Address.ToArray, Target, New FileChecker(MinSize:=1024 * 64))}) With {.ProgressWeight = 15})
|
||||||
'启动
|
'启动
|
||||||
@@ -1759,7 +1743,7 @@ Retry:
|
|||||||
Task.Progress = 0.5
|
Task.Progress = 0.5
|
||||||
'构造文件请求
|
'构造文件请求
|
||||||
Task.Output = New List(Of NetFile) From {New NetFile({
|
Task.Output = New List(Of NetFile) From {New NetFile({
|
||||||
"https://download.mcbbs.net/fabric-meta/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json",
|
"https://bmclapi2.bangbang93.com/fabric-meta/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json",
|
||||||
"https://meta.fabricmc.net/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json"
|
"https://meta.fabricmc.net/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json"
|
||||||
}, VersionFolder & Id & ".json", New FileChecker(IsJson:=True))}
|
}, VersionFolder & Id & ".json", New FileChecker(IsJson:=True))}
|
||||||
'新建 mods 文件夹
|
'新建 mods 文件夹
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
<StackPanel Orientation="Horizontal" Height="35">
|
<StackPanel Orientation="Horizontal" Height="35">
|
||||||
<local:MyButton x:Name="BtnIntroWeb" MinWidth="140" Text="转到 CurseForge" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
|
<local:MyButton x:Name="BtnIntroWeb" MinWidth="140" Text="转到 CurseForge" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
|
||||||
<local:MyButton x:Name="BtnIntroWiki" MinWidth="140" Text="转到 MC 百科" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
<local:MyButton x:Name="BtnIntroWiki" MinWidth="140" Text="转到 MC 百科" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
||||||
<local:MyButton x:Name="BtnIntroMCBBS" MinWidth="140" Text="转到 MCBBS" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
|
||||||
<local:MyButton x:Name="BtnIntroCopy" MinWidth="140" Text="复制名称" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
<local:MyButton x:Name="BtnIntroCopy" MinWidth="140" Text="复制名称" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -145,7 +145,6 @@
|
|||||||
'决定按钮显示
|
'决定按钮显示
|
||||||
BtnIntroWeb.Text = If(Project.FromCurseForge, "转到 CurseForge", "转到 Modrinth")
|
BtnIntroWeb.Text = If(Project.FromCurseForge, "转到 CurseForge", "转到 Modrinth")
|
||||||
BtnIntroWiki.Visibility = If(Project.WikiId = 0, Visibility.Collapsed, Visibility.Visible)
|
BtnIntroWiki.Visibility = If(Project.WikiId = 0, Visibility.Collapsed, Visibility.Visible)
|
||||||
BtnIntroMCBBS.Visibility = If(Project.MCBBS = 0, Visibility.Collapsed, Visibility.Visible)
|
|
||||||
|
|
||||||
AniControlEnabled -= 1
|
AniControlEnabled -= 1
|
||||||
End Sub
|
End Sub
|
||||||
@@ -323,9 +322,6 @@
|
|||||||
Private Sub BtnIntroWiki_Click(sender As Object, e As EventArgs) Handles BtnIntroWiki.Click
|
Private Sub BtnIntroWiki_Click(sender As Object, e As EventArgs) Handles BtnIntroWiki.Click
|
||||||
OpenWebsite("https://www.mcmod.cn/class/" & Project.WikiId & ".html")
|
OpenWebsite("https://www.mcmod.cn/class/" & Project.WikiId & ".html")
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub BtnIntroMCBBS_Click(sender As Object, e As EventArgs) Handles BtnIntroMCBBS.Click
|
|
||||||
OpenWebsite("https://www.mcbbs.net/thread-" & Project.MCBBS & "-1-1.html")
|
|
||||||
End Sub
|
|
||||||
Private Sub BtnIntroCopy_Click(sender As Object, e As EventArgs) Handles BtnIntroCopy.Click
|
Private Sub BtnIntroCopy_Click(sender As Object, e As EventArgs) Handles BtnIntroCopy.Click
|
||||||
ClipboardSet(CompItem.LabTitle.Text)
|
ClipboardSet(CompItem.LabTitle.Text)
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<Path Name="PathTypeOne" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="{DynamicResource ColorBrush3}" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center"
|
<Path Name="PathTypeOne" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="{DynamicResource ColorBrush3}" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center"
|
||||||
Data="">
|
Data="">
|
||||||
<Path.RenderTransform>
|
<Path.RenderTransform>
|
||||||
<ScaleTransform ScaleX="1.2" ScaleY="1.2" />
|
<ScaleTransform ScaleX="1.05" ScaleY="1.05" />
|
||||||
</Path.RenderTransform>
|
</Path.RenderTransform>
|
||||||
</Path>
|
</Path>
|
||||||
<TextBlock Name="LabTypeOne" Text="" FontSize="14" VerticalAlignment="Center" Grid.Column="1" Foreground="{DynamicResource ColorBrush3}" Margin="15,0,12,0" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
|
<TextBlock Name="LabTypeOne" Text="" FontSize="14" VerticalAlignment="Center" Grid.Column="1" Foreground="{DynamicResource ColorBrush3}" Margin="15,0,12,0" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ UnknownType:
|
|||||||
Setup.Set("LoginType", McLoginType.Ms)
|
Setup.Set("LoginType", McLoginType.Ms)
|
||||||
PanType.Visibility = Visibility.Collapsed
|
PanType.Visibility = Visibility.Collapsed
|
||||||
PanTypeOne.Visibility = Visibility.Visible
|
PanTypeOne.Visibility = Visibility.Visible
|
||||||
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonMs)
|
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonShield)
|
||||||
LabTypeOne.Text = "正版登录"
|
LabTypeOne.Text = "正版登录"
|
||||||
RadioLoginType5.Visibility = Visibility.Visible
|
RadioLoginType5.Visibility = Visibility.Visible
|
||||||
RadioLoginType0.Visibility = Visibility.Collapsed
|
RadioLoginType0.Visibility = Visibility.Collapsed
|
||||||
@@ -295,7 +295,7 @@ UnknownType:
|
|||||||
Setup.Set("LoginType", McLoginType.Legacy)
|
Setup.Set("LoginType", McLoginType.Legacy)
|
||||||
PanType.Visibility = Visibility.Collapsed
|
PanType.Visibility = Visibility.Collapsed
|
||||||
PanTypeOne.Visibility = Visibility.Visible
|
PanTypeOne.Visibility = Visibility.Visible
|
||||||
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonUser)
|
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonOffline)
|
||||||
LabTypeOne.Text = "离线登录"
|
LabTypeOne.Text = "离线登录"
|
||||||
Case 3 '统一通行证
|
Case 3 '统一通行证
|
||||||
If Setup.Get("CacheNideAccess") = "" Then
|
If Setup.Get("CacheNideAccess") = "" Then
|
||||||
|
|||||||
@@ -58,307 +58,21 @@
|
|||||||
|
|
||||||
'检查网络状态
|
'检查网络状态
|
||||||
Private Shared Sub InitPingCheck(Task As LoaderTask(Of Integer, Integer))
|
Private Shared Sub InitPingCheck(Task As LoaderTask(Of Integer, Integer))
|
||||||
PingTime = 0
|
|
||||||
Try
|
|
||||||
Log("[HiPer] 网络检测:连通检测开始")
|
|
||||||
Dim StartTime = Date.Now.Ticks
|
|
||||||
Dim Result As String = NetGetCodeByClient("https://www.baidu.com/duty/", Encoding.UTF8, 20000, "")
|
|
||||||
Dim DuringTime As Integer = (Date.Now.Ticks - StartTime) / 10000
|
|
||||||
If Result.Contains("百度") Then
|
|
||||||
Log("[HiPer] 网络检测:连通检测成功(" & DuringTime & "ms)")
|
|
||||||
PingTime = DuringTime
|
|
||||||
Else
|
|
||||||
Log("[HiPer] 网络检测:连通检测失败(获取的内容有误)")
|
|
||||||
PingTime = -1
|
|
||||||
End If
|
|
||||||
Catch ex As ThreadInterruptedException
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "连通检测失败")
|
|
||||||
PingTime = -1
|
|
||||||
End Try
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub InitIpCheck()
|
Private Shared Sub InitIpCheck()
|
||||||
IpCheckStatus = LoadState.Loading
|
|
||||||
Try
|
|
||||||
Log("[HiPer] 网络检测:IP 地址检测开始")
|
|
||||||
Dim IpCheckResult As String = NetRequestOnce("https://ipinfo.io/json", "GET", "", "application/json", 10000)
|
|
||||||
Dim Country As String = GetJson(IpCheckResult)("country")
|
|
||||||
IpIsInChina = Country = "CN"
|
|
||||||
IpCheckStatus = LoadState.Finished
|
|
||||||
Log("[HiPer] 网络检测:IP 地址检测结果:" & Country)
|
|
||||||
Catch ex As ThreadInterruptedException
|
|
||||||
IpCheckStatus = LoadState.Aborted
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "IP 地址检测失败")
|
|
||||||
IpCheckStatus = LoadState.Failed
|
|
||||||
IpIsInChina = True
|
|
||||||
End Try
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared PingTime As Integer, IpCheckStatus As LoadState = LoadState.Loading, IpIsInChina As Boolean
|
Private Shared PingTime As Integer, IpCheckStatus As LoadState = LoadState.Loading, IpIsInChina As Boolean
|
||||||
Private Shared Sub InitCheck(Task As LoaderTask(Of Integer, Integer))
|
Private Shared Sub InitCheck(Task As LoaderTask(Of Integer, Integer))
|
||||||
'检查协议
|
|
||||||
If Not Setup.Get("LinkEula") Then
|
|
||||||
Reopen:
|
|
||||||
Select Case MyMsgBox("PCL 的联机服务由速聚授权提供。" & vbCrLf & "在使用前,你需要同意速聚的用户服务协议和隐私政策。", "协议授权", "同意", "拒绝", "查看用户服务协议和隐私政策")
|
|
||||||
Case 1
|
|
||||||
Setup.Set("LinkEula", True)
|
|
||||||
Case 2
|
|
||||||
Throw New Exception("$你拒绝了用户服务协议……")
|
|
||||||
Case 3
|
|
||||||
OpenWebsite("https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxMTMyODk3Mg==&action=getalbum&album_id=2585385685407514625&scene=173&from_msgid=2247483720&from_itemidx=1&count=3&nolastread=1#wechat_redirect")
|
|
||||||
GoTo Reopen
|
|
||||||
End Select
|
|
||||||
End If
|
|
||||||
'等待网络环境检查加载器结束
|
|
||||||
SetLoadDesc("正在检查网络环境……", "检查网络环境")
|
|
||||||
Do While Task.State = LoadState.Loading AndAlso Not (PingTime <> 0 AndAlso IpCheckStatus <> LoadState.Loading)
|
|
||||||
Thread.Sleep(50)
|
|
||||||
Loop
|
|
||||||
'获取网络环境检查结果
|
|
||||||
If IpCheckStatus = LoadState.Finished AndAlso Not IpIsInChina Then
|
|
||||||
If MyMsgBox("检测到你的 IP 不在中国,这会导致联机变得非常不稳定。" & vbCrLf &
|
|
||||||
"如果你正开着加速器或者 VPN,请先关闭它们,然后再继续……", "警告", "继续", "取消", IsWarn:=True, ForceWait:=True) = 2 Then
|
|
||||||
Throw New Exception("$请在关闭加速器或者 VPN 后点击重试。")
|
|
||||||
End If
|
|
||||||
Task.Progress = 0.5
|
|
||||||
InitIpCheck() '重新进行检查
|
|
||||||
End If
|
|
||||||
'没有联网
|
|
||||||
If IpCheckStatus = LoadState.Failed AndAlso PingTime = -1 Then
|
|
||||||
Throw New Exception("$PCL 没法连上网……" & vbCrLf & "如果你改变了网络环境,请重启 PCL。")
|
|
||||||
End If
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'获取所需文件
|
'获取所需文件
|
||||||
Private Shared Sub InitGetFile(Task As LoaderTask(Of Integer, List(Of NetFile)))
|
Private Shared Sub InitGetFile(Task As LoaderTask(Of Integer, List(Of NetFile)))
|
||||||
'初始化
|
|
||||||
SetLoadDesc("正在初始化……", "初始化")
|
|
||||||
Directory.CreateDirectory(PathHiper)
|
|
||||||
WriteFile(PathHiper & "HiPer 联机模块.vbs", "createobject(""wscript.shell"").run """"""" & PathHiper & "HiPer 联机模块.exe"""" v"", 0", Encoding:=Encoding.GetEncoding("GB18030")) '准备启动脚本
|
|
||||||
'获取索引码文件
|
|
||||||
SetLoadDesc("正在获取索引码文件……", "获取索引码文件")
|
|
||||||
Dim Cert As String = RunInUiWait(Function() FrmLinkHiper.TextCert.Text)
|
|
||||||
Log("[Hiper] 联机索引码:" & Cert)
|
|
||||||
If Cert = Setup.Get("LinkHiperCertLast") AndAlso File.Exists(PathHiper & "cert.yml") Then
|
|
||||||
Log("[Hiper] 索引码与上次输入的一致,跳过获取步骤")
|
|
||||||
Else
|
|
||||||
Dim CertRaw As String
|
|
||||||
Try
|
|
||||||
CertRaw = NetRequestOnce("https://cert.mcer.cn/" & Cert & ".yml", "GET", "", "")
|
|
||||||
Catch ex As Exception
|
|
||||||
If GetExceptionSummary(ex).Contains("(404)") Then
|
|
||||||
Throw New CertOutdatedException '索引码无效或已过期
|
|
||||||
ElseIf GetExceptionSummary(ex).Contains("too many requests") Then
|
|
||||||
Throw New Exception("你的尝试太频繁了,请暂时啥都别点,等两分钟后再试……")
|
|
||||||
Else
|
|
||||||
Throw
|
|
||||||
End If
|
|
||||||
End Try
|
|
||||||
If Not CertRaw.Contains("WARNING <<< AUTO SYNC AREA") Then Throw New Exception("获取到的索引码文件内容有误!")
|
|
||||||
WriteFile(PathHiper & "cert.yml", CertRaw)
|
|
||||||
Setup.Set("LinkHiperCertLast", Cert)
|
|
||||||
Setup.Set("LinkHiperCertTime", "")
|
|
||||||
End If
|
|
||||||
Task.Progress = 0.25
|
|
||||||
'获取 CPU 架构
|
|
||||||
SetLoadDesc("正在获取 CPU 架构……", "获取 CPU 架构")
|
|
||||||
Dim Architecture As String
|
|
||||||
Select Case GetType(String).Assembly.GetName().ProcessorArchitecture
|
|
||||||
Case Reflection.ProcessorArchitecture.X86
|
|
||||||
Architecture = "386"
|
|
||||||
Case Reflection.ProcessorArchitecture.Amd64
|
|
||||||
Architecture = "amd64"
|
|
||||||
Case Reflection.ProcessorArchitecture.Arm
|
|
||||||
Architecture = "arm64"
|
|
||||||
Case Else
|
|
||||||
Architecture = "arm64"
|
|
||||||
Log("[Hiper] 当前 CPU 架构为 " & GetStringFromEnum(GetType(String).Assembly.GetName().ProcessorArchitecture) & ",没有最适合的项,这可能会导致联机模块无法启动!", LogLevel.Debug)
|
|
||||||
End Select
|
|
||||||
Log("[Hiper] CPU 架构:" & Architecture)
|
|
||||||
'检查更新:hiper.exe
|
|
||||||
SetLoadDesc("正在检查联机模块本体更新……", "检查联机模块本体更新")
|
|
||||||
Dim RequiredFiles As New List(Of NetFile)
|
|
||||||
Dim Checksums As String = Nothing, ChecksumHiper As String = Nothing
|
|
||||||
If File.Exists(PathHiper & "HiPer 联机模块.exe") Then
|
|
||||||
Try
|
|
||||||
Checksums = NetGetCodeByDownload({
|
|
||||||
"http://mirror.hiper.cn.s2.the.bb/packages.sha1",
|
|
||||||
"http://mirror.hiper.cn.s3.the.bb:175/packages.sha1",
|
|
||||||
"https://gitcode.net/to/hiper/-/raw/master/packages.sha1",
|
|
||||||
"https://cert.mcer.cn/mirror/packages.sha1"
|
|
||||||
})
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "获取联机模块更新信息失败,将会强制启动联机模块", LogLevel.Hint)
|
|
||||||
GoTo FinishHiperFileCheck
|
|
||||||
End Try
|
|
||||||
ChecksumHiper = RegexSeek(Checksums, "[0-9a-f]{40}(?= windows-" & Architecture & "/hiper.exe)")
|
|
||||||
If ChecksumHiper Is Nothing Then
|
|
||||||
Log("[Hiper] 未找到联机模块更新信息,将会强制启动联机模块", LogLevel.Hint)
|
|
||||||
GoTo FinishHiperFileCheck
|
|
||||||
End If
|
|
||||||
Log("[Hiper] hiper.exe 的所需 SHA1:" & ChecksumHiper)
|
|
||||||
If ChecksumHiper = GetFileSHA1(PathHiper & "HiPer 联机模块.exe") Then
|
|
||||||
Log("[Hiper] hiper.exe 文件校验通过,无需重新下载")
|
|
||||||
GoTo FinishHiperFileCheck
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Log("[Hiper] 需要重新下载 hiper.exe")
|
|
||||||
RequiredFiles.Add(New NetFile({"http://mirror.hiper.cn.s2.the.bb/windows-" & Architecture & "/hiper.exe",
|
|
||||||
"http://mirror.hiper.cn.s3.the.bb:175/windows-" & Architecture & "/hiper.exe",
|
|
||||||
"https://gitcode.net/to/hiper/-/raw/master/windows-" & Architecture & "/hiper.exe?inline=false",
|
|
||||||
"https://cert.mcer.cn/mirror/windows-" & Architecture & "/hiper.exe"},
|
|
||||||
PathHiper & "HiPer 联机模块.exe",
|
|
||||||
New FileChecker(Hash:=ChecksumHiper, MinSize:=1024 * 200))) 'Hash 的默认值即为 Nothing,所以 Checksum 可以为 Nothing
|
|
||||||
FinishHiperFileCheck:
|
|
||||||
Task.Progress = 0.5
|
|
||||||
'检查更新:wintun.dll
|
|
||||||
Dim ChecksumWintun As String = Nothing
|
|
||||||
If File.Exists(PathHiper & "wintun.dll") Then
|
|
||||||
Try
|
|
||||||
If Checksums Is Nothing Then
|
|
||||||
Checksums = NetGetCodeByDownload({
|
|
||||||
"http://mirror.hiper.cn.s2.the.bb/packages.sha1",
|
|
||||||
"http://mirror.hiper.cn.s3.the.bb:175/packages.sha1",
|
|
||||||
"https://gitcode.net/to/hiper/-/raw/master/packages.sha1",
|
|
||||||
"https://cert.mcer.cn/mirror/packages.sha1"
|
|
||||||
})
|
|
||||||
End If
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "获取联机模块更新信息失败,将会强制启动联机模块", LogLevel.Hint)
|
|
||||||
GoTo FinishWintunFileCheck
|
|
||||||
End Try
|
|
||||||
ChecksumWintun = RegexSeek(Checksums, "[0-9a-f]{40}(?= windows-" & Architecture & "/wintun.dll)")
|
|
||||||
If ChecksumWintun Is Nothing Then
|
|
||||||
Log("[Hiper] 未找到联机模块更新信息,将会强制启动联机模块", LogLevel.Hint)
|
|
||||||
GoTo FinishWintunFileCheck
|
|
||||||
End If
|
|
||||||
Log("[Hiper] wintun.dll 的所需 SHA1:" & ChecksumWintun)
|
|
||||||
If ChecksumWintun = GetFileSHA1(PathHiper & "wintun.dll") Then
|
|
||||||
Log("[Hiper] wintun.dll 文件校验通过,无需重新下载")
|
|
||||||
GoTo FinishWintunFileCheck
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Log("[Hiper] 需要重新下载 wintun.dll")
|
|
||||||
RequiredFiles.Add(New NetFile({"http://mirror.hiper.cn.s2.the.bb/windows-" & Architecture & "/wintun.dll",
|
|
||||||
"http://mirror.hiper.cn.s3.the.bb:175/windows-" & Architecture & "/wintun.dll",
|
|
||||||
"https://gitcode.net/to/hiper/-/raw/master/windows-" & Architecture & "/wintun.dll?inline=false",
|
|
||||||
"https://cert.mcer.cn/mirror/windows-" & Architecture & "/wintun.dll"},
|
|
||||||
PathHiper & "wintun.dll",
|
|
||||||
New FileChecker(Hash:=ChecksumWintun, MinSize:=1024 * 200))) 'Hash 的默认值即为 Nothing,所以 Checksum 可以为 Nothing
|
|
||||||
FinishWintunFileCheck:
|
|
||||||
Task.Progress = 0.75
|
|
||||||
'检查更新:MCB
|
|
||||||
If Not IsServerSide Then
|
|
||||||
SetLoadDesc("正在检查联机模块组件更新……", "检查联机模块组件更新")
|
|
||||||
Dim ChecksumMcb As String = Nothing
|
|
||||||
If File.Exists(PathHiper & "MCB 联机模块.exe") Then
|
|
||||||
Try
|
|
||||||
Checksums = NetGetCodeByDownload({
|
|
||||||
"http://mirror.hiper.cn.s2.the.bb/utils/minecraft-broadcast/packages.sha1",
|
|
||||||
"http://mirror.hiper.cn.s3.the.bb:175/utils/minecraft-broadcast/packages.sha1",
|
|
||||||
"https://gitcode.net/to/hiper/-/raw/master/utils/minecraft-broadcast/packages.sha1",
|
|
||||||
"https://cert.mcer.cn/mirror/utils/minecraft-broadcast/packages.sha1"
|
|
||||||
})
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "获取联机模块组件更新信息失败,将会强制启动联机模块组件", LogLevel.Hint)
|
|
||||||
GoTo FinishMcbFileCheck
|
|
||||||
End Try
|
|
||||||
ChecksumMcb = RegexSeek(Checksums, "[0-9a-f]{40}(?= mcb-windows-" & Architecture & ".exe)")
|
|
||||||
If ChecksumMcb Is Nothing Then
|
|
||||||
Log("[Hiper] 未找到联机模块组件更新信息,将会强制启动联机模块组件", LogLevel.Hint)
|
|
||||||
GoTo FinishMcbFileCheck
|
|
||||||
End If
|
|
||||||
Log("[Hiper] mcb.exe 的所需 SHA1:" & ChecksumMcb)
|
|
||||||
If ChecksumMcb = GetFileSHA1(PathHiper & "MCB 联机模块.exe") Then
|
|
||||||
Log("[Hiper] mcb.exe 文件校验通过,无需重新下载")
|
|
||||||
GoTo FinishMcbFileCheck
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Log("[Hiper] 需要重新下载 mcb.exe")
|
|
||||||
RequiredFiles.Add(New NetFile({
|
|
||||||
"http://mirror.hiper.cn.s2.the.bb/utils/minecraft-broadcast/mcb-windows-" & Architecture & ".exe",
|
|
||||||
"http://mirror.hiper.cn.s3.the.bb:175/utils/minecraft-broadcast/mcb-windows-" & Architecture & ".exe",
|
|
||||||
"https://gitcode.net/to/hiper/-/raw/master/utils/minecraft-broadcast/mcb-windows-" & Architecture & ".exe?inline=false",
|
|
||||||
"https://cert.mcer.cn/mirror/utils/minecraft-broadcast/mcb-windows-" & Architecture & ".exe"},
|
|
||||||
PathHiper & "MCB 联机模块.exe",
|
|
||||||
New FileChecker(Hash:=ChecksumMcb, MinSize:=1024 * 200))) 'Hash 的默认值即为 Nothing,所以 Checksum 可以为 Nothing
|
|
||||||
FinishMcbFileCheck:
|
|
||||||
End If
|
|
||||||
'添加 point.yml
|
|
||||||
RequiredFiles.Add(New NetFile({"https://cert.mcer.cn/point.yml"}, PathHiper & "point.yml", New FileChecker(MinSize:=200)))
|
|
||||||
'开始下载
|
|
||||||
SetLoadDesc("正在下载联机模块……", "下载联机模块")
|
|
||||||
Task.Output = RequiredFiles
|
|
||||||
End Sub
|
End Sub
|
||||||
Public Class CertOutdatedException
|
Public Class CertOutdatedException
|
||||||
Inherits Exception
|
Inherits Exception
|
||||||
End Class
|
End Class
|
||||||
'启动联机模块
|
'启动联机模块
|
||||||
Private Shared Sub InitLaunch(Task As LoaderTask(Of Integer, Integer))
|
Private Shared Sub InitLaunch(Task As LoaderTask(Of Integer, Integer))
|
||||||
'关闭运行中的 HiPer,然后再刷新凭证文件
|
|
||||||
SetLoadDesc("正在关闭运行中的联机模块……", "关闭运行中的联机模块")
|
|
||||||
HiperStop(True)
|
|
||||||
'准备凭证文件
|
|
||||||
SetLoadDesc("正在准备索引码文件……", "准备索引码文件")
|
|
||||||
Dim CertFile As String = ReadFile(PathHiper & "cert.yml")
|
|
||||||
'添加防火墙配置
|
|
||||||
If IsServerSide Then
|
|
||||||
CertFile += ("\n\ninbound:\n port: " & HostPort & "\n proto: tcp\n host: any").Replace("\n", vbCrLf)
|
|
||||||
Else
|
|
||||||
CertFile += ("\n\noutbound:\n port: " & HostPort & "\n proto: tcp\n host: " & HostIp).Replace("\n", vbCrLf)
|
|
||||||
End If
|
|
||||||
CertFile += "\nlogging:\n format: json".Replace("\n", vbCrLf)
|
|
||||||
'更新 point.yml 段
|
|
||||||
Const SyncAreaRegex As String = "(?<=#[ ]*WARNING >>> AUTO SYNC AREA)[\s\S]+?(?=#[ ]*WARNING <<< AUTO SYNC AREA)"
|
|
||||||
CertFile = CertFile.Replace(RegexSeek(CertFile, SyncAreaRegex), RegexSeek(ReadFile(PathHiper & "point.yml"), SyncAreaRegex))
|
|
||||||
WriteFile(PathHiper & "config.yml", CertFile)
|
|
||||||
AllNodes = RegexSearch(CertFile.Replace(vbLf, "cr"), "(?<="")[0-9]+.[0-9]+.[0-9]+.[0-9]+(?=""( )?:( )?cr - "")").Distinct.
|
|
||||||
Where(Function(l) Not (l = "6.6.1.1" OrElse l = "6.6.2.2" OrElse l = "6.6.3.3")).ToList
|
|
||||||
If AllNodes.Count < 2 Then Throw New Exception("$索引码文件格式有误,未找到节点 IP!")
|
|
||||||
Task.Progress = 0.05
|
|
||||||
'尝试启动
|
|
||||||
HiperStart(Task) '启动失败会直接抛出异常
|
|
||||||
Task.Progress = 0.2
|
|
||||||
'检查连接情况
|
|
||||||
SetLoadDesc("正在连接到联机节点 (1/2)……" & If(IpIsInChina, "", vbCrLf & "由于网络不在中国,可能要花费很长时间。"), "检查联机节点")
|
|
||||||
If Not IsServerSide AndAlso HostIp = HiperIp Then Throw New Exception("$还搁这自己连自己?!不是吧?!")
|
|
||||||
Dim PingNodeResults As New List(Of Integer)
|
|
||||||
Dim UnpingedNodes As New List(Of String)(AllNodes)
|
|
||||||
Do Until PingNodeResults.Count >= 2 OrElse Task.IsAborted
|
|
||||||
Dim SelectedNode = RandomOne(UnpingedNodes)
|
|
||||||
Dim PingNode = Ping(SelectedNode, 4000)
|
|
||||||
If PingNode = -1 Then
|
|
||||||
Task.Progress += (If(PingNodeResults.Count = 0, 0.58, 0.88) - Task.Progress) * 0.3
|
|
||||||
Else
|
|
||||||
SetLoadDesc("正在连接到联机节点 (2/2)……" & If(IpIsInChina, "", vbCrLf & "由于网络不在中国,可能要花费很长时间。"), "检查联机节点")
|
|
||||||
Task.Progress = 0.6
|
|
||||||
PingNodeResults.Add(PingNode)
|
|
||||||
UnpingedNodes.Remove(SelectedNode)
|
|
||||||
End If
|
|
||||||
Loop
|
|
||||||
PingNodes = PingNodeResults.Min
|
|
||||||
Task.Progress = 0.9
|
|
||||||
'与房主 Ping 一下看看
|
|
||||||
If Not IsServerSide Then
|
|
||||||
SetLoadDesc("正在连接到房主……", "检查房主")
|
|
||||||
HostPing = -1 '实际上不使用本次 Ping 的结果,因为它真的偏大……
|
|
||||||
Do
|
|
||||||
Dim PingHost = Ping(HostIp, 4000, False)
|
|
||||||
If PingHost = -1 Then
|
|
||||||
Thread.Sleep(500)
|
|
||||||
Else
|
|
||||||
Exit Do
|
|
||||||
End If
|
|
||||||
Loop Until Task.IsAborted
|
|
||||||
'在等待 2 秒后再次触发 Ping,以刷新显示的 Ping
|
|
||||||
RunInNewThread(Sub()
|
|
||||||
Thread.Sleep(2000)
|
|
||||||
TaskPingHost.Start(True, IsForceRestart:=True)
|
|
||||||
End Sub, "HiPer Delayed Ping")
|
|
||||||
End If
|
|
||||||
'刷新完成页面
|
|
||||||
SetLoadDesc("正在加载完成页面……", "加载完成页面")
|
|
||||||
RunInUiWait(AddressOf FrmLinkHiper.WatcherTimer1)
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared PingNodes As Integer, AllNodes As List(Of String)
|
Private Shared PingNodes As Integer, AllNodes As List(Of String)
|
||||||
|
|
||||||
@@ -389,40 +103,6 @@ FinishMcbFileCheck:
|
|||||||
''' </summary>
|
''' </summary>
|
||||||
Public Shared Function HiperStop(SleepWhenKilled As Boolean) As Boolean
|
Public Shared Function HiperStop(SleepWhenKilled As Boolean) As Boolean
|
||||||
Return False
|
Return False
|
||||||
HiperStop = False
|
|
||||||
'修改凭证
|
|
||||||
Dim ConfigContent As String = ReadFile(PathHiper & "config.yml")
|
|
||||||
If Not ConfigContent.Contains("enable: false") Then
|
|
||||||
WriteFile(PathHiper & "config.yml", ConfigContent & vbCrLf & "enable: false")
|
|
||||||
End If
|
|
||||||
'关闭所有进程
|
|
||||||
For Each ProcessObject In Process.GetProcesses
|
|
||||||
Dim IsHiper As Boolean = ProcessObject.ProcessName = "HiPer 联机模块"
|
|
||||||
Dim IsMcb As Boolean = ProcessObject.ProcessName = "MCB 联机模块"
|
|
||||||
If Not IsHiper AndAlso Not IsMcb Then Continue For
|
|
||||||
HiperStop = True
|
|
||||||
Try
|
|
||||||
If IsMcb Then
|
|
||||||
ProcessObject.Kill()
|
|
||||||
Log("[HiPer] 已结束进程 PID " & ProcessObject.Id & ":" & ProcessObject.ProcessName)
|
|
||||||
If HiperStop AndAlso SleepWhenKilled Then Thread.Sleep(1000) '等待 1 秒确认进程已退出
|
|
||||||
Else 'IsHiper
|
|
||||||
If SleepWhenKilled Then
|
|
||||||
Thread.Sleep(4000) '等待 4 秒确认进程已退出
|
|
||||||
If Not ProcessObject.HasExited Then
|
|
||||||
ProcessObject.Kill()
|
|
||||||
Log("[HiPer] 已结束进程 PID " & ProcessObject.Id & ":" & ProcessObject.ProcessName)
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "结束进程失败(" & ProcessObject.Id & "," & ProcessObject.ProcessName & ")")
|
|
||||||
End Try
|
|
||||||
Next
|
|
||||||
'初始化
|
|
||||||
HiperState = LoadState.Waiting
|
|
||||||
HiperProcessId = -1 : McbProcessId = -1
|
|
||||||
HiperCertTime = Nothing
|
|
||||||
End Function
|
End Function
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 启动程序,并等待初始化完成后退出运行,同时更新 HiperIp。
|
''' 启动程序,并等待初始化完成后退出运行,同时更新 HiperIp。
|
||||||
@@ -430,125 +110,10 @@ FinishMcbFileCheck:
|
|||||||
''' 若程序正在运行,则会先停止其运行。
|
''' 若程序正在运行,则会先停止其运行。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Shared Sub HiperStart(Task As LoaderTask(Of Integer, Integer))
|
Public Shared Sub HiperStart(Task As LoaderTask(Of Integer, Integer))
|
||||||
Try
|
|
||||||
SetLoadDesc("正在启动联机模块……", "启动联机模块")
|
|
||||||
PossibleFailReason = Nothing
|
|
||||||
'启动 Hiper
|
|
||||||
Log("[Hiper] 启动 Hiper 进程")
|
|
||||||
DeleteDirectory(PathHiper & "logs") '清理日志
|
|
||||||
Dim HiperInfo = New ProcessStartInfo With {
|
|
||||||
.FileName = "wscript",
|
|
||||||
.Arguments = """" & PathHiper & "HiPer 联机模块.vbs""",
|
|
||||||
.Verb = "runas" '需要管理员权限
|
|
||||||
}
|
|
||||||
Dim HiperVbsProcess As New Process() With {.StartInfo = HiperInfo}
|
|
||||||
HiperVbsProcess.Start()
|
|
||||||
'查找真正的 Hiper 进程
|
|
||||||
SetLoadDesc("联机模块正在启动……", "联机模块加载")
|
|
||||||
Do
|
|
||||||
Dim GotProcesses = Process.GetProcesses.
|
|
||||||
Where(Function(l) l.ProcessName = "HiPer 联机模块" AndAlso Math.Abs((l.StartTime - Date.Now).TotalMinutes) < 1)
|
|
||||||
If GotProcesses.Count > 0 Then
|
|
||||||
HiperProcessId = GotProcesses.First.Id
|
|
||||||
Log("[Hiper] 已发现 Hiper 进程,PID:" & HiperProcessId)
|
|
||||||
Exit Do
|
|
||||||
End If
|
|
||||||
Thread.Sleep(50)
|
|
||||||
Loop While Task.State = LoadState.Loading AndAlso Not Task.IsAborted
|
|
||||||
If HiperProcessId = -1 Then Throw New Exception("联机模块未能成功启动!")
|
|
||||||
HiperState = LoadState.Loading
|
|
||||||
Task.Progress = 0.15
|
|
||||||
'抓取日志
|
|
||||||
Dim LogLine As Integer = 0
|
|
||||||
Do
|
|
||||||
Thread.Sleep(100)
|
|
||||||
If Not File.Exists(PathHiper & "logs\hiper.log") Then Continue Do
|
|
||||||
Dim LogLines As String() = ReadFile(PathHiper & "logs\hiper.log").TrimEnd(vbLf).Split(vbLf)
|
|
||||||
For i = LogLine To LogLines.Count - 1
|
|
||||||
HiperLogLine(LogLines(i), Task)
|
|
||||||
Next
|
|
||||||
LogLine = LogLines.Count
|
|
||||||
Loop While HiperState = LoadState.Loading AndAlso Not Task.IsAborted AndAlso Process.GetProcesses.Any(Function(l) l.Id = HiperProcessId)
|
|
||||||
'输出
|
|
||||||
If HiperState = LoadState.Finished Then
|
|
||||||
Log("[Hiper] Hiper 启动完成")
|
|
||||||
ElseIf PossibleFailReason IsNot Nothing AndAlso PossibleFailReason.Contains("索引码已过期") Then
|
|
||||||
Throw New CertOutdatedException()
|
|
||||||
Else
|
|
||||||
Throw New Exception(If(PossibleFailReason, "联机模块因未知原因启动失败!"))
|
|
||||||
End If
|
|
||||||
'启动 MCB
|
|
||||||
Task.Progress = 0.25
|
|
||||||
If Not IsServerSide Then
|
|
||||||
Try
|
|
||||||
Log("[Hiper] 启动 MCB 进程")
|
|
||||||
Dim McbInfo = New ProcessStartInfo With {
|
|
||||||
.FileName = PathHiper & "MCB 联机模块.exe", .WorkingDirectory = PathHiper,
|
|
||||||
.UseShellExecute = False, .CreateNoWindow = True,
|
|
||||||
.RedirectStandardError = True, .RedirectStandardOutput = True,
|
|
||||||
.Arguments = "-addr " & HostIp & ":" & HostPort & " -motd ""PCL 联机房间"""
|
|
||||||
}
|
|
||||||
Dim McbProcess As New Process() With {.StartInfo = McbInfo}
|
|
||||||
McbProcess.Start()
|
|
||||||
McbProcessId = McbProcess.Id
|
|
||||||
Catch ex As Exception
|
|
||||||
Throw New Exception("联机模块组件启动失败", ex)
|
|
||||||
End Try
|
|
||||||
End If
|
|
||||||
Catch ex As Exception
|
|
||||||
Try
|
|
||||||
HiperStop(True) '由于启动失败停止进程
|
|
||||||
Catch
|
|
||||||
End Try
|
|
||||||
HiperState = LoadState.Failed
|
|
||||||
Throw
|
|
||||||
End Try
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'Hiper 日志
|
'Hiper 日志
|
||||||
Private Shared Sub HiperLogLine(Content As String, Task As LoaderTask(Of Integer, Integer))
|
Private Shared Sub HiperLogLine(Content As String, Task As LoaderTask(Of Integer, Integer))
|
||||||
|
|
||||||
'检查报错
|
|
||||||
Dim ContentTest As String = Content.ToLower
|
|
||||||
Dim ErrorMessage As String = Nothing
|
|
||||||
Dim ContentJson As JObject = Nothing
|
|
||||||
If Content.StartsWith("{""") AndAlso Content.EndsWith("}") Then
|
|
||||||
ContentJson = GetJson(Content)
|
|
||||||
ContentTest = If(ContentJson("error"), ContentJson("msg")).ToString.ToLower
|
|
||||||
ErrorMessage = ContentJson("error")
|
|
||||||
End If
|
|
||||||
If ContentTest.Contains("hiper certificate for this host is expired") Then
|
|
||||||
PossibleFailReason = "$你的索引码已过期,请更换新的索引码!"
|
|
||||||
ElseIf ContentTest.Contains("error creating interface: access is denied") Then
|
|
||||||
PossibleFailReason = "$没有获得管理员权限,无法创建网络通道!"
|
|
||||||
ElseIf ContentTest.Contains("cannot create a file when that file already exists") Then
|
|
||||||
PossibleFailReason = "$请不要重复开启多个联机模块!"
|
|
||||||
ElseIf Content.Contains("failed to load config") Then
|
|
||||||
PossibleFailReason = "$索引码文件内容存在错误!"
|
|
||||||
ElseIf Content.Contains("system cannot find the file specified") Then
|
|
||||||
PossibleFailReason = "$创建网络通道失败!" & vbCrLf & "如果你曾启动过 VPN 软件,请先打开那个软件,然后关掉它,最后再重试。虽然不知道为啥,但这样大概管用……"
|
|
||||||
End If
|
|
||||||
If PossibleFailReason Is Nothing AndAlso ErrorMessage IsNot Nothing Then PossibleFailReason = ErrorMessage
|
|
||||||
|
|
||||||
'检查结束
|
|
||||||
If ContentJson IsNot Nothing Then
|
|
||||||
Dim Message As String = ContentJson("msg")
|
|
||||||
If Message = "HiPer interface is active" Then
|
|
||||||
HiperIp = ContentJson("network").ToString.Split("/").First
|
|
||||||
If IsServerSide Then HostIp = HiperIp
|
|
||||||
Log("[Hiper] Hiper 启动完成,IP:" & HiperIp)
|
|
||||||
HiperState = LoadState.Finished
|
|
||||||
ElseIf Message = "Validity of client certificate" Then
|
|
||||||
Dim VaildTime As String = ContentJson("valid")
|
|
||||||
Date.TryParseExact(VaildTime, "yyyy-MM-dd HH:mm:ss", Globalization.CultureInfo.InvariantCulture, Globalization.DateTimeStyles.None, HiperCertTime)
|
|
||||||
Log("[Hiper] 索引码到期时间:" & HiperCertTime.ToString)
|
|
||||||
Setup.Set("LinkHiperCertTime", HiperCertTime.ToString)
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
|
|
||||||
'写入日志
|
|
||||||
If ModeDebug OrElse Content.Contains("""error""") Then Log("[Hiper] " & Content)
|
|
||||||
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared PossibleFailReason As String = Nothing
|
Private Shared PossibleFailReason As String = Nothing
|
||||||
|
|
||||||
@@ -643,42 +208,6 @@ FinishMcbFileCheck:
|
|||||||
'每 15 秒执行的 Timer
|
'每 15 秒执行的 Timer
|
||||||
Private Shared HostPing As Integer = -1
|
Private Shared HostPing As Integer = -1
|
||||||
Private Sub WatcherTimer15()
|
Private Sub WatcherTimer15()
|
||||||
If Not (HiperState = LoadState.Finished OrElse HiperState = LoadState.Loading) Then Exit Sub
|
|
||||||
'检查 HiPer 崩溃
|
|
||||||
Try
|
|
||||||
Process.GetProcessById(HiperProcessId)
|
|
||||||
Catch
|
|
||||||
Dim LogLines = ReadFile(PathHiper & "logs\hiper.log").TrimEnd(vbLf).Split(vbLf)
|
|
||||||
HiperExit(False)
|
|
||||||
MyMsgBox("由于联机模块异常退出,已退出联机房间。" & vbCrLf & vbCrLf &
|
|
||||||
"联机模块最后的日志:" & vbCrLf & Join(LogLines.Skip(LogLines.Count - 3).ToList, vbCrLf), "联机断开")
|
|
||||||
End Try
|
|
||||||
'下面的部分需要完全完成加载
|
|
||||||
If HiperState <> LoadState.Finished Then Exit Sub
|
|
||||||
'检查 MCB 崩溃
|
|
||||||
Try
|
|
||||||
If Not IsServerSide Then Process.GetProcessById(McbProcessId)
|
|
||||||
Catch
|
|
||||||
HiperExit(False)
|
|
||||||
MyMsgBox("由于 MCB 联机模块异常退出,已退出联机房间。", "联机断开")
|
|
||||||
End Try
|
|
||||||
'重新检查 Ping
|
|
||||||
If Not IsServerSide Then
|
|
||||||
Dim PingHostFailedCount As Integer = 0
|
|
||||||
Do
|
|
||||||
TaskPingHost.WaitForExit(True, IsForceRestart:=True)
|
|
||||||
If TaskPingHost.Output = -1 Then
|
|
||||||
PingHostFailedCount += 1
|
|
||||||
Log("[HiPer] Ping 房主失败(第 " & PingHostFailedCount & " 次)")
|
|
||||||
If PingHostFailedCount >= 3 Then
|
|
||||||
HiperExit(False) : MyMsgBox("与房主断开连接,已退出联机房间。", "联机断开") : Exit Sub
|
|
||||||
End If
|
|
||||||
Else
|
|
||||||
If PingHostFailedCount > 0 Then Log("[HiPer] Ping 房主已恢复成功(" & HostPing & "ms)")
|
|
||||||
Exit Do
|
|
||||||
End If
|
|
||||||
Loop While True
|
|
||||||
End If
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
@@ -711,14 +240,6 @@ FinishMcbFileCheck:
|
|||||||
|
|
||||||
'创建房间
|
'创建房间
|
||||||
Private Sub BtnSelectCreate_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectCreate.MouseLeftButtonUp
|
Private Sub BtnSelectCreate_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectCreate.MouseLeftButtonUp
|
||||||
''获取端口号
|
|
||||||
'Dim PortInput As String = MyMsgBoxInput("", New ObjectModel.Collection(Of Validate) From {
|
|
||||||
' New ValidateInteger(2, 65535),
|
|
||||||
' New ValidateExceptSame({"55555", "55557"}, "端口不能为 %!")
|
|
||||||
' }, "在 MC 的暂停画面选择【对局域网开放】", "输入端口号", "确定", "取消")
|
|
||||||
'If PortInput Is Nothing Then Exit Sub
|
|
||||||
''开始
|
|
||||||
'RoomCreate(Val(PortInput))
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub RoomCreate(Port As Integer)
|
Private Sub RoomCreate(Port As Integer)
|
||||||
'记录信息
|
'记录信息
|
||||||
@@ -730,34 +251,6 @@ FinishMcbFileCheck:
|
|||||||
|
|
||||||
'加入房间
|
'加入房间
|
||||||
Private Sub BtnSelectJoin_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectJoin.MouseLeftButtonUp
|
Private Sub BtnSelectJoin_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnSelectJoin.MouseLeftButtonUp
|
||||||
' '获取信息
|
|
||||||
' Dim Code As String = MyMsgBoxInput("", New ObjectModel.Collection(Of Validate) From {New ValidateLength(8, 99)}, "",
|
|
||||||
' "输入联机码", "确定", "取消")
|
|
||||||
' If Code Is Nothing Then Exit Sub
|
|
||||||
' '记录信息
|
|
||||||
' If Not Code.EndsWith(RequestVersion) OrElse Not Code.StartsWith("P") Then GoTo WrongCode
|
|
||||||
' Dim Ip As String, Port As Integer
|
|
||||||
' Try
|
|
||||||
' Dim IpAndPort As Long = RadixConvert(Code.Substring(1, Code.Length - 2).ToUpper, 36, 10)
|
|
||||||
' 'IpAndPort = HostPort + IpParts(0) * 65536 + IpParts(1) * 65536 * 256 + IpParts(2) * 65536 * 256 * 256 + IpParts(3) * 65536 * 256 * 256 * 256
|
|
||||||
' Ip = Math.Floor(IpAndPort / (65536L * 256 * 256 * 256))
|
|
||||||
' IpAndPort = IpAndPort Mod (65536L * 256 * 256 * 256)
|
|
||||||
' Ip = Math.Floor(IpAndPort / (65536L * 256 * 256)) & "." & Ip
|
|
||||||
' IpAndPort = IpAndPort Mod (65536L * 256 * 256)
|
|
||||||
' Ip = Math.Floor(IpAndPort / (65536L * 256)) & "." & Ip
|
|
||||||
' IpAndPort = IpAndPort Mod (65536L * 256)
|
|
||||||
' Ip = Math.Floor(IpAndPort / (65536L)) & "." & Ip
|
|
||||||
' Port = IpAndPort Mod 65536
|
|
||||||
' Catch
|
|
||||||
' GoTo WrongCode
|
|
||||||
' End Try
|
|
||||||
' '启动
|
|
||||||
' RoomJoin(Ip, Port)
|
|
||||||
' Exit Sub
|
|
||||||
'WrongCode:
|
|
||||||
' If Not Code.StartsWith("P") AndAlso Code.Length >= 49 Then Hint("你输入的可能是 IOI 的联机码,请在左侧的联机方式中选择 IOI!", HintType.Critical) : Exit Sub
|
|
||||||
' If Code.StartsWith("P") AndAlso Not Code.EndsWith(RequestVersion) Then Hint("你的 PCL 版本与房主的 PCL 版本不一致!", HintType.Critical) : Exit Sub
|
|
||||||
' Hint("你输入的联机码无效!", HintType.Critical)
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub RoomJoin(Ip As String, Port As Integer)
|
Private Sub RoomJoin(Ip As String, Port As Integer)
|
||||||
'记录信息
|
'记录信息
|
||||||
@@ -773,54 +266,6 @@ FinishMcbFileCheck:
|
|||||||
|
|
||||||
'承接状态切换的 UI 改变
|
'承接状态切换的 UI 改变
|
||||||
Private Sub OnLoadStateChanged(Loader As LoaderBase, NewState As LoadState, OldState As LoadState)
|
Private Sub OnLoadStateChanged(Loader As LoaderBase, NewState As LoadState, OldState As LoadState)
|
||||||
Select Case NewState
|
|
||||||
Case LoadState.Loading
|
|
||||||
UpdateProgress(0)
|
|
||||||
If IsServerSide Then
|
|
||||||
LabLoadTitle.Text = "正在创建联机房间"
|
|
||||||
Log("[Hiper] 正在创建联机房间,端口 " & HostPort)
|
|
||||||
Else
|
|
||||||
LabLoadTitle.Text = "正在加入联机房间"
|
|
||||||
Log("[Hiper] 正在加入联机房间,目标 IP " & HostIp & ":" & HostPort)
|
|
||||||
End If
|
|
||||||
LabLoadDesc.Text = "正在初始化……"
|
|
||||||
LoadStep = "准备初始化"
|
|
||||||
Case LoadState.Failed
|
|
||||||
UpdateProgress(1)
|
|
||||||
If IsServerSide Then
|
|
||||||
LabLoadTitle.Text = "创建联机房间失败"
|
|
||||||
Else
|
|
||||||
LabLoadTitle.Text = "加入联机房间失败"
|
|
||||||
End If
|
|
||||||
Dim RealException As Exception = If(Loader.Error.InnerException, Loader.Error)
|
|
||||||
If TypeOf RealException Is CertOutdatedException Then
|
|
||||||
LabCertTitle.Text = "索引码无效"
|
|
||||||
LabCertDesc.Text = "你的 HiPer 索引码无效或者已经过期!" & vbCrLf & "请重新输入索引码。"
|
|
||||||
HiperExit(True)
|
|
||||||
ElseIf RealException.Message.StartsWith("$") Then
|
|
||||||
LabLoadDesc.Text = RealException.Message.TrimStart("$") & vbCrLf &
|
|
||||||
"点击镐子重试,或者点击灰色的 × 取消。"
|
|
||||||
Else
|
|
||||||
LabLoadDesc.Text = LoadStep & "失败:" & GetExceptionSummary(RealException) & vbCrLf &
|
|
||||||
"点击镐子重试,或者点击灰色的 × 取消。"
|
|
||||||
End If
|
|
||||||
Log(Loader.Error, "HiPer 联机尝试失败")
|
|
||||||
Case LoadState.Finished
|
|
||||||
UpdateProgress(1)
|
|
||||||
CurrentSubpage = Subpages.PanFinish
|
|
||||||
BtnFinishPing.Visibility = If(IsServerSide, Visibility.Collapsed, Visibility.Visible)
|
|
||||||
LineFinishPing.Visibility = If(IsServerSide, Visibility.Collapsed, Visibility.Visible)
|
|
||||||
BtnFinishCopy.Visibility = If(IsServerSide, Visibility.Visible, Visibility.Collapsed)
|
|
||||||
If IsServerSide Then
|
|
||||||
LabFinishTitle.Text = "已创建联机房间"
|
|
||||||
LabFinishDesc.Text = "已在端口 " & HostPort & " 创建了联机房间。" & vbCrLf & "点击下方的复制联机码按钮,然后把联机码发给朋友吧!"
|
|
||||||
Else
|
|
||||||
LabFinishTitle.Text = "已加入联机房间"
|
|
||||||
LabFinishDesc.Text = "启动游戏,进入多人游戏页面后稍等片刻,房间就会出现在服务器列表的最下方。" & vbCrLf & "如果提示无效会话,不要退出联机房间,重新启动游戏即可!"
|
|
||||||
End If
|
|
||||||
LabFinishIp.Text = HostIp & ":" & HostPort
|
|
||||||
Log("[Hiper] 已完成连接")
|
|
||||||
End Select
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared LoadStep As String = "准备初始化"
|
Private Shared LoadStep As String = "准备初始化"
|
||||||
Private Shared Sub SetLoadDesc(Intro As String, [Step] As String)
|
Private Shared Sub SetLoadDesc(Intro As String, [Step] As String)
|
||||||
@@ -888,10 +333,6 @@ FinishMcbFileCheck:
|
|||||||
|
|
||||||
'复制联机码
|
'复制联机码
|
||||||
Private Sub BtnFinishCopy_Click(sender As Object, e As EventArgs) Handles BtnFinishCopy.Click
|
Private Sub BtnFinishCopy_Click(sender As Object, e As EventArgs) Handles BtnFinishCopy.Click
|
||||||
Dim IpParts = HostIp.Split(".").Select(Function(l) Val(l)).ToList
|
|
||||||
Dim IpAndPort As Long = HostPort + IpParts(0) * 65536 + IpParts(1) * 65536 * 256 + IpParts(2) * 65536 * 256 * 256 + IpParts(3) * 65536 * 256 * 256 * 256
|
|
||||||
ClipboardSet("P" & RadixConvert(IpAndPort, 10, 36) & RequestVersion, False)
|
|
||||||
Hint("已复制联机码!", HintType.Finish)
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'Ping 房主
|
'Ping 房主
|
||||||
|
|||||||
@@ -1,204 +1,10 @@
|
|||||||
Imports System.Net
|
Imports System.Net.Sockets
|
||||||
Imports System.Net.Sockets
|
|
||||||
|
|
||||||
Public Class PageLinkIoi
|
Public Class PageLinkIoi
|
||||||
Public Const RequestVersion As Integer = 4
|
Public Const RequestVersion As Integer = 4
|
||||||
Public Const IoiVersion As Integer = 10 '由于已关闭更新渠道,在提升 IoiVersion 时必须提升 RequestVersion
|
Public Const IoiVersion As Integer = 10 '由于已关闭更新渠道,在提升 IoiVersion 时必须提升 RequestVersion
|
||||||
Public Shared PathIoi As String = PathAppdata & "联机模块\IOI 联机模块.exe"
|
Public Shared PathIoi As String = PathAppdata & "联机模块\IOI 联机模块.exe"
|
||||||
|
|
||||||
#Region "初始化"
|
|
||||||
|
|
||||||
'页面初始化
|
|
||||||
Private IsLoad As Boolean = False
|
|
||||||
Private Sub MeLoaded() Handles Me.Loaded
|
|
||||||
FormMain.EndProgramForce(Result.Aborted)
|
|
||||||
|
|
||||||
'重复加载部分
|
|
||||||
PanBack.ScrollToHome()
|
|
||||||
RefreshUi()
|
|
||||||
|
|
||||||
'非重复加载部分
|
|
||||||
If IsLoad Then Exit Sub
|
|
||||||
IsLoad = True
|
|
||||||
|
|
||||||
'更新线程
|
|
||||||
RunInNewThread(Sub()
|
|
||||||
Do While True
|
|
||||||
Thread.Sleep(200)
|
|
||||||
If FrmMain.PageCurrent.Page = FormMain.PageType.Link AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.LinkIoi Then RunInUiWait(Sub() FrmLinkIoi.RefreshUi())
|
|
||||||
RefreshWorker()
|
|
||||||
Loop
|
|
||||||
End Sub, "Link Timer")
|
|
||||||
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
'加载器初始化与左边栏处理
|
|
||||||
Private Sub LoaderInit() Handles Me.Initialized
|
|
||||||
PageLoaderInit(Load, PanLoad, PanBack, PanAlways, InitLoader, Sub()
|
|
||||||
End Sub)
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
'初始化加载器与步骤
|
|
||||||
Public Shared WithEvents InitLoader As New LoaderCombo(Of Integer)("联机模块初始化", {
|
|
||||||
New LoaderTask(Of Integer, Integer)("端口检查", AddressOf InitPortCheck) With {.ProgressWeight = 1},
|
|
||||||
New LoaderTask(Of Integer, Integer)("启动请求核心", AddressOf StartSocketListener) With {.ProgressWeight = 1},
|
|
||||||
New LoaderTask(Of Integer, List(Of NetFile))("初次启动尝试", AddressOf InitFirst) With {.ProgressWeight = 4},
|
|
||||||
New LoaderDownload("下载更新文件", New List(Of NetFile)) With {.ProgressWeight = 6},
|
|
||||||
New LoaderTask(Of List(Of NetFile), Boolean)("二次启动尝试", AddressOf InitSecond) With {.ProgressWeight = 3},
|
|
||||||
New LoaderTask(Of Boolean, Boolean)("创建请求核心房间", AddressOf InitRequest) With {.ProgressWeight = 2}
|
|
||||||
})
|
|
||||||
'判断端口是否被占用
|
|
||||||
Private Shared Sub InitPortCheck()
|
|
||||||
'检查协议
|
|
||||||
If Not Setup.Get("LinkEula") Then
|
|
||||||
Reopen:
|
|
||||||
Select Case MyMsgBox("PCL 的联机服务由速聚授权提供。" & vbCrLf & "在使用前,你需要同意速聚的用户服务协议和隐私政策。", "协议授权", "同意", "拒绝", "查看用户服务协议和隐私政策")
|
|
||||||
Case 1
|
|
||||||
Setup.Set("LinkEula", True)
|
|
||||||
Case 2
|
|
||||||
Throw New Exception("你拒绝了用户服务协议……")
|
|
||||||
Case 3
|
|
||||||
OpenWebsite("https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxMTMyODk3Mg==&action=getalbum&album_id=2585385685407514625&scene=173&from_msgid=2247483720&from_itemidx=1&count=3&nolastread=1#wechat_redirect")
|
|
||||||
GoTo Reopen
|
|
||||||
End Select
|
|
||||||
End If
|
|
||||||
'先掐死
|
|
||||||
IoiStop(True)
|
|
||||||
'检查端口
|
|
||||||
Dim HasConflict As Boolean = False
|
|
||||||
For Each Port In Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()
|
|
||||||
If Port.Port <> 55555 AndAlso Port.Port <> 55557 Then Continue For
|
|
||||||
Log("[IOI] 发现端口 " & Port.Port & " 被占用")
|
|
||||||
HasConflict = True
|
|
||||||
Next
|
|
||||||
If Not HasConflict Then Exit Sub
|
|
||||||
'对应的报错
|
|
||||||
For Each Line As String In ShellAndGetOutput("netstat", "-ano", 30000).Split({vbCrLf}, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
If Not (Line.Contains("127.0.0.1:55555") OrElse Line.Contains("127.0.0.1:55557")) Then Continue For
|
|
||||||
Dim ProcessName As String
|
|
||||||
Try
|
|
||||||
ProcessName = Process.GetProcessById(Line.Split(" ").Last).ProcessName
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "获取占用端口的进程信息失败,假定进程已结束")
|
|
||||||
Continue For
|
|
||||||
End Try
|
|
||||||
If ProcessName = "联机模块" Then
|
|
||||||
Throw New Exception("由于一个已知问题,请在重启电脑后再尝试使用联机功能")
|
|
||||||
ElseIf ProcessName = "Idle" Then
|
|
||||||
'不知道为啥反正又没占用了
|
|
||||||
Log("[IOI] 未发现占用此端口的程序,继续执行")
|
|
||||||
Else
|
|
||||||
Throw New Exception("端口被程序 " & ProcessName & " 占用,无法启动联机模块,请在任务管理器关闭此程序后再试")
|
|
||||||
End If
|
|
||||||
Next
|
|
||||||
End Sub
|
|
||||||
'下载更新前尝试启动
|
|
||||||
Private Shared Sub InitFirst(Task As LoaderTask(Of Integer, List(Of NetFile)))
|
|
||||||
'初次启动尝试
|
|
||||||
If IoiVersion <> Setup.Get("LinkIoiVersion") Then
|
|
||||||
Log("[IOI] 设置版本强制要求联机模块更新")
|
|
||||||
Setup.Set("LinkIoiVersion", IoiVersion)
|
|
||||||
ElseIf File.Exists(PathIoi) Then
|
|
||||||
Task.Progress = 0.2
|
|
||||||
CheckFirewall()
|
|
||||||
If IoiStart() Then
|
|
||||||
'已完成启动与初始化
|
|
||||||
Task.Output = New List(Of NetFile)
|
|
||||||
Exit Sub
|
|
||||||
Else
|
|
||||||
'需要更新
|
|
||||||
IoiStop(True)
|
|
||||||
File.Delete(PathIoi)
|
|
||||||
GoTo StartDownload
|
|
||||||
End If
|
|
||||||
'如果抛出异常则直接使加载器失败
|
|
||||||
End If
|
|
||||||
'开始下载
|
|
||||||
StartDownload:
|
|
||||||
Task.Progress = 0.8
|
|
||||||
Log("[IOI] 需要下载联机模块")
|
|
||||||
If File.Exists(PathTemp & "联机模块.zip") Then File.Delete(PathTemp & "联机模块.zip")
|
|
||||||
Task.Output = New List(Of NetFile) From {New NetFile(
|
|
||||||
{"https://gitcode.net/to/cato_bin/-/raw/master/ioi_v2_x" & If(Is32BitSystem, 32, 64) & ".zip",
|
|
||||||
"http://mirror.hiper.cn.s2.the.bb/ioi_v2_x" & If(Is32BitSystem, 32, 64) & ".zip",
|
|
||||||
"http://mirror.hiper.cn.s3.the.bb:175/ioi_v2_x" & If(Is32BitSystem, 32, 64) & ".zip",
|
|
||||||
"https://pcl2-server-1253424809.file.myqcloud.com/link/ioi_v2_x" & If(Is32BitSystem, 32, 64) & ".zip{CDN}"},
|
|
||||||
PathTemp & "联机模块.zip")}
|
|
||||||
End Sub
|
|
||||||
'下载更新后尝试启动
|
|
||||||
Private Shared Sub InitSecond(Task As LoaderTask(Of List(Of NetFile), Boolean))
|
|
||||||
'若首次尝试已经成功,则直接跳过
|
|
||||||
If IoiState = LoadState.Finished Then Exit Sub
|
|
||||||
'解压更新包
|
|
||||||
Log("[IOI] 解压联机模块以完成下载")
|
|
||||||
If File.Exists(PathTemp & "ioi.exe") Then File.Delete(PathTemp & "ioi.exe")
|
|
||||||
If File.Exists(PathIoi) Then File.Delete(PathIoi)
|
|
||||||
ExtractFile(PathTemp & "联机模块.zip", PathTemp)
|
|
||||||
File.Delete(PathTemp & "联机模块.zip")
|
|
||||||
CopyFile(PathTemp & "ioi.exe", PathIoi)
|
|
||||||
File.Delete(PathTemp & "ioi.exe")
|
|
||||||
Task.Progress = 0.4
|
|
||||||
'再次尝试启动
|
|
||||||
CheckFirewall()
|
|
||||||
If IoiStart() Then Exit Sub
|
|
||||||
IoiStop(True)
|
|
||||||
Throw New Exception("联机模块初始化失败")
|
|
||||||
End Sub
|
|
||||||
'在 IOI 启动后建立 55557 房间
|
|
||||||
Private Shared Sub InitRequest()
|
|
||||||
Try
|
|
||||||
Dim Result As JObject = GetJson(NetRequestOnce("http://127.0.0.1:55555/api/port?proto=tcp&port=55557" & "&password=" & IoiPassword, "PUT", "", "", 100000))
|
|
||||||
If Result("msg") IsNot Nothing Then Throw New InvalidOperationException(Result("msg").ToString)
|
|
||||||
Catch ex As InvalidOperationException
|
|
||||||
'API 返回的错误
|
|
||||||
Log("创建请求核心房间失败:" & ex.Message, LogLevel.Msgbox)
|
|
||||||
Catch ex As Exception
|
|
||||||
'常规错误
|
|
||||||
Log(ex, "创建请求核心房间失败", LogLevel.Msgbox)
|
|
||||||
End Try
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
'检查防火墙权限,并添加对应的权限
|
|
||||||
Private Shared Sub CheckFirewall()
|
|
||||||
Try
|
|
||||||
Log("[IOI] Windows 防火墙:检测开始")
|
|
||||||
If Not PageLinkLeft.FirewallIsBlock(PathIoi) Then Exit Try
|
|
||||||
If PageLinkLeft.FirewallPolicy.CurrentProfile.ExceptionsNotAllowed Then
|
|
||||||
'禁止白名单
|
|
||||||
MyMsgBox("由于 Windows 防火墙阻止了所有传入连接,PCL 无法获取防火墙通行权限。" & vbCrLf &
|
|
||||||
"联机会有很大概率失败,就算连上了,延迟也会变高……" & vbCrLf & vbCrLf &
|
|
||||||
"请先关闭 Windows 防火墙中的 " & vbLQ & "阻止所有传入连接" & vbRQ & " 选项,然后重启 PCL。", "遭到防火墙拦截")
|
|
||||||
ElseIf IsAdmin() Then
|
|
||||||
'有管理员权限
|
|
||||||
Log("[IOI] Windows 防火墙:尝试添加防火墙通行权限")
|
|
||||||
Try
|
|
||||||
PageLinkLeft.FirewallAddAuthorized("Plain Craft Launcher 启动器(IOI 联机模块)", PathIoi)
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "无法将联机模块添加至防火墙白名单,可能导致联机失败", LogLevel.Msgbox)
|
|
||||||
End Try
|
|
||||||
Else
|
|
||||||
'无管理员权限
|
|
||||||
If MyMsgBox("由于你开启了 Windows 防火墙,PCL 需要获取防火墙通行权限。" & vbCrLf & vbCrLf &
|
|
||||||
"若继续,PCL 将尝试以管理员权限重新启动。" & vbCrLf &
|
|
||||||
"若拒绝,联机模块可能会被防火墙拦截,联机会有很大概率失败。", "需要管理员权限", "继续", "拒绝") = 1 Then
|
|
||||||
Log("[IOI] Windows 防火墙:尝试提升权限")
|
|
||||||
If RunAsAdmin("--link ioi") Then
|
|
||||||
FrmMain.EndProgram(False) '已重新运行
|
|
||||||
Else
|
|
||||||
Hint("获取管理员权限失败,请尝试右键 PCL,选择 " & vbLQ & "以管理员身份运行" & vbRQ & ",然后再进入联机页面!", HintType.Critical)
|
|
||||||
End If
|
|
||||||
Else
|
|
||||||
Hint("在没有防火墙权限的情况下尝试联机,很可能会导致联机失败!", HintType.Critical)
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Log("[IOI] Windows 防火墙:无防火墙通行权限")
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "无法检测防火墙状态,可能导致联机失败", LogLevel.Msgbox)
|
|
||||||
End Try
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
#End Region
|
|
||||||
|
|
||||||
#Region "进程管理"
|
#Region "进程管理"
|
||||||
|
|
||||||
Private Shared IoiId As String, IoiPassword As String
|
Private Shared IoiId As String, IoiPassword As String
|
||||||
@@ -209,38 +15,7 @@ StartDownload:
|
|||||||
''' 若 Ioi 正在运行,则结束 Ioi 进程,同时初始化状态数据。返回是否关闭了对应进程。
|
''' 若 Ioi 正在运行,则结束 Ioi 进程,同时初始化状态数据。返回是否关闭了对应进程。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Shared Function IoiStop(SleepWhenKilled As Boolean) As Boolean
|
Public Shared Function IoiStop(SleepWhenKilled As Boolean) As Boolean
|
||||||
IoiStop = False
|
Return False
|
||||||
'发送断开信息
|
|
||||||
Try
|
|
||||||
If IoiProcess IsNot Nothing AndAlso Not IoiProcess.HasExited Then
|
|
||||||
For i = 0 To UserList.Count - 1
|
|
||||||
If i > UserList.Count - 1 Then Exit For
|
|
||||||
Dim User = UserList.Values(i)
|
|
||||||
SendDisconnectRequest(User)
|
|
||||||
Next
|
|
||||||
End If
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "结束 IOI 进程时发送 Disconnect 信息失败")
|
|
||||||
End Try
|
|
||||||
'关闭所有 Ioi 进程
|
|
||||||
For Each ProcessObject In Process.GetProcesses
|
|
||||||
If ProcessObject.ProcessName <> "IOI 联机模块" Then Continue For
|
|
||||||
IoiStop = True
|
|
||||||
Try
|
|
||||||
ProcessObject.Kill()
|
|
||||||
Log("[IOI] 已关闭联机模块:" & ProcessObject.Id)
|
|
||||||
If SleepWhenKilled Then Thread.Sleep(3000) '等待 3 秒确认进程已退出
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "关闭联机模块失败(" & ProcessObject.Id & ")")
|
|
||||||
End Try
|
|
||||||
Next
|
|
||||||
'初始化
|
|
||||||
IoiProcess = Nothing
|
|
||||||
IoiId = Nothing
|
|
||||||
IoiPassword = Nothing
|
|
||||||
IoiState = LoadState.Waiting
|
|
||||||
UserList = New Dictionary(Of String, LinkUserIoi)
|
|
||||||
RoomListForMe = New List(Of RoomEntry)
|
|
||||||
End Function
|
End Function
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 启动 Ioi,并等待初始化完成后退出运行,同时更新 IoiId 与 IoiPassword。
|
''' 启动 Ioi,并等待初始化完成后退出运行,同时更新 IoiId 与 IoiPassword。
|
||||||
@@ -248,130 +23,11 @@ StartDownload:
|
|||||||
''' 若 Ioi 正在运行,则会先停止其运行。
|
''' 若 Ioi 正在运行,则会先停止其运行。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Shared Function IoiStart() As Boolean
|
Public Shared Function IoiStart() As Boolean
|
||||||
IoiStop(True)
|
Return False
|
||||||
Log("[IOI] 启动联机模块进程")
|
|
||||||
Dim Info = New ProcessStartInfo With {
|
|
||||||
.FileName = PathIoi,
|
|
||||||
.UseShellExecute = False,
|
|
||||||
.CreateNoWindow = True,
|
|
||||||
.RedirectStandardError = True,
|
|
||||||
.RedirectStandardOutput = True,
|
|
||||||
.WorkingDirectory = PathTemp
|
|
||||||
}
|
|
||||||
IoiProcess = New Process() With {.StartInfo = Info}
|
|
||||||
Using outputWaitHandle As New AutoResetEvent(False)
|
|
||||||
Using errorWaitHandle As New AutoResetEvent(False)
|
|
||||||
AddHandler IoiProcess.OutputDataReceived, Function(sender, e)
|
|
||||||
Try
|
|
||||||
If e.Data Is Nothing Then
|
|
||||||
outputWaitHandle.[Set]()
|
|
||||||
Else
|
|
||||||
IoiLogLine(e.Data)
|
|
||||||
End If
|
|
||||||
Catch ex As ObjectDisposedException
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "读取联机模块信息失败")
|
|
||||||
IoiState = LoadState.Failed
|
|
||||||
End Try
|
|
||||||
Return Nothing
|
|
||||||
End Function
|
|
||||||
AddHandler IoiProcess.ErrorDataReceived, Function(sender, e)
|
|
||||||
Try
|
|
||||||
If e.Data Is Nothing Then
|
|
||||||
errorWaitHandle.[Set]()
|
|
||||||
Else
|
|
||||||
IoiLogLine(e.Data)
|
|
||||||
End If
|
|
||||||
Catch ex As ObjectDisposedException
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "读取联机模块错误信息失败")
|
|
||||||
IoiState = LoadState.Failed
|
|
||||||
End Try
|
|
||||||
Return Nothing
|
|
||||||
End Function
|
|
||||||
IoiProcess.Start()
|
|
||||||
IoiState = LoadState.Loading
|
|
||||||
IoiProcess.BeginOutputReadLine()
|
|
||||||
IoiProcess.BeginErrorReadLine()
|
|
||||||
'等待
|
|
||||||
Do Until IoiProcess.HasExited OrElse IoiState <> LoadState.Loading
|
|
||||||
Thread.Sleep(10)
|
|
||||||
Loop
|
|
||||||
'输出
|
|
||||||
If IoiState = LoadState.Finished Then
|
|
||||||
Log("[IOI] 联机模块启动成功")
|
|
||||||
Return True
|
|
||||||
Else
|
|
||||||
Throw New Exception("联机模块启动失败")
|
|
||||||
End If
|
|
||||||
'Select Case IoiState
|
|
||||||
' Case LoadState.Finished
|
|
||||||
' Log("[IOI] 联机模块启动成功")
|
|
||||||
' Return True
|
|
||||||
' Case LoadState.Aborted
|
|
||||||
' Log("[IOI] 联机模块要求更新")
|
|
||||||
' Return False
|
|
||||||
' Case LoadState.Failed
|
|
||||||
' Log("[IOI] 联机模块启动出现异常")
|
|
||||||
' Return False
|
|
||||||
' Case Else 'LoadState.Loading
|
|
||||||
' Throw New Exception("联机模块启动失败,请检查你的网络连接")
|
|
||||||
'End Select
|
|
||||||
End Using
|
|
||||||
End Using
|
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
'Ioi 日志
|
'Ioi 日志
|
||||||
Private Shared Sub IoiLogLine(Content As String)
|
Private Shared Sub IoiLogLine(Content As String)
|
||||||
|
|
||||||
'初始化
|
|
||||||
If Content.Contains(" > http://127.0.0.1:55555/") Then Exit Sub
|
|
||||||
If Content.Contains("All done") Then
|
|
||||||
If IoiId IsNot Nothing AndAlso IoiPassword IsNot Nothing Then
|
|
||||||
IoiState = LoadState.Finished
|
|
||||||
Else
|
|
||||||
Log("[IOI] 联机模块汇报初始化完成,但未提供账户信息")
|
|
||||||
IoiState = LoadState.Failed
|
|
||||||
End If
|
|
||||||
Exit Sub
|
|
||||||
End If
|
|
||||||
If Content.Contains("Password :: ") Then
|
|
||||||
IoiPassword = Content.Split({"Password :: "}, StringSplitOptions.None)(1)
|
|
||||||
Exit Sub '为保证安全不记录密码到 Log
|
|
||||||
End If
|
|
||||||
|
|
||||||
'初始化
|
|
||||||
If Content.Contains("ID :: ") Then IoiId = Content.Split({"ID :: "}, StringSplitOptions.None)(1)
|
|
||||||
If Content.Contains("Initialization failed") OrElse Content.Contains("The version is ") Then IoiState = LoadState.Aborted
|
|
||||||
|
|
||||||
'系统回应
|
|
||||||
If Content.Contains("'portssub' from ") Then LastPortsId = Content.Split(" ").Last
|
|
||||||
If Content.Contains("Listening tcp ") Then
|
|
||||||
If UserList.ContainsKey(LastPortsId) Then
|
|
||||||
UserList(LastPortsId).Ports(Content.Split(" ").Last) = RegexSeek(Content, "(?<=Listening tcp )[^:]+")
|
|
||||||
Else
|
|
||||||
Log("[IOI] 未在列表中的用户出现意料外的连接信息")
|
|
||||||
NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & LastPortsId & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
|
|
||||||
'断开连接
|
|
||||||
If Content.Contains("Closed tcp connection from ") AndAlso Content.Contains(":55557") Then
|
|
||||||
For i = 0 To UserList.Count - 1
|
|
||||||
Dim User = UserList.Values(i)
|
|
||||||
If Not Content.Contains(User.Ports(55557)) OrElse User.IsDisposed Then Continue For
|
|
||||||
Log("[IOI] 检测到 55557 端口断开(" & User.DisplayName & ")")
|
|
||||||
UserRemove(User, True)
|
|
||||||
Exit For
|
|
||||||
Next
|
|
||||||
End If
|
|
||||||
|
|
||||||
'写入日志
|
|
||||||
If Not Content.Contains("read /dev/stdin: The handle is invalid.") AndAlso LogLinesCount < If(ModeDebug, 10000, 1000) Then
|
|
||||||
LogLinesCount += 1
|
|
||||||
Log("[IOI] " & Content)
|
|
||||||
End If
|
|
||||||
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared LogLinesCount As Integer = 0
|
Private Shared LogLinesCount As Integer = 0
|
||||||
Private Shared LastPortsId As String = "" '上一个收到 portssub 的 ID,用于记录端口
|
Private Shared LastPortsId As String = "" '上一个收到 portssub 的 ID,用于记录端口
|
||||||
@@ -384,94 +40,10 @@ StartDownload:
|
|||||||
Private Shared UserListIdentifyCache As String = ""
|
Private Shared UserListIdentifyCache As String = ""
|
||||||
Private Shared RoomListIdentifyCache As String = ""
|
Private Shared RoomListIdentifyCache As String = ""
|
||||||
Public Sub RefreshUi()
|
Public Sub RefreshUi()
|
||||||
Try
|
|
||||||
'确认用户列表缓存
|
|
||||||
Dim UserListIdentify As String = Join(UserList, vbCrLf)
|
|
||||||
If UserListIdentify <> UserListIdentifyCache Then
|
|
||||||
UserListIdentifyCache = UserListIdentify
|
|
||||||
'刷新列表项
|
|
||||||
PanUserList.Children.Clear()
|
|
||||||
For i = 0 To UserList.Count - 1
|
|
||||||
If i > UserList.Count - 1 Then Exit For
|
|
||||||
PanUserList.Children.Add(UserList.Values(i).ToListItem)
|
|
||||||
Next
|
|
||||||
'刷新列表标题
|
|
||||||
CardUser.Title = "已连接的玩家 (" & PanUserList.Children.Count & ")"
|
|
||||||
End If
|
|
||||||
'刷新用户列表项
|
|
||||||
For Each UserItem As MyListItem In PanUserList.Children
|
|
||||||
CType(UserItem.Tag, LinkUserIoi).RefreshUi(UserItem)
|
|
||||||
Next
|
|
||||||
'确认房间列表缓存
|
|
||||||
Dim RoomListIdentify As String = Join(GetRoomList(), vbCrLf)
|
|
||||||
If RoomListIdentify <> RoomListIdentifyCache Then
|
|
||||||
RoomListIdentifyCache = RoomListIdentify
|
|
||||||
'刷新列表项
|
|
||||||
PanRoom.Children.Clear()
|
|
||||||
For Each Room In GetRoomList()
|
|
||||||
PanRoom.Children.Add(Room.ToListItem)
|
|
||||||
Next
|
|
||||||
End If
|
|
||||||
'刷新房间列表项
|
|
||||||
For Each RoomItem As MyListItem In PanRoom.Children
|
|
||||||
CType(RoomItem.Tag, RoomEntry).RefreshUi(RoomItem)
|
|
||||||
Next
|
|
||||||
'刷新操作提示
|
|
||||||
If UserList.Count = 0 Then
|
|
||||||
If RoomListForMe.Count = 0 Then
|
|
||||||
LabHint.Text = "若想创建房间,请点击创建房间按钮,并按说明进行操作。" & vbCrLf & "若想加入他人的房间,请点击建立连接,然后输入对方的联机码。"
|
|
||||||
Else
|
|
||||||
LabHint.Text = "若想让其他人加入你的房间,请点击复制联机码,然后让你的朋友输入你的联机码以建立连接。"
|
|
||||||
End If
|
|
||||||
Else
|
|
||||||
If GetRoomList.Count = 0 Then
|
|
||||||
LabHint.Text = "若想创建房间,请点击创建房间按钮,然后输入对局域网开放后 MC 显示的端口号,或本地服务端的端口号。"
|
|
||||||
ElseIf RoomListForMe.Count = 0 Then
|
|
||||||
'已有连接,本人没有房间,对方有房间
|
|
||||||
LabHint.Text = "若想加入某个房间,直接点击该房间即可获取说明。"
|
|
||||||
Else
|
|
||||||
'已有连接,且本人有房间
|
|
||||||
LabHint.Text = "指向你所创建的房间,能在右侧找到修改房间名称、关闭房间等选项。" &
|
|
||||||
If(RoomListForMe.Count <> GetRoomList.Count, vbCrLf & "若想加入其他人的房间,直接点击该房间即可获取说明。", "")
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "联机模块 UI 时钟运行失败", LogLevel.Feedback)
|
|
||||||
End Try
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'工作线程刷新
|
'工作线程刷新
|
||||||
Public Sub RefreshWorker()
|
Public Sub RefreshWorker()
|
||||||
Try
|
|
||||||
'检测退出
|
|
||||||
If InitLoader.State = LoadState.Finished AndAlso IoiProcess.HasExited Then
|
|
||||||
Log("[IOI] 联机模块出现异常!", LogLevel.Hint)
|
|
||||||
ModuleStopManually()
|
|
||||||
End If
|
|
||||||
'检测用户
|
|
||||||
For i = 0 To UserList.Values.Count - 1
|
|
||||||
If i > UserList.Values.Count - 1 Then Exit For
|
|
||||||
Dim User = UserList.Values(i)
|
|
||||||
If User.Progress < 1 Then Continue For '跳过连接中的用户
|
|
||||||
'发送心跳包
|
|
||||||
If Date.Now - User.LastSend > New TimeSpan(0, 0, RandomInteger(50, 30)) Then
|
|
||||||
RunInNewThread(Sub()
|
|
||||||
Try
|
|
||||||
SendUpdateRequest(User, 1)
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "心跳包发送失败(" & User.DisplayName & ")", LogLevel.Normal)
|
|
||||||
End Try
|
|
||||||
End Sub, "Link Heartbeat " & User.Id)
|
|
||||||
End If
|
|
||||||
'检测被动离线
|
|
||||||
If Date.Now - User.LastReceive > New TimeSpan(0, 2, 0) Then
|
|
||||||
SendDisconnectRequest(User)
|
|
||||||
Hint("与 " & User.DisplayName & " 的连接已中断!", HintType.Critical)
|
|
||||||
End If
|
|
||||||
Next
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "联机模块工作时钟运行失败", LogLevel.Feedback)
|
|
||||||
End Try
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
@@ -482,65 +54,6 @@ StartDownload:
|
|||||||
''' 发送 Portsub 请求并等待获取控制台端口。进度将从 0 变化至 80%。
|
''' 发送 Portsub 请求并等待获取控制台端口。进度将从 0 变化至 80%。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Shared Sub SendPortsubRequest(User As LinkUserIoi)
|
Private Shared Sub SendPortsubRequest(User As LinkUserIoi)
|
||||||
Log("[IOI] 尝试建立连接:" & User.Id)
|
|
||||||
'向对方发送 portsub 请求
|
|
||||||
Dim Retry As Integer = 0
|
|
||||||
RetryLink:
|
|
||||||
Dim Result As JObject = GetJson(NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "PUT", "", "", 100000))
|
|
||||||
'失败与重试
|
|
||||||
If Result("msg") IsNot Nothing Then
|
|
||||||
Dim ErrorMessage As String = Result("msg").ToString
|
|
||||||
Select Case ErrorMessage
|
|
||||||
Case "failed to find any peer in table"
|
|
||||||
Retry += 1
|
|
||||||
ErrorMessage = "我方网络环境不佳,连接失败。" '初始化对等机列表超时
|
|
||||||
Log("[IOI] 尝试建立连接结果:未找到对等机,第 " & Retry & " 级重试")
|
|
||||||
Case "routing: not found"
|
|
||||||
Retry += 4
|
|
||||||
ErrorMessage = "我方或对方网络环境不佳,或对方已关闭联机模块,未找到路由。" '未知情况
|
|
||||||
Log("[IOI] 尝试建立连接结果:无法连接到路由,第 " & Retry & " 级重试")
|
|
||||||
Case "you are already connected to specified host"
|
|
||||||
If User.IsDisposed Then Throw New ThreadInterruptedException("用户对象已被释放")
|
|
||||||
Log("[IOI] 尝试建立连接结果:已与对方连接")
|
|
||||||
GoTo Done
|
|
||||||
'Retry += 1
|
|
||||||
'NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 100000)
|
|
||||||
'ErrorMessage = "已与对方连接。" '双向连接偶尔导致
|
|
||||||
'Log("[IOI] 已与对方连接,尝试中断现有连接,第 " & Retry & " 级重试")
|
|
||||||
Case "dial backoff"
|
|
||||||
Retry += 20
|
|
||||||
ErrorMessage = "对方网络环境不佳,或对方已关闭联机模块。请尝试让对方主动连接你,而不是你去连接对方。" 'NAT2 连 NAT4 导致
|
|
||||||
Log("[IOI] 尝试建立连接结果:NAT 异常,第 " & Retry & " 级重试")
|
|
||||||
Case Else
|
|
||||||
If ErrorMessage.Contains("all dials failed") Then
|
|
||||||
Retry += 8
|
|
||||||
ErrorMessage = "我方或对方网络环境不佳,或对方已关闭联机模块,连接失败。" '网络不佳,或对方已关闭模块
|
|
||||||
Log("[IOI] 尝试建立连接结果:连接失败,第 " & Retry & " 级重试")
|
|
||||||
Else
|
|
||||||
Retry += 8
|
|
||||||
Log("[IOI] 尝试建立连接结果:未知错误(" & ErrorMessage & "),第 " & Retry & " 级重试")
|
|
||||||
End If
|
|
||||||
End Select
|
|
||||||
If User.IsDisposed Then Throw New ThreadInterruptedException("用户对象已被释放")
|
|
||||||
If Retry <= 64 Then
|
|
||||||
User.Progress = Retry * 0.01 + 0.05
|
|
||||||
Thread.Sleep(3000)
|
|
||||||
GoTo RetryLink
|
|
||||||
Else
|
|
||||||
Throw New InvalidOperationException(ErrorMessage)
|
|
||||||
End If
|
|
||||||
End If
|
|
||||||
Log("[IOI] 尝试建立连接结果:成功")
|
|
||||||
'等待获取对方端口
|
|
||||||
Done:
|
|
||||||
Dim WaitCount As Integer = 0
|
|
||||||
Do Until User.Ports.ContainsKey(55555) AndAlso User.Ports.ContainsKey(55557)
|
|
||||||
WaitCount += 1
|
|
||||||
User.Progress = 0.7 + WaitCount / 200 * 0.1 '70% ~ 80%
|
|
||||||
If WaitCount = 100 Then Throw New Exception("连接超时,请尝试重新连接(未收到端口回报)!")
|
|
||||||
Thread.Sleep(150)
|
|
||||||
Loop
|
|
||||||
User.Progress = 0.8
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
@@ -584,20 +97,6 @@ Done:
|
|||||||
''' 尝试发送断开请求,并将其从用户列表中移除。
|
''' 尝试发送断开请求,并将其从用户列表中移除。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Shared Sub SendDisconnectRequest(User As LinkUserIoi, Optional Message As String = Nothing, Optional IsError As Boolean = False)
|
Private Shared Sub SendDisconnectRequest(User As LinkUserIoi, Optional Message As String = Nothing, Optional IsError As Boolean = False)
|
||||||
Dim RawJson As New JObject()
|
|
||||||
RawJson("id") = IoiId
|
|
||||||
RawJson("type") = "disconnect"
|
|
||||||
If Message IsNot Nothing Then
|
|
||||||
RawJson("message") = Message
|
|
||||||
RawJson("isError") = IsError
|
|
||||||
End If
|
|
||||||
Try
|
|
||||||
User.Send(RawJson)
|
|
||||||
Thread.Sleep(50)
|
|
||||||
Catch
|
|
||||||
End Try
|
|
||||||
NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
||||||
User.Dispose()
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
@@ -606,29 +105,9 @@ Done:
|
|||||||
|
|
||||||
'刷新连接
|
'刷新连接
|
||||||
Private Shared Sub BtnListRefresh_Click(sender As MyIconButton, e As EventArgs)
|
Private Shared Sub BtnListRefresh_Click(sender As MyIconButton, e As EventArgs)
|
||||||
Dim User As LinkUserIoi = sender.Tag
|
|
||||||
User.PingRecord.Clear()
|
|
||||||
FrmLinkIoi.RefreshUi()
|
|
||||||
RunInThread(Sub()
|
|
||||||
Try
|
|
||||||
SendUpdateRequest(User, 1)
|
|
||||||
Catch ex As Exception
|
|
||||||
If InitLoader.State = LoadState.Finished Then Log(ex, "刷新与 " & User.DisplayName & " 的连接失败", LogLevel.Hint)
|
|
||||||
End Try
|
|
||||||
End Sub)
|
|
||||||
End Sub
|
End Sub
|
||||||
'断开连接
|
'断开连接
|
||||||
Private Shared Sub BtnListDisconnect_Click(sender As MyIconButton, e As EventArgs)
|
Private Shared Sub BtnListDisconnect_Click(sender As MyIconButton, e As EventArgs)
|
||||||
Dim User As LinkUserIoi = sender.Tag
|
|
||||||
sender.IsEnabled = False
|
|
||||||
RunInThread(Sub()
|
|
||||||
If User.Progress < 1 AndAlso User.RelativeThread IsNot Nothing AndAlso User.RelativeThread.IsAlive Then
|
|
||||||
NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
||||||
User.Dispose()
|
|
||||||
Else
|
|
||||||
SendDisconnectRequest(User, GetPlayerName() & " 主动断开了连接!")
|
|
||||||
End If
|
|
||||||
End Sub)
|
|
||||||
End Sub
|
End Sub
|
||||||
'复制联机码
|
'复制联机码
|
||||||
Public Shared Sub BtnLeftCopy_Click() Handles BtnLeftCopy.Click
|
Public Shared Sub BtnLeftCopy_Click() Handles BtnLeftCopy.Click
|
||||||
@@ -680,46 +159,10 @@ Done:
|
|||||||
|
|
||||||
#Region "请求核心"
|
#Region "请求核心"
|
||||||
|
|
||||||
Private Shared Listener As Socket = Nothing
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' 启动 Socket 监听核心。
|
''' 启动 Socket 监听核心。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Shared Sub StartSocketListener()
|
Public Shared Sub StartSocketListener()
|
||||||
If Listener IsNot Nothing Then Exit Sub '已经启动过了
|
|
||||||
Listener = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) With {.ReceiveTimeout = 1000000000, .SendTimeout = 1000000000}
|
|
||||||
Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True)
|
|
||||||
Try
|
|
||||||
Listener.Bind(New IPEndPoint(IPAddress.Any, 55557))
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "初次启动 Socket 监听核心失败,开始重试")
|
|
||||||
Thread.Sleep(1000)
|
|
||||||
Listener.Bind(New IPEndPoint(IPAddress.Any, 55557))
|
|
||||||
End Try
|
|
||||||
Listener.Listen(100)
|
|
||||||
Log("[IOI] 已启动 Socket 监听核心")
|
|
||||||
RunInNewThread(Sub()
|
|
||||||
While True
|
|
||||||
Try
|
|
||||||
'获取新的 Socket
|
|
||||||
Dim bytes(1024) As Byte
|
|
||||||
Dim ClientSocket As Socket = Listener.Accept()
|
|
||||||
'获取初始输入信息
|
|
||||||
Dim RequestInput As String = Encoding.UTF8.GetString(bytes, 0, ClientSocket.Receive(bytes))
|
|
||||||
If Not RequestInput.StartsWith("PCL - ") Then Exit Sub
|
|
||||||
Dim RawData As String
|
|
||||||
Try
|
|
||||||
RawData = SecretDecrypt(WebUtility.UrlDecode(RequestInput.Substring(6)))
|
|
||||||
Log("[IOI] 接收到新的 Socket:" & RawData)
|
|
||||||
PageLinkIoi.ReceiveJson(GetJson(RawData), ClientSocket)
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "新的 Socket 处理出错(内容:" & RequestInput & ")")
|
|
||||||
End Try
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "Socket 监听出错")
|
|
||||||
Thread.Sleep(3000) '防止死循环出错
|
|
||||||
End Try
|
|
||||||
End While
|
|
||||||
End Sub, "Socket Listener")
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
#End Region
|
#End Region
|
||||||
@@ -738,40 +181,9 @@ Done:
|
|||||||
'请求管理
|
'请求管理
|
||||||
Public Socket As Socket = Nothing
|
Public Socket As Socket = Nothing
|
||||||
Public Sub Send(Request As JObject)
|
Public Sub Send(Request As JObject)
|
||||||
If Socket Is Nothing Then Throw New Exception("该用户尚未绑定 Socket")
|
|
||||||
Dim Data As String = Request.ToString(Newtonsoft.Json.Formatting.None)
|
|
||||||
If ModeDebug Then Log("[IOI] 发送联机数据包(" & DisplayName & "):" & Data)
|
|
||||||
Data = "PCL - " & WebUtility.UrlEncode(SecretEncrypt(Data))
|
|
||||||
Me.LastSend = Date.Now
|
|
||||||
Socket.Send(Encoding.UTF8.GetBytes(Data))
|
|
||||||
End Sub
|
End Sub
|
||||||
Public ListenerThread As Thread = Nothing
|
Public ListenerThread As Thread = Nothing
|
||||||
Public Sub StartListener()
|
Public Sub StartListener()
|
||||||
If ListenerThread IsNot Nothing Then Exit Sub
|
|
||||||
'启动监听
|
|
||||||
ListenerThread = RunInNewThread(Sub()
|
|
||||||
Try
|
|
||||||
Dim bytes(1024) As Byte
|
|
||||||
While PageLinkIoi.UserList.ContainsValue(Me)
|
|
||||||
Dim RequestInput As String = Encoding.UTF8.GetString(bytes, 0, Socket.Receive(bytes))
|
|
||||||
If Not RequestInput.StartsWith("PCL - ") Then Exit Sub
|
|
||||||
Dim RawData As String = SecretDecrypt(WebUtility.UrlDecode(RequestInput.Substring(6)))
|
|
||||||
If ModeDebug Then Log("[IOI] 接收联机数据包(" & DisplayName & "):" & RawData)
|
|
||||||
PageLinkIoi.ReceiveJson(GetJson(RawData)) '调用去实际的联机模块
|
|
||||||
End While
|
|
||||||
Catch ex As ThreadInterruptedException
|
|
||||||
Log("[IOI] 用户监听已中断(" & DisplayName & ")")
|
|
||||||
Catch ex As Exception
|
|
||||||
If IsDisposed Then Exit Sub
|
|
||||||
If ex.GetType.Equals(GetType(SocketException)) AndAlso CType(ex, SocketException).SocketErrorCode = 10053 Then
|
|
||||||
Log("[IOI] 客户端已关闭(" & DisplayName & ")")
|
|
||||||
PageLinkIoi.UserRemove(CType(Me, PageLinkIoi.LinkUserIoi), True)
|
|
||||||
Exit Sub
|
|
||||||
End If
|
|
||||||
Log(ex, "用户监听出错(" & DisplayName & ")")
|
|
||||||
PageLinkIoi.UserRemove(CType(Me, PageLinkIoi.LinkUserIoi), True)
|
|
||||||
End Try
|
|
||||||
End Sub, "Link Listener " & DisplayName)
|
|
||||||
End Sub
|
End Sub
|
||||||
Public Sub BindSocket(Socket As Socket)
|
Public Sub BindSocket(Socket As Socket)
|
||||||
If Me.Socket IsNot Nothing Then Throw New Exception("该用户已经绑定了 Socket")
|
If Me.Socket IsNot Nothing Then Throw New Exception("该用户已经绑定了 Socket")
|
||||||
@@ -975,135 +387,12 @@ Done:
|
|||||||
|
|
||||||
'正向与反向连接
|
'正向与反向连接
|
||||||
Public Shared Sub BtnLeftCreate_Click() Handles BtnLeftCreate.Click
|
Public Shared Sub BtnLeftCreate_Click() Handles BtnLeftCreate.Click
|
||||||
''获取信息
|
|
||||||
'Dim Code As String = MyMsgBoxInput("", New ObjectModel.Collection(Of Validate) From {New ValidateLength(9, 99999)}, "", "输入对方的联机码", "确定", "取消")
|
|
||||||
'If Code Is Nothing Then Exit Sub
|
|
||||||
''检查
|
|
||||||
'If Code.StartsWith("P") AndAlso Code.Length < 48 Then
|
|
||||||
' Hint("你输入的可能是 HiPer 的联机码,请在左侧的联机方式中选择 HiPer!", HintType.Critical) : Exit Sub
|
|
||||||
'End If
|
|
||||||
'Dim Id As String, DisplayName As String
|
|
||||||
'Try '解密失败检查
|
|
||||||
' Id = "12D3" & Code.Substring(0, 48)
|
|
||||||
' DisplayName = SecretDecrypt(Code.Substring(48))
|
|
||||||
'Catch
|
|
||||||
' Hint("你输入的联机码有误!", HintType.Critical)
|
|
||||||
' Exit Sub
|
|
||||||
'End Try
|
|
||||||
'If Id = IoiId Then '自我连接检查
|
|
||||||
' Hint("我连我自己?搁这卡 Bug 呢?", HintType.Critical)
|
|
||||||
' Exit Sub
|
|
||||||
'End If
|
|
||||||
''开始
|
|
||||||
'Dim User As New LinkUserIoi(Id, DisplayName)
|
|
||||||
'User.RelativeThread = RunInNewThread(Sub()
|
|
||||||
' Dim WaitCount As Integer = 0
|
|
||||||
' Try
|
|
||||||
' '加入列表
|
|
||||||
' If UserList.ContainsKey(Id) Then
|
|
||||||
' Hint(UserList(Id).DisplayName & " 已在列表中,无需再次连接!")
|
|
||||||
' Exit Sub
|
|
||||||
' Else
|
|
||||||
' UserList.Add(Id, User)
|
|
||||||
' End If
|
|
||||||
' '发送 portsub 请求(0% -> 80%)
|
|
||||||
' SendPortsubRequest(User)
|
|
||||||
' '构建 Socket(81% -> 82%)
|
|
||||||
' Dim ClientSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) With {.ReceiveTimeout = 1000000000, .SendTimeout = 1000000000}
|
|
||||||
' ClientSocket.Connect(New IPEndPoint(IPAddress.Parse(User.Ports(55557)), 55557))
|
|
||||||
' User.BindSocket(ClientSocket)
|
|
||||||
' User.Progress = 0.82
|
|
||||||
' '发送 connect 请求(83% -> 85%)
|
|
||||||
' SendConnectRequest(User)
|
|
||||||
' User.Progress = 0.85
|
|
||||||
' '等待对方向自己请求
|
|
||||||
' Log("[IOI] 加入成功,等待反向请求")
|
|
||||||
' Do While User.Progress < 0.9999
|
|
||||||
' User.Progress += 0.0002
|
|
||||||
' If User.Progress > 0.98 AndAlso User.Progress < 0.9999 Then Throw New Exception("对方未回应连接请求!")
|
|
||||||
' Thread.Sleep(100)
|
|
||||||
' Loop
|
|
||||||
' Hint("已连接到 " & User.DisplayName & "!", HintType.Finish)
|
|
||||||
' Catch ex As ThreadInterruptedException
|
|
||||||
' Log("[IOI] 已中断主动发起的连接(" & User.DisplayName & ")")
|
|
||||||
' Catch ex As InvalidOperationException
|
|
||||||
' 'API 返回的错误
|
|
||||||
' NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
||||||
' User.Dispose()
|
|
||||||
' If InitLoader.State = LoadState.Finished Then Log("与 " & DisplayName & " 建立连接失败:" & ex.Message, LogLevel.Msgbox)
|
|
||||||
' Catch ex As Exception
|
|
||||||
' '常规错误
|
|
||||||
' NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
||||||
' User.Dispose()
|
|
||||||
' If ex.InnerException IsNot Nothing AndAlso TypeOf ex.InnerException Is ThreadInterruptedException Then Exit Sub
|
|
||||||
' If InitLoader.State = LoadState.Finished Then Log(ex, "与 " & DisplayName & " 建立连接失败", LogLevel.Msgbox)
|
|
||||||
' End Try
|
|
||||||
' End Sub, "Link Create " & DisplayName)
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub SendPortsubBack(User As LinkUserIoi, TargetVersion As Integer)
|
Private Shared Sub SendPortsubBack(User As LinkUserIoi, TargetVersion As Integer)
|
||||||
Try
|
|
||||||
SendPortsubRequest(User)
|
|
||||||
User.Progress = 0.9
|
|
||||||
If TargetVersion > RequestVersion Then
|
|
||||||
SendDisconnectRequest(User, "无法连接到 " & GetPlayerName() & ":对方的 PCL 版本过低!", True)
|
|
||||||
Throw New InvalidOperationException("你的 PCL 版本过低!")
|
|
||||||
ElseIf TargetVersion < RequestVersion Then
|
|
||||||
SendDisconnectRequest(User, "无法连接到 " & GetPlayerName() & ":你的 PCL 版本过低!", True)
|
|
||||||
Throw New InvalidOperationException("对方的 PCL 版本过低!")
|
|
||||||
Else
|
|
||||||
SendUpdateRequest(User, 1)
|
|
||||||
User.Progress = 1
|
|
||||||
Hint(User.DisplayName & " 已与你建立连接!")
|
|
||||||
End If
|
|
||||||
Catch ex As ThreadInterruptedException
|
|
||||||
Log("[IOI] 已中断被动建立的连接(" & User.DisplayName & ")")
|
|
||||||
Catch ex As InvalidOperationException
|
|
||||||
'API 返回的错误
|
|
||||||
NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
||||||
User.Dispose()
|
|
||||||
If InitLoader.State = LoadState.Finished Then Log("与 " & User.DisplayName & " 建立连接失败:" & ex.Message, LogLevel.Hint)
|
|
||||||
Catch ex As Exception
|
|
||||||
'常规错误
|
|
||||||
NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
||||||
User.Dispose()
|
|
||||||
If InitLoader.State = LoadState.Finished Then Log(ex, "与 " & User.DisplayName & " 建立连接失败", LogLevel.Hint)
|
|
||||||
End Try
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'创建房间
|
'创建房间
|
||||||
Private Sub LinkCreate() Handles BtnCreate.Click
|
Private Sub LinkCreate() Handles BtnCreate.Click
|
||||||
'If MyMsgBox("请先进入 MC 并暂停游戏,在暂停页面选择对局域网开放,然后在下一个窗口输入 MC 显示的端口号。" & vbCrLf & "若使用服务端开服,则直接在下一个窗口输入服务器配置中的端口号即可。", "提示", "继续", "取消") = 2 Then Exit Sub
|
|
||||||
''获取端口号
|
|
||||||
'Dim Port As String = MyMsgBoxInput("", New ObjectModel.Collection(Of Validate) From {
|
|
||||||
' New ValidateInteger(0, 65535),
|
|
||||||
' New ValidateExceptSame({"55555", "55557"}, "端口不能为 %!"),
|
|
||||||
' New ValidateExceptSame(RoomListForMe.Select(AddressOf RoomEntry.SelectPort), "端口 % 已创建过房间,请在删除该房间后继续!")
|
|
||||||
' }, "", "输入端口号", "确定", "取消")
|
|
||||||
'If Port Is Nothing Then Exit Sub
|
|
||||||
''获取显示名称
|
|
||||||
'Dim DisplayName As String = MyMsgBoxInput(GetPlayerName() & " 的房间 - " & Port, New ObjectModel.Collection(Of Validate) From {
|
|
||||||
' New ValidateNullOrWhiteSpace(), New ValidateLength(1, 40), New ValidateFilter()
|
|
||||||
' }, "", "输入房间名(建议包含游戏版本等信息)", "确定", "取消")
|
|
||||||
'If DisplayName Is Nothing Then Exit Sub
|
|
||||||
'DisplayName = DisplayName.Trim
|
|
||||||
''开始
|
|
||||||
'RunInThread(Sub()
|
|
||||||
' Try
|
|
||||||
' '请求
|
|
||||||
' Dim Result As JObject = GetJson(NetRequestOnce("http://127.0.0.1:55555/api/port?proto=tcp&port=" & Port & "&password=" & IoiPassword, "PUT", "", "", 100000))
|
|
||||||
' If Result("msg") IsNot Nothing Then Throw New InvalidOperationException(Result("msg").ToString)
|
|
||||||
' '成功
|
|
||||||
' RoomListForMe.Add(New RoomEntry(Port, DisplayName))
|
|
||||||
' Hint("房间 " & DisplayName & " 已创建!", HintType.Finish)
|
|
||||||
' SendUpdateRequestToAllUsers()
|
|
||||||
' Catch ex As InvalidOperationException
|
|
||||||
' 'API 返回的错误
|
|
||||||
' Log("创建房间失败:" & ex.Message, LogLevel.Msgbox)
|
|
||||||
' Catch ex As Exception
|
|
||||||
' '常规错误
|
|
||||||
' Log(ex, "创建房间失败", LogLevel.Msgbox)
|
|
||||||
' End Try
|
|
||||||
' End Sub)
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub SendUpdateRequestToAllUsers()
|
Private Shared Sub SendUpdateRequestToAllUsers()
|
||||||
For i = 0 To UserList.Count - 1
|
For i = 0 To UserList.Count - 1
|
||||||
@@ -1119,18 +408,6 @@ Done:
|
|||||||
End Sub
|
End Sub
|
||||||
'修改房间名称
|
'修改房间名称
|
||||||
Private Shared Sub BtnRoomEdit_Click(sender As MyIconButton, e As EventArgs)
|
Private Shared Sub BtnRoomEdit_Click(sender As MyIconButton, e As EventArgs)
|
||||||
'Dim Room As RoomEntry = sender.Tag
|
|
||||||
''获取房间名
|
|
||||||
'Dim DisplayName As String = MyMsgBoxInput(Room.DisplayName, New ObjectModel.Collection(Of Validate) From {
|
|
||||||
' New ValidateNullOrWhiteSpace(),
|
|
||||||
' New ValidateLength(1, 40)
|
|
||||||
' }, "", "输入房间名(建议包含游戏版本等信息)", "确定", "取消")
|
|
||||||
'If DisplayName Is Nothing Then Exit Sub
|
|
||||||
'DisplayName = DisplayName.Trim
|
|
||||||
''修改
|
|
||||||
'Room.DisplayName = DisplayName
|
|
||||||
'FrmLinkIoi.RefreshUi()
|
|
||||||
'SendUpdateRequestToAllUsers()
|
|
||||||
End Sub
|
End Sub
|
||||||
'加入房间
|
'加入房间
|
||||||
Private Shared Sub BtnRoom_Click(sender As MyListItem, e As EventArgs)
|
Private Shared Sub BtnRoom_Click(sender As MyListItem, e As EventArgs)
|
||||||
@@ -1141,25 +418,6 @@ Done:
|
|||||||
End Sub
|
End Sub
|
||||||
'关闭房间
|
'关闭房间
|
||||||
Private Shared Sub BtnRoomClose_Click(sender As MyIconButton, e As EventArgs)
|
Private Shared Sub BtnRoomClose_Click(sender As MyIconButton, e As EventArgs)
|
||||||
Dim Room As RoomEntry = sender.Tag
|
|
||||||
RunInThread(Sub()
|
|
||||||
Try
|
|
||||||
'远程移除
|
|
||||||
Dim Result As JObject = GetJson(NetRequestOnce("http://127.0.0.1:55555/api/port?proto=tcp&port=" & Room.Port & "&password=" & IoiPassword, "DELETE", "", "", 100000))
|
|
||||||
If Result("msg") IsNot Nothing Then Throw New InvalidOperationException(Result("msg").ToString)
|
|
||||||
'本地移除
|
|
||||||
RoomListForMe.Remove(Room)
|
|
||||||
'成功
|
|
||||||
RunInUi(Sub() FrmLinkIoi.RefreshUi())
|
|
||||||
SendUpdateRequestToAllUsers()
|
|
||||||
Catch ex As InvalidOperationException
|
|
||||||
'API 返回的错误
|
|
||||||
If InitLoader.State = LoadState.Finished Then Log("移除房间失败:" & ex.Message, LogLevel.Msgbox)
|
|
||||||
Catch ex As Exception
|
|
||||||
'常规错误
|
|
||||||
If InitLoader.State = LoadState.Finished Then Log(ex, "移除房间失败", LogLevel.Msgbox)
|
|
||||||
End Try
|
|
||||||
End Sub)
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'获取数据包
|
'获取数据包
|
||||||
@@ -1238,21 +496,9 @@ Done:
|
|||||||
''' 从用户列表中移除一位用户。提示信息视作该用户主动离开。
|
''' 从用户列表中移除一位用户。提示信息视作该用户主动离开。
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Shared Sub UserRemove(User As LinkUserIoi, ShowLeaveMessage As Boolean)
|
Public Shared Sub UserRemove(User As LinkUserIoi, ShowLeaveMessage As Boolean)
|
||||||
If Not UserList.ContainsKey(User.Id) Then Exit Sub
|
|
||||||
If ShowLeaveMessage Then Hint(User.DisplayName & " 已离开!")
|
|
||||||
NetRequestOnce("http://127.0.0.1:55555/api/link?id=" & User.Id & "&password=" & IoiPassword, "DELETE", "", "", 500)
|
|
||||||
User.Dispose()
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'关闭联机模块按钮
|
|
||||||
Private Shared Sub ModuleStateChanged(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) Handles InitLoader.OnStateChangedUi
|
|
||||||
If FrmLinkLeft IsNot Nothing Then CType(FrmLinkLeft.ItemIoi.Buttons(0), MyIconButton).Visibility = If(NewState = LoadState.Finished, Visibility.Visible, Visibility.Collapsed)
|
|
||||||
End Sub
|
|
||||||
Public Shared Sub ModuleStopManually()
|
Public Shared Sub ModuleStopManually()
|
||||||
IoiStop(False)
|
|
||||||
InitLoader.Error = New Exception("联机模块已关闭,点击以重新启动")
|
|
||||||
InitLoader.State = LoadState.Failed
|
|
||||||
IoiState = LoadState.Failed
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
End Class
|
End Class
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
Imports NetFwTypeLib
|
Public Class PageLinkLeft
|
||||||
|
|
||||||
Public Class PageLinkLeft
|
|
||||||
|
|
||||||
Private IsLoad As Boolean = False
|
Private IsLoad As Boolean = False
|
||||||
Private IsPageSwitched As Boolean = False '如果在 Loaded 前切换到其他页面,会导致触发 Loaded 时再次切换一次
|
Private IsPageSwitched As Boolean = False '如果在 Loaded 前切换到其他页面,会导致触发 Loaded 时再次切换一次
|
||||||
@@ -15,84 +13,6 @@ Public Class PageLinkLeft
|
|||||||
IsPageSwitched = False
|
IsPageSwitched = False
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
#Region "Windows 防火墙"
|
|
||||||
|
|
||||||
'为联机模块添加防火墙通行权限的函数库
|
|
||||||
'不加防火墙权限你要我怎么办,这联机根本连都连不上,球球你们别看到防火墙就说是后门了,真的很恼火……
|
|
||||||
|
|
||||||
''' <summary>
|
|
||||||
''' 获取某个文件是否被 Windows 防火墙阻止。
|
|
||||||
''' </summary>
|
|
||||||
Public Shared Function FirewallIsBlock(FilePath As String) As Boolean
|
|
||||||
'获取配置
|
|
||||||
If FirewallPolicy Is Nothing Then
|
|
||||||
Try
|
|
||||||
FirewallPolicy = FirewallPolicyGet()
|
|
||||||
Catch ex As Exception
|
|
||||||
Log(ex, "Windows 防火墙:可能关闭得太死了,根本检测不到,笑死", LogLevel.Normal)
|
|
||||||
Return False
|
|
||||||
End Try
|
|
||||||
End If
|
|
||||||
'检查是否开启
|
|
||||||
If Not FirewallPolicy.CurrentProfile.FirewallEnabled Then
|
|
||||||
Log("[Link] Windows 防火墙:防火墙关闭")
|
|
||||||
Return False
|
|
||||||
End If
|
|
||||||
'检查是否允许例外
|
|
||||||
If FirewallPolicy.CurrentProfile.ExceptionsNotAllowed Then
|
|
||||||
Log("[Link] Windows 防火墙:防火墙开启,不允许例外")
|
|
||||||
Return True
|
|
||||||
End If
|
|
||||||
'检查白名单
|
|
||||||
Dim Target As String = FilePath.Replace(PathTemp.Split("\").First, "").ToLower
|
|
||||||
For Each App As INetFwAuthorizedApplication In FirewallPolicy.CurrentProfile.AuthorizedApplications
|
|
||||||
If ModeDebug Then Log("[Link] 防火墙白名单(" & App.Enabled & "):" & App.ProcessImageFileName)
|
|
||||||
If Not App.Enabled Then Continue For
|
|
||||||
'信标的奇妙盘符 E:0/xxxxx/xxx 导致误判……
|
|
||||||
Dim FileNameTrimmed As String = App.ProcessImageFileName.Replace(App.ProcessImageFileName.Split("\").First, "")
|
|
||||||
If App.ProcessImageFileName.ToLower.Contains(FilePath) Then
|
|
||||||
Log("[Link] Windows 防火墙:开启,已在白名单中(" & FilePath & ")")
|
|
||||||
Return False
|
|
||||||
End If
|
|
||||||
Next
|
|
||||||
Log("[Link] Windows 防火墙:开启,未在白名单中(" & FilePath & ")")
|
|
||||||
Return True
|
|
||||||
End Function
|
|
||||||
''' <summary>
|
|
||||||
''' 添加防火墙通行权限。需要管理员权限。
|
|
||||||
''' </summary>
|
|
||||||
Public Shared Sub FirewallAddAuthorized(DisplayName As String, FilePath As String)
|
|
||||||
Log("[Link] Windows 防火墙:添加通行权限(" & FilePath & ")")
|
|
||||||
'获取配置
|
|
||||||
If FirewallPolicy Is Nothing Then FirewallPolicy = FirewallPolicyGet()
|
|
||||||
'添加项目
|
|
||||||
FirewallPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_DOMAIN).AuthorizedApplications.Add(New FirewallApp(DisplayName, FilePath))
|
|
||||||
FirewallPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD).AuthorizedApplications.Add(New FirewallApp(DisplayName, FilePath))
|
|
||||||
FirewallPolicy.CurrentProfile.AuthorizedApplications.Add(New FirewallApp(DisplayName, FilePath))
|
|
||||||
End Sub
|
|
||||||
Private Class FirewallApp
|
|
||||||
Implements INetFwAuthorizedApplication
|
|
||||||
Public Property Name As String Implements INetFwAuthorizedApplication.Name
|
|
||||||
Public Property ProcessImageFileName As String Implements INetFwAuthorizedApplication.ProcessImageFileName
|
|
||||||
Public Property IpVersion As NET_FW_IP_VERSION_ = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY Implements INetFwAuthorizedApplication.IpVersion
|
|
||||||
Public Property Scope As NET_FW_SCOPE_ = NET_FW_SCOPE_.NET_FW_SCOPE_ALL Implements INetFwAuthorizedApplication.Scope
|
|
||||||
Public Property RemoteAddresses As String = "*" Implements INetFwAuthorizedApplication.RemoteAddresses
|
|
||||||
Public Property Enabled As Boolean = True Implements INetFwAuthorizedApplication.Enabled
|
|
||||||
Public Sub New(DisplayName As String, FilePath As String)
|
|
||||||
Name = DisplayName
|
|
||||||
ProcessImageFileName = FilePath
|
|
||||||
End Sub
|
|
||||||
End Class
|
|
||||||
'获取防火墙配置
|
|
||||||
Public Shared FirewallPolicy As INetFwPolicy = Nothing
|
|
||||||
Public Shared Function FirewallPolicyGet() As INetFwPolicy
|
|
||||||
Const CLSID_FIREWALL_MANAGER As String = "{304CE942-6E39-40D8-943A-B913C40C9CD4}"
|
|
||||||
Dim objType As Type = Type.GetTypeFromCLSID(New Guid(CLSID_FIREWALL_MANAGER))
|
|
||||||
Return TryCast(Activator.CreateInstance(objType), INetFwMgr).LocalPolicy
|
|
||||||
End Function
|
|
||||||
|
|
||||||
#End Region
|
|
||||||
|
|
||||||
#Region "页面切换"
|
#Region "页面切换"
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
@@ -184,7 +104,6 @@ Public Class PageLinkLeft
|
|||||||
PageLinkHiper.ModuleStopManually()
|
PageLinkHiper.ModuleStopManually()
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub BtnIoiStop_Loaded(sender As Object, e As RoutedEventArgs)
|
Private Sub BtnIoiStop_Loaded(sender As Object, e As RoutedEventArgs)
|
||||||
sender.Visibility = If(PageLinkIoi.InitLoader.State = LoadState.Finished, Visibility.Visible, Visibility.Collapsed)
|
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub BtnIoiStop_Click(sender As Object, e As EventArgs)
|
Private Sub BtnIoiStop_Click(sender As Object, e As EventArgs)
|
||||||
PageLinkIoi.ModuleStopManually()
|
PageLinkIoi.ModuleStopManually()
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏窗口标题" Margin="0,0,25,0" />
|
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏窗口标题" Margin="0,0,25,0" />
|
||||||
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="0" Grid.ColumnSpan="2" Tag="LaunchArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则不进行更改。
支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {name}:游戏版本名
 · {time}:当前的系统时间
 · {version}:游戏对应的原版版本号" HintText="默认" MaxLength="100" />
|
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="0" Grid.ColumnSpan="2" Tag="LaunchArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则不进行更改。
支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {name}:游戏版本名
 · {date}、{time}:当前的系统时间
 · {version}:游戏对应的原版版本号" HintText="默认" MaxLength="100" />
|
||||||
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义信息" Margin="0,0,25,0" />
|
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义信息" Margin="0,0,25,0" />
|
||||||
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchArgumentInfo" Text="Plain Craft Launcher 2" Grid.Column="1" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角">
|
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchArgumentInfo" Text="Plain Craft Launcher 2" Grid.Column="1" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角">
|
||||||
<local:MyTextBox.ValidateRules>
|
<local:MyTextBox.ValidateRules>
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。
例如输入 --demo 则会以试玩模式启动游戏。" />
|
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。
例如输入 --demo 则会以试玩模式启动游戏。" />
|
||||||
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,0" />
|
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,0" />
|
||||||
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchAdvanceRun" Grid.Column="1" HintText=""
|
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchAdvanceRun" Grid.Column="1" HintText=""
|
||||||
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

可以使用以下替换标记实现相对路径(路径均以 \ 结尾):
 · {path}:PCL 的 exe 文件所在的文件夹
 · {minecraft}:.minecraft 文件夹
 · {verpath}:版本文件夹(.minecraft\versions\版本名\)
 · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹
 · {java}:游戏运行时的 Java 文件夹

除此之外,也支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {uuid}:玩家的 UUID
 · {name}:游戏版本名
 · {time}:当前的系统时间
 · {version}:游戏对应的原版版本号

例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}option.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。" />
|
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

可以使用以下替换标记实现相对路径(路径均以 \ 结尾):
 · {path}:PCL 的 exe 文件所在的文件夹
 · {minecraft}:.minecraft 文件夹
 · {verpath}:版本文件夹(.minecraft\versions\版本名\)
 · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹
 · {java}:游戏运行时的 Java 文件夹

除此之外,也支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {uuid}:玩家的 UUID
 · {name}:游戏版本名
 · {date}、{time}:当前的系统时间
 · {version}:游戏对应的原版版本号

例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}option.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
|
||||||
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="LaunchAdvanceRunWait" Visibility="Collapsed"
|
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="LaunchAdvanceRunWait" Visibility="Collapsed"
|
||||||
Text="等待命令执行完成后再继续启动" Margin="0,8,0,7" />
|
Text="等待命令执行完成后再继续启动" Margin="0,8,0,7" />
|
||||||
<StackPanel Margin="0,12,0,4" Orientation="Horizontal" Grid.Row="6" Grid.ColumnSpan="2">
|
<StackPanel Margin="0,12,0,4" Orientation="Horizontal" Grid.Row="6" Grid.ColumnSpan="2">
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="版本列表获取" Margin="0,0,25,0" />
|
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="版本列表获取" Margin="0,0,25,0" />
|
||||||
<local:MyComboBox x:Name="ComboDownloadVersion" Grid.ColumnSpan="2" Tag="ToolDownloadVersion" Grid.Column="1">
|
<local:MyComboBox x:Name="ComboDownloadVersion" Grid.ColumnSpan="2" Tag="ToolDownloadVersion" Grid.Column="1">
|
||||||
@@ -55,6 +56,9 @@
|
|||||||
<local:MyCheckBox Margin="0,2,0,4" Text="简化 Mod 加载器显示" Grid.Row="8" Height="22" Grid.ColumnSpan="2"
|
<local:MyCheckBox Margin="0,2,0,4" Text="简化 Mod 加载器显示" Grid.Row="8" Height="22" Grid.ColumnSpan="2"
|
||||||
x:Name="CheckDownloadIgnoreQuilt" Tag="ToolDownloadIgnoreQuilt"
|
x:Name="CheckDownloadIgnoreQuilt" Tag="ToolDownloadIgnoreQuilt"
|
||||||
ToolTip="下载 Mod 时,若该 Mod 支持 Forge 和 Fabric,则显示为支持任意 Mod 加载器。
例如,开启时 JEI 显示支持全版本,关闭后 JEI 就会显示仅支持 Forge / Fabric 全版本。" />
|
ToolTip="下载 Mod 时,若该 Mod 支持 Forge 和 Fabric,则显示为支持任意 Mod 加载器。
例如,开启时 JEI 显示支持全版本,关闭后 JEI 就会显示仅支持 Forge / Fabric 全版本。" />
|
||||||
|
<local:MyCheckBox Margin="0,2,0,4" Text="验证 SSL 证书" Grid.Row="9" Height="22" Grid.ColumnSpan="2"
|
||||||
|
x:Name="CheckDownloadCert" Tag="ToolDownloadCert"
|
||||||
|
ToolTip="在进行连接时,检查 SSL 证书是否正常。
进行验证会提高安全性,但疑似会导致少部分玩家的微软登录失败。" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</local:MyCard>
|
</local:MyCard>
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
ComboDownloadTranslate.SelectedIndex = Setup.Get("ToolDownloadTranslate")
|
ComboDownloadTranslate.SelectedIndex = Setup.Get("ToolDownloadTranslate")
|
||||||
CheckDownloadKeepModpack.Checked = Setup.Get("ToolDownloadKeepModpack")
|
CheckDownloadKeepModpack.Checked = Setup.Get("ToolDownloadKeepModpack")
|
||||||
CheckDownloadIgnoreQuilt.Checked = Setup.Get("ToolDownloadIgnoreQuilt")
|
CheckDownloadIgnoreQuilt.Checked = Setup.Get("ToolDownloadIgnoreQuilt")
|
||||||
|
CheckDownloadCert.Checked = Setup.Get("ToolDownloadCert")
|
||||||
|
|
||||||
'Minecraft 更新提示
|
'Minecraft 更新提示
|
||||||
CheckUpdateRelease.Checked = Setup.Get("ToolUpdateRelease")
|
CheckUpdateRelease.Checked = Setup.Get("ToolUpdateRelease")
|
||||||
@@ -88,6 +89,7 @@
|
|||||||
Setup.Reset("ToolDownloadTranslate")
|
Setup.Reset("ToolDownloadTranslate")
|
||||||
Setup.Reset("ToolDownloadKeepModpack")
|
Setup.Reset("ToolDownloadKeepModpack")
|
||||||
Setup.Reset("ToolDownloadIgnoreQuilt")
|
Setup.Reset("ToolDownloadIgnoreQuilt")
|
||||||
|
Setup.Reset("ToolDownloadCert")
|
||||||
Setup.Reset("ToolUpdateRelease")
|
Setup.Reset("ToolUpdateRelease")
|
||||||
Setup.Reset("ToolUpdateSnapshot")
|
Setup.Reset("ToolUpdateSnapshot")
|
||||||
Setup.Reset("ToolHelpChinese")
|
Setup.Reset("ToolHelpChinese")
|
||||||
@@ -109,7 +111,7 @@
|
|||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
'将控件改变路由到设置改变
|
'将控件改变路由到设置改变
|
||||||
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckDebugMode.Change, CheckDebugDelay.Change, CheckDebugSkipCopy.Change, CheckUpdateRelease.Change, CheckUpdateSnapshot.Change, CheckHelpChinese.Change, CheckDownloadKeepModpack.Change, CheckDownloadIgnoreQuilt.Change
|
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckDebugMode.Change, CheckDebugDelay.Change, CheckDebugSkipCopy.Change, CheckUpdateRelease.Change, CheckUpdateSnapshot.Change, CheckHelpChinese.Change, CheckDownloadKeepModpack.Change, CheckDownloadIgnoreQuilt.Change, CheckDownloadCert.Change
|
||||||
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
|
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderDebugAnim.Change, SliderDownloadThread.Change, SliderDownloadSpeed.Change
|
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderDebugAnim.Change, SliderDownloadThread.Change, SliderDownloadSpeed.Change
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
Public Class PageVersionMod
|
Imports System.Security.Principal
|
||||||
|
|
||||||
|
Public Class PageVersionMod
|
||||||
|
|
||||||
#Region "初始化"
|
#Region "初始化"
|
||||||
|
|
||||||
@@ -65,12 +67,12 @@
|
|||||||
PanBack.Visibility = Visibility.Collapsed
|
PanBack.Visibility = Visibility.Collapsed
|
||||||
Exit Sub
|
Exit Sub
|
||||||
End If
|
End If
|
||||||
SearchBox.Text = ""
|
|
||||||
'输出结果
|
'输出结果
|
||||||
ModItems.Clear()
|
ModItems.Clear()
|
||||||
For Each ModEntity As McMod In Mods
|
For Each ModEntity As McMod In Mods
|
||||||
ModItems(ModEntity.RawFileName) = McModListItem(ModEntity)
|
ModItems(ModEntity.RawFileName) = McModListItem(ModEntity)
|
||||||
Next
|
Next
|
||||||
|
SearchBox.Text = "" '这会触发结果刷新,所以需要在 ModItems 更新之后,详见 #3124 的视频
|
||||||
RefreshResult(Mods)
|
RefreshResult(Mods)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Log(ex, "加载 Mod 列表 UI 失败", LogLevel.Feedback)
|
Log(ex, "加载 Mod 列表 UI 失败", LogLevel.Feedback)
|
||||||
@@ -333,20 +335,33 @@
|
|||||||
End Sub
|
End Sub
|
||||||
Private Sub EDMods(ModList As IEnumerable(Of McMod), IsEnable As Boolean)
|
Private Sub EDMods(ModList As IEnumerable(Of McMod), IsEnable As Boolean)
|
||||||
Dim IsSuccessful As Boolean = True
|
Dim IsSuccessful As Boolean = True
|
||||||
For Each ModEntity In ModList.ToList
|
For Each ModE In ModList.ToList
|
||||||
|
Dim ModEntity = ModE '仅用于去除迭代变量无法修改的限制
|
||||||
Dim NewPath As String = Nothing
|
Dim NewPath As String = Nothing
|
||||||
If ModEntity.State = McMod.McModState.Fine AndAlso Not IsEnable Then
|
If ModEntity.State = McMod.McModState.Fine AndAlso Not IsEnable Then
|
||||||
'禁用
|
'禁用
|
||||||
NewPath = ModEntity.Path & ".disabled"
|
NewPath = ModEntity.Path & If(File.Exists(ModEntity.Path & ".old"), ".old", ".disabled")
|
||||||
ElseIf ModEntity.State = McMod.McModState.Disabled AndAlso IsEnable Then
|
ElseIf ModEntity.State = McMod.McModState.Disabled AndAlso IsEnable Then
|
||||||
'启用
|
'启用
|
||||||
NewPath = ModEntity.Path.Replace(".disabled", "").Replace(".old", "")
|
NewPath = ModEntity.RawPath
|
||||||
Else
|
Else
|
||||||
Continue For
|
Continue For
|
||||||
End If
|
End If
|
||||||
'重命名
|
'重命名
|
||||||
Try
|
Try
|
||||||
If File.Exists(NewPath) AndAlso Not File.Exists(ModEntity.Path) Then Continue For '因为未知原因 Mod 的状态已经切换完了
|
If File.Exists(NewPath) Then
|
||||||
|
If File.Exists(ModEntity.Path) Then
|
||||||
|
'同时存在两个名称的 Mod
|
||||||
|
If GetFileMD5(ModEntity.Path) <> GetFileMD5(NewPath) Then
|
||||||
|
MyMsgBox($"目前同时存在启用和禁用的两个 Mod 文件:{vbCrLf} - {NewPath}{vbCrLf} - {ModEntity.Path}{vbCrLf}{vbCrLf}注意,这两个文件的内容并不相同。{vbCrLf}在手动删除或重命名其中一个文件后,才能继续操作。", "存在文件冲突")
|
||||||
|
Continue For
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
'已经重命名过了
|
||||||
|
Log("[Mod] Mod 的状态已被切换", LogLevel.Debug)
|
||||||
|
Continue For
|
||||||
|
End If
|
||||||
|
End If
|
||||||
File.Delete(NewPath)
|
File.Delete(NewPath)
|
||||||
FileSystem.Rename(ModEntity.Path, NewPath)
|
FileSystem.Rename(ModEntity.Path, NewPath)
|
||||||
Catch ex As FileNotFoundException
|
Catch ex As FileNotFoundException
|
||||||
@@ -389,6 +404,16 @@
|
|||||||
Try
|
Try
|
||||||
Dim IsSuccessful As Boolean = True
|
Dim IsSuccessful As Boolean = True
|
||||||
Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
|
Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
|
||||||
|
'确认需要删除的文件
|
||||||
|
ModList = ModList.SelectMany(
|
||||||
|
Function(Target As McMod)
|
||||||
|
If Target.State = McMod.McModState.Fine Then
|
||||||
|
Return {Target.Path, Target.Path & If(File.Exists(Target.Path & ".old"), ".old", ".disabled")}
|
||||||
|
Else
|
||||||
|
Return {Target.Path, Target.RawPath}
|
||||||
|
End If
|
||||||
|
End Function).Distinct.Where(Function(m) File.Exists(m)).Select(Function(m) New McMod(m)).ToList()
|
||||||
|
'实际删除文件
|
||||||
For Each ModEntity In ModList
|
For Each ModEntity In ModList
|
||||||
'删除
|
'删除
|
||||||
Try
|
Try
|
||||||
@@ -410,8 +435,8 @@
|
|||||||
'更改 Loader 和 UI 中的列表
|
'更改 Loader 和 UI 中的列表
|
||||||
McModLoader.Output.Remove(ModEntity)
|
McModLoader.Output.Remove(ModEntity)
|
||||||
ModItems.Remove(ModEntity.RawFileName)
|
ModItems.Remove(ModEntity.RawFileName)
|
||||||
Dim IndexOfUi As Integer = PanList.Children.IndexOf(PanList.Children.OfType(Of MyLocalModItem).First(Function(i) i.Entry Is ModEntity))
|
Dim IndexOfUi As Integer = PanList.Children.IndexOf(PanList.Children.OfType(Of MyLocalModItem).FirstOrDefault(Function(i) i.Entry.Equals(ModEntity)))
|
||||||
PanList.Children.RemoveAt(IndexOfUi)
|
If IndexOfUi >= 0 Then PanList.Children.RemoveAt(IndexOfUi)
|
||||||
Next
|
Next
|
||||||
RefreshTitle()
|
RefreshTitle()
|
||||||
If Not IsSuccessful Then
|
If Not IsSuccessful Then
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏窗口标题" Margin="0,0,25,0" />
|
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏窗口标题" Margin="0,0,25,0" />
|
||||||
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="0" Grid.ColumnSpan="2" Tag="VersionArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则使用全局设置的值。
支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {name}:游戏版本名
 · {time}:当前的系统时间
 · {version}:游戏对应的原版版本号" HintText="使用全局设置" MaxLength="100" />
|
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="0" Grid.ColumnSpan="2" Tag="VersionArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则使用全局设置的值。
支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {name}:游戏版本名
 · {date}、{time}:当前的系统时间
 · {version}:游戏对应的原版版本号" HintText="使用全局设置" MaxLength="100" />
|
||||||
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义信息" Margin="0,0,25,0" />
|
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义信息" Margin="0,0,25,0" />
|
||||||
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionArgumentInfo" Grid.Column="1" HintText="使用全局设置" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。
若留空,则使用全局设置的值。">
|
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionArgumentInfo" Grid.Column="1" HintText="使用全局设置" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。
若留空,则使用全局设置的值。">
|
||||||
<local:MyTextBox.ValidateRules>
|
<local:MyTextBox.ValidateRules>
|
||||||
@@ -168,10 +168,8 @@
|
|||||||
<Grid Height="35" Name="PanServerNide" Margin="0,12,0,0">
|
<Grid Height="35" Name="PanServerNide" Margin="0,12,0,0">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<local:MyButton x:Name="BtnServerNideWeb" Grid.Column="0" MinWidth="140" Text="服主后台" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
|
<local:MyButton x:Name="BtnServerNideWeb" Grid.Column="0" MinWidth="140" Text="服主后台" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
|
||||||
<local:MyButton x:Name="BtnServerNideBbs" Grid.Column="1" MinWidth="140" Text="查看简介" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<local:MyButton x:Name="BtnServerAuthLittle" Height="35" MinWidth="150" Margin="0,12,0,0" Text="设置为 LittleSkin" HorizontalAlignment="Left" ColorType="Highlight" />
|
<local:MyButton x:Name="BtnServerAuthLittle" Height="35" MinWidth="150" Margin="0,12,0,0" Text="设置为 LittleSkin" HorizontalAlignment="Left" ColorType="Highlight" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -199,7 +197,7 @@
|
|||||||
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。
例如输入 --demo 则会以试玩模式启动游戏。
若留空,则使用全局设置的值。" HintText="使用全局设置" />
|
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。
例如输入 --demo 则会以试玩模式启动游戏。
若留空,则使用全局设置的值。" HintText="使用全局设置" />
|
||||||
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" />
|
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" />
|
||||||
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3"
|
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3"
|
||||||
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。

在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

可以使用以下替换标记实现相对路径(路径均以 \ 结尾):
 · {path}:PCL 的 exe 文件所在的文件夹
 · {minecraft}:.minecraft 文件夹
 · {verpath}:版本文件夹(.minecraft\versions\版本名\)
 · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹
 · {java}:游戏运行时的 Java 文件夹

除此之外,也支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {uuid}:玩家的 UUID
 · {name}:游戏版本名
 · {time}:当前的系统时间
 · {version}:游戏对应的原版版本号

例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}option.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。" />
|
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。

在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

可以使用以下替换标记实现相对路径(路径均以 \ 结尾):
 · {path}:PCL 的 exe 文件所在的文件夹
 · {minecraft}:.minecraft 文件夹
 · {verpath}:版本文件夹(.minecraft\versions\版本名\)
 · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹
 · {java}:游戏运行时的 Java 文件夹

除此之外,也支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {uuid}:玩家的 UUID
 · {name}:游戏版本名
 · {date}、{time}:当前的系统时间
 · {version}:游戏对应的原版版本号

例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}option.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
|
||||||
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="VersionAdvanceRunWait" Visibility="Collapsed"
|
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="VersionAdvanceRunWait" Visibility="Collapsed"
|
||||||
Text="等待命令执行完成后再继续启动" Margin="0,5,0,0" />
|
Text="等待命令执行完成后再继续启动" Margin="0,5,0,0" />
|
||||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal" Grid.Row="6" Grid.ColumnSpan="2">
|
<StackPanel Margin="0,10,0,0" Orientation="Horizontal" Grid.Row="6" Grid.ColumnSpan="2">
|
||||||
|
|||||||
@@ -121,9 +121,10 @@
|
|||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextServerEnter.ValidatedTextChanged, TextArgumentInfo.ValidatedTextChanged, TextAdvanceGame.ValidatedTextChanged, TextAdvanceJvm.ValidatedTextChanged, TextServerNide.ValidatedTextChanged, TextServerAuthName.ValidatedTextChanged, TextServerAuthRegister.ValidatedTextChanged, TextServerAuthServer.ValidatedTextChanged, TextArgumentTitle.ValidatedTextChanged, TextAdvanceRun.ValidatedTextChanged
|
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextServerEnter.ValidatedTextChanged, TextArgumentInfo.ValidatedTextChanged, TextAdvanceGame.ValidatedTextChanged, TextAdvanceJvm.ValidatedTextChanged, TextServerNide.ValidatedTextChanged, TextServerAuthName.ValidatedTextChanged, TextServerAuthRegister.ValidatedTextChanged, TextServerAuthServer.ValidatedTextChanged, TextArgumentTitle.ValidatedTextChanged, TextAdvanceRun.ValidatedTextChanged
|
||||||
If AniControlEnabled = 0 Then
|
If AniControlEnabled = 0 Then
|
||||||
Dim HandledText As String = sender.Text
|
'#3194,不能删减 /
|
||||||
If sender.Tag = "VersionServerAuthServer" OrElse sender.Tag = "VersionServerAuthRegister" Then HandledText = HandledText.TrimEnd("/")
|
'Dim HandledText As String = sender.Text
|
||||||
Setup.Set(sender.Tag, HandledText, Version:=PageVersionLeft.Version)
|
'If sender.Tag = "VersionServerAuthServer" OrElse sender.Tag = "VersionServerAuthRegister" Then HandledText = HandledText.TrimEnd("/")
|
||||||
|
Setup.Set(sender.Tag, sender.Text, Version:=PageVersionLeft.Version)
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change
|
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change
|
||||||
@@ -398,14 +399,12 @@ PreFin:
|
|||||||
Private Sub BtnServerNideWeb_Click(sender As Object, e As EventArgs) Handles BtnServerNideWeb.Click
|
Private Sub BtnServerNideWeb_Click(sender As Object, e As EventArgs) Handles BtnServerNideWeb.Click
|
||||||
OpenWebsite("https://login.mc-user.com:233/server/intro")
|
OpenWebsite("https://login.mc-user.com:233/server/intro")
|
||||||
End Sub
|
End Sub
|
||||||
Private Sub BtnServerNideBbs_Click(sender As Object, e As EventArgs) Handles BtnServerNideBbs.Click
|
|
||||||
OpenWebsite("https://www.mcbbs.net/thread-729821-1-1.html")
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
'LittleSkin
|
'LittleSkin
|
||||||
Private Sub BtnServerAuthLittle_Click(sender As Object, e As EventArgs) Handles BtnServerAuthLittle.Click
|
Private Sub BtnServerAuthLittle_Click(sender As Object, e As EventArgs) Handles BtnServerAuthLittle.Click
|
||||||
If TextServerAuthServer.Text <> "" AndAlso TextServerAuthServer.Text <> "https://littleskin.cn/api/yggdrasil" AndAlso
|
If TextServerAuthServer.Text <> "" AndAlso TextServerAuthServer.Text <> "https://littleskin.cn/api/yggdrasil" AndAlso
|
||||||
MyMsgBox("即将把第三方登录设置覆盖为自动使用 LittleSkin 登录,是否继续?", "覆盖确认", "确定", "取消") = 2 Then Exit Sub
|
MyMsgBox("即将把第三方登录设置覆盖为 LittleSkin 登录。" & vbCrLf & "除非你是服主,或者服主要求你这样做,否则请不要继续。" & vbCrLf & vbCrLf & "是否确实需要覆盖当前设置?",
|
||||||
|
"设置覆盖确认", "继续", "取消") = 2 Then Exit Sub
|
||||||
TextServerAuthServer.Text = "https://littleskin.cn/api/yggdrasil"
|
TextServerAuthServer.Text = "https://littleskin.cn/api/yggdrasil"
|
||||||
TextServerAuthRegister.Text = "https://littleskin.cn/auth/register"
|
TextServerAuthRegister.Text = "https://littleskin.cn/auth/register"
|
||||||
TextServerAuthName.Text = "LittleSkin 登录"
|
TextServerAuthName.Text = "LittleSkin 登录"
|
||||||
|
|||||||
@@ -838,9 +838,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="Images\Blocks\Fabric.png" />
|
<Resource Include="Images\Blocks\Fabric.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Resource Include="Images\Heads\MCBBS.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Resources\forge-installer.jar" />
|
<None Include="Resources\forge-installer.jar" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
Text="任意项目都可以添加 Width 与 Height 属性来控制宽高。HorizontalAlignment 属性可以控制对齐:Center 代表居中,Right 代表居右,例如这段文本就被居右了。" />
|
Text="任意项目都可以添加 Width 与 Height 属性来控制宽高。HorizontalAlignment 属性可以控制对齐:Center 代表居中,Right 代表居右,例如这段文本就被居右了。" />
|
||||||
<TextBlock TextWrapping="Wrap" Margin="0,0,0,6"
|
<TextBlock TextWrapping="Wrap" Margin="0,0,0,6"
|
||||||
Text="Image 代表图片,你需要在它的 Source 属性中填写一个网址或文件路径,它会从该处获取图片并显示。通常需要使用 Height 限制它的高度。" />
|
Text="Image 代表图片,你需要在它的 Source 属性中填写一个网址或文件路径,它会从该处获取图片并显示。通常需要使用 Height 限制它的高度。" />
|
||||||
<Image Height="50" HorizontalAlignment="Center" Source="https://www.mcbbs.net/template/mcbbs/image/logo_sc.png" />
|
<Image Height="50" HorizontalAlignment="Center" Source="https://zh.minecraft.wiki/images/Grass_Block_JE7_BE6.png?bf67e" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</local:MyCard>
|
</local:MyCard>
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
|
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
|
||||||
Text="将按钮的 EventType 属性设为 打开网页,然后在 EventData 属性中写入网址,即可通过点击按钮打开网页。" />
|
Text="将按钮的 EventType 属性设为 打开网页,然后在 EventData 属性中写入网址,即可通过点击按钮打开网页。" />
|
||||||
<local:MyButton Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
|
<local:MyButton Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
|
||||||
Text="打开 MCBBS" EventType="打开网页" EventData="https://www.mcbbs.net/" />
|
Text="打开 Minecraft Wiki" EventType="打开网页" EventData="https://zh.minecraft.wiki/" />
|
||||||
<TextBlock TextWrapping="Wrap" Margin="0,10,0,10"
|
<TextBlock TextWrapping="Wrap" Margin="0,10,0,10"
|
||||||
Text="或者将 EventType 属性改为 弹出窗口,然后在 EventData 属性中写入弹窗的标题与内容……" />
|
Text="或者将 EventType 属性改为 弹出窗口,然后在 EventData 属性中写入弹窗的标题与内容……" />
|
||||||
<local:MyButton Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
|
<local:MyButton Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
|
||||||
@@ -119,7 +119,7 @@
|
|||||||
<TextBlock Margin="0,0,0,4"
|
<TextBlock Margin="0,0,0,4"
|
||||||
Text="· 下载文件:在点击时要求选择文件保存位置,并且下载 EventData 的链接中的文件" />
|
Text="· 下载文件:在点击时要求选择文件保存位置,并且下载 EventData 的链接中的文件" />
|
||||||
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
||||||
Text="下载 MCBBS 的 Logo" EventType="下载文件" EventData="https://www.mcbbs.net/template/mcbbs/image/logo_sc.png" />
|
Text="下载百度的 Logo" EventType="下载文件" EventData="https://www.baidu.com/img/flexible/logo/pc/result.png" />
|
||||||
<TextBlock Margin="0,4,0,4"
|
<TextBlock Margin="0,4,0,4"
|
||||||
Text="· 打开帮助:跳转到 EventData 对应的帮助文件(输入相对 Help 文件夹的路径)"/>
|
Text="· 打开帮助:跳转到 EventData 对应的帮助文件(输入相对 Help 文件夹的路径)"/>
|
||||||
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
<local:MyButton Margin="0,0,10,0" Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
|
<local:MyButton Margin="0,0,10,0" Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
|
||||||
Text="内存优化" EventType="内存优化" />
|
Text="内存优化" EventType="内存优化" />
|
||||||
<local:MyButton Margin="0,0,10,0" Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
|
<local:MyButton Margin="0,0,10,0" Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
|
||||||
Text="下载作者的头像" EventType="下载文件" EventData="https://www.mcbbs.net/uc_server/data/avatar/000/14/51/06_avatar_small.jpg?ts=1471402592" />
|
Text="下载百度的 Logo" EventType="下载文件" EventData="https://www.baidu.com/img/flexible/logo/pc/result.png" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</local:MyCard>
|
</local:MyCard>
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
<TextBlock TextWrapping="Wrap" Text=" 浓度 7 " Margin="5,0" Background="{DynamicResource ColorBrush7}" />
|
<TextBlock TextWrapping="Wrap" Text=" 浓度 7 " Margin="5,0" Background="{DynamicResource ColorBrush7}" />
|
||||||
<TextBlock TextWrapping="Wrap" Text=" 浓度 8 " Margin="5,0" Background="{DynamicResource ColorBrush8}" />
|
<TextBlock TextWrapping="Wrap" Text=" 浓度 8 " Margin="5,0" Background="{DynamicResource ColorBrush8}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock Margin="0,15,0,8" Foreground="{DynamicResource ColorBrush2}" Background="{DynamicResource ColorBrush6}"
|
<TextBlock TextWrapping="Wrap" Margin="0,15,0,8" Foreground="{DynamicResource ColorBrush2}" Background="{DynamicResource ColorBrush6}"
|
||||||
Text="除了字体颜色,你也可以将主题色用于背景色、边框颜色等颜色参数。例如这行字的颜色为浓度 2,背景为浓度 6。" />
|
Text="除了字体颜色,你也可以将主题色用于背景色、边框颜色等颜色参数。例如这行字的颜色为浓度 2,背景为浓度 6。" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</local:MyCard>
|
</local:MyCard>
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Reference in New Issue
Block a user