2.4.5
This commit is contained in:
@@ -174,10 +174,17 @@
|
||||
TargetType = AnalyzeFileType.CrashReport
|
||||
DirectFile = LogFile
|
||||
ElseIf FileName = "latest.log" OrElse FileName = "latest log.txt" OrElse
|
||||
FileName = "debug.log" OrElse FileName = "debug log.txt" OrElse FileName = "游戏崩溃前的输出.txt" OrElse
|
||||
FileName = "rawoutput.log" OrElse FileName = "启动器日志.txt" OrElse FileName = "PCL2 启动器日志.txt" OrElse FileName = "log1.txt" Then
|
||||
FileName = "debug.log" OrElse FileName = "debug log.txt" OrElse
|
||||
FileName = "游戏崩溃前的输出.txt" OrElse FileName = "rawoutput.log" Then
|
||||
TargetType = AnalyzeFileType.MinecraftLog
|
||||
If DirectFile Is Nothing Then DirectFile = LogFile
|
||||
ElseIf FileName = "启动器日志.txt" OrElse FileName = "PCL2 启动器日志.txt" OrElse FileName = "log1.txt" Then
|
||||
If LogFile.Value.Any(Function(s) s.Contains("以下为游戏输出的最后一段内容")) Then
|
||||
TargetType = AnalyzeFileType.MinecraftLog
|
||||
If DirectFile Is Nothing Then DirectFile = LogFile
|
||||
Else
|
||||
TargetType = AnalyzeFileType.ExtraLog
|
||||
End If
|
||||
ElseIf FileName.EndsWith(".log") OrElse FileName.EndsWith(".txt") Then
|
||||
TargetType = AnalyzeFileType.ExtraLog
|
||||
Else
|
||||
@@ -455,9 +462,9 @@ Done:
|
||||
If LogMc.Contains("The driver does not appear to support OpenGL") Then AppendReason(CrashReason.显卡不支持OpenGL)
|
||||
If LogMc.Contains("java.lang.ClassCastException: java.base/jdk") Then AppendReason(CrashReason.使用JDK)
|
||||
If LogMc.Contains("java.lang.ClassCastException: class jdk.") Then AppendReason(CrashReason.使用JDK)
|
||||
If LogMc.Contains("Cannot read field ""ofTelemetry"" because ""net.optifine.Config.gameSettings"" is null") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("TRANSFORMER/net.optifine/net.optifine.reflect.Reflector.<clinit>(Reflector.java") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("Open J9 is not supported") OrElse LogMc.Contains("OpenJ9 is incompatible") OrElse LogMc.Contains(".J9VMInternals.") Then AppendReason(CrashReason.使用OpenJ9)
|
||||
If LogMc.Contains("java.lang.NoSuchFieldException: ucp") Then AppendReason(CrashReason.Java版本过高)
|
||||
If LogMc.Contains("Unsupported class file major version") Then AppendReason(CrashReason.Java版本过高)
|
||||
If LogMc.Contains("because module java.base does not export") Then AppendReason(CrashReason.Java版本过高)
|
||||
If LogMc.Contains("java.lang.ClassNotFoundException: jdk.nashorn.api.scripting.NashornScriptEngineFactory") Then AppendReason(CrashReason.Java版本过高)
|
||||
@@ -487,11 +494,11 @@ Done:
|
||||
'找不到或无法加载主类
|
||||
If (RegexCheck(LogMc, "^[^\n.]+.\w+.[^\n]+\n\[$") OrElse RegexCheck(LogMc, "^\[[^\]]+\] [^\n.]+.\w+.[^\n]+\n\[")) AndAlso
|
||||
Not (LogMc.Contains("at net.") OrElse LogMc.Contains("/INFO]")) AndAlso
|
||||
LogHs Is Nothing AndAlso LogCrash Is Nothing Then
|
||||
LogHs Is Nothing AndAlso LogCrash Is Nothing AndAlso LogMc.Length < 500 Then
|
||||
AppendReason(CrashReason.路径包含中文且存在编码问题导致找不到或无法加载主类)
|
||||
End If
|
||||
'Mod 导致的崩溃
|
||||
If LogMc.Contains("Mixin prepare failed ") OrElse LogMc.Contains("mixin.injection.throwables.") OrElse LogMc.Contains(".mixins.json] FAILED during )") Then
|
||||
If LogMc.Contains("Mixin prepare failed ") OrElse LogMc.Contains("Mixin apply failed ") OrElse LogMc.Contains("mixin.injection.throwables.") OrElse LogMc.Contains(".mixins.json] FAILED during )") Then
|
||||
Dim ModId As String = RegexSeek(LogMc, "(?<=in )[^./ ]+(?=.mixins.json.+failed injection check)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in )[^./ ]+(?=.mixins.json)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[)[^./ ]+(?=.mixins.json\] FAILED during )")
|
||||
@@ -499,7 +506,6 @@ Done:
|
||||
AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(If(ModId, "").TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
End If
|
||||
If LogMc.Contains("Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogMc, "[^\n]+?(?)"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
If LogMc.Contains("Failed to create mod instance.") Then AppendReason(CrashReason.Mod初始化失败, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModID: )[^,]+"), If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModId )[^\n]+(?= for )"), "")).TrimEnd(vbCrLf)))
|
||||
End If
|
||||
|
||||
'虚拟机日志分析
|
||||
@@ -529,6 +535,7 @@ Done:
|
||||
End If
|
||||
End If
|
||||
If LogCrash.Contains("Multiple entries with same key: ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=Multiple entries with same key: )[^=]+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
If LogCrash.Contains("due to errors, provided by ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
If LogCrash.Contains("LoaderExceptionModCrash: Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=LoaderExceptionModCrash: Caught exception from )[^\n]+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
If LogCrash.Contains("Failed loading config file ") Then AppendReason(CrashReason.Mod配置文件导致游戏崩溃, {TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=Failed loading config file .+ for modid )[^\n]+"), "").TrimEnd(vbCrLf)).First, If(RegexSeek(LogCrash, "(?<=Failed loading config file ).+(?= of type)"), "").TrimEnd(vbCrLf)})
|
||||
End If
|
||||
@@ -542,6 +549,8 @@ Done:
|
||||
'游戏日志分析
|
||||
If LogMc IsNot Nothing Then
|
||||
If LogMc.Contains("]: Warnings were found!") Then AppendReason(CrashReason.Fabric报错, If(RegexSeek(LogMc, "(?<=\]: Warnings were found! ?[\n]+)[\w\W]+?(?=[\n]+\[)"), "").Trim(vbCrLf.ToCharArray))
|
||||
'Mixin 失败可以导致大量 Mod 实例创建失败
|
||||
If LogMc.Contains("Failed to create mod instance.") Then AppendReason(CrashReason.Mod初始化失败, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModID: )[^,]+"), If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModId )[^\n]+(?= for )"), "")).TrimEnd(vbCrLf)))
|
||||
End If
|
||||
|
||||
'崩溃报告分析
|
||||
|
||||
@@ -967,7 +967,7 @@
|
||||
Public CategoryId As Integer = 0 '421: Mod(?), 4780: Fabric
|
||||
Public IsModPack As Boolean = False
|
||||
Public GameVersion As String = Nothing
|
||||
Public PageSize As String = 50
|
||||
Public PageSize As Integer = 50
|
||||
Public SearchFilter As String = Nothing
|
||||
Public Index As Integer? = Nothing
|
||||
Public ModLoader As Integer? = Nothing
|
||||
@@ -1270,11 +1270,11 @@
|
||||
If Task.Input.IsModPack Then Throw New Exception("整合包搜索仅支持英文")
|
||||
ReleaseCfDatabase()
|
||||
'构造搜索请求
|
||||
Dim SearchEntries As New List(Of SearchEntry(Of String))
|
||||
Dim SearchEntries As New List(Of SearchEntry(Of DlCfDbEntry))
|
||||
For Each Entry In DlCfProjectDb.Values
|
||||
If If(Entry.ChineseName, "").Contains("动态的树") Then Continue For '傻逼 Mod 的附属太多了
|
||||
SearchEntries.Add(New SearchEntry(Of String) With {
|
||||
.Item = Entry.ChineseName,
|
||||
SearchEntries.Add(New SearchEntry(Of DlCfDbEntry) With {
|
||||
.Item = Entry,
|
||||
.SearchSource = New List(Of KeyValuePair(Of String, Double)) From {
|
||||
New KeyValuePair(Of String, Double)(Entry.ChineseName & Entry.CurseForgeId, 1)
|
||||
}
|
||||
@@ -1284,20 +1284,21 @@
|
||||
Dim SearchResults = Search(SearchEntries, Task.Input.SearchFilter, 3)
|
||||
If SearchResults.Count = 0 Then Throw New Exception("无搜索结果,请尝试搜索英文名称")
|
||||
Dim SearchResult As String = ""
|
||||
For i = 0 To SearchResults.Count - 1
|
||||
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 个结果拼合以提高准确度
|
||||
SearchResult += SearchResults(i).Item.Replace(" - ", "§").Split("§").First.Replace(" (", "|").Split("|").Last.TrimEnd(")") & " "
|
||||
SearchResult += SearchResults(i).Item.CurseForgeId.Replace("-", " ") & " "
|
||||
SearchResult += SearchResults(i).Item.ChineseName.Replace(" (", "|").Split("|").Last.TrimEnd(") ").Replace(" - ", "§").Split("§").First & " "
|
||||
Next
|
||||
Log("[Download] CurseForge 工程列表中文搜索原始关键词:" & SearchResult, LogLevel.Developer)
|
||||
Log("[Download] CurseForge 中文搜索原始关键词:" & SearchResult, LogLevel.Developer)
|
||||
'去除常见连接词
|
||||
Dim RealFilter As String = ""
|
||||
For Each Word In SearchResult.Split(" ")
|
||||
If {"the", "of", "a", "mod"}.Contains(Word.ToLower) Then Continue For
|
||||
If {"the", "of", "a", "mod"}.Contains(Word.ToLower) OrElse Val(Word) > 0 Then Continue For
|
||||
If SearchResult.Split(" ").Count > 3 AndAlso {"ftb"}.Contains(Word.ToLower) Then Continue For
|
||||
RealFilter += Word & " "
|
||||
RealFilter += Word.TrimStart("{[(").TrimEnd("}])") & " "
|
||||
Next
|
||||
Task.Input.SearchFilter = RealFilter
|
||||
Log("[Download] CurseForge 工程列表中文搜索最终关键词:" & RealFilter, LogLevel.Developer)
|
||||
Log("[Download] CurseForge 中文搜索最终关键词:" & RealFilter, LogLevel.Developer)
|
||||
End If
|
||||
'驼峰英文请求关键字处理
|
||||
Dim SpacedKeywords = RegexReplace(Task.Input.SearchFilter, "$& ", "([A-Z]+|[a-z]+?)(?=[A-Z]+[a-z]+[a-z ]*)")
|
||||
@@ -1307,8 +1308,9 @@
|
||||
Dim RightKeywords As New List(Of String)
|
||||
For Each Keyword In AllPossibleKeywords.Split(" ")
|
||||
If Keyword.Trim = "" Then Continue For
|
||||
If Keyword = "forge" OrElse Keyword = "fabric" OrElse Keyword = "for" OrElse Keyword = "mod" Then 'https://github.com/Hex-Dragon/PCL2/issues/208
|
||||
Log("[Download] 已跳过搜索关键词 " & Keyword, LogLevel.Developer)
|
||||
If {"forge", "fabric", "for", "mod",
|
||||
"forge/fabric", "fabric/forge", "fabric/quilt", "quilt/fabric"}.Contains(Keyword) Then 'https://github.com/Hex-Dragon/PCL2/issues/208
|
||||
Log("[Download] 已跳过搜索关键词:" & Keyword, LogLevel.Developer)
|
||||
Continue For
|
||||
End If
|
||||
RightKeywords.Add(Keyword)
|
||||
@@ -1387,18 +1389,25 @@
|
||||
Private Sub ReleaseCfDatabase()
|
||||
If DlCfProjectDb IsNot Nothing Then Exit Sub
|
||||
DlCfProjectDb = New Dictionary(Of String, DlCfDbEntry)
|
||||
Dim i As Integer = 0
|
||||
For Each Line In DecodeBytes(GetResources("ModData")).Split(vbLf)
|
||||
Dim Entry = New DlCfDbEntry
|
||||
Dim SplitedLine = Line.Split("|")
|
||||
Entry.CurseForgeId = SplitedLine(0)
|
||||
Entry.WikiId = SplitedLine(1)
|
||||
Entry.ChineseName = SplitedLine(2)
|
||||
Entry.MCBBS = If(SplitedLine.Count = 4, SplitedLine(3), Nothing)
|
||||
If Entry.ChineseName.Contains("*") Then '处理 *
|
||||
Entry.ChineseName = Entry.ChineseName.Replace("*", " (" &
|
||||
String.Join(" ", Entry.CurseForgeId.Split("-").Select(Function(w) w.Substring(0, 1).ToUpper & w.Substring(1, w.Length - 1))) & ")")
|
||||
End If
|
||||
DlCfProjectDb.Add(Entry.CurseForgeId, Entry)
|
||||
i += 1
|
||||
If Line = "" Then Continue For
|
||||
For Each EntryData As String In Line.Split("¨")
|
||||
Dim Entry = New DlCfDbEntry
|
||||
Dim SplitedLine = EntryData.Split("|")
|
||||
Entry.CurseForgeId = SplitedLine(0)
|
||||
Entry.WikiId = i
|
||||
If SplitedLine.Count >= 2 Then
|
||||
Entry.ChineseName = SplitedLine(1)
|
||||
Entry.MCBBS = If(SplitedLine.Count >= 3, SplitedLine(2), Nothing)
|
||||
If Entry.ChineseName.Contains("*") Then '处理 *
|
||||
Entry.ChineseName = Entry.ChineseName.Replace("*", " (" &
|
||||
String.Join(" ", Entry.CurseForgeId.Split("-").Select(Function(w) w.Substring(0, 1).ToUpper & w.Substring(1, w.Length - 1))) & ")")
|
||||
End If
|
||||
End If
|
||||
DlCfProjectDb.Add(Entry.CurseForgeId, Entry)
|
||||
Next
|
||||
Next
|
||||
End Sub
|
||||
Public Class DlCfDbEntry
|
||||
|
||||
@@ -48,6 +48,7 @@ Public Module ModLaunch
|
||||
McVersionCurrent = Options.Version
|
||||
Setup.Set("LaunchVersionSelect", McVersionCurrent.Name)
|
||||
FrmLaunchLeft.RefreshButtonsUI()
|
||||
FrmLaunchLeft.RefreshPage(False, False)
|
||||
End If
|
||||
FrmMain.AprilGiveup()
|
||||
'禁止进入版本选择页面(否则就可以在启动中切换 McVersionCurrent 了)
|
||||
@@ -108,6 +109,7 @@ Public Module ModLaunch
|
||||
New LoaderTask(Of String, List(Of McLibToken))("获取启动参数", AddressOf McLaunchArgumentMain) With {.ProgressWeight = 2},
|
||||
New LoaderTask(Of List(Of McLibToken), Integer)("解压文件", AddressOf McLaunchNatives) With {.ProgressWeight = 2},
|
||||
New LoaderTask(Of Integer, Integer)("预启动处理", AddressOf McLaunchPrerun) With {.ProgressWeight = 1},
|
||||
New LoaderTask(Of Integer, Integer)("执行自定义命令", AddressOf McLaunchCustom) With {.ProgressWeight = 1},
|
||||
New LoaderTask(Of Integer, Process)("启动进程", AddressOf McLaunchRun) With {.ProgressWeight = 2},
|
||||
New LoaderTask(Of Process, Integer)("等待游戏窗口出现", AddressOf McLaunchWait) With {.ProgressWeight = 1},
|
||||
New LoaderTask(Of Integer, Integer)("结束处理", AddressOf McLaunchEnd) With {.ProgressWeight = 1}
|
||||
@@ -130,7 +132,7 @@ Public Module ModLaunch
|
||||
Hint(McVersionCurrent.Name & " 启动成功!", HintType.Finish)
|
||||
Case LoadState.Aborted
|
||||
If AbortHint Is Nothing Then
|
||||
Hint("已取消启动!", HintType.Info)
|
||||
Hint(If(Loader.Input.SaveBatch Is Nothing, "已取消启动!", "已取消导出启动脚本!"), HintType.Info)
|
||||
Else
|
||||
Hint(AbortHint, HintType.Finish)
|
||||
End If
|
||||
@@ -145,7 +147,7 @@ NextInner:
|
||||
If CurrentEx.Message.StartsWith("$") Then
|
||||
'若有以 $ 开头的错误信息,则以此为准显示提示
|
||||
'若错误信息为 $$,则不提示
|
||||
If Not CurrentEx.Message = "$$" Then MyMsgBox(CurrentEx.Message.TrimStart("$"), "启动失败")
|
||||
If Not CurrentEx.Message = "$$" Then MyMsgBox(CurrentEx.Message.TrimStart("$"), If(Loader.Input.SaveBatch Is Nothing, "启动失败", "导出启动脚本失败"))
|
||||
Throw
|
||||
ElseIf CurrentEx.InnerException IsNot Nothing Then
|
||||
'检查下一级错误
|
||||
@@ -154,7 +156,7 @@ NextInner:
|
||||
Else
|
||||
'没有特殊处理过的错误信息
|
||||
McLaunchLog("错误:" & GetExceptionDetail(ex))
|
||||
Log(ex, "Minecraft 启动失败", LogLevel.Msgbox, "启动失败")
|
||||
Log(ex, If(Loader.Input.SaveBatch Is Nothing, "Minecraft 启动失败", "导出启动脚本失败"), LogLevel.Msgbox, If(Loader.Input.SaveBatch Is Nothing, "启动失败", "导出启动脚本失败"))
|
||||
Throw
|
||||
End If
|
||||
End Try
|
||||
@@ -177,10 +179,11 @@ NextInner:
|
||||
RunInUiWait(Sub()
|
||||
Dim LoginInput As McLoginData = McLoginInput()
|
||||
CheckResult = McLoginAble(LoginInput)
|
||||
If LoginInput.Type = McLoginType.Legacy AndAlso '离线登录
|
||||
If CheckResult = "" AndAlso
|
||||
LoginInput.Type = McLoginType.Legacy AndAlso '离线登录
|
||||
Not RegexCheck(CType(LoginInput, McLoginLegacy).UserName, "^[0-9A-Za-z_]+$") AndAlso
|
||||
McVersionCurrent.Version.McCodeMain >= 18 Then 'MC 1.18 以上
|
||||
CheckResult = "用户名中不可包含除数字、英文、下划线以外的特殊字符!"
|
||||
CheckResult = "玩家名只能由数字、英文和下划线组成,不能包含中文或特殊字符!"
|
||||
End If
|
||||
End Sub)
|
||||
If CheckResult <> "" Then Throw New ArgumentException(CheckResult)
|
||||
@@ -845,10 +848,13 @@ LoginFinish:
|
||||
If OsVersion <= New Version(10, 0, 17763, 0) Then
|
||||
SystemBrowser:
|
||||
'Windows 7 或老版 Windows 10 登录
|
||||
MyMsgBox("PCL2 即将打开登录网页。登录后会转到一个空白页面(这代表登录成功了),请将该空白页面的网址复制到 PCL2。" & vbCrLf &
|
||||
"如果网络环境不佳,登录网页可能一直加载不出来,此时请尝试使用 VPN 或加速器,然后再试。", "登录说明", "开始", ForceWait:=True)
|
||||
OpenWebsite(FormLoginOAuth.LoginUrl1)
|
||||
Dim Result As String = MyMsgBoxInput("", New ObjectModel.Collection(Of Validate) From {New ValidateRegex("(?<=code\=)[^&]+", "返回网址应以 https://login.live.com/oauth20_desktop.srf?code= 开头")}, "https://login.live.com/oauth20_desktop.srf?code=XXXXXX", "输入登录返回码", "确定", "取消")
|
||||
Dim Result As String =
|
||||
MyMsgBoxInput("等待网页登录",
|
||||
"在登录成功后,网页会变成一片空白,请将该空白页面的网址复制到下面的框中。" & vbCrLf &
|
||||
"如果网络环境不佳,登录网页可能一直加载不出来,此时请尝试使用 VPN 或加速器,然后再试。",
|
||||
ValidateRules:=New ObjectModel.Collection(Of Validate) From {New ValidateRegex("(?<=code\=)[^&]+", "返回网址应以 https://login.live.com/oauth20_desktop.srf?code= 开头")},
|
||||
HintText:="https://login.live.com/oauth20_desktop.srf?code=XXXXXX")
|
||||
If Result Is Nothing Then
|
||||
McLaunchLog("微软登录已在步骤 1 被取消")
|
||||
Throw New ThreadInterruptedException("$$")
|
||||
@@ -1138,7 +1144,7 @@ SystemBrowser:
|
||||
MinVer = New Version(1, 17, 0, 0)
|
||||
ElseIf (McVersionCurrent.ReleaseTime >= New Date(2021, 5, 11) AndAlso McVersionCurrent.Version.McCodeMain = 99) OrElse
|
||||
(McVersionCurrent.Version.McCodeMain >= 17 AndAlso McVersionCurrent.Version.McCodeMain <> 99) Then
|
||||
'21w19a+:至少 Java 16
|
||||
'1.17+ (21w19a+):至少 Java 16
|
||||
MinVer = New Version(1, 16, 0, 0)
|
||||
ElseIf McVersionCurrent.ReleaseTime.Year >= 2017 Then 'Minecraft 1.12 与 1.11 的分界线正好是 2017 年,太棒了
|
||||
'1.12+:至少 Java 8
|
||||
@@ -1173,6 +1179,9 @@ SystemBrowser:
|
||||
ElseIf McVersionCurrent.Version.McCodeMain <= 15 AndAlso McVersionCurrent.Version.McCodeMain > 0 Then
|
||||
'1.15:Java 8 - 15
|
||||
MinVer = New Version(1, 8, 0, 0) : MaxVer = New Version(1, 15, 999, 999)
|
||||
ElseIf VersionSortBoolean(McVersionCurrent.Version.ForgeVersion, "34.0.0") AndAlso VersionSortBoolean("36.2.25", McVersionCurrent.Version.ForgeVersion) Then
|
||||
'1.16.X,Forge 34.X ~ 36.2.25:最高 Java 8u320
|
||||
MaxVer = New Version(1, 8, 0, 320)
|
||||
ElseIf McVersionCurrent.Version.McCodeMain >= 18 AndAlso McVersionCurrent.Version.McCodeMain < 99 AndAlso McVersionCurrent.Version.HasOptiFine Then '#305
|
||||
'1.18+:若安装了 OptiFine,最高 Java 18
|
||||
MaxVer = New Version(1, 18, 999, 999)
|
||||
@@ -1192,7 +1201,7 @@ SystemBrowser:
|
||||
|
||||
'统一通行证检测
|
||||
If Setup.Get("LoginType") = McLoginType.Nide Then
|
||||
'至少 Java 8.101 (1.8.0.101)
|
||||
'至少 Java 8u101
|
||||
MinVer = If(New Version(1, 8, 0, 101) > MinVer, New Version(1, 8, 0, 101), MinVer)
|
||||
End If
|
||||
|
||||
@@ -1243,16 +1252,15 @@ SystemBrowser:
|
||||
''' 获取 Java Wrapper 所在的文件夹,不以 \ 结尾。
|
||||
''' </summary>
|
||||
Public Function GetJavaWrapperDir() As String
|
||||
Dim WrapperPath As String = PathAppdata.TrimEnd("\")
|
||||
If Encoding.UTF8.GetByteCount(WrapperPath) <> WrapperPath.Length Then
|
||||
Log("[Java] AppData 路径中包含非 ASCII 字符,换用 Temp 目录")
|
||||
WrapperPath = PathTemp.TrimEnd("\")
|
||||
If Encoding.UTF8.GetByteCount(PathTemp) <> PathTemp.Length Then
|
||||
Log("[Java] Temp 路径中包含非 ASCII 字符,换用 C 盘根目录")
|
||||
WrapperPath = "C:\PCL"
|
||||
End If
|
||||
If Encoding.UTF8.GetByteCount(PathAppdata) = PathAppdata.Length Then
|
||||
Return PathAppdata.TrimEnd("\")
|
||||
ElseIf Encoding.UTF8.GetByteCount(PathTemp) = PathTemp.Length Then
|
||||
Log("[Java] Wrapper:AppData 路径中包含非 ASCII 字符,换用 Temp 目录")
|
||||
Return PathTemp.TrimEnd("\")
|
||||
Else
|
||||
Log("[Java] Wrapper:AppData 路径与 Temp 路径中均包含非 ASCII 字符,换用 ProgramData 目录")
|
||||
Return OsDrive & "ProgramData\PCL"
|
||||
End If
|
||||
Return WrapperPath
|
||||
End Function
|
||||
|
||||
'主方法,合并 Jvm、Game、Replace 三部分的参数数据
|
||||
@@ -1825,9 +1833,13 @@ NextVersion:
|
||||
PackFormat = 9
|
||||
End If
|
||||
Case 19
|
||||
PackFormat = 9
|
||||
If McVersionCurrent.Version.McCodeSub <= 2 Then
|
||||
PackFormat = 9
|
||||
Else
|
||||
PackFormat = 12
|
||||
End If
|
||||
Case Else
|
||||
PackFormat = 10
|
||||
PackFormat = 13
|
||||
End Select
|
||||
McLaunchLog("正在构建自定义皮肤资源包,格式为:" & PackFormat)
|
||||
'准备文件
|
||||
@@ -1898,7 +1910,11 @@ IgnoreCustomSkin:
|
||||
End Try
|
||||
|
||||
End Sub
|
||||
Private Sub McLaunchRun(Loader As LoaderTask(Of Integer, Process))
|
||||
Private Sub McLaunchCustom(Loader As LoaderTask(Of Integer, Integer))
|
||||
|
||||
'获取自定义命令
|
||||
Dim CustomCommand As String = Setup.Get("VersionAdvanceRun", Version:=McVersionCurrent)
|
||||
If CustomCommand <> "" Then CustomCommand = ArgumentReplace(CustomCommand)
|
||||
|
||||
'输出 bat
|
||||
Try
|
||||
@@ -1908,10 +1924,12 @@ IgnoreCustomSkin:
|
||||
"echo 游戏正在启动,请稍候。" & vbCrLf &
|
||||
"set APPDATA=""" & PathMcFolder & """" & vbCrLf &
|
||||
"cd /D """ & PathMcFolder & """" & vbCrLf &
|
||||
CustomCommand & vbCrLf &
|
||||
"""" & McLaunchJavaSelected.PathJava & """ " & McLaunchArgument & vbCrLf &
|
||||
"echo 游戏已退出。" & vbCrLf &
|
||||
"pause"
|
||||
WriteFile(If(McLaunchLoader.Input.SaveBatch, Path & "PCL\LatestLaunch.bat"), CmdString, Encoding:=Encoding.GetEncoding("GB18030"))
|
||||
WriteFile(If(McLaunchLoader.Input.SaveBatch, Path & "PCL\LatestLaunch.bat"), CmdString,
|
||||
Encoding:=If(Encoding.Default.Equals(Encoding.UTF8), Encoding.UTF8, Encoding.GetEncoding("GB18030")))
|
||||
If McLaunchLoader.Input.SaveBatch IsNot Nothing Then
|
||||
McLaunchLog("导出启动脚本完成,强制结束启动过程")
|
||||
AbortHint = "导出启动脚本成功!"
|
||||
@@ -1924,6 +1942,30 @@ IgnoreCustomSkin:
|
||||
If McLaunchLoader.Input.SaveBatch IsNot Nothing Then Throw ex '直接触发启动失败
|
||||
End Try
|
||||
|
||||
'执行自定义命令
|
||||
If CustomCommand <> "" Then
|
||||
McLaunchLog("正在执行自定义命令:" & CustomCommand)
|
||||
Try
|
||||
Dim Cmd As New Process
|
||||
Cmd.StartInfo.FileName = "cmd.exe"
|
||||
Cmd.StartInfo.Arguments = "/c """ & CustomCommand & """"
|
||||
Cmd.StartInfo.WorkingDirectory = Path
|
||||
Cmd.StartInfo.UseShellExecute = False
|
||||
Cmd.StartInfo.CreateNoWindow = True
|
||||
Cmd.Start()
|
||||
If Setup.Get("VersionAdvanceRunWait", Version:=McVersionCurrent) Then
|
||||
Do Until Cmd.HasExited OrElse Loader.IsAborted
|
||||
Thread.Sleep(10)
|
||||
Loop
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "执行自定义命令失败", LogLevel.Hint)
|
||||
End Try
|
||||
End If
|
||||
|
||||
End Sub
|
||||
Private Sub McLaunchRun(Loader As LoaderTask(Of Integer, Process))
|
||||
|
||||
'启动信息
|
||||
Dim GameProcess = New Process()
|
||||
Dim StartInfo As New ProcessStartInfo(McLaunchJavaSelected.PathJavaw)
|
||||
@@ -2046,6 +2088,45 @@ IgnoreCustomSkin:
|
||||
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 在启动结束时,对 PCL 约定的替换标记进行处理。
|
||||
''' </summary>
|
||||
Private Function ArgumentReplace(Raw As String) As String
|
||||
If Raw Is Nothing Then Return Nothing
|
||||
'路径替换
|
||||
Raw = Raw.Replace("{minecraft}", PathMcFolder)
|
||||
Raw = Raw.Replace("{verpath}", McVersionCurrent.Path)
|
||||
Raw = Raw.Replace("{verindie}", McVersionCurrent.PathIndie)
|
||||
Raw = Raw.Replace("{java}", McLaunchJavaSelected.PathFolder)
|
||||
'普通替换
|
||||
Raw = Raw.Replace("{user}", McLoginLoader.Output.Name)
|
||||
Raw = Raw.Replace("{uuid}", McLoginLoader.Output.Uuid)
|
||||
Select Case McLoginLoader.Input.Type
|
||||
Case McLoginType.Legacy
|
||||
If PageLinkHiper.HiperState = LoadState.Finished Then
|
||||
Raw = Raw.Replace("{login}", "联机离线")
|
||||
Else
|
||||
Raw = Raw.Replace("{login}", "离线")
|
||||
End If
|
||||
Case McLoginType.Mojang
|
||||
Raw = Raw.Replace("{login}", "Mojang 正版")
|
||||
Case McLoginType.Ms
|
||||
Raw = Raw.Replace("{login}", "微软正版")
|
||||
Case McLoginType.Nide
|
||||
Raw = Raw.Replace("{login}", "统一通行证")
|
||||
Case McLoginType.Auth
|
||||
Raw = Raw.Replace("{login}", "Authlib-Injector")
|
||||
End Select
|
||||
Raw = Raw.Replace("{name}", McVersionCurrent.Name)
|
||||
If {"unknown", "old", "pending"}.Contains(McVersionCurrent.Version.McName.ToLower) Then
|
||||
Raw = Raw.Replace("{version}", McVersionCurrent.Name)
|
||||
Else
|
||||
Raw = Raw.Replace("{version}", McVersionCurrent.Version.McName)
|
||||
End If
|
||||
Raw = Raw.Replace("{path}", Path)
|
||||
Return Raw
|
||||
End Function
|
||||
|
||||
#End Region
|
||||
|
||||
End Module
|
||||
|
||||
@@ -10,7 +10,7 @@ Public Module ModMinecraft
|
||||
''' <summary>
|
||||
''' 目前所有可用的 Java。
|
||||
''' </summary>
|
||||
Public JavaList As List(Of JavaEntry)
|
||||
Public JavaList As New List(Of JavaEntry)
|
||||
''' <summary>
|
||||
''' 初始化 Java 列表,但除非没有 Java,否则不进行检查。
|
||||
''' </summary>
|
||||
@@ -72,7 +72,7 @@ Public Module ModMinecraft
|
||||
End Get
|
||||
End Property
|
||||
''' <summary>
|
||||
''' Javaw.exe 文件所在文件夹的路径,以 \ 结尾且只含有 \。
|
||||
''' Javaw.exe 文件所在文件夹的路径,以 \ 结尾。
|
||||
''' </summary>
|
||||
Public PathFolder As String
|
||||
''' <summary>
|
||||
@@ -156,7 +156,8 @@ Public Module ModMinecraft
|
||||
End If
|
||||
IsJre = Not File.Exists(PathFolder & "javac.exe")
|
||||
'运行 -version
|
||||
Output = ShellAndGetOutput(PathFolder & "java.exe", "-version", 8000).ToLower
|
||||
Output = ShellAndGetOutput(PathFolder & "java.exe", "-version", 15000).ToLower
|
||||
If Output = "" Then Throw New Exception("尝试运行该 Java 失败")
|
||||
If ModeDebug Then Log("[Java] Java 检查输出:" & PathFolder & "java.exe" & vbCrLf & Output)
|
||||
'获取详细信息
|
||||
Dim VersionString = If(RegexSeek(Output, "(?<=version "")[^""]+"), If(RegexSeek(Output, "(?<=openjdk )[0-9]+"), "")).Replace("_", ".").Split("-").First
|
||||
@@ -281,7 +282,10 @@ Public Module ModMinecraft
|
||||
|
||||
'确保可用并获取详细信息,转入正式列表
|
||||
Dim NewJavaList As New List(Of JavaEntry)
|
||||
For Each Entry In JavaPreList
|
||||
For Each Entry In ArrayNoDouble(JavaPreList.ToList,
|
||||
Function(a As KeyValuePair(Of String, Boolean), b As KeyValuePair(Of String, Boolean))
|
||||
Return a.Key.ToLower = b.Key.ToLower '#794
|
||||
End Function)
|
||||
NewJavaList.Add(New JavaEntry(Entry.Key, Entry.Value))
|
||||
Next
|
||||
NewJavaList = Sort(JavaCheckList(NewJavaList), AddressOf JavaSorter)
|
||||
@@ -469,8 +473,8 @@ RetryGet:
|
||||
Try
|
||||
UserJava = JavaEntry.FromJson(GetJson(UserSetup))
|
||||
Catch ex As Exception
|
||||
Setup.Set("LaunchArgumentJavaSelect", "")
|
||||
Log(ex, "获取储存的 Java 失败")
|
||||
Setup.Set("LaunchArgumentJavaSelect", "使用全局设置")
|
||||
Log(ex, "版本指定的 Java 信息已损坏,已重置版本设置中指定的 Java")
|
||||
GoTo UserPass
|
||||
End Try
|
||||
For Each Java In AllowedJavaList
|
||||
@@ -483,20 +487,25 @@ RetryGet:
|
||||
Log("[Java] 发现用户指定的不兼容 Java:" & UserJava.ToString)
|
||||
'弹窗要求选择
|
||||
Dim Requirement As String = ""
|
||||
If (MinVersion Is Nothing OrElse MinVersion.Minor = 0) AndAlso (MaxVersion IsNot Nothing AndAlso MaxVersion.Minor < 99) Then
|
||||
Requirement = "最高兼容到 Java " & MaxVersion.Minor & If(MaxVersion.MinorRevision < 99, "." & MaxVersion.MinorRevision & "." & MaxVersion.Revision, "")
|
||||
ElseIf (MinVersion IsNot Nothing AndAlso MinVersion.Minor > 0) AndAlso (MaxVersion Is Nothing OrElse MaxVersion.Minor >= 99) Then
|
||||
Requirement = "至少需要 Java " & MinVersion.Minor & If(MinVersion.MinorRevision > 0 OrElse MinVersion.Revision > 0, "." & MinVersion.MinorRevision & "." & MinVersion.Revision, "")
|
||||
ElseIf (MinVersion IsNot Nothing AndAlso MinVersion.Minor > 0) AndAlso (MaxVersion IsNot Nothing AndAlso MaxVersion.Minor < 99) Then
|
||||
Dim Left As String = MinVersion.Minor & If(MinVersion.MinorRevision > 0 OrElse MinVersion.Revision > 0, "." & MinVersion.MinorRevision & "." & MinVersion.Revision, "")
|
||||
Dim Right As String = MaxVersion.Minor & If(MaxVersion.MinorRevision < 99, "." & MaxVersion.MinorRevision & "." & MaxVersion.Revision, "")
|
||||
Dim ShowRevision As Boolean = False
|
||||
If (MinVersion Is Nothing OrElse MinVersion.Minor = 0) AndAlso (MaxVersion IsNot Nothing AndAlso MaxVersion.Minor < 999) Then
|
||||
ShowRevision = MaxVersion.MinorRevision < 999
|
||||
Requirement = "最高兼容到 Java " & MaxVersion.Minor & If(ShowRevision, "." & MaxVersion.MajorRevision & "." & MaxVersion.MinorRevision, "")
|
||||
ElseIf (MinVersion IsNot Nothing AndAlso MinVersion.Minor > 0) AndAlso (MaxVersion Is Nothing OrElse MaxVersion.Minor >= 999) Then
|
||||
ShowRevision = MinVersion.MinorRevision > 0 OrElse MinVersion.MajorRevision > 0
|
||||
Requirement = "至少需要 Java " & MinVersion.Minor & If(ShowRevision, "." & MinVersion.MajorRevision & "." & MinVersion.MinorRevision, "")
|
||||
ElseIf (MinVersion IsNot Nothing AndAlso MinVersion.Minor > 0) AndAlso (MaxVersion IsNot Nothing AndAlso MaxVersion.Minor < 999) Then
|
||||
ShowRevision = MinVersion.MinorRevision > 0 OrElse MinVersion.MajorRevision > 0 OrElse MaxVersion.MinorRevision < 999
|
||||
Dim Left As String = MinVersion.Minor & If(ShowRevision, "." & MinVersion.MajorRevision & "." & MinVersion.MinorRevision, "")
|
||||
Dim Right As String = MaxVersion.Minor & If(ShowRevision, "." & MaxVersion.MajorRevision & "." & MaxVersion.MinorRevision, "")
|
||||
Requirement = "需要 Java " & If(Left = Right, Left, Left & " ~ " & Right)
|
||||
End If
|
||||
Dim JavaCurrent As String = UserJava.VersionCode & If(ShowRevision, "." & UserJava.Version.MajorRevision & "." & UserJava.Version.MinorRevision, "")
|
||||
If Setup.Get("LaunchAdvanceJava") Then
|
||||
'直接跳过弹窗
|
||||
Hint("设置中指定了使用 Java " & UserJava.VersionCode & ",但当前版本" & Requirement & ",这可能会导致游戏崩溃!", HintType.Critical)
|
||||
Hint("设置中指定了使用 Java " & JavaCurrent & ",但当前版本" & Requirement & ",这可能会导致游戏崩溃!", HintType.Critical)
|
||||
AllowedJavaList = New List(Of JavaEntry) From {UserJava}
|
||||
ElseIf MyMsgBox("你在启动设置中指定了使用 Java " & UserJava.VersionCode & ",但当前版本" & Requirement & "。" & vbCrLf &
|
||||
ElseIf MyMsgBox("你在启动设置中指定了使用 Java " & JavaCurrent & ",但当前版本" & Requirement & "。" & vbCrLf &
|
||||
"如果强制使用该 Java,可能会导致游戏崩溃。" & vbCrLf &
|
||||
vbCrLf &
|
||||
" - 指定的 Java:" & UserJava.ToString,
|
||||
@@ -530,6 +539,7 @@ UserPass:
|
||||
SelectedJava.Check()
|
||||
Catch ex As Exception
|
||||
Log(ex, "找到的 Java 已无法使用,尝试进行搜索")
|
||||
AllowedJavaList = New List(Of JavaEntry)
|
||||
JavaSearchLoader.Start(IsForceRestart:=True)
|
||||
GoTo RetryGet
|
||||
End Try
|
||||
@@ -558,11 +568,19 @@ UserPass:
|
||||
If UserSetupVersion <> "使用全局设置" Then UserSetup = UserSetupVersion
|
||||
End If
|
||||
If UserSetup <> "" Then
|
||||
Dim UserJava = JavaEntry.FromJson(GetJson(UserSetup))
|
||||
Dim UserJava As JavaEntry = Nothing
|
||||
Try
|
||||
UserJava = JavaEntry.FromJson(GetJson(UserSetup))
|
||||
Catch ex As Exception
|
||||
Log(ex, "版本指定的 Java 信息已损坏,已重置版本设置中指定的 Java")
|
||||
Setup.Set("VersionArgumentJavaSelect", "使用全局设置", Version:=RelatedVersion)
|
||||
GoTo NoUserJava
|
||||
End Try
|
||||
For Each Java In JavaList
|
||||
If Java.PathFolder = UserJava.PathFolder Then Return UserJava.Is64Bit
|
||||
Next
|
||||
End If
|
||||
NoUserJava:
|
||||
'检查列表
|
||||
For Each Java In JavaList
|
||||
If Java.Is64Bit Then Return True
|
||||
@@ -571,7 +589,6 @@ UserPass:
|
||||
Catch ex As Exception
|
||||
Log(ex, "检查 Java 类别时出错", LogLevel.Feedback)
|
||||
Setup.Set("LaunchArgumentJavaSelect", "")
|
||||
Setup.Set("VersionArgumentJavaSelect", "", Version:=RelatedVersion)
|
||||
Return True
|
||||
End Try
|
||||
End Function
|
||||
@@ -615,7 +632,7 @@ UserPass:
|
||||
MyMsgBox("PCL2 未找到 Java 7。" & vbCrLf &
|
||||
"请自行百度安装 Java 7,安装后在 PCL2 的 设置 → 启动设置 → 游戏 Java 中通过搜索或导入,确保安装的 Java 已列入 Java 列表。",
|
||||
"未找到 Java")
|
||||
Case 8
|
||||
Case 8 '291
|
||||
If Is32BitSystem Then
|
||||
OpenWebsite("https://wwa.lanzoui.com/i7RyXq0jbub")
|
||||
Else
|
||||
@@ -816,6 +833,8 @@ UserPass:
|
||||
_McVersionCurrent = value '由于有可能是 Nothing,导致无法初始化,才得这样弄一圈
|
||||
_McVersionLast = value
|
||||
If value Is Nothing Then Exit Property
|
||||
'重置缓存的 Mod 文件夹
|
||||
PageDownloadCfDetail.CachedFolder = Nothing
|
||||
'统一通行证重判
|
||||
If AniControlEnabled = 0 AndAlso
|
||||
Setup.Get("VersionServerNide", Version:=value) <> Setup.Get("CacheNideServer") AndAlso
|
||||
@@ -936,6 +955,7 @@ UserPass:
|
||||
''' </summary>
|
||||
Public ReadOnly Property Modable As Boolean
|
||||
Get
|
||||
If Not IsLoaded Then Load()
|
||||
Return Version.HasFabric OrElse Version.HasForge OrElse Version.HasLiteLoader OrElse
|
||||
DisplayType = McVersionCardType.API '#223
|
||||
End Get
|
||||
@@ -1770,7 +1790,8 @@ OnLoaded:
|
||||
Version.State = ReadIni(Version.Path & "PCL\Setup.ini", "State", Version.State)
|
||||
Version.IsStar = ReadIni(Version.Path & "PCL\Setup.ini", "IsStar", False)
|
||||
Version.DisplayType = ReadIni(Path & "PCL\Setup.ini", "DisplayType", McVersionCardType.Auto)
|
||||
If Version.State <> McVersionState.Error Then
|
||||
If Version.State <> McVersionState.Error AndAlso
|
||||
ReadIni(Version.Path & "PCL\Setup.ini", "VersionOriginal", "Unknown") <> "Unknown" Then '旧版本可能没有这一项,导致 Version 不加载(#643)
|
||||
Dim VersionInfo As New McVersionInfo With {
|
||||
.FabricVersion = ReadIni(Version.Path & "PCL\Setup.ini", "VersionFabric", ""),
|
||||
.ForgeVersion = ReadIni(Version.Path & "PCL\Setup.ini", "VersionForge", ""),
|
||||
@@ -3511,10 +3532,16 @@ VersionFindFail:
|
||||
'获取 Mod 文件夹下的可用文件列表
|
||||
Dim ModFileList As New List(Of FileInfo)
|
||||
If Directory.Exists(Loader.Input) Then
|
||||
For Each File As FileInfo In New DirectoryInfo(Loader.Input).EnumerateFiles("*.*", SearchOption.AllDirectories)
|
||||
Dim DirName As String = File.DirectoryName.ToLower
|
||||
If DirName.StartsWith(Loader.Input & "memory_repo") OrElse DirName.StartsWith(".") OrElse
|
||||
((DirName & "\") <> Loader.Input AndAlso DirName.Contains("voxel")) Then Continue For
|
||||
Dim RawName As String = Loader.Input.ToLower
|
||||
For Each File As FileInfo In EnumerateFiles(Loader.Input)
|
||||
If File.DirectoryName.ToLower & "\" <> RawName Then
|
||||
'仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod
|
||||
If Not (PageVersionLeft.Version IsNot Nothing AndAlso PageVersionLeft.Version.Version.HasForge AndAlso
|
||||
PageVersionLeft.Version.Version.McCodeMain < 13 AndAlso
|
||||
File.Directory.Name = "1." & PageVersionLeft.Version.Version.McCodeMain & "." & PageVersionLeft.Version.Version.McCodeSub) Then
|
||||
Continue For
|
||||
End If
|
||||
End If
|
||||
If McMod.IsModFile(File.FullName) Then ModFileList.Add(File)
|
||||
Next
|
||||
End If
|
||||
@@ -3730,7 +3757,7 @@ VersionFindFail:
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 比较两个版本名的排序,若 Left 较新则返回 True。无法比较两个 Pre 的大小。
|
||||
''' 比较两个版本名的排序,若 Left 较新或相同则返回 True(Left >= Right)。无法比较两个 Pre 的大小。
|
||||
''' 支持的格式范例:未知版本, 1.13.2, 1.7.10-pre4, 1.8_pre, 1.14 Pre-Release 2, 1.14.4 C6
|
||||
''' </summary>
|
||||
Public Function VersionSortBoolean(Left As String, Right As String) As Boolean
|
||||
@@ -3829,46 +3856,5 @@ NextEntry:
|
||||
Return "".PadLeft(Account.Count, "*")
|
||||
End If
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 对 PCL 约定的替换标记进行处理。
|
||||
''' </summary>
|
||||
Public Function ArgumentReplace(Raw As String) As String
|
||||
If Raw Is Nothing Then Return Nothing
|
||||
Raw = Raw.Replace("{user}", If(IsNothing(McLoginLoader.Output), "尚未登录", McLoginLoader.Output.Name))
|
||||
If IsNothing(McLoginLoader.Input) Then
|
||||
Raw = Raw.Replace("{login}", "尚未登录")
|
||||
Else
|
||||
Select Case McLoginLoader.Input.Type
|
||||
Case McLoginType.Legacy
|
||||
If PageLinkHiper.HiperState = LoadState.Finished Then
|
||||
Raw = Raw.Replace("{login}", "联机离线")
|
||||
Else
|
||||
Raw = Raw.Replace("{login}", "离线")
|
||||
End If
|
||||
Case McLoginType.Mojang
|
||||
Raw = Raw.Replace("{login}", "Mojang 正版")
|
||||
Case McLoginType.Ms
|
||||
Raw = Raw.Replace("{login}", "微软正版")
|
||||
Case McLoginType.Nide
|
||||
Raw = Raw.Replace("{login}", "统一通行证")
|
||||
Case McLoginType.Auth
|
||||
Raw = Raw.Replace("{login}", "Authlib-Injector")
|
||||
End Select
|
||||
End If
|
||||
If McVersionCurrent Is Nothing Then
|
||||
Raw = Raw.Replace("{name}", "无可用版本")
|
||||
Raw = Raw.Replace("{version}", "无可用版本")
|
||||
Else
|
||||
Raw = Raw.Replace("{name}", McVersionCurrent.Name)
|
||||
If Not McVersionCurrent.IsLoaded Then McVersionCurrent.Load()
|
||||
If {"unknown", "old", "pending"}.Contains(McVersionCurrent.Version.McName.ToLower) Then
|
||||
Raw = Raw.Replace("{version}", McVersionCurrent.Name)
|
||||
Else
|
||||
Raw = Raw.Replace("{version}", McVersionCurrent.Version.McName)
|
||||
End If
|
||||
End If
|
||||
Raw = Raw.Replace("{path}", Path)
|
||||
Return Raw
|
||||
End Function
|
||||
|
||||
End Module
|
||||
|
||||
@@ -329,8 +329,7 @@ Retry:
|
||||
Dim PackName As String = If(Json("name"), "")
|
||||
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
|
||||
If Validate.Validate(PackName) <> "" Then PackName = ""
|
||||
VersionName = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
|
||||
Title:="输入版本名", Button2:="取消")
|
||||
VersionName = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
|
||||
If String.IsNullOrEmpty(VersionName) Then Exit Sub
|
||||
End If
|
||||
|
||||
@@ -358,8 +357,7 @@ Retry:
|
||||
Dim PackName As String = If(Json("name"), "")
|
||||
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
|
||||
If Validate.Validate(PackName) <> "" Then PackName = ""
|
||||
Dim VersionName As String = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
|
||||
Title:="输入版本名", Button2:="取消")
|
||||
Dim VersionName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
|
||||
If VersionName Is Nothing Then Exit Sub
|
||||
'解压与配置文件
|
||||
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
|
||||
@@ -454,8 +452,7 @@ Retry:
|
||||
Dim PackName As String = If(RegexSeek(PackInstance, "(?<=\nname\=)[^\n]+"), "")
|
||||
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
|
||||
If Validate.Validate(PackName) <> "" Then PackName = ""
|
||||
Dim VersionName As String = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
|
||||
Title:="输入版本名", Button2:="取消")
|
||||
Dim VersionName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
|
||||
If VersionName Is Nothing Then Exit Sub
|
||||
'解压与配置文件
|
||||
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
|
||||
@@ -542,8 +539,7 @@ Retry:
|
||||
Dim PackName As String = If(Json("name"), "")
|
||||
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
|
||||
If Validate.Validate(PackName) <> "" Then PackName = ""
|
||||
Dim VersionName As String = MyMsgBoxInput(PackName, New ObjectModel.Collection(Of Validate) From {Validate},
|
||||
Title:="输入版本名", Button2:="取消")
|
||||
Dim VersionName As String = MyMsgBoxInput("输入版本名称", "", PackName, New ObjectModel.Collection(Of Validate) From {Validate})
|
||||
If VersionName Is Nothing Then Exit Sub
|
||||
'解压与配置文件
|
||||
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
|
||||
@@ -625,9 +621,8 @@ Retry:
|
||||
If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Exit Sub
|
||||
If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Exit Sub
|
||||
'要求显示名称
|
||||
Dim NewName As String = MyMsgBoxInput(GetFolderNameFromPath(TargetFolder), New ObjectModel.Collection(Of Validate) From {
|
||||
New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})
|
||||
},, "输入它在列表中的显示名称",, "取消")
|
||||
Dim NewName As String = MyMsgBoxInput("输入显示名称", "输入该文件夹在左边栏列表中显示的名称。", GetFolderNameFromPath(TargetFolder),
|
||||
New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})})
|
||||
If String.IsNullOrWhiteSpace(NewName) Then Exit Sub
|
||||
'解压
|
||||
Hint("正在解压压缩包……")
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
Public HasRunningMinecraft As Boolean = False
|
||||
Private Sub WatcherStateChanged()
|
||||
Dim IsRunning As Boolean = False
|
||||
Dim IsCrashed As Boolean = False
|
||||
Dim TriggerLauncherShutdown As Boolean = True
|
||||
For Each Watcher In McWatcherList
|
||||
If Watcher.State = Watcher.MinecraftState.Loading OrElse Watcher.State = Watcher.MinecraftState.Running Then
|
||||
IsRunning = True
|
||||
Exit For
|
||||
ElseIf Watcher.State = Watcher.MinecraftState.Crashed Then
|
||||
IsCrashed = True
|
||||
ElseIf Watcher.State = Watcher.MinecraftState.Crashed OrElse Watcher.State = Watcher.MinecraftState.Canceled Then
|
||||
TriggerLauncherShutdown = False
|
||||
End If
|
||||
Next
|
||||
If IsWatcherRunning = IsRunning Then Exit Sub
|
||||
@@ -20,7 +20,7 @@
|
||||
If IsWatcherRunning Then
|
||||
MinecraftStart()
|
||||
Else
|
||||
MinecraftStop(IsCrashed)
|
||||
MinecraftStop(TriggerLauncherShutdown)
|
||||
End If
|
||||
End Sub
|
||||
Private Sub MinecraftStart()
|
||||
@@ -28,7 +28,7 @@
|
||||
HasRunningMinecraft = True
|
||||
FrmMain.BtnExtraShutdown.ShowRefresh()
|
||||
End Sub
|
||||
Private Sub MinecraftStop(HasMinecraftCrashed As Boolean)
|
||||
Private Sub MinecraftStop(TriggerLauncherShutdown As Boolean)
|
||||
McLaunchLog("[全局] 已无运行中的 Minecraft")
|
||||
HasRunningMinecraft = False
|
||||
FrmMain.BtnExtraShutdown.ShowRefresh()
|
||||
@@ -42,10 +42,10 @@
|
||||
Select Case Setup.Get("LaunchArgumentVisible")
|
||||
Case 2
|
||||
'直接关闭
|
||||
If HasMinecraftCrashed Then
|
||||
RunInUi(Sub() FrmMain.Hidden = False)
|
||||
Else
|
||||
If TriggerLauncherShutdown Then
|
||||
RunInUi(Sub() FrmMain.EndProgram(False))
|
||||
Else
|
||||
RunInUi(Sub() FrmMain.Hidden = False)
|
||||
End If
|
||||
Case 3
|
||||
'恢复
|
||||
@@ -73,7 +73,7 @@
|
||||
'更改列表
|
||||
Dim NewWatcherList As New List(Of Watcher)
|
||||
For Each Watch In McWatcherList
|
||||
If Watch.State = MinecraftState.Crashed OrElse Watch.State = MinecraftState.Ended Then Continue For
|
||||
If Watch.State = MinecraftState.Crashed OrElse Watch.State = MinecraftState.Ended OrElse Watch.State = MinecraftState.Canceled Then Continue For
|
||||
NewWatcherList.Add(Watch)
|
||||
Next
|
||||
NewWatcherList.Add(Me)
|
||||
@@ -90,8 +90,7 @@
|
||||
'初始化时钟
|
||||
RunInNewThread(Sub()
|
||||
Try
|
||||
MinecraftBeforeLaunch = GetAllMinecraftWindowHandle(False).Keys.ToList
|
||||
Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse Loader.State = LoadState.Aborted
|
||||
Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse State = MinecraftState.Canceled OrElse Loader.State = LoadState.Aborted
|
||||
TimerWindow()
|
||||
TimerLog()
|
||||
'设置窗口标题
|
||||
@@ -128,6 +127,7 @@
|
||||
Running
|
||||
Crashed
|
||||
Ended
|
||||
Canceled
|
||||
End Enum
|
||||
|
||||
'日志
|
||||
@@ -250,77 +250,72 @@
|
||||
Private IsWindowAppeared As Boolean = False
|
||||
Private IsWindowFinished As Boolean = False
|
||||
Private WindowHandle As IntPtr
|
||||
Private MinecraftBeforeLaunch As List(Of IntPtr)
|
||||
Private Sub TimerWindow()
|
||||
Try
|
||||
If GameProcess.HasExited Then Exit Sub
|
||||
If Not IsWindowFinished Then
|
||||
'获取全部窗口,检查是否有新增的
|
||||
Dim MinecraftWindows = GetAllMinecraftWindowHandle(True)
|
||||
For Each Window In MinecraftBeforeLaunch
|
||||
If MinecraftWindows.ContainsKey(Window) Then MinecraftWindows.Remove(Window)
|
||||
Next
|
||||
If MinecraftWindows.Count = 0 Then Exit Sub
|
||||
'已找到窗口
|
||||
If MinecraftWindows.Values(0) Then
|
||||
'已找到 Minecraft 窗口
|
||||
WindowHandle = MinecraftWindows.Keys(0)
|
||||
WatcherLog("Minecraft 窗口已加载:" & WindowHandle.ToInt64)
|
||||
IsWindowFinished = True
|
||||
'最大化
|
||||
If Setup.Get("LaunchArgumentWindowType") = 4 Then
|
||||
RunInNewThread(Sub()
|
||||
Try
|
||||
'如果最大化导致屏幕渲染大小不对,那是 MC 的 Bug,不是我的 Bug
|
||||
'……虽然我很想这样说,但总有人反馈,算了
|
||||
Thread.Sleep(1000)
|
||||
ShowWindow(WindowHandle, 3)
|
||||
Catch ex As Exception
|
||||
Log(ex, "最大化 Minecraft 窗口时出现错误")
|
||||
End Try
|
||||
End Sub, "MinecraftWindowMaximize")
|
||||
End If
|
||||
ElseIf Not IsWindowAppeared Then
|
||||
'已找到 FML 窗口
|
||||
WatcherLog("FML 窗口已加载:" & MinecraftWindows.Keys(0).ToInt64)
|
||||
If IsWindowFinished Then Exit Sub
|
||||
'获取全部窗口,检查是否有新增的
|
||||
Dim MinecraftWindow = TryGetMinecraftWindow()
|
||||
If MinecraftWindow Is Nothing Then Exit Sub
|
||||
Dim MinecraftWindowName = MinecraftWindow.Value.Value, MinecraftWindowHandle = MinecraftWindow.Value.Key
|
||||
'已找到窗口
|
||||
If Not MinecraftWindowName.StartsWith("FML") Then
|
||||
'已找到 Minecraft 窗口
|
||||
WindowHandle = MinecraftWindowHandle
|
||||
WatcherLog("Minecraft 窗口已加载:" & MinecraftWindowName & "(" & MinecraftWindowHandle.ToInt64 & ")")
|
||||
IsWindowFinished = True
|
||||
'最大化
|
||||
If Setup.Get("LaunchArgumentWindowType") = 4 Then
|
||||
RunInNewThread(Sub()
|
||||
Try
|
||||
'如果最大化导致屏幕渲染大小不对,那是 MC 的 Bug,不是我的 Bug
|
||||
'……虽然我很想这样说,但总有人反馈,算了
|
||||
Thread.Sleep(2000)
|
||||
ShowWindow(WindowHandle, 3)
|
||||
Catch ex As Exception
|
||||
Log(ex, "最大化 Minecraft 窗口时出现错误")
|
||||
End Try
|
||||
End Sub, "MinecraftWindowMaximize")
|
||||
End If
|
||||
IsWindowAppeared = True
|
||||
ElseIf Not IsWindowAppeared Then
|
||||
'已找到 FML 窗口
|
||||
WatcherLog("FML 窗口已加载:" & MinecraftWindowName & "(" & MinecraftWindowHandle.ToInt64 & ")")
|
||||
End If
|
||||
IsWindowAppeared = True
|
||||
Catch ex As Exception
|
||||
Log(ex, "检查 Minecraft 窗口失败", LogLevel.Feedback)
|
||||
End Try
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 获取所有 Minecraft 窗口句柄。
|
||||
''' Value: 是否为 Minecraft 窗口,而不是 FML 窗口。
|
||||
''' 获取可能是当前进程对应的 Minecraft 窗口的句柄和标题。
|
||||
''' Nothing 代表未找到。
|
||||
''' </summary>
|
||||
''' <param name="CanUseFml">是否包含 FML 窗口</param>
|
||||
Private Function GetAllMinecraftWindowHandle(CanUseFml As Boolean) As Dictionary(Of IntPtr, Boolean)
|
||||
Dim AllList As New Dictionary(Of IntPtr, Boolean)
|
||||
EnumWindows(Sub(hwnd As IntPtr, lParam As Integer)
|
||||
'检查类名
|
||||
Dim str As New StringBuilder(512)
|
||||
GetClassName(hwnd, str, str.Capacity)
|
||||
Dim ClassName As String = str.ToString
|
||||
If Not (ClassName = "GLFW30" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Exit Sub
|
||||
'检查窗口标题名
|
||||
str = New StringBuilder(512)
|
||||
GetWindowText(hwnd, str, str.Capacity)
|
||||
Dim WindowText As String = str.ToString
|
||||
If CanUseFml AndAlso WindowText.StartsWith("FML") Then
|
||||
AllList.Add(hwnd, False)
|
||||
ElseIf Not (WindowText.StartsWith("GLFW") OrElse WindowText = "PopupMessageWindow") Then
|
||||
'有的 Mod 可以修改窗口标题,不能检测是否为 Minecraft 打头
|
||||
'部分版本会搞个 GLFW message window 出来所以得反选
|
||||
AllList.Add(hwnd, True)
|
||||
End If
|
||||
'If WindowText.StartsWith("Minecraft") Then
|
||||
' AllList.Add(hwnd, True)
|
||||
'ElseIf CanUseFml AndAlso WindowText.StartsWith("FML") Then
|
||||
' AllList.Add(hwnd, False)
|
||||
'End If
|
||||
End Sub, 0)
|
||||
Return AllList
|
||||
Private Function TryGetMinecraftWindow() As KeyValuePair(Of IntPtr, String)?
|
||||
TryGetMinecraftWindow = Nothing
|
||||
EnumWindows(
|
||||
Sub(hwnd As IntPtr, lParam As Integer)
|
||||
If TryGetMinecraftWindow IsNot Nothing Then Exit Sub
|
||||
'检查类名
|
||||
Dim str As New StringBuilder(512)
|
||||
GetClassName(hwnd, str, str.Capacity)
|
||||
Dim ClassName As String = str.ToString
|
||||
If Not (ClassName = "GLFW30" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Exit Sub
|
||||
'获取窗口标题名
|
||||
str = New StringBuilder(512)
|
||||
GetWindowText(hwnd, str, str.Capacity)
|
||||
Dim WindowText As String = str.ToString
|
||||
'有的 Mod 可以修改窗口标题,所以不能检测是否为 Minecraft 打头,这并不准确
|
||||
'部分版本会搞个 GLFW message window 出来所以得反选
|
||||
If Not (WindowText.StartsWith("FML") OrElse (WindowText <> "PopupMessageWindow") AndAlso Not WindowText.StartsWith("GLFW")) Then Exit Sub
|
||||
'获取窗口关联的进程
|
||||
Dim ProcessId As Integer
|
||||
GetWindowThreadProcessId(hwnd, ProcessId)
|
||||
Dim WindowProcess = Process.GetProcessById(ProcessId)
|
||||
If WindowProcess.StartTime < GameProcess.StartTime Then Exit Sub '需要是此后启动的进程
|
||||
'返回
|
||||
TryGetMinecraftWindow = New KeyValuePair(Of IntPtr, String)(hwnd, WindowText)
|
||||
End Sub, 0)
|
||||
Return TryGetMinecraftWindow
|
||||
End Function
|
||||
Private Delegate Sub EnumWindowsSub(hwnd As IntPtr, lParam As Integer)
|
||||
Private Declare Function EnumWindows Lib "user32" (hWnd As EnumWindowsSub, lParam As Integer) As Boolean
|
||||
@@ -328,6 +323,7 @@
|
||||
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (hWnd As Integer, str As StringBuilder, maxCount As Integer) As Integer
|
||||
Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (hWnd As Integer, str As String) As Boolean
|
||||
Private Declare Function ShowWindow Lib "user32" (hWnd As IntPtr, cmdWindow As UInteger) As Boolean
|
||||
Private Declare Function GetWindowThreadProcessId Lib "user32" (hWnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
|
||||
|
||||
'崩溃处理
|
||||
Private Sub Crashed()
|
||||
@@ -356,7 +352,7 @@
|
||||
|
||||
'强制关闭
|
||||
Public Sub Kill()
|
||||
State = MinecraftState.Ended
|
||||
State = MinecraftState.Canceled
|
||||
WatcherLog("尝试强制结束 Minecraft 进程")
|
||||
Try
|
||||
If Not GameProcess.HasExited Then GameProcess.Kill()
|
||||
|
||||
Reference in New Issue
Block a user