龙腾猫跃 hace 4 años
padre
commit
c400836de8

+ 3 - 3
.github/ISSUE_TEMPLATE/bug1.yml

@@ -8,9 +8,9 @@ body:
     label: "检查项"
     label: "检查项"
     description: "请逐个检查下列项目,并勾选确认。"
     description: "请逐个检查下列项目,并勾选确认。"
     options:
     options:
-    - label: "**我所启动的游戏不是整合包,且未开启安装 Mod。** 安装 Mod 后的游戏崩溃不是 PCL2 的原因,请 **不要** 提交反馈。你可以在 QQ 群里或者论坛找人求助,但这里并不是你求助的地方。"
+    - label: "**我所启动的游戏不是整合包,且未安装任何 Mod。** 安装 Mod 后的游戏崩溃不是 PCL2 的原因,请 **不要** 提交反馈。你可以在 QQ 群里或者论坛找人求助,但这里并不是你求助的地方。"
       required: true
       required: true
-    - label: "**我已尝试使用其他启动器,其他启动器没有出现问题。** 如果其他启动器也存在问题,证明是游戏本身存在问题,并非 PCL2 的问题,请 **不要** 提交反馈。[下载其他启动器](https://www.mcbbs.net/forum.php?mod=forumdisplay&fid=43&filter=typeid&typeid=908)"
+    - label: "**我已尝试使用其他启动器,其他启动器没有出现问题。** 如果其他启动器也存在问题,证明是游戏本身的问题,并非 PCL2 的问题,请 **不要** 提交反馈。[下载其他启动器](https://www.mcbbs.net/forum.php?mod=forumdisplay&fid=43&filter=typeid&typeid=908)"
       required: true
       required: true
     - label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未修复这个 Bug。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
     - label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未修复这个 Bug。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
       required: true
       required: true
@@ -27,7 +27,7 @@ body:
   id: "yml-3"
   id: "yml-3"
   attributes:
   attributes:
     label: 错误报告、日志与附件
     label: 错误报告、日志与附件
-    description: "上传 PCL2 提供的错误报告。如果没有,也可以上传 PCL 文件夹中的 Log1~5.txt。"
+    description: "上传 PCL2 提供的错误报告(在崩溃时选择导出错误报告)。如果没有,也可以上传 PCL 文件夹中的 Log1~5.txt。"
     placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
     placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
   validations:
   validations:
     required: true
     required: true

+ 2 - 1
.gitignore

@@ -350,7 +350,8 @@ PageOtherAbout.*
 PageOtherTest.*
 PageOtherTest.*
 PageSetupUI.*
 PageSetupUI.*
 # 公开联机代码可能导致安全风险
 # 公开联机代码可能导致安全风险
-PageLink/
+Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb
+Plain Craft Launcher 2/Pages/PageLink/PageLinkHiPer.xaml.vb
 # 开发者工具
 # 开发者工具
 ModDevelop.vb
 ModDevelop.vb
 # 不公开底层函数库,以免抄袭
 # 不公开底层函数库,以免抄袭

+ 6 - 1
Plain Craft Launcher 2/FormMain.xaml.vb

@@ -142,9 +142,14 @@ Public Class FormMain
         '3:小*
         '3:小*
         '2:极度严重的 Bug
         '2:极度严重的 Bug
         '1:严重的 Bug
         '1:严重的 Bug
+        If LastVersion < 264 Then 'Snapshot 2.3.5
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法启动部分 Forge 版本的 Bug"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复多个可能导致 OptiFine、Forge 安装失败的 Bug"))
+            FeatureCount += 2
+            BugCount += 3
+        End If
         If LastVersion < 263 Then 'Snapshot 2.3.4
         If LastVersion < 263 Then 'Snapshot 2.3.4
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复部分情况下无法启动路径带有中文的游戏的 Bug"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复部分情况下无法启动路径带有中文的游戏的 Bug"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复多个可能导致 OptiFine、Forge 安装失败的 Bug"))
             FeatureCount += 11
             FeatureCount += 11
             BugCount += 5
             BugCount += 5
         End If
         End If

+ 11 - 3
Plain Craft Launcher 2/Modules/Base/ModBase.vb

@@ -10,12 +10,12 @@ Public Module ModBase
 #Region "声明"
 #Region "声明"
 
 
     '下列版本信息由更新器自动修改
     '下列版本信息由更新器自动修改
-    Public Const VersionBaseName As String = "2.3.4" '不含分支前缀的显示用版本名
-    Public Const VersionStandardCode As String = "2.3.4." & VersionBranchCode '标准格式的四段式版本号
+    Public Const VersionBaseName As String = "2.3.5" '不含分支前缀的显示用版本名
+    Public Const VersionStandardCode As String = "2.3.5." & VersionBranchCode '标准格式的四段式版本号
 #If BETA Then
 #If BETA Then
     Public Const VersionCode As Integer = 260 'Release
     Public Const VersionCode As Integer = 260 'Release
 #Else
 #Else
-    Public Const VersionCode As Integer = 263 'Snapshot
+    Public Const VersionCode As Integer = 264 'Snapshot
 #End If
 #End If
     '自动生成的版本信息
     '自动生成的版本信息
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -2476,6 +2476,14 @@ Retry:
         If Not Exp Then Throw New Exception("断言命中")
         If Not Exp Then Throw New Exception("断言命中")
     End Sub
     End Sub
 
 
+    '获取当前的堆栈信息
+    Public Function GetStackTrace() As String
+        Dim Stack As New StackTrace()
+        Return Join(Stack.GetFrames().Skip(1).Select(Function(f) f.GetMethod).
+                    Select(Function(f) f.Name & "(" & Join(f.GetParameters.Select(Function(p) p.ToString).ToList, ", ") & ") - " & f.Module.ToString).ToList,
+                    vbCrLf).Replace(vbCrLf & vbCrLf, vbCrLf)
+    End Function
+
 #End Region
 #End Region
 
 
 #Region "随机"
 #Region "随机"

+ 8 - 3
Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb

@@ -340,6 +340,7 @@
         没有可用的分析文件
         没有可用的分析文件
         使用32位Java导致JVM无法分配足够多的内存
         使用32位Java导致JVM无法分配足够多的内存
         Mod重复安装
         Mod重复安装
+        OptiFine与Forge不兼容
         Fabric报错
         Fabric报错
         Fabric报错并给出解决方案
         Fabric报错并给出解决方案
         Forge报错
         Forge报错
@@ -449,6 +450,8 @@ Done:
             If LogMc.Contains("The driver does not appear to support OpenGL") Then AppendReason(CrashReason.显卡不支持OpenGL)
             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: java.base/jdk") Then AppendReason(CrashReason.使用JDK)
             If LogMc.Contains("java.lang.ClassCastException: class 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("Open J9 is not supported") OrElse LogMc.Contains("OpenJ9 is incompatible") OrElse LogMc.Contains(".J9VMInternals.") Then AppendReason(CrashReason.使用OpenJ9)
             If LogMc.Contains("because module java.base does not export") Then AppendReason(CrashReason.Java版本过高)
             If LogMc.Contains("because module java.base does not export") Then AppendReason(CrashReason.Java版本过高)
             If LogMc.Contains("java.lang.ClassNotFoundException: java.lang.invoke.LambdaMetafactory") Then AppendReason(CrashReason.Java版本过高)
             If LogMc.Contains("java.lang.ClassNotFoundException: java.lang.invoke.LambdaMetafactory") Then AppendReason(CrashReason.Java版本过高)
@@ -554,7 +557,7 @@ Done:
         For Each Stack As String In StackSearchResults
         For Each Stack As String In StackSearchResults
             'If Not Stack.Contains(".") Then Continue For
             'If Not Stack.Contains(".") Then Continue For
             For Each IgnoreStack In {
             For Each IgnoreStack In {
-                "java", "sun", "javax", "jdk",
+                "java", "sun", "javax", "jdk", "oolloo",
                 "org.lwjgl", "com.sun", "net.minecraftforge", "com.mojang", "net.minecraft", "cpw.mods", "com.google", "org.apache", "org.spongepowered", "net.fabricmc", "com.mumfrey",
                 "org.lwjgl", "com.sun", "net.minecraftforge", "com.mojang", "net.minecraft", "cpw.mods", "com.google", "org.apache", "org.spongepowered", "net.fabricmc", "com.mumfrey",
                 "com.electronwill.nightconfig", "it.unimi.dsi",
                 "com.electronwill.nightconfig", "it.unimi.dsi",
                 "MojangTricksIntelDriversForPerformance_javaw"}
                 "MojangTricksIntelDriversForPerformance_javaw"}
@@ -580,9 +583,9 @@ NextStack:
                 If {"com", "org", "net", "asm", "fml", "mod", "jar", "sun", "lib", "map", "gui", "dev", "nio", "api", "dsi",
                 If {"com", "org", "net", "asm", "fml", "mod", "jar", "sun", "lib", "map", "gui", "dev", "nio", "api", "dsi",
                     "core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base",
                     "core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base",
                     "forge", "setup", "block", "model", "mixin", "event", "unimi",
                     "forge", "setup", "block", "model", "mixin", "event", "unimi",
-                    "common", "server", "config", "loader", "launch", "entity", "assist", "client", "modapi", "mojang", "shader", "events", "github",
+                    "common", "server", "config", "loader", "launch", "entity", "assist", "client", "modapi", "mojang", "shader", "events", "github", "recipe",
                     "preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content",
                     "preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content",
-                    "fastutil", "optifine", "minecraft", "transformers", "universal", "internal", "multipart", "minecraftforge", "override"
+                    "fastutil", "optifine", "minecraft", "transformers", "universal", "internal", "multipart", "minecraftforge", "override", "blockentity"
                    }.Contains(Word.ToLower) Then Continue For
                    }.Contains(Word.ToLower) Then Continue For
                 PossibleWords.Add(Word.Trim)
                 PossibleWords.Add(Word.Trim)
             Next
             Next
@@ -819,6 +822,8 @@ NextStack:
                 Else
                 Else
                     ResultString = "游戏似乎因为世界中的某些实体出现了问题。\n\n你可以创建一个新世界,并生成各种实体,观察游戏的运行情况:\n - 若正常运行,则是某些实体导致出错,你或许需要删除该世界。\n - 若仍然出错,问题就可能来自其他原因……\h"
                     ResultString = "游戏似乎因为世界中的某些实体出现了问题。\n\n你可以创建一个新世界,并生成各种实体,观察游戏的运行情况:\n - 若正常运行,则是某些实体导致出错,你或许需要删除该世界。\n - 若仍然出错,问题就可能来自其他原因……\h"
                 End If
                 End If
+            Case CrashReason.OptiFine与Forge不兼容
+                ResultString = "由于 OptiFine 与当前版本的 Forge 不兼容,导致了游戏崩溃。\n\n请前往 OptiFine 官网(https://optifine.net/downloads)查看 OptiFine 所兼容的 Forge 版本,并严格按照对应版本重新安装游戏。\n经测试,Forge 版本过高或过低都可能导致崩溃。"
             Case CrashReason.低版本Forge与高版本Java不兼容
             Case CrashReason.低版本Forge与高版本Java不兼容
                 ResultString = "由于低版本 Forge 与当前 Java 不兼容,导致了游戏崩溃。\n\n请尝试以下解决方案:\n - 更新 Forge 到 36.2.26 或更高版本\n - 换用版本低于 8.0.320 的 Java"
                 ResultString = "由于低版本 Forge 与当前 Java 不兼容,导致了游戏崩溃。\n\n请尝试以下解决方案:\n - 更新 Forge 到 36.2.26 或更高版本\n - 换用版本低于 8.0.320 的 Java"
             Case CrashReason.版本Json中存在多个Forge
             Case CrashReason.版本Json中存在多个Forge

+ 3 - 0
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb

@@ -1266,6 +1266,9 @@
             RightKeywords.Add(Keyword)
             RightKeywords.Add(Keyword)
         Next
         Next
         Task.Input.SearchFilter = Join(ArrayNoDouble(RightKeywords), " ").ToLower
         Task.Input.SearchFilter = Join(ArrayNoDouble(RightKeywords), " ").ToLower
+        '例外项:OptiForge、OptiFabric(拆词后因为包含 Forge/Fabric 导致无法搜到实际的 Mod)
+        If RawFilter.ToLower.Contains("optiforge") Then Task.Input.SearchFilter = "optiforge"
+        If RawFilter.ToLower.Contains("optifabric") Then Task.Input.SearchFilter = "optifabric"
         Log("[Download] CurseForge 工程列表搜索最终文本:" & Task.Input.SearchFilter, LogLevel.Developer)
         Log("[Download] CurseForge 工程列表搜索最终文本:" & Task.Input.SearchFilter, LogLevel.Developer)
         '正式获取
         '正式获取
         Dim Url = Task.Input.GetAddress()
         Dim Url = Task.Input.GetAddress()

+ 17 - 17
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb

@@ -1163,13 +1163,18 @@ SystemBrowser:
         'Authlib-Injector
         'Authlib-Injector
         If McLoginLoader.Output.Type = "Auth" Then
         If McLoginLoader.Output.Type = "Auth" Then
             Dim Server As String = Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent)
             Dim Server As String = Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent)
-            Dim Response As String = NetGetCodeByRequestRetry(Server, Encoding.UTF8)
-            DataList.Insert(0, "-javaagent:authlib-injector.jar=" & Server &
+            Try
+                Dim Response As String = NetGetCodeByRequestRetry(Server, Encoding.UTF8)
+                DataList.Insert(0, "-javaagent:authlib-injector.jar=" & Server &
                               " -Dauthlibinjector.side=client" &
                               " -Dauthlibinjector.side=client" &
                               " -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response)))
                               " -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response)))
+            Catch ex As Exception
+                Throw New Exception("无法连接到第三方登录服务器(" & If(Server, Nothing) & ")", ex)
+            End Try
         End If
         End If
 
 
         '添加 Java Wrapper 作为主 Jar
         '添加 Java Wrapper 作为主 Jar
+        If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
         Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
         Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
         If Not File.Exists(WrapperPath) Then
         If Not File.Exists(WrapperPath) Then
             WriteFile(WrapperPath, GetResources("JavaWrapper"))
             WriteFile(WrapperPath, GetResources("JavaWrapper"))
@@ -1233,10 +1238,19 @@ NextVersion:
                               " -Dauthlibinjector.side=client" &
                               " -Dauthlibinjector.side=client" &
                               " -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response)))
                               " -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response)))
             Catch ex As Exception
             Catch ex As Exception
-                Throw New Exception("无法连接到第三方登录服务器(" & If(Server, Nothing) & ")")
+                Throw New Exception("无法连接到第三方登录服务器(" & If(Server, Nothing) & ")", ex)
             End Try
             End Try
         End If
         End If
 
 
+        '添加 Java Wrapper 作为主 Jar
+        If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
+        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
+        If Not File.Exists(WrapperPath) Then
+            WriteFile(WrapperPath, GetResources("JavaWrapper"))
+            McLaunchLog("已自动释放 Java Wrapper")
+        End If
+        DataList.Add("-jar """ & WrapperPath & """")
+
         '将 "-XXX" 与后面 "XXX" 合并到一起
         '将 "-XXX" 与后面 "XXX" 合并到一起
         '如果不合并,会导致 Forge 1.17 启动无效,它有两个 --add-exports,进一步导致其中一个在后面被去重
         '如果不合并,会导致 Forge 1.17 启动无效,它有两个 --add-exports,进一步导致其中一个在后面被去重
         Dim DeDuplicateDataList As New List(Of String)
         Dim DeDuplicateDataList As New List(Of String)
@@ -1258,14 +1272,6 @@ NextVersion:
         '去重
         '去重
         Dim Result As String = Join(ArrayNoDouble(DeDuplicateDataList), " ")
         Dim Result As String = Join(ArrayNoDouble(DeDuplicateDataList), " ")
 
 
-        '添加 Java Wrapper 作为主 Jar
-        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
-        If Not File.Exists(WrapperPath) Then
-            WriteFile(WrapperPath, GetResources("JavaWrapper"))
-            McLaunchLog("已自动释放 Java Wrapper")
-        End If
-        Result += " -jar """ & WrapperPath & """"
-
         '添加 MainClass
         '添加 MainClass
         If Version.JsonObject("mainClass") Is Nothing Then
         If Version.JsonObject("mainClass") Is Nothing Then
             Throw New Exception("版本 Json 中没有 mainClass 项!")
             Throw New Exception("版本 Json 中没有 mainClass 项!")
@@ -1285,9 +1291,6 @@ NextVersion:
         If Not BasicString.Contains("--height") Then BasicString += " --height ${resolution_height} --width ${resolution_width}"
         If Not BasicString.Contains("--height") Then BasicString += " --height ${resolution_height} --width ${resolution_width}"
         DataList.Add(BasicString)
         DataList.Add(BasicString)
 
 
-        '添加 Wrapper 导出参数
-        DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
-
         Dim Result As String = Join(DataList, " ")
         Dim Result As String = Join(DataList, " ")
 
 
         '特别改变 OptiFineTweaker
         '特别改变 OptiFineTweaker
@@ -1341,9 +1344,6 @@ NextVersion:
             GoTo NextVersion
             GoTo NextVersion
         End If
         End If
 
 
-        '添加 Wrapper 导出参数
-        DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
-
         '将 "-XXX" 与后面 "XXX" 合并到一起
         '将 "-XXX" 与后面 "XXX" 合并到一起
         '如果不进行合并 Impact 会启动无效,它有两个 --tweakclass
         '如果不进行合并 Impact 会启动无效,它有两个 --tweakclass
         Dim DeDuplicateDataList As New List(Of String)
         Dim DeDuplicateDataList As New List(Of String)

+ 3 - 3
Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb

@@ -592,7 +592,7 @@ UserPass:
 
 
     '缺失
     '缺失
     ''' <summary>
     ''' <summary>
-    ''' 提示 Java 缺失并跳转下载。支持 Java 7、8、16。
+    ''' 提示 Java 缺失并跳转下载。支持 Java 7、8、16、17。
     ''' </summary>
     ''' </summary>
     Public Sub JavaMissing(VersionCode As Integer)
     Public Sub JavaMissing(VersionCode As Integer)
         Select Case VersionCode
         Select Case VersionCode
@@ -613,8 +613,8 @@ UserPass:
                 If Is32BitSystem Then
                 If Is32BitSystem Then
                     MyMsgBox("该版本的 MC 已不支持 32 位操作系统。你必须增加内存并重装为 64 位系统才能继续。", "系统兼容性提示")
                     MyMsgBox("该版本的 MC 已不支持 32 位操作系统。你必须增加内存并重装为 64 位系统才能继续。", "系统兼容性提示")
                 Else
                 Else
-                    OpenWebsite("https://www.oracle.com/java/technologies/downloads/#jdk17-windows")
-                    MyMsgBox("PCL2 未找到 Java " & VersionCode & "。" & vbCrLf &
+                    OpenWebsite("https://www.oracle.com/java/technologies/downloads/#java17")
+                    MyMsgBox("PCL2 未找到 Java 17。" & vbCrLf &
                              "请在打开的网页中选择 x64 Installer,下载并安装。" & vbCrLf &
                              "请在打开的网页中选择 x64 Installer,下载并安装。" & vbCrLf &
                              "安装后在 PCL2 的 设置 → 启动设置 → 游戏 Java 中通过搜索或导入,确保安装的 Java 已列入 Java 列表。",
                              "安装后在 PCL2 的 设置 → 启动设置 → 游戏 Java 中通过搜索或导入,确保安装的 Java 已列入 Java 列表。",
                              "未找到 Java")
                              "未找到 Java")

+ 2 - 2
Plain Craft Launcher 2/My Project/AssemblyInfo.vb

@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
 ' 方法是按如下所示使用“*”
 ' 方法是按如下所示使用“*”
 
 
-<Assembly: AssemblyVersion("2.3.4.0")>
-<Assembly: AssemblyFileVersion("2.3.4.0")>
+<Assembly: AssemblyVersion("2.3.5.0")>
+<Assembly: AssemblyFileVersion("2.3.5.0")>
 <Assembly: NeutralResourcesLanguage("")>
 <Assembly: NeutralResourcesLanguage("")>

+ 229 - 214
Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb

@@ -1,6 +1,8 @@
 Imports System.IO.Compression
 Imports System.IO.Compression
 
 
 Public Module ModDownloadLib
 Public Module ModDownloadLib
+    '如果 OptiFine 与 Forge 同时开始安装,就会导致 Forge 安装失败
+    Private InstallSyncLock As New Object
 
 
 #Region "Minecraft 下载"
 #Region "Minecraft 下载"
 
 
@@ -372,90 +374,100 @@ Public Module ModDownloadLib
         '选择 Java
         '选择 Java
         Dim Java = JavaSelect(New Version(1, 8, 0, 0))
         Dim Java = JavaSelect(New Version(1, 8, 0, 0))
         If Java Is Nothing Then
         If Java Is Nothing Then
-            JavaMissing(8)
+            JavaMissing(17)
             Throw New Exception("未找到用于安装 OptiFine 的 Java")
             Throw New Exception("未找到用于安装 OptiFine 的 Java")
         End If
         End If
-        '开始启动
-        Dim Info = New ProcessStartInfo With {
-            .FileName = Java.PathJavaw,
-            .Arguments = "-Duser.home=""" & BaseMcFolderHome & """ -cp """ & Target & """ optifine.Installer",
-            .UseShellExecute = False,
-            .CreateNoWindow = True,
-            .RedirectStandardError = True,
-            .RedirectStandardOutput = True,
-            .WorkingDirectory = BaseMcFolderHome
-        }
-        If Info.EnvironmentVariables.ContainsKey("appdata") Then
-            Info.EnvironmentVariables("appdata") = BaseMcFolderHome
-        Else
-            Info.EnvironmentVariables.Add("appdata", BaseMcFolderHome)
+        '添加 Java Wrapper 作为主 Jar
+        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
+        If Not File.Exists(WrapperPath) Then
+            WriteFile(WrapperPath, GetResources("JavaWrapper"))
+            McLaunchLog("已自动释放 Java Wrapper")
         End If
         End If
-        Log("[Download] 开始安装 OptiFine:" & Target)
-        Dim TotalLength As Integer = 0
-        Dim process As New Process With {.StartInfo = Info}
-        Dim LastResult As String = ""
-        Using outputWaitHandle As New AutoResetEvent(False)
-            Using errorWaitHandle As New AutoResetEvent(False)
-                AddHandler process.OutputDataReceived, Function(sender, e)
-                                                           Try
-                                                               If e.Data Is Nothing Then
-                                                                   outputWaitHandle.[Set]()
-                                                               Else
-                                                                   LastResult = e.Data
-                                                                   If ModeDebug Then Log("[Installer] " & LastResult)
-                                                                   TotalLength += 1
-                                                                   Task.Progress += 0.9 / 7000
-                                                               End If
-                                                           Catch ex As ObjectDisposedException
-                                                           Catch ex As Exception
-                                                               Log(ex, "读取 OptiFine 安装器信息失败")
-                                                           End Try
-                                                           Try
-                                                               If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
-                                                                   Log("[Installer] 由于任务取消,已中止 OptiFine 安装")
-                                                                   process.Kill()
-                                                               End If
-                                                           Catch
-                                                           End Try
-                                                           Return Nothing
-                                                       End Function
-                AddHandler process.ErrorDataReceived, Function(sender, e)
-                                                          Try
-                                                              If e.Data Is Nothing Then
-                                                                  errorWaitHandle.[Set]()
-                                                              Else
-                                                                  LastResult = e.Data
-                                                                  If ModeDebug Then Log("[Installer] " & LastResult)
-                                                                  TotalLength += 1
-                                                                  Task.Progress += 0.9 / 7000
-                                                              End If
-                                                          Catch ex As ObjectDisposedException
-                                                          Catch ex As Exception
-                                                              Log(ex, "读取 OptiFine 安装器错误信息失败")
-                                                          End Try
-                                                          Try
-                                                              If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
-                                                                  Log("[Installer] 由于任务取消,已中止 OptiFine 安装")
-                                                                  process.Kill()
-                                                              End If
-                                                          Catch
-                                                          End Try
-                                                          Return Nothing
-                                                      End Function
-                process.Start()
-                process.BeginOutputReadLine()
-                process.BeginErrorReadLine()
-                '等待
-                Do Until process.HasExited
-                    Thread.Sleep(10)
-                Loop
-                '输出
-                outputWaitHandle.WaitOne(10000)
-                errorWaitHandle.WaitOne(10000)
-                process.Dispose()
-                If TotalLength < 1000 Then Throw New Exception("安装器运行出错,末行为 " & LastResult)
+        Dim Arguments = "-Duser.home=""" & BaseMcFolderHome & """ -cp """ & Target & """ -jar """ & WrapperPath & """ optifine.Installer"
+        If Java.VersionCode >= 9 Then Arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " & Arguments
+        '开始启动
+        SyncLock InstallSyncLock
+            Dim Info = New ProcessStartInfo With {
+                .FileName = Java.PathJavaw,
+                .Arguments = Arguments,
+                .UseShellExecute = False,
+                .CreateNoWindow = True,
+                .RedirectStandardError = True,
+                .RedirectStandardOutput = True,
+                .WorkingDirectory = BaseMcFolderHome
+            }
+            If Info.EnvironmentVariables.ContainsKey("appdata") Then
+                Info.EnvironmentVariables("appdata") = BaseMcFolderHome
+            Else
+                Info.EnvironmentVariables.Add("appdata", BaseMcFolderHome)
+            End If
+            Log("[Download] 开始安装 OptiFine:" & Target)
+            Dim TotalLength As Integer = 0
+            Dim process As New Process With {.StartInfo = Info}
+            Dim LastResult As String = ""
+            Using outputWaitHandle As New AutoResetEvent(False)
+                Using errorWaitHandle As New AutoResetEvent(False)
+                    AddHandler process.OutputDataReceived, Function(sender, e)
+                                                               Try
+                                                                   If e.Data Is Nothing Then
+                                                                       outputWaitHandle.[Set]()
+                                                                   Else
+                                                                       LastResult = e.Data
+                                                                       If ModeDebug Then Log("[Installer] " & LastResult)
+                                                                       TotalLength += 1
+                                                                       Task.Progress += 0.9 / 7000
+                                                                   End If
+                                                               Catch ex As ObjectDisposedException
+                                                               Catch ex As Exception
+                                                                   Log(ex, "读取 OptiFine 安装器信息失败")
+                                                               End Try
+                                                               Try
+                                                                   If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
+                                                                       Log("[Installer] 由于任务取消,已中止 OptiFine 安装")
+                                                                       process.Kill()
+                                                                   End If
+                                                               Catch
+                                                               End Try
+                                                               Return Nothing
+                                                           End Function
+                    AddHandler process.ErrorDataReceived, Function(sender, e)
+                                                              Try
+                                                                  If e.Data Is Nothing Then
+                                                                      errorWaitHandle.[Set]()
+                                                                  Else
+                                                                      LastResult = e.Data
+                                                                      If ModeDebug Then Log("[Installer] " & LastResult)
+                                                                      TotalLength += 1
+                                                                      Task.Progress += 0.9 / 7000
+                                                                  End If
+                                                              Catch ex As ObjectDisposedException
+                                                              Catch ex As Exception
+                                                                  Log(ex, "读取 OptiFine 安装器错误信息失败")
+                                                              End Try
+                                                              Try
+                                                                  If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
+                                                                      Log("[Installer] 由于任务取消,已中止 OptiFine 安装")
+                                                                      process.Kill()
+                                                                  End If
+                                                              Catch
+                                                              End Try
+                                                              Return Nothing
+                                                          End Function
+                    process.Start()
+                    process.BeginOutputReadLine()
+                    process.BeginErrorReadLine()
+                    '等待
+                    Do Until process.HasExited
+                        Thread.Sleep(10)
+                    Loop
+                    '输出
+                    outputWaitHandle.WaitOne(10000)
+                    errorWaitHandle.WaitOne(10000)
+                    process.Dispose()
+                    If TotalLength < 1000 Then Throw New Exception("安装器运行出错,末行为 " & LastResult)
+                End Using
             End Using
             End Using
-        End Using
+        End SyncLock
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
@@ -536,50 +548,50 @@ Public Module ModDownloadLib
         If IsNewVersion Then
         If IsNewVersion Then
             Log("[Download] 检测为新版 OptiFine:" & DownloadInfo.Inherit)
             Log("[Download] 检测为新版 OptiFine:" & DownloadInfo.Inherit)
             Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 OptiFine(方式 A)",
             Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 OptiFine(方式 A)",
-                                                            Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
-                                                                Dim BaseMcFolderHome As String = PathTemp & "InstallOptiFine" & RandomInteger(0, 100000)
-                                                                Dim BaseMcFolder As String = BaseMcFolderHome & "\.minecraft\"
-                                                                Try
-                                                                    '准备安装环境
-                                                                    If Directory.Exists(BaseMcFolder & "versions\" & DownloadInfo.Inherit) Then
-                                                                        DeleteDirectory(BaseMcFolder & "versions\" & DownloadInfo.Inherit)
-                                                                    End If
-                                                                    My.Computer.FileSystem.CreateDirectory(BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\")
-                                                                    McFolderLauncherProfilesJsonCreate(BaseMcFolder)
-                                                                    CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json",
-                                                                              BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json")
-                                                                    CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar",
-                                                                              BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar")
-                                                                    Task.Progress = 0.06
-                                                                    '进行安装
-                                                                    McDownloadOptiFineInstall(BaseMcFolderHome, Target, Task)
-                                                                    Task.Progress = 0.96
-                                                                    '复制文件
-                                                                    File.Delete(BaseMcFolder & "launcher_profiles.json")
-                                                                    My.Computer.FileSystem.CopyDirectory(BaseMcFolder, McFolder, True)
-                                                                    Task.Progress = 0.98
-                                                                    '清理文件
-                                                                    My.Computer.FileSystem.DeleteFile(Target)
-                                                                    DeleteDirectory(BaseMcFolderHome)
-                                                                Catch ex As Exception
-                                                                    Throw New Exception("安装新版 OptiFine 版本失败", ex)
-                                                                End Try
-                                                            End Sub) With {.ProgressWeight = 8})
+            Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
+                Dim BaseMcFolderHome As String = PathTemp & "InstallOptiFine" & RandomInteger(0, 100000)
+                Dim BaseMcFolder As String = BaseMcFolderHome & "\.minecraft\"
+                Try
+                    '准备安装环境
+                    If Directory.Exists(BaseMcFolder & "versions\" & DownloadInfo.Inherit) Then
+                        DeleteDirectory(BaseMcFolder & "versions\" & DownloadInfo.Inherit)
+                    End If
+                    My.Computer.FileSystem.CreateDirectory(BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\")
+                    McFolderLauncherProfilesJsonCreate(BaseMcFolder)
+                    CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json",
+                              BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json")
+                    CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar",
+                              BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar")
+                    Task.Progress = 0.06
+                    '进行安装
+                    McDownloadOptiFineInstall(BaseMcFolderHome, Target, Task)
+                    Task.Progress = 0.96
+                    '复制文件
+                    File.Delete(BaseMcFolder & "launcher_profiles.json")
+                    My.Computer.FileSystem.CopyDirectory(BaseMcFolder, McFolder, True)
+                    Task.Progress = 0.98
+                    '清理文件
+                    My.Computer.FileSystem.DeleteFile(Target)
+                    DeleteDirectory(BaseMcFolderHome)
+                Catch ex As Exception
+                    Throw New Exception("安装新版 OptiFine 版本失败", ex)
+                End Try
+            End Sub) With {.ProgressWeight = 8})
         Else
         Else
             Log("[Download] 检测为旧版 OptiFine:" & DownloadInfo.Inherit)
             Log("[Download] 检测为旧版 OptiFine:" & DownloadInfo.Inherit)
             Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 OptiFine(方式 B)",
             Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 OptiFine(方式 B)",
-                                                            Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
-                                                                Try
-                                                                    '新建版本文件夹
-                                                                    Directory.CreateDirectory(VersionFolder)
-                                                                    Task.Progress = 0.1
-                                                                    '复制 Jar 文件
-                                                                    If File.Exists(VersionFolder & Id & ".jar") Then File.Delete(VersionFolder & Id & ".jar")
-                                                                    CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar", VersionFolder & Id & ".jar")
-                                                                    Task.Progress = 0.7
-                                                                    '建立 Json 文件
-                                                                    Dim InheritVersion As New McVersion(McFolder & "versions\" & DownloadInfo.Inherit)
-                                                                    Dim Json As String = "{
+            Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
+                Try
+                    '新建版本文件夹
+                    Directory.CreateDirectory(VersionFolder)
+                    Task.Progress = 0.1
+                    '复制 Jar 文件
+                    If File.Exists(VersionFolder & Id & ".jar") Then File.Delete(VersionFolder & Id & ".jar")
+                    CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar", VersionFolder & Id & ".jar")
+                    Task.Progress = 0.7
+                    '建立 Json 文件
+                    Dim InheritVersion As New McVersion(McFolder & "versions\" & DownloadInfo.Inherit)
+                    Dim Json As String = "{
     ""id"": """ & Id & """,
     ""id"": """ & Id & """,
     ""inheritsFrom"": """ & DownloadInfo.Inherit & """,
     ""inheritsFrom"": """ & DownloadInfo.Inherit & """,
     ""time"": """ & If(DownloadInfo.ReleaseTime = "", InheritVersion.ReleaseTime.ToString("yyyy-MM-dd"), DownloadInfo.ReleaseTime.Replace("/", "-")) & "T23:33:33+08:00"",
     ""time"": """ & If(DownloadInfo.ReleaseTime = "", InheritVersion.ReleaseTime.ToString("yyyy-MM-dd"), DownloadInfo.ReleaseTime.Replace("/", "-")) & "T23:33:33+08:00"",
@@ -590,16 +602,16 @@ Public Module ModDownloadLib
         {""name"": ""net.minecraft:launchwrapper:1.12""}
         {""name"": ""net.minecraft:launchwrapper:1.12""}
     ],
     ],
     ""mainClass"": ""net.minecraft.launchwrapper.Launch"","
     ""mainClass"": ""net.minecraft.launchwrapper.Launch"","
-                                                                    Task.Progress = 0.8
-                                                                    If InheritVersion.IsOldJson Then
-                                                                        '输出旧版 Json 格式
-                                                                        Json += "
+                    Task.Progress = 0.8
+                    If InheritVersion.IsOldJson Then
+                        '输出旧版 Json 格式
+                        Json += "
     ""minimumLauncherVersion"": 18,
     ""minimumLauncherVersion"": 18,
     ""minecraftArguments"": """ & InheritVersion.JsonObject("minecraftArguments").ToString & "  --tweakClass optifine.OptiFineTweaker""
     ""minecraftArguments"": """ & InheritVersion.JsonObject("minecraftArguments").ToString & "  --tweakClass optifine.OptiFineTweaker""
 }"
 }"
-                                                                    Else
-                                                                        '输出新版 Json 格式
-                                                                        Json += "
+                    Else
+                        '输出新版 Json 格式
+                        Json += "
     ""minimumLauncherVersion"": ""21"",
     ""minimumLauncherVersion"": ""21"",
     ""arguments"": {
     ""arguments"": {
         ""game"": [
         ""game"": [
@@ -608,12 +620,12 @@ Public Module ModDownloadLib
         ]
         ]
     }
     }
 }"
 }"
-                                                                    End If
-                                                                    WriteFile(VersionFolder & Id & ".json", Json)
-                                                                Catch ex As Exception
-                                                                    Throw New Exception("安装旧版 OptiFine 版本失败", ex)
-                                                                End Try
-                                                            End Sub) With {.ProgressWeight = 1})
+                    End If
+                    WriteFile(VersionFolder & Id & ".json", Json)
+                Catch ex As Exception
+                    Throw New Exception("安装旧版 OptiFine 版本失败", ex)
+                End Try
+            End Sub) With {.ProgressWeight = 1})
         End If
         End If
 
 
         '下载支持库
         '下载支持库
@@ -1078,90 +1090,93 @@ Public Module ModDownloadLib
         '选择 Java
         '选择 Java
         Dim Java = JavaSelect(New Version(1, 8, 0, 60))
         Dim Java = JavaSelect(New Version(1, 8, 0, 60))
         If Java Is Nothing Then
         If Java Is Nothing Then
-            JavaMissing(8)
+            JavaMissing(17)
             Throw New Exception("未找到用于安装 Forge 的 Java")
             Throw New Exception("未找到用于安装 Forge 的 Java")
         End If
         End If
+        '添加 Java Wrapper 作为主 Jar
+        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
+        If Not File.Exists(WrapperPath) Then
+            WriteFile(WrapperPath, GetResources("JavaWrapper"))
+            McLaunchLog("已自动释放 Java Wrapper")
+        End If
+        Dim Arguments = "-cp """ & PathTemp & "Cache\forge_installer.jar;" & Target & """ -jar """ & WrapperPath & """  com.bangbang93.ForgeInstaller """ & McFolder
+        If Java.VersionCode >= 9 Then Arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " & Arguments
         '开始启动
         '开始启动
-        Dim Argument As String = String.Format("-cp ""{0};{1}"" com.bangbang93.ForgeInstaller ""{2}", PathTemp & "Cache\forge_installer.jar", Target, McFolder)
-        Dim Info = New ProcessStartInfo With {
-            .FileName = Java.PathJavaw,
-            .Arguments = Argument,
-            .UseShellExecute = False,
-            .CreateNoWindow = True,
-            .RedirectStandardError = True,
-            .RedirectStandardOutput = True
-        }
-        Log("[Download] 开始安装 Forge:" & Argument)
-        Dim process As New Process With {.StartInfo = Info}
-        Dim LastResults As New Queue(Of String)
-        Using outputWaitHandle As New AutoResetEvent(False)
-            Using errorWaitHandle As New AutoResetEvent(False)
-                AddHandler process.OutputDataReceived, Function(sender, e)
-                                                           Try
-                                                               If e.Data Is Nothing Then
-                                                                   outputWaitHandle.[Set]()
-                                                               Else
-                                                                   LastResults.Enqueue(e.Data)
-                                                                   If LastResults.Count > 100 Then LastResults.Dequeue()
-                                                                   ForgeInjectorLine(e.Data, Task)
-                                                               End If
-                                                           Catch ex As ObjectDisposedException
-                                                           Catch ex As Exception
-                                                               Log(ex, "读取 Forge 安装器信息失败")
-                                                           End Try
-                                                           Try
-                                                               If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
-                                                                   Log("[Installer] 由于任务取消,已中止 Forge 安装")
-                                                                   process.Kill()
-                                                               End If
-                                                           Catch
-                                                           End Try
-                                                           Return Nothing
-                                                       End Function
-                AddHandler process.ErrorDataReceived, Function(sender, e)
-                                                          Try
-                                                              If e.Data Is Nothing Then
-                                                                  errorWaitHandle.[Set]()
-                                                              Else
-                                                                  LastResults.Enqueue(e.Data)
-                                                                  If LastResults.Count > 100 Then LastResults.Dequeue()
-                                                                  ForgeInjectorLine(e.Data, Task)
-                                                              End If
-                                                          Catch ex As ObjectDisposedException
-                                                          Catch ex As Exception
-                                                              Log(ex, "读取 Forge 安装器错误信息失败")
-                                                          End Try
-                                                          Try
-                                                              If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
-                                                                  Log("[Installer] 由于任务取消,已中止 Forge 安装")
-                                                                  process.Kill()
-                                                              End If
-                                                          Catch
-                                                          End Try
-                                                          Return Nothing
-                                                      End Function
-                process.Start()
-                process.BeginOutputReadLine()
-                process.BeginErrorReadLine()
-                '等待
-                Do Until process.HasExited
-                    Thread.Sleep(10)
-                Loop
-                '输出
-                outputWaitHandle.WaitOne(10000)
-                errorWaitHandle.WaitOne(10000)
-                process.Dispose()
-                If LastResults.Last = "true" Then Exit Sub
-                Log(Join(LastResults, vbCrLf))
-                Throw New Exception("Forge 安装器出错,末行为 " & LastResults.Last)
+        SyncLock InstallSyncLock
+            Dim Info = New ProcessStartInfo With {
+                .FileName = Java.PathJavaw,
+                .Arguments = Arguments,
+                .UseShellExecute = False,
+                .CreateNoWindow = True,
+                .RedirectStandardError = True,
+                .RedirectStandardOutput = True
+            }
+            Log("[Download] 开始安装 Forge:" & Arguments)
+            Dim process As New Process With {.StartInfo = Info}
+            Dim LastResults As New Queue(Of String)
+            Using outputWaitHandle As New AutoResetEvent(False)
+                Using errorWaitHandle As New AutoResetEvent(False)
+                    AddHandler process.OutputDataReceived, Function(sender, e)
+                                                               Try
+                                                                   If e.Data Is Nothing Then
+                                                                       outputWaitHandle.[Set]()
+                                                                   Else
+                                                                       LastResults.Enqueue(e.Data)
+                                                                       If LastResults.Count > 100 Then LastResults.Dequeue()
+                                                                       ForgeInjectorLine(e.Data, Task)
+                                                                   End If
+                                                               Catch ex As ObjectDisposedException
+                                                               Catch ex As Exception
+                                                                   Log(ex, "读取 Forge 安装器信息失败")
+                                                               End Try
+                                                               Try
+                                                                   If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
+                                                                       Log("[Installer] 由于任务取消,已中止 Forge 安装")
+                                                                       process.Kill()
+                                                                   End If
+                                                               Catch
+                                                               End Try
+                                                               Return Nothing
+                                                           End Function
+                    AddHandler process.ErrorDataReceived, Function(sender, e)
+                                                              Try
+                                                                  If e.Data Is Nothing Then
+                                                                      errorWaitHandle.[Set]()
+                                                                  Else
+                                                                      LastResults.Enqueue(e.Data)
+                                                                      If LastResults.Count > 100 Then LastResults.Dequeue()
+                                                                      ForgeInjectorLine(e.Data, Task)
+                                                                  End If
+                                                              Catch ex As ObjectDisposedException
+                                                              Catch ex As Exception
+                                                                  Log(ex, "读取 Forge 安装器错误信息失败")
+                                                              End Try
+                                                              Try
+                                                                  If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
+                                                                      Log("[Installer] 由于任务取消,已中止 Forge 安装")
+                                                                      process.Kill()
+                                                                  End If
+                                                              Catch
+                                                              End Try
+                                                              Return Nothing
+                                                          End Function
+                    process.Start()
+                    process.BeginOutputReadLine()
+                    process.BeginErrorReadLine()
+                    '等待
+                    Do Until process.HasExited
+                        Thread.Sleep(10)
+                    Loop
+                    '输出
+                    outputWaitHandle.WaitOne(10000)
+                    errorWaitHandle.WaitOne(10000)
+                    process.Dispose()
+                    If LastResults.Last = "true" Then Exit Sub
+                    Log(Join(LastResults, vbCrLf))
+                    Throw New Exception("Forge 安装器出错,末行为 " & LastResults.Last)
+                End Using
             End Using
             End Using
-        End Using
-        ''判断结果
-        'Dim ReturnData As String =
-        'If ModeDebug Then Log("[Download] Forge 安装器 Log:" & vbCrLf & ReturnData & vbCrLf)
-        '                                                            If Not ReturnData.TrimEnd(vbCrLf.ToCharArray()).EndsWith("true") Then
-        '    Throw New Exception("自动安装过程出错,日志尾部:" & vbCrLf & ReturnData.Substring(Math.Max(0, ReturnData.Length - 1000)))
-        'End If
+        End SyncLock
     End Sub
     End Sub
     Private Sub ForgeInjectorLine(Content As String, Task As LoaderTask(Of Boolean, Boolean))
     Private Sub ForgeInjectorLine(Content As String, Task As LoaderTask(Of Boolean, Boolean))
         If Content.StartsWith("  Data") OrElse Content.StartsWith("  Slim") Then
         If Content.StartsWith("  Data") OrElse Content.StartsWith("  Slim") Then

+ 34 - 0
Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml

@@ -0,0 +1,34 @@
+<local:MyPageRight
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             mc:Ignorable="d" x:Class="PageLinkFeedback"
+             d:DesignWidth="800" d:DesignHeight="800">
+    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+        <local:MyCard Title="反馈途径选择">
+            <StackPanel Margin="20,40,18,18">
+                <local:MyListItem Title="联机模块反馈" Info="向联机模块开发者反馈联机失败等异常"
+                              Type="Clickable" EventType="打开网页" EventData="https://mcer.cn/"
+                              PaddingRight="20" Logo="pack://application:,,,/images/Blocks/RedstoneBlock.png" />
+                <local:MyListItem Title="违法违规举报" Info="投诉、举报联机使用者的各类违法违规行为"
+                              Type="Clickable" EventType="打开网页" EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW#anchor-7x6P"
+                              PaddingRight="20" Logo="pack://application:,,,/images/Blocks/RedstoneBlock.png" />
+            </StackPanel>
+        </local:MyCard>
+        <local:MyCard Margin="0,20,0,15">
+            <Grid Margin="15,12">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="1*"/>
+                    <ColumnDefinition Width="Auto" />
+                    <ColumnDefinition Width="Auto" />
+                    <ColumnDefinition Width="Auto" />
+                    <ColumnDefinition Width="1*"/>
+                </Grid.ColumnDefinitions>
+                <TextBlock Grid.Column="1" Text="联机服务由 " Opacity="0.5"/>
+                <local:MyTextButton Grid.Column="2" Text="阿猫" x:Name="BtnNoin" Opacity="0.5"
+                                    EventType="打开网页" EventData="https://mcer.cn" />
+                <TextBlock Grid.Column="3" Text=" 授权提供" Opacity="0.5"/>
+            </Grid>
+        </local:MyCard>
+    </StackPanel>
+</local:MyPageRight>

+ 3 - 0
Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml.vb

@@ -0,0 +1,3 @@
+Public Class PageLinkFeedback
+
+End Class

+ 48 - 0
Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml

@@ -0,0 +1,48 @@
+<local:MyPageRight
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:System="clr-namespace:System;assembly=mscorlib" 
+             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             mc:Ignorable="d" x:Class="PageLinkIoi"
+             d:DesignWidth="800" d:DesignHeight="800">
+    <Grid>
+        <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
+            <StackPanel Orientation="Vertical" Margin="25,10">
+                <local:MyHint Margin="0,15,0,0" Text="联机功能仍处于测试阶段,尚未制作完成,因此延迟很高,且存在较多 Bug。延迟与内存占用高的问题将在后续优化,请多多包涵……" />
+                <local:MyCard Margin="0,15,0,0" x:Name="CardUser" Title="已连接的玩家 (0)">
+                    <StackPanel Margin="20,37,20,15">
+                        <local:MyHint Margin="5,2,5,8" x:Name="LabHint" IsWarn="False" />
+                        <StackPanel x:Name="PanUserList" />
+                        <Grid Height="35" Margin="5,8,5,5">
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
+                                <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
+                            </Grid.ColumnDefinitions>
+                            <local:MyButton x:Name="BtnLeftCreate" Grid.Column="0" MinWidth="140" Text="建立连接" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
+                            <local:MyButton x:Name="BtnLeftCopy" Grid.Column="1" MinWidth="140" Text="复制连接码" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
+                        </Grid>
+                    </StackPanel>
+                </local:MyCard>
+                <local:MyCard Margin="0,15" Title="房间列表" x:Name="CardRoom">
+                    <StackPanel Margin="20,37,20,15">
+                        <StackPanel x:Name="PanRoom">
+                            <!--<local:MyListItem Type="Clickable" PaddingRight="60" Height="40" Title="00ll00" Info="已连接,1100 ms" Logo="pack://application:,,,/images/Blocks/Grass.png">
+                                <local:MyListItem.Buttons>
+                                    <x:Array Type="{x:Type local:MyIconButton}">
+                                        <local:MyIconButton ToolTip="刷新" ToolTipService.Placement="Bottom" ToolTipService.HorizontalOffset="-10" ToolTipService.VerticalOffset="5" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
+                                        <local:MyIconButton ToolTip="断开" ToolTipService.Placement="Bottom" ToolTipService.HorizontalOffset="-10" ToolTipService.VerticalOffset="5" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.85" Logo="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z" />
+                                    </x:Array>
+                                </local:MyListItem.Buttons>
+                            </local:MyListItem>-->
+                        </StackPanel>
+                        <local:MyListItem x:Name="BtnCreate" Type="Clickable" Title="创建房间" Height="34" PaddingLeft="0"
+                          Logo="M512.277 954.412c-118.89 0-230.659-46.078-314.73-129.73S67.12 629.666 67.12 511.222s46.327-229.744 130.398-313.427 195.82-129.73 314.73-129.73 230.659 46.078 314.72 129.73S957.397 392.81 957.397 511.183 911.078 740.96 826.97 824.642s-195.8 129.77-314.692 129.77z m0-822.784c-101.972 0-197.809 39.494-269.865 111.222s-111.7 166.997-111.7 268.373 39.653 196.695 111.67 268.335S410.246 890.78 512.248 890.78s197.809-39.484 269.865-111.222 111.7-166.998 111.67-268.374c-0.03-101.375-39.654-196.665-111.67-268.303S614.22 131.628 512.277 131.628z m222.585 347.8H544.073V288.64c-0.76-17.561-15.613-31.18-33.173-30.419-16.495 0.714-29.704 13.924-30.419 30.419v190.787H289.703c-17.56 0.761-31.179 15.614-30.419 33.174 0.715 16.494 13.924 29.703 30.42 30.418H480.48v190.788c0.761 17.56 15.614 31.179 33.174 30.419 16.494-0.715 29.703-13.925 30.418-30.42V543.02h190.788c17.56 0.762 32.413-12.857 33.173-30.418 0.762-17.561-12.858-32.414-30.419-33.174a31.683 31.683 0 0 0-2.753 0z" />
+                    </StackPanel>
+                </local:MyCard>
+            </StackPanel>
+        </local:MyScrollViewer>
+        <local:MyCard Opacity="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40,0" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
+            <local:MyLoading Text="正在加载联机模块" Margin="20,20,20,17" x:Name="Load" ShowProgress="True" HorizontalAlignment="Center" VerticalAlignment="Center" />
+        </local:MyCard>
+    </Grid>
+</local:MyPageRight>

+ 54 - 0
Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml

@@ -0,0 +1,54 @@
+<local:MyPageLeft x:Class="PageLinkLeft"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+      xmlns:local="clr-namespace:PCL"
+      mc:Ignorable="d" AnimatedControl="{Binding ElementName=PanItem}" MinWidth="150">
+    <StackPanel Orientation="Vertical" x:Name="PanItem" Margin="0,12,0,0">
+        <local:MyListItem x:Name="ItemNet" IsScaleAnimationEnabled="False" Type="None" PaddingLeft="2" Height="36" Title="网络检测中" PaddingRight="35" 
+            LogoScale="0.75" Logo="M512 817c-48.601 0-88-39.399-88-88s39.399-88 88-88 88 39.399 88 88-39.399 88-88 88zM237.671 565.74C308.335 474.58 397.369 429 504.774 429c118.433 0 214.225 55.421 287.377 166.264l-53.407 30.369c-13.84 7.87-31.362 4.367-41.114-8.219-50.291-64.911-114.577-97.367-192.856-97.367-86.851 0-156.835 40.318-209.95 120.953l-47.995-28.02c-15.263-8.91-20.412-28.507-11.502-43.77a32 32 0 0 1 2.344-3.47zM107.691 419.47C205.24 278.491 337.805 208 505.379 208c178.77 0 317.694 80.224 416.772 240.672l-56.54 31.73c-13.686 7.68-30.922 4.303-40.697-7.975C735.581 360.213 629.07 303.009 505.38 300.815 373.997 298.485 261.637 362.88 168.3 494l-50.116-28.505c-15.362-8.738-20.732-28.275-11.994-43.637a32 32 0 0 1 1.5-2.387z"
+            ToolTipService.Placement="Bottom" ToolTipService.HorizontalOffset="10" ToolTipService.VerticalOffset="0" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="20">
+            <local:MyListItem.Buttons>
+                <x:Array Type="{x:Type local:MyIconButton}">
+                    <local:MyIconButton Click="BtnNetRescan_Click" ToolTip="重新检测" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" ToolTipService.VerticalOffset="-2" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" Visibility="Collapsed"
+                                    LogoScale="0.85" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
+                </x:Array>
+            </local:MyListItem.Buttons>
+        </local:MyListItem>
+        <TextBlock Text="联机方式" Margin="13,18,5,5" Opacity="0.6" FontSize="12" />
+        <local:MyListItem x:Name="ItemCato" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="2" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="Cato" Visibility="Collapsed" 
+                          LogoScale="0.85" Logo="M554.496 170.496c141.312 0 256 114.688 256 256s-114.688 256-256 256H402.432c-22.016-1.536-39.424-19.968-39.424-42.496a42.391 42.391 0 0 1 42.496-42.496h149.504c94.208 0 170.496-76.288 170.496-170.496S648.704 256 554.496 256h-256C204.288 256 128 332.288 128 426.496c0 38.4 12.8 73.728 33.792 102.4 5.632 7.168 8.704 15.872 8.704 25.6A42.391 42.391 0 0 1 128 596.992c-11.264 0-20.992-4.096-28.672-11.264l-0.512 0.512c-35.328-44.032-56.32-99.328-56.32-159.744 0-141.312 114.688-256 256-256h256z m64 192h3.072c22.016 1.536 39.424 19.968 39.424 42.496a42.391 42.391 0 0 1-42.496 42.496H469.504c-94.208 0-170.496 76.288-170.496 170.496S375.296 788.48 469.504 788.48h256C819.712 788.48 896 712.192 896 617.984c0-38.4-12.8-73.728-33.792-102.4-5.632-7.168-8.704-15.872-8.704-25.6A42.391 42.391 0 0 1 896 447.488c11.264 0 20.992 4.096 28.672 11.264l0.512-0.512c35.328 44.032 56.32 99.328 56.32 159.744 0 141.312-114.688 256-256 256h-256c-141.312 0-256-114.688-256-256s114.688-256 256-256h148.992z">
+            <local:MyListItem.Buttons>
+                <x:Array Type="{x:Type local:MyIconButton}">
+                    <local:MyIconButton ToolTip="关闭联机模块" Loaded="BtnCatoStop_Loaded" Click="BtnCatoStop_Click"
+                                        ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" ToolTipService.VerticalOffset="-2" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.7" 
+                                        Logo="M576 512l277.333333 277.333333-64 64-277.333333-277.333333L234.666667 853.333333 170.666667 789.333333l277.333333-277.333333L170.666667 234.666667 234.666667 170.666667l277.333333 277.333333L789.333333 170.666667 853.333333 234.666667 576 512z" />
+                </x:Array>
+            </local:MyListItem.Buttons>
+        </local:MyListItem>
+        <local:MyListItem x:Name="ItemIoi" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="3" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="IOI"
+                          LogoScale="0.85" Logo="M554.496 170.496c141.312 0 256 114.688 256 256s-114.688 256-256 256H402.432c-22.016-1.536-39.424-19.968-39.424-42.496a42.391 42.391 0 0 1 42.496-42.496h149.504c94.208 0 170.496-76.288 170.496-170.496S648.704 256 554.496 256h-256C204.288 256 128 332.288 128 426.496c0 38.4 12.8 73.728 33.792 102.4 5.632 7.168 8.704 15.872 8.704 25.6A42.391 42.391 0 0 1 128 596.992c-11.264 0-20.992-4.096-28.672-11.264l-0.512 0.512c-35.328-44.032-56.32-99.328-56.32-159.744 0-141.312 114.688-256 256-256h256z m64 192h3.072c22.016 1.536 39.424 19.968 39.424 42.496a42.391 42.391 0 0 1-42.496 42.496H469.504c-94.208 0-170.496 76.288-170.496 170.496S375.296 788.48 469.504 788.48h256C819.712 788.48 896 712.192 896 617.984c0-38.4-12.8-73.728-33.792-102.4-5.632-7.168-8.704-15.872-8.704-25.6A42.391 42.391 0 0 1 896 447.488c11.264 0 20.992 4.096 28.672 11.264l0.512-0.512c35.328 44.032 56.32 99.328 56.32 159.744 0 141.312-114.688 256-256 256h-256c-141.312 0-256-114.688-256-256s114.688-256 256-256h148.992z">
+            <local:MyListItem.Buttons>
+                <x:Array Type="{x:Type local:MyIconButton}">
+                    <local:MyIconButton ToolTip="关闭联机模块" Loaded="BtnIoiStop_Loaded" Click="BtnIoiStop_Click"
+                                        ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" ToolTipService.VerticalOffset="-2" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.7" 
+                                        Logo="M576 512l277.333333 277.333333-64 64-277.333333-277.333333L234.666667 853.333333 170.666667 789.333333l277.333333-277.333333L170.666667 234.666667 234.666667 170.666667l277.333333 277.333333L789.333333 170.666667 853.333333 234.666667 576 512z" />
+                </x:Array>
+            </local:MyListItem.Buttons>
+        </local:MyListItem>
+        <TextBlock Text="更多选项" Margin="13,18,5,5" Opacity="0.6" FontSize="12" />
+        <local:MyListItem x:Name="ItemSetup" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="5" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="设置"
+                          LogoScale="0.85" Logo="M940.4 463.7L773.3 174.2c-17.3-30-49.2-48.4-83.8-48.4H340.2c-34.6 0-66.5 18.5-83.8 48.4L89.2 463.7c-17.3 30-17.3 66.9 0 96.8L256.4 850c17.3 30 49.2 48.4 83.8 48.4h349.2c34.6 0 66.5-18.5 83.8-48.4l167.2-289.5c17.3-29.9 17.3-66.8 0-96.8z m-94.6 96.8L725.9 768.1c-17.3 30-49.2 48.4-83.8 48.4H387.5c-34.6 0-66.5-18.5-83.8-48.4L183.9 560.5c-17.3-30-17.3-66.9 0-96.8l119.8-207.5c17.3-30 49.2-48.4 83.8-48.4h254.6c34.6 0 66.5 18.5 83.8 48.4l119.8 207.5c17.3 30 17.3 66.9 0.1 96.8z M522.3 321.2c-2.5-0.1-5-0.2-7.5-0.2-119.9 0-214 110.3-186.3 235 15.8 70.9 71.5 126.6 142.4 142.4 17.5 3.9 34.7 5.4 51.4 4.7 102.1-3.9 183.6-87.9 183.6-191 0.1-103-81.5-187-183.6-190.9z m68.6 269.1c-18.5 18-43 28.9-68.6 30.7l-6 0.3c-30.2 0.4-58.6-11.4-79.7-33-19.5-20.1-30.7-47-30.9-75-0.3-29.6 11.1-57.4 32-78.3 20.6-20.6 48-32 77.2-32 2.5 0 5 0.1 7.5 0.3 26.7 1.8 51.5 13.2 70.5 32.5 19.6 20 30.8 46.9 31.2 74.9 0.2 30.2-11.5 58.6-33.2 79.6z">
+            <local:MyListItem.Buttons>
+                <x:Array Type="{x:Type local:MyIconButton}">
+                    <local:MyIconButton Tag="5" ToolTip="初始化设置" ToolTipService.Placement="Right" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" Click="Reset" Logo="M835.072 184.32l-77.824 81.92c-64.512-66.56-153.6-106.496-251.904-106.496-195.584 0-355.328 159.744-355.328 354.304 0 195.584 159.744 354.304 355.328 354.304 147.456 0 304.128-80.896 337.92-245.76 3.072-15.36-9.216-23.552-21.504-23.552l-72.704 0c-15.36 0-28.672 14.336-29.696 24.576 0 2.048 0 3.072-1.024 3.072-32.768 96.256-107.52 119.808-212.992 119.808-128 0-232.448-104.448-232.448-232.448s104.448-231.424 232.448-231.424c64.512 0 121.856 26.624 165.888 69.632l-101.376 100.352c-1.024 0-1.024 1.024-2.048 1.024-20.48 22.528-12.288 37.888 11.264 37.888l256 0c22.528 0 36.864-15.36 36.864-37.888L871.936 193.536C870.912 174.08 857.6 166.912 835.072 184.32z" LogoScale="0.9" />
+                </x:Array>
+            </local:MyListItem.Buttons>
+        </local:MyListItem>
+        <local:MyListItem x:Name="ItemHelp" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="6" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="常见问题"
+                          LogoScale="0.97" Logo="M520.6 620.3c-11.3-0.6-20.1-4-26.9-10.5-6.6-6.3-8.1-11-10.1-20.8-1.9-9.5-1.5-16.7-1-24.9l0.3-5.3c0.5-9.9 3.5-19.6 8.8-28.1 5.7-9 12.5-17.2 20.8-25.1 8.6-8 17.7-15.7 27-22.9 9.4-7.2 18.7-14.8 27.7-22.7 9-7.9 16.2-15.8 22.1-24.3 6.2-9 9.3-18.8 9.3-29.4 1.2-20.3-6.5-37.7-22.8-51.3-16-13.3-37.4-20-63.5-20-13.7 0-26.3 3.3-37.4 10-10.9 6.5-20.2 14.5-27.7 23.8-7.5 9.2-13.5 19-17.9 29.2-4.5 10.6-6.7 19.4-6.7 26.8 0 9.2-3.3 16-10.1 20.8-6.9 4.8-14.6 7.3-22.8 7.3h-1.3c-9-0.3-17-3.3-24.6-9.2-7.3-5.6-11.1-14.6-11.6-27.5-0.6-11.5 1.9-26.1 7.2-43.5 5.4-17.4 14.8-34.4 28.1-50.5 13.4-16.3 31.2-30.4 52.8-41.8 21.6-11.4 49.2-17.2 81.9-17.2 26.4 0 49.6 3.9 69.1 11.7 19.4 7.7 35.4 18.2 47.5 31.1l1.6 1.7c11.8 12.6 20.3 21.7 29.4 44.4 11.6 28.9 7.1 52.1 5.5 58.5-5.8 22.6-12.6 37.7-22.7 50.4-11.7 14.6-24.9 28.2-39.2 40.4-14 11.7-39.2 33.3-39.2 33.3-13.3 11.4-19.4 22.1-18.6 32.9V587c0.5 8.7-2.4 16.1-8.8 22.8-6.2 6.4-14.8 10-26.2 10.5zM519 766.1c-13 0-23.6-4.2-32.2-12.9-8.7-8.7-13-19-13-31.4 0-12.9 4.2-23.5 12.9-32.2 8.7-8.7 19.2-12.9 32.2-12.9 13 0 23.5 4.2 32.2 12.9s12.9 19.2 12.9 32.2c0 12.4-4.2 22.7-12.9 31.4-8.6 8.6-19.2 12.9-32.1 12.9z M515 928.3c-228.1 0-413.7-185.6-413.7-413.7S286.9 100.9 515 100.9s413.7 185.6 413.7 413.7c0.1 228.1-185.5 413.7-413.7 413.7z m0-747.4c-184 0-333.7 149.7-333.7 333.7S331 848.3 515 848.3s333.7-149.7 333.7-333.7S699 180.9 515 180.9z" />
+        <local:MyListItem x:Name="ItemFeedback" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="7" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="反馈"
+                          LogoScale="0.9" Logo="M613.717333 64.426667l3.413334 3.242666 331.861333 331.861334a85.333333 85.333333 0 0 1 3.2 117.269333l-3.2 3.413333L573.162667 896H960a21.333333 21.333333 0 0 1 21.333333 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333333 21.333333H64a21.333333 21.333333 0 0 1-21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h295.338667L74.069333 610.709333a85.333333 85.333333 0 0 1-3.221333-117.269333l3.2-3.413333 422.4-422.357334a85.333333 85.333333 0 0 1 117.269333-3.221333z m-20.629333 99.882666l-21.418667 321.493334a85.333333 85.333333 0 0 1-74.944 79.04l-4.522666 0.426666-321.493334 21.44 295.552 295.530667 422.4-422.378667L593.066667 164.309333z m-86.442667 13.824L184.533333 500.266667l301.994667-20.117334 20.117333-301.994666z" />
+    </StackPanel>
+</local:MyPageLeft>