Jelajahi Sumber

refactor: 合并 Forge 和 NeoForge 部分代码

Pigeon0v0 2 tahun lalu
induk
melakukan
cf43244264

+ 6 - 5
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb

@@ -787,12 +787,9 @@
                 Dim Version As String = Token.Replace("neoforge-", "")
                 Dim Version As String = Token.Replace("neoforge-", "")
                 Dim Inherit As String = $"1.{Version.Split(".")(0)}.{Token.Split(".")(1)}"
                 Dim Inherit As String = $"1.{Version.Split(".")(0)}.{Token.Split(".")(1)}"
                 If Inherit.EndsWith(".0") Then Inherit = Inherit.Replace(".0", "")
                 If Inherit.EndsWith(".0") Then Inherit = Inherit.Replace(".0", "")
-                If Versions.Contains(Inherit) Then
-                    Continue For
-                Else
-                    Versions.Add(Inherit)
-                End If
+                Versions.Add(Inherit)
             Next
             Next
+            Versions = Versions.Distinct().ToList()
         Catch ex As Exception
         Catch ex As Exception
             Log(ex, LogLevel.Feedback)
             Log(ex, LogLevel.Feedback)
         End Try
         End Try
@@ -892,6 +889,10 @@
                 End If
                 End If
             End Get
             End Get
         End Property
         End Property
+        ''' <summary>
+        ''' 文件扩展名
+        ''' </summary>
+        Public ReadOnly Property FileSuffix As String = ".jar"
     End Class
     End Class
     ''' <summary>
     ''' <summary>
     ''' NeoForge 版本列表,主加载器。
     ''' NeoForge 版本列表,主加载器。

+ 108 - 548
Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb

@@ -1005,15 +1005,16 @@ Retry:
 
 
 #End Region
 #End Region
 
 
-#Region "Forge 下载"
+#Region "Forge / NeoForge 下载"
 
 
-    Public Sub McDownloadForge(DownloadInfo As DlForgeVersionEntry)
+    Public Sub McDownloadForge(IsNeo As Boolean, Optional DownloadForgeInfo As DlForgeVersionEntry = Nothing, Optional DownloadNeoInfo As DlNeoForgeVersionEntry = Nothing)
+        Dim DownloadInfo = If(IsNeo, DownloadNeoInfo, DownloadForgeInfo)
         '老版本提示
         '老版本提示
         If DownloadInfo.Category = "client" Then
         If DownloadInfo.Category = "client" Then
             If MyMsgBox("该 Forge 版本过于古老,PCL 暂不支持该版本的自动安装。" & vbCrLf &
             If MyMsgBox("该 Forge 版本过于古老,PCL 暂不支持该版本的自动安装。" & vbCrLf &
                         "若你仍然希望继续,PCL 将把安装程序下载到你指定的位置,但不会进行安装。",
                         "若你仍然希望继续,PCL 将把安装程序下载到你指定的位置,但不会进行安装。",
                         "版本过老", "继续", "取消") = 1 Then
                         "版本过老", "继续", "取消") = 1 Then
-                McDownloadForgeSave(DownloadInfo)
+                McDownloadForgeSave(IsNeo, DownloadInfo)
             End If
             End If
             Exit Sub
             Exit Sub
         End If
         End If
@@ -1021,15 +1022,15 @@ Retry:
             If MyMsgBox("该 Forge 版本过于古老,PCL 暂不支持该版本的自动安装。" & vbCrLf &
             If MyMsgBox("该 Forge 版本过于古老,PCL 暂不支持该版本的自动安装。" & vbCrLf &
                         "若你仍然希望继续,PCL 将把安装程序下载到你指定的位置,但不会进行安装。",
                         "若你仍然希望继续,PCL 将把安装程序下载到你指定的位置,但不会进行安装。",
                         "版本过老", "继续", "取消") = 1 Then
                         "版本过老", "继续", "取消") = 1 Then
-                McDownloadForgeSave(DownloadInfo)
+                McDownloadForgeSave(IsNeo, DownloadInfo)
             End If
             End If
             Exit Sub
             Exit Sub
         End If
         End If
         '初始化参数
         '初始化参数
-        Dim Id As String = DownloadInfo.Inherit & "-forge-" & DownloadInfo.Version
-        Dim Target As String = PathTemp & "Cache\Code\ForgeInstall-" & DownloadInfo.Version & "_" & GetUuid() & "." & DownloadInfo.FileSuffix
+        Dim Id As String = DownloadInfo.Inherit & $"-{If(IsNeo, "neo", "")}forge-" & DownloadInfo.Version
+        Dim Target As String = PathTemp & $"Cache\Code\{If(IsNeo, "Neo", "")}ForgeInstall-" & DownloadInfo.Version & "_" & GetUuid() & "." & DownloadInfo.FileSuffix
         Dim VersionFolder As String = PathMcFolder & "versions\" & Id & "\"
         Dim VersionFolder As String = PathMcFolder & "versions\" & Id & "\"
-        Dim DisplayName As String = "Forge " & DownloadInfo.Inherit & " - " & DownloadInfo.Version
+        Dim DisplayName As String = $"{If(IsNeo, "Neo", "")}Forge " & DownloadInfo.Inherit & " - " & DownloadInfo.Version
         Try
         Try
 
 
             '重复任务检查
             '重复任务检查
@@ -1053,14 +1054,14 @@ Retry:
             End If
             End If
 
 
             '启动
             '启动
-            Dim Loader As New LoaderCombo(Of String)(DisplayName & " 下载", McDownloadForgeLoader(DownloadInfo.Version, DownloadInfo.Inherit, DownloadInfo)) With {.OnStateChanged = AddressOf McInstallState}
+            Dim Loader As New LoaderCombo(Of String)(DisplayName & " 下载", McDownloadForgeLoader(IsNeo, DownloadInfo.Version, DownloadInfo.Inherit, DownloadInfo)) With {.OnStateChanged = AddressOf McInstallState}
             Loader.Start(VersionFolder)
             Loader.Start(VersionFolder)
             LoaderTaskbarAdd(Loader)
             LoaderTaskbarAdd(Loader)
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.Ribble()
             FrmMain.BtnExtraDownload.Ribble()
 
 
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, "开始 Forge 下载失败", LogLevel.Feedback)
+            Log(ex, $"开始 {If(IsNeo, "Neo", "")}Forge 下载失败", LogLevel.Feedback)
         Finally
         Finally
             '删除安装包
             '删除安装包
             Try
             Try
@@ -1069,10 +1070,11 @@ Retry:
             End Try
             End Try
         End Try
         End Try
     End Sub
     End Sub
-    Public Sub McDownloadForgeSave(DownloadInfo As DlForgeVersionEntry)
+    Public Sub McDownloadForgeSave(IsNeo As Boolean, Optional DownloadForgeInfo As DlForgeVersionEntry = Nothing, Optional DownloadNeoInfo As DlNeoForgeVersionEntry = Nothing)
+        Dim DownloadInfo = If(IsNeo, DownloadNeoInfo, DownloadForgeInfo)
         Try
         Try
-            Dim Target As String = SelectAs("选择保存位置", DownloadInfo.FileName, "Forge 文件 (*." & DownloadInfo.FileSuffix & ")|*." & DownloadInfo.FileSuffix)
-            Dim DisplayName As String = "Forge " & DownloadInfo.Inherit & " - " & DownloadInfo.Version
+            Dim Target As String = SelectAs("选择保存位置", DownloadInfo.FileName, $"{If(IsNeo, "Neo", "")}Forge 文件 (*." & DownloadInfo.FileSuffix & ")|*." & DownloadInfo.FileSuffix)
+            Dim DisplayName As String = $"{If(IsNeo, "Neo", "")}Forge " & DownloadInfo.Inherit & " - " & If(IsNeo, DownloadInfo.VersionCode, DownloadInfo.Version)
             If Not Target.Contains("\") Then Exit Sub
             If Not Target.Contains("\") Then Exit Sub
 
 
             '重复任务检查
             '重复任务检查
@@ -1088,31 +1090,47 @@ Retry:
             '构造步骤加载器
             '构造步骤加载器
             Dim Loaders As New List(Of LoaderBase)
             Dim Loaders As New List(Of LoaderBase)
             '获取下载地址
             '获取下载地址
-            Loaders.Add(New LoaderTask(Of DlForgeVersionEntry, List(Of NetFile))("获取下载地址",
-            Sub(Task As LoaderTask(Of DlForgeVersionEntry, List(Of NetFile)))
-                Dim Files As New List(Of NetFile)
-                Files.Add(New NetFile({
-                    "https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
-                    "https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
-                }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash)))
-                Task.Output = Files
-            End Sub) With {.ProgressWeight = 0.1, .Show = False})
+            If IsNeo Then
+                'NeoForge
+                Loaders.Add(New LoaderTask(Of DlNeoForgeVersionEntry, List(Of NetFile))("获取下载地址",
+                Sub(Task As LoaderTask(Of DlNeoForgeVersionEntry, List(Of NetFile)))
+                    Dim Files As New List(Of NetFile)
+                    Dim IsLegacyNeo As Boolean = DownloadInfo.VersionCode.StartsWith("47.")
+                    Files.Add(New NetFile({
+                        $"https://bmclapi2.bangbang93.com/maven/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}",
+                        $"https://maven.neoforged.net/releases/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}"
+                    }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash)))
+                    Task.Output = Files
+                End Sub) With {.ProgressWeight = 0.1, .Show = False})
+            Else
+                'Forge
+                Loaders.Add(New LoaderTask(Of DlForgeVersionEntry, List(Of NetFile))("获取下载地址",
+                Sub(Task As LoaderTask(Of DlForgeVersionEntry, List(Of NetFile)))
+                    Dim Files As New List(Of NetFile)
+                    Files.Add(New NetFile({
+                        "https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
+                        "https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
+                    }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash)))
+                    Task.Output = Files
+                End Sub) With {.ProgressWeight = 0.1, .Show = False})
+            End If
             '下载
             '下载
             Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile)) With {.ProgressWeight = 6})
             Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile)) With {.ProgressWeight = 6})
 
 
             '启动
             '启动
-            Dim Loader As New LoaderCombo(Of DlForgeVersionEntry)(DisplayName & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
+            Dim Loader = If(IsNeo, New LoaderCombo(Of DlNeoForgeVersionEntry)(DisplayName & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave},
+                New LoaderCombo(Of DlForgeVersionEntry)(DisplayName & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave})
             Loader.Start(DownloadInfo)
             Loader.Start(DownloadInfo)
             LoaderTaskbarAdd(Loader)
             LoaderTaskbarAdd(Loader)
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.Ribble()
             FrmMain.BtnExtraDownload.Ribble()
 
 
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, "开始 Forge 下载失败", LogLevel.Feedback)
+            Log(ex, $"开始 {If(IsNeo, "Neo", "")}Forge 下载失败", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
 
 
-    Private Sub ForgeInjector(Target As String, Task As LoaderTask(Of Boolean, Boolean), McFolder As String, UseJavaWrapper As Boolean)
+    Private Sub ForgeInjector(Target As String, Task As LoaderTask(Of Boolean, Boolean), McFolder As String, UseJavaWrapper As Boolean, IsNeoForge As Boolean)
         '选择 Java
         '选择 Java
         Dim Java As JavaEntry
         Dim Java As JavaEntry
         SyncLock JavaLock
         SyncLock JavaLock
@@ -1153,7 +1171,7 @@ Retry:
                 .RedirectStandardError = True,
                 .RedirectStandardError = True,
                 .RedirectStandardOutput = True
                 .RedirectStandardOutput = True
             }
             }
-            Log("[Download] 开始安装 Forge:" & Arguments)
+            Log($"[Download] 开始安装 {If(IsNeoForge, "Neo", "")}Forge:" & Arguments)
             Dim process As New Process With {.StartInfo = Info}
             Dim process As New Process With {.StartInfo = Info}
             Dim LastResults As New Queue(Of String)
             Dim LastResults As New Queue(Of String)
             Using outputWaitHandle As New AutoResetEvent(False)
             Using outputWaitHandle As New AutoResetEvent(False)
@@ -1170,11 +1188,11 @@ Retry:
                             End If
                             End If
                         Catch ex As ObjectDisposedException
                         Catch ex As ObjectDisposedException
                         Catch ex As Exception
                         Catch ex As Exception
-                            Log(ex, "读取 Forge 安装器信息失败")
+                            Log(ex, $"读取 {If(IsNeoForge, "Neo", "")}Forge 安装器信息失败")
                         End Try
                         End Try
                         Try
                         Try
                             If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
                             If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
-                                Log("[Installer] 由于任务取消,已中止 Forge 安装")
+                                Log($"[Installer] 由于任务取消,已中止 {If(IsNeoForge, "Neo", "")}Forge 安装")
                                 process.Kill()
                                 process.Kill()
                             End If
                             End If
                         Catch
                         Catch
@@ -1193,11 +1211,11 @@ Retry:
                             End If
                             End If
                         Catch ex As ObjectDisposedException
                         Catch ex As ObjectDisposedException
                         Catch ex As Exception
                         Catch ex As Exception
-                            Log(ex, "读取 Forge 安装器错误信息失败")
+                            Log(ex, $"读取 {If(IsNeoForge, "Neo", "")}Forge 安装器错误信息失败")
                         End Try
                         End Try
                         Try
                         Try
                             If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
                             If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
-                                Log("[Installer] 由于任务取消,已中止 Forge 安装")
+                                Log($"[Installer] 由于任务取消,已中止 {If(IsNeoForge, "Neo", "")}Forge 安装")
                                 process.Kill()
                                 process.Kill()
                             End If
                             End If
                         Catch
                         Catch
@@ -1222,7 +1240,7 @@ Retry:
                     For i As Integer = Math.Max(0, LastResults.Count - 5) To LastResults.Count - 1 '最后 5 行
                     For i As Integer = Math.Max(0, LastResults.Count - 5) To LastResults.Count - 1 '最后 5 行
                         LastLines &= vbCrLf & LastResults(i)
                         LastLines &= vbCrLf & LastResults(i)
                     Next
                     Next
-                    Throw New Exception("Forge 安装器出错,日志结束部分为:" & LastLines)
+                    Throw New Exception($"{If(IsNeoForge, "Neo", "")}Forge 安装器出错,日志结束部分为:" & LastLines)
                 End Using
                 End Using
             End Using
             End Using
         End SyncLock
         End SyncLock
@@ -1273,31 +1291,43 @@ Retry:
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
-    ''' 获取下载某个 Forge 版本的加载器列表。
+    ''' 获取下载某个 Forge / NeoForge 版本的加载器列表。
     ''' </summary>
     ''' </summary>
-    Private Function McDownloadForgeLoader(Version As String, Inherit As String, Optional DownloadInfo As DlForgeVersionEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
+    Private Function McDownloadForgeLoader(IsNeo As Boolean, Version As String, Inherit As String, Optional DownloadForgeInfo As DlForgeVersionEntry = Nothing, Optional DownloadNeoInfo As DlNeoForgeVersionEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
 
 
         '参数初始化
         '参数初始化
+        Dim DownloadInfo = If(IsNeo, DownloadNeoInfo, DownloadForgeInfo)
+        If DownloadNeoInfo Is Nothing AndAlso IsNeo Then          '兜底,有的时候 DownloadInfo 可能是空的
+            DownloadInfo.VersionName = Version
+            Version = Version.Replace("neoforge-", "").Replace("-beta", "").Replace("1.20.1-", "")
+            DownloadInfo.VersionCode = Version
+            If Version.Contains("-beta") Then DownloadInfo.IsBeta = True
+        ElseIf IsNeo Then
+            DownloadInfo = DownloadNeoInfo
+            Version = DownloadInfo.VersionCode
+        Else
+            DownloadInfo = DownloadForgeInfo
+        End If
         McFolder = If(McFolder, PathMcFolder)
         McFolder = If(McFolder, PathMcFolder)
-        If Version.StartsWithF("1.") AndAlso Version.Contains("-") Then
+        If Not IsNeo AndAlso Version.StartsWithF("1.") AndAlso Version.Contains("-") Then
             '类似 1.19.3-41.2.8 格式,优先使用 Version 中要求的版本而非 Inherit(例如 1.19.3 却使用了 1.19 的 Forge)
             '类似 1.19.3-41.2.8 格式,优先使用 Version 中要求的版本而非 Inherit(例如 1.19.3 却使用了 1.19 的 Forge)
             Inherit = Version.Before("-")
             Inherit = Version.Before("-")
             Version = Version.After("-")
             Version = Version.After("-")
         End If
         End If
         Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
         Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
-        Dim Id As String = Inherit & "-forge-" & Version
-        Dim InstallerAddress As String = PathTemp & "Cache\Code\ForgeInstall-" & Version & "_" & RandomInteger(0, 100000)
+        Dim Id As String = If(IsNeo, DownloadInfo.VersionName, Inherit & "-forge-" & Version)
+        Dim InstallerAddress As String = PathTemp & $"Cache\Code\{If(IsNeo, "Neo", "")}ForgeInstall-" & Version & "_" & RandomInteger(0, 100000)
         Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
         Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
-        Dim DisplayName As String = "Forge " & Inherit & " - " & Version
+        Dim DisplayName As String = $"{If(IsNeo, "Neo", "")}Forge " & Inherit & " - " & Version
         Dim Loaders As New List(Of LoaderBase)
         Dim Loaders As New List(Of LoaderBase)
         Dim LibVersionFolder As String = PathMcFolder & "versions\" & Id & "\" '作为 Lib 文件目标的版本文件夹
         Dim LibVersionFolder As String = PathMcFolder & "versions\" & Id & "\" '作为 Lib 文件目标的版本文件夹
 
 
         '获取下载信息
         '获取下载信息
         If DownloadInfo Is Nothing Then
         If DownloadInfo Is Nothing Then
-            Loaders.Add(New LoaderTask(Of String, String)("获取 Forge 详细信息",
+            Loaders.Add(New LoaderTask(Of String, String)($"获取 {If(IsNeo, "Neo", "")}Forge 详细信息",
             Sub(Task As LoaderTask(Of String, String))
             Sub(Task As LoaderTask(Of String, String))
-                '获取 Forge 版本列表
-                Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("McDownloadForgeLoader " & Inherit, AddressOf DlForgeVersionMain)
+                '获取 Forge / NeoForge 版本列表
+                Dim ForgeLoader = If(IsNeo, New LoaderTask(Of String, List(Of DlNeoForgeVersionEntry))("McDownloadForgeLoader " & Inherit, AddressOf DlNeoForgeVersionMain), New LoaderTask(Of String, List(Of DlForgeVersionEntry))("McDownloadForgeLoader " & Inherit, AddressOf DlForgeVersionMain))
                 ForgeLoader.WaitForExit(Inherit)
                 ForgeLoader.WaitForExit(Inherit)
                 Task.Progress = 0.8
                 Task.Progress = 0.8
                 '查找对应版本
                 '查找对应版本
@@ -1307,11 +1337,11 @@ Retry:
                         Exit Sub
                         Exit Sub
                     End If
                     End If
                 Next
                 Next
-                Throw New Exception("未能找到 Forge " & Inherit & "-" & Version & " 的详细信息!")
+                Throw New Exception($"未能找到 {If(IsNeo, "Neo", "")}Forge " & Inherit & "-" & Version & " 的详细信息!")
             End Sub) With {.ProgressWeight = 3})
             End Sub) With {.ProgressWeight = 3})
         End If
         End If
-        '下载 Forge 主文件
-        Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("准备下载 Forge",
+        '下载 Forge / NeoForge 主文件
+        Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"准备下载 {If(IsNeo, "Neo", "")}Forge",
             Sub(Task As LoaderTask(Of String, List(Of NetFile)))
             Sub(Task As LoaderTask(Of String, List(Of NetFile)))
                 '启动依赖版本的下载
                 '启动依赖版本的下载
                 If ClientDownloadLoader Is Nothing Then
                 If ClientDownloadLoader Is Nothing Then
@@ -1319,19 +1349,28 @@ Retry:
                     ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, Inherit)
                     ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, Inherit)
                 End If
                 End If
                 '添加主文件
                 '添加主文件
-                Dim Files As New List(Of NetFile) From {New NetFile({
+                Dim Files
+                If IsNeo Then 'NeoForge
+                    Dim IsLegacyNeo As Boolean = DownloadInfo.VersionCode.StartsWith("47.")
+                    Files = New List(Of NetFile) From {New NetFile({
+                        $"https://bmclapi2.bangbang93.com/maven/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}",
+                        $"https://maven.neoforged.net/releases/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}"
+                    }, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash))}
+                Else 'Forge
+                    Files = New List(Of NetFile) From {New NetFile({
                     "https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
                     "https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
                     "https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
                     "https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
                 }, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash))}
                 }, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash))}
+                End If
                 Task.Output = Files
                 Task.Output = Files
             End Sub) With {.ProgressWeight = 0.5, .Show = False})
             End Sub) With {.ProgressWeight = 0.5, .Show = False})
-        Loaders.Add(New LoaderDownload("下载 Forge 主文件", New List(Of NetFile)) With {.ProgressWeight = 9})
+        Loaders.Add(New LoaderDownload($"下载 {If(IsNeo, "Neo", "")}Forge 主文件", New List(Of NetFile)) With {.ProgressWeight = 9})
 
 
         '安装(仅在新版安装时需要原版 Jar)
         '安装(仅在新版安装时需要原版 Jar)
         If Version.Before(".") >= 20 Then
         If Version.Before(".") >= 20 Then
-            Log("[Download] 检测为新版 Forge:" & Version)
+            Log($"[Download] 检测为{If(IsNeo, " Neo", "新版 ")}Forge:" & Version)
             Dim Libs As List(Of McLibToken) = Nothing
             Dim Libs As List(Of McLibToken) = Nothing
-            Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 Forge 支持库文件",
+            Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"分析 {If(IsNeo, "Neo", "")}Forge 支持库文件",
             Sub(Task As LoaderTask(Of String, List(Of NetFile)))
             Sub(Task As LoaderTask(Of String, List(Of NetFile)))
                 Task.Output = New List(Of NetFile)
                 Task.Output = New List(Of NetFile)
                 Dim Installer As ZipArchive = Nothing
                 Dim Installer As ZipArchive = Nothing
@@ -1357,27 +1396,27 @@ Retry:
                         Log("[Download] 需要下载 Mappings:" & Address)
                         Log("[Download] 需要下载 Mappings:" & Address)
                     End If
                     End If
                     Task.Progress = 0.8
                     Task.Progress = 0.8
-                    '去除其中的原始 Forge 项
+                    '去除其中的原始 Forge / NeoForge 项
                     For i = 0 To Libs.Count - 1
                     For i = 0 To Libs.Count - 1
-                        If Libs(i).LocalPath.EndsWithF("forge-" & Inherit & "-" & Version & ".jar") OrElse
+                        If Libs(i).LocalPath.EndsWithF($"{If(IsNeo, "neo", "")}forge-" & Inherit & "-" & Version & ".jar") OrElse
                                                                                                       Libs(i).LocalPath.EndsWithF("forge-" & Inherit & "-" & Version & "-client.jar") Then
                                                                                                       Libs(i).LocalPath.EndsWithF("forge-" & Inherit & "-" & Version & "-client.jar") Then
-                            Log("[Download] 已从待下载 Forge 支持库中移除:" & Libs(i).LocalPath, LogLevel.Debug)
+                            Log($"[Download] 已从待下载 {If(IsNeo, "Neo", "")}Forge 支持库中移除:" & Libs(i).LocalPath, LogLevel.Debug)
                             Libs.RemoveAt(i)
                             Libs.RemoveAt(i)
                             Exit For
                             Exit For
                         End If
                         End If
                     Next
                     Next
                     Task.Output = McLibFixFromLibToken(Libs, PathMcFolder)
                     Task.Output = McLibFixFromLibToken(Libs, PathMcFolder)
                 Catch ex As Exception
                 Catch ex As Exception
-                    Throw New Exception("获取新版 Forge 支持库列表失败", ex)
+                    Throw New Exception($"获取{If(IsNeo, " Neo", "新版 ")}Forge 支持库列表失败", ex)
                 Finally
                 Finally
                     '释放文件
                     '释放文件
                     If Installer IsNot Nothing Then Installer.Dispose()
                     If Installer IsNot Nothing Then Installer.Dispose()
                 End Try
                 End Try
             End Sub) With {.ProgressWeight = 2})
             End Sub) With {.ProgressWeight = 2})
-            Loaders.Add(New LoaderDownload("下载 Forge 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 12})
-            Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("获取 Forge 支持库文件",
+            Loaders.Add(New LoaderDownload($"下载 {If(IsNeo, "Neo", "")}Forge 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 12})
+            Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)($"获取 {If(IsNeo, "Neo", "")}Forge 支持库文件",
             Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
             Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
-#Region "Forge 文件"
+#Region "Forge / NeoForge 文件"
                 If IsCustomFolder Then
                 If IsCustomFolder Then
                     For Each LibFile As McLibToken In Libs
                     For Each LibFile As McLibToken In Libs
                         Dim RealPath As String = LibFile.LocalPath.Replace(PathMcFolder, McFolder)
                         Dim RealPath As String = LibFile.LocalPath.Replace(PathMcFolder, McFolder)
@@ -1385,7 +1424,7 @@ Retry:
                             Directory.CreateDirectory(IO.Path.GetDirectoryName(RealPath))
                             Directory.CreateDirectory(IO.Path.GetDirectoryName(RealPath))
                             CopyFile(LibFile.LocalPath, RealPath)
                             CopyFile(LibFile.LocalPath, RealPath)
                         End If
                         End If
-                        If ModeDebug Then Log("[Download] 复制的 Forge 支持库文件:" & LibFile.LocalPath)
+                        If ModeDebug Then Log($"[Download] 复制的 {If(IsNeo, "Neo", "")}Forge 支持库文件:" & LibFile.LocalPath)
                     Next
                     Next
                 End If
                 End If
 #End Region
 #End Region
@@ -1395,7 +1434,7 @@ Retry:
                 Dim TargetLoaders As List(Of LoaderBase) =
                 Dim TargetLoaders As List(Of LoaderBase) =
                                                                                 ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
                                                                                 ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
                                                                                 Where(Function(l) l.State <> LoadState.Finished).ToList
                                                                                 Where(Function(l) l.State <> LoadState.Finished).ToList
-                If TargetLoaders.Any Then Log("[Download] Forge 安装正在等待原版文件下载完成")
+                If TargetLoaders.Any Then Log($"[Download] {If(IsNeo, "Neo", "")}Forge 安装正在等待原版文件下载完成")
                 Do While TargetLoaders.Any AndAlso Not Task.IsAborted
                 Do While TargetLoaders.Any AndAlso Not Task.IsAborted
                     TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
                     TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
                     Thread.Sleep(50)
                     Thread.Sleep(50)
@@ -1415,11 +1454,11 @@ Retry:
                 End SyncLock
                 End SyncLock
 #End Region
 #End Region
             End Sub) With {.ProgressWeight = 0.1, .Show = False})
             End Sub) With {.ProgressWeight = 0.1, .Show = False})
-            Loaders.Add(New LoaderTask(Of Boolean, Boolean)("安装 Forge(方式 A)",
+            Loaders.Add(New LoaderTask(Of Boolean, Boolean)(If(IsNeo, "安装 NeoForge", "安装 Forge(方式 A)"),
             Sub(Task As LoaderTask(Of Boolean, Boolean))
             Sub(Task As LoaderTask(Of Boolean, Boolean))
                 Dim Installer As ZipArchive = Nothing
                 Dim Installer As ZipArchive = Nothing
                 Try
                 Try
-                    Log("[Download] 开始进行新版方式 Forge 安装:" & InstallerAddress)
+                    Log($"[Download] 开始进行{If(IsNeo, " Neo", "新版方式 ")}Forge 安装:" & InstallerAddress)
                     '记录当前文件夹列表(在新建目标文件夹之前)
                     '记录当前文件夹列表(在新建目标文件夹之前)
                     Dim OldList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.
                     Dim OldList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.
                                                                         Select(Function(i) i.FullName).ToList()
                                                                         Select(Function(i) i.FullName).ToList()
@@ -1440,15 +1479,15 @@ Retry:
                         WriteFile(PathTemp & "Cache\forge_installer.jar", GetResources("ForgeInstaller"))
                         WriteFile(PathTemp & "Cache\forge_installer.jar", GetResources("ForgeInstaller"))
                         Task.Progress = 0.06
                         Task.Progress = 0.06
                         '运行注入器
                         '运行注入器
-                        ForgeInjector(InstallerAddress, Task, McFolder, UseJavaWrapper)
+                        ForgeInjector(InstallerAddress, Task, McFolder, UseJavaWrapper, False)
                         Task.Progress = 0.97
                         Task.Progress = 0.97
                     Catch ex As Exception
                     Catch ex As Exception
                         If UseJavaWrapper Then
                         If UseJavaWrapper Then
-                            Log(ex, "使用 JavaWrapper 安装 Forge 失败,将不使用 JavaWrapper 并重试")
+                            Log(ex, $"使用 JavaWrapper 安装 {If(IsNeo, "Neo", "")}Forge 失败,将不使用 JavaWrapper 并重试")
                             UseJavaWrapper = False
                             UseJavaWrapper = False
                             GoTo Retry
                             GoTo Retry
                         Else
                         Else
-                            Throw New Exception("运行 Forge 安装器失败", ex)
+                            Throw New Exception($"运行 {If(IsNeo, "Neo", "")}Forge 安装器失败", ex)
                         End If
                         End If
                     End Try
                     End Try
                     '拷贝新增的版本 Json
                     '拷贝新增的版本 Json
@@ -1457,7 +1496,7 @@ Retry:
                     If DeltaList.Count > 1 Then
                     If DeltaList.Count > 1 Then
                         '它可能和 OptiFine 安装同时运行,导致增加的文件不止一个(这导致了 #151)
                         '它可能和 OptiFine 安装同时运行,导致增加的文件不止一个(这导致了 #151)
                         '也可能是因为 Forge 安装器的 Bug,生成了一个名字错误的文件夹,所以需要检查文件夹是否为空
                         '也可能是因为 Forge 安装器的 Bug,生成了一个名字错误的文件夹,所以需要检查文件夹是否为空
-                        DeltaList = DeltaList.Where(Function(l) l.Name.Contains("forge") AndAlso l.EnumerateFiles.Any).ToList
+                        DeltaList = DeltaList.Where(Function(l) l.Name.Contains($"{If(IsNeo, "neo", "")}forge") AndAlso l.EnumerateFiles.Any).ToList
                     End If
                     End If
                     If DeltaList.Count = 1 Then '如果没有新增文件夹,那么预测的文件夹名就是正确的
                     If DeltaList.Count = 1 Then '如果没有新增文件夹,那么预测的文件夹名就是正确的
                         Dim JsonFile As FileInfo = DeltaList(0).EnumerateFiles.First()
                         Dim JsonFile As FileInfo = DeltaList(0).EnumerateFiles.First()
@@ -1466,14 +1505,14 @@ Retry:
                     '新建 mods 文件夹
                     '新建 mods 文件夹
                     Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
                     Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
                 Catch ex As Exception
                 Catch ex As Exception
-                    Throw New Exception("安装新 Forge 版本失败", ex)
+                    Throw New Exception($"安装新 {If(IsNeo, "Neo", "")}Forge 版本失败", ex)
                 Finally
                 Finally
                     '清理文件
                     '清理文件
                     Try
                     Try
                         If Installer IsNot Nothing Then Installer.Dispose()
                         If Installer IsNot Nothing Then Installer.Dispose()
                         If File.Exists(InstallerAddress) Then File.Delete(InstallerAddress)
                         If File.Exists(InstallerAddress) Then File.Delete(InstallerAddress)
                     Catch ex As Exception
                     Catch ex As Exception
-                        Log(ex, "安装 Forge 清理文件时出错")
+                        Log(ex, $"安装 {If(IsNeo, "Neo", "")}Forge 清理文件时出错")
                     End Try
                     End Try
                 End Try
                 End Try
             End Sub) With {.ProgressWeight = 10})
             End Sub) With {.ProgressWeight = 10})
@@ -1534,8 +1573,8 @@ Retry:
             End Sub) With {.ProgressWeight = 1})
             End Sub) With {.ProgressWeight = 1})
             If FixLibrary Then
             If FixLibrary Then
                 If IsCustomFolder Then Throw New Exception("若需要补全支持库,就不能自定义 MC 文件夹")
                 If IsCustomFolder Then Throw New Exception("若需要补全支持库,就不能自定义 MC 文件夹")
-                Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 Forge 支持库文件", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
-                Loaders.Add(New LoaderDownload("下载 Forge 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 11})
+                Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"分析 {If(IsNeo, "Neo", "")}Forge 支持库文件", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
+                Loaders.Add(New LoaderDownload($"下载 {If(IsNeo, "Neo", "")}Forge 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 11})
             End If
             End If
         End If
         End If
 
 
@@ -1634,7 +1673,7 @@ Retry:
         Else
         Else
             Version = sender.Parent.Parent.Tag
             Version = sender.Parent.Parent.Tag
         End If
         End If
-        McDownloadForgeSave(Version)
+        McDownloadForgeSave(False, Version)
     End Sub
     End Sub
 
 
 #End Region
 #End Region
@@ -1696,485 +1735,6 @@ Retry:
 
 
 #End Region
 #End Region
 
 
-#Region "NeoForge 下载"
-
-    Public Sub McDownloadNeoForge(DownloadInfo As DlNeoForgeVersionEntry)
-        '初始化参数
-        Dim Id As String = DownloadInfo.Inherit & "-neoforge-" & DownloadInfo.VersionName
-        Dim Target As String = PathTemp & "Cache\Code\NeoForgeInstall-" & DownloadInfo.VersionName & "_" & GetUuid() & ".jar"
-        Dim VersionFolder As String = PathMcFolder & "versions\" & Id & "\"
-        Dim DisplayName As String = "NeoForge " & DownloadInfo.Inherit & " - " & DownloadInfo.VersionName
-        Try
-
-            '重复任务检查
-            SyncLock LoaderTaskbarLock
-                For i = 0 To LoaderTaskbar.Count - 1
-                    If LoaderTaskbar(i).Name = DisplayName & " 下载" Then
-                        Hint("该版本正在下载中!", HintType.Critical)
-                        Exit Sub
-                    End If
-                Next
-            End SyncLock
-
-            '已有版本检查
-            If File.Exists(VersionFolder & Id & ".json") Then
-                If MyMsgBox("版本 " & Id & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 Json 和 Jar 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
-                    File.Delete(VersionFolder & Id & ".jar")
-                    File.Delete(VersionFolder & Id & ".json")
-                Else
-                    Exit Sub
-                End If
-            End If
-
-            '启动
-            Dim Loader As New LoaderCombo(Of String)(DisplayName & " 下载", McDownloadNeoForgeLoader(DownloadInfo.VersionName, DownloadInfo.Inherit, DownloadInfo)) With {.OnStateChanged = AddressOf McInstallState}
-            Loader.Start(VersionFolder)
-            LoaderTaskbarAdd(Loader)
-            FrmMain.BtnExtraDownload.ShowRefresh()
-            FrmMain.BtnExtraDownload.Ribble()
-
-        Catch ex As Exception
-            Log(ex, "开始 NeoForge 下载失败", LogLevel.Feedback)
-        Finally
-            '删除安装包
-            Try
-                If File.Exists(Target) Then File.Delete(Target)
-            Catch
-            End Try
-        End Try
-    End Sub
-    Public Sub McDownloadNeoForgeSave(DownloadInfo As DlNeoForgeVersionEntry)
-        Try
-            Dim Target As String = SelectAs("选择保存位置", DownloadInfo.FileName, "NeoForge 文件 (*.jar)")
-            Dim DisplayName As String = "NeoForge " & DownloadInfo.Inherit & " - " & DownloadInfo.VersionName
-            If Not Target.Contains("\") Then Exit Sub
-
-            '重复任务检查
-            SyncLock LoaderTaskbarLock
-                For i = 0 To LoaderTaskbar.Count - 1
-                    If LoaderTaskbar(i).Name = DisplayName & " 下载" Then
-                        Hint("该版本正在下载中!", HintType.Critical)
-                        Exit Sub
-                    End If
-                Next
-            End SyncLock
-
-            '构造步骤加载器
-            Dim Loaders As New List(Of LoaderBase)
-            '获取下载地址
-            Loaders.Add(New LoaderTask(Of DlNeoForgeVersionEntry, List(Of NetFile))("获取下载地址",
-            Sub(Task As LoaderTask(Of DlNeoForgeVersionEntry, List(Of NetFile)))
-                Dim Files As New List(Of NetFile)
-                If DownloadInfo.VersionCode.StartsWith("47.") Then          '1.20.1 NeoForge 下载地址不同
-                    Files.Add(New NetFile({
-                    "https://bmclapi2.bangbang93.com/maven/net/neoforged/forge/" & "1.20.1-" & DownloadInfo.VersionCode & If(DownloadInfo.IsBeta, "-beta", "") & "/" & DownloadInfo.FileName,
-                    "https://maven.neoforged.net/releases/net/neoforged/forge/" & "1.20.1-" & DownloadInfo.VersionCode & If(DownloadInfo.IsBeta, "-beta", "") & "/" & DownloadInfo.FileName
-                }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash)))
-                Else
-                    Files.Add(New NetFile({
-                    "https://bmclapi2.bangbang93.com/maven/net/neoforged/neoforge/" & DownloadInfo.VersionCode & If(DownloadInfo.IsBeta, "-beta", "") & "/" & DownloadInfo.FileName,
-                    "https://maven.neoforged.net/releases/net/neoforged/neoforge/" & DownloadInfo.VersionCode & If(DownloadInfo.IsBeta, "-beta", "") & "/" & DownloadInfo.FileName
-                }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash)))
-                End If
-                Task.Output = Files
-            End Sub) With {.ProgressWeight = 0.1, .Show = False})
-            '下载
-            Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile)) With {.ProgressWeight = 6})
-
-            '启动
-            Dim Loader As New LoaderCombo(Of DlNeoForgeVersionEntry)(DisplayName & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
-            Loader.Start(DownloadInfo)
-            LoaderTaskbarAdd(Loader)
-            FrmMain.BtnExtraDownload.ShowRefresh()
-            FrmMain.BtnExtraDownload.Ribble()
-
-        Catch ex As Exception
-            Log(ex, "开始 NeoForge 下载失败", LogLevel.Feedback)
-        End Try
-    End Sub
-
-    Private Sub NeoForgeInjector(Target As String, Task As LoaderTask(Of Boolean, Boolean), McFolder As String, UseJavaWrapper As Boolean)
-        '选择 Java
-        Dim Java As JavaEntry
-        SyncLock JavaLock
-            Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 60))
-            If Java Is Nothing Then
-                If Not JavaDownloadConfirm("Java 8 或更高版本") Then Throw New Exception("由于未找到 Java,已取消安装。")
-                '开始自动下载
-                Dim JavaLoader = JavaFixLoaders(17)
-                Try
-                    JavaLoader.Start(17, IsForceRestart:=True)
-                    Do While JavaLoader.State = LoadState.Loading AndAlso Not Task.IsAborted
-                        Thread.Sleep(10)
-                    Loop
-                Finally
-                    JavaLoader.Abort() '确保取消时中止 Java 下载
-                End Try
-                '检查下载结果
-                Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 60))
-                If Task.IsAborted Then Exit Sub
-                If Java Is Nothing Then Throw New Exception("由于未找到 Java,已取消安装。")
-            End If
-        End SyncLock
-        '添加 Java Wrapper 作为主 Jar
-        Dim Arguments As String
-        If UseJavaWrapper Then
-            Arguments = $"-Doolloo.jlw.tmpdir=""{GetJavaWrapperDir()}"" -cp ""{PathTemp}Cache\neoforge_installer.jar;{Target}"" -jar ""{ExtractJavaWrapper()}"" com.bangbang93.ForgeInstaller ""{McFolder}"
-        Else
-            Arguments = $"-cp ""{PathTemp}Cache\neoforge_installer.jar;{Target}"" com.bangbang93.ForgeInstaller ""{McFolder}"
-        End If
-        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
-            }
-            Log("[Download] 开始安装 NeoForge:" & 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()
-                                NeoForgeInjectorLine(e.Data, Task)
-                            End If
-                        Catch ex As ObjectDisposedException
-                        Catch ex As Exception
-                            Log(ex, "读取 NeoForge 安装器信息失败")
-                        End Try
-                        Try
-                            If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
-                                Log("[Installer] 由于任务取消,已中止 NeoForge 安装")
-                                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()
-                                NeoForgeInjectorLine(e.Data, Task)
-                            End If
-                        Catch ex As ObjectDisposedException
-                        Catch ex As Exception
-                            Log(ex, "读取 NeoForge 安装器错误信息失败")
-                        End Try
-                        Try
-                            If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
-                                Log("[Installer] 由于任务取消,已中止 NeoForge 安装")
-                                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()
-                    '检查是否安装成功:最后两行中是否有 true(true 可能在倒数第二行,见 #832)
-                    If LastResults.Last = "true" OrElse (LastResults.Count >= 2 AndAlso LastResults(LastResults.Count - 2) = "true") Then Exit Sub
-                    Log(Join(LastResults, vbCrLf))
-                    Dim LastLines As String = ""
-                    For i As Integer = Math.Max(0, LastResults.Count - 5) To LastResults.Count - 1 '最后 5 行
-                        LastLines &= vbCrLf & LastResults(i)
-                    Next
-                    Throw New Exception("NeoForge 安装器出错,日志结束部分为:" & LastLines)
-                End Using
-            End Using
-        End SyncLock
-    End Sub
-    Private Sub NeoForgeInjectorLine(Content As String, Task As LoaderTask(Of Boolean, Boolean))
-        If Content.StartsWithF("  Data") OrElse Content.StartsWithF("  Slim") Then
-            If ModeDebug Then Log("[Installer] " & Content)
-        ElseIf Content.StartsWithF("  Reading patch ") Then
-            If ModeDebug Then Log("[Installer] " & Content)
-            Task.Progress = 0.86
-        Else
-            Select Case Content
-                Case "Extracting json"
-                    Log("[Installer] " & Content)
-                    Task.Progress = 0.07
-                Case "Downloading libraries"
-                    Log("[Installer] " & Content)
-                    Task.Progress = 0.08
-                Case "  File exists: Checksum validated."
-                    If ModeDebug Then Log("[Installer] " & Content)
-                    Task.Progress += 0.003
-                Case "Building Processors"
-                    Task.Progress = 0.38
-                Case "Task: DOWNLOAD_MOJMAPS" 'B
-                    Task.Progress = 0.4
-                Case "Task: MERGE_MAPPING" 'B
-                    Task.Progress = 0.6
-                Case "Splitting: "
-                    Task.Progress = 0.62
-                Case "Parameter Annotations" 'B
-                    Task.Progress = 0.66
-                Case "Processing Complete" 'B
-                    Task.Progress = 0.7
-                Case "Remapping final jar" 'A
-                    Task.Progress = 0.72
-                Case "Remapping jar... 50%" 'A
-                    Task.Progress = 0.76
-                Case "Remapping jar... 100%" 'A
-                    Task.Progress = 0.81
-                Case "Injecting profile"
-                    Task.Progress = 0.91
-                Case Else
-                    If ModeDebug Then Log("[Installer] " & Content)
-                    Exit Sub
-            End Select
-            Log("[Installer] " & Content)
-        End If
-    End Sub
-
-    ''' <summary>
-    ''' 获取下载某个 NeoForge 版本的加载器列表。
-    ''' </summary>
-    Private Function McDownloadNeoForgeLoader(Version As String, Inherit As String, Optional DownloadRawInfo As DlNeoForgeVersionEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
-
-        '参数初始化
-        Dim DownloadInfo As New DlNeoForgeVersionEntry
-        McFolder = If(McFolder, PathMcFolder)
-        If DownloadRawInfo Is Nothing Then          '兜底,有的时候 DownloadInfo 可能是空的
-            If Version.Contains("-beta") Then
-                DownloadInfo.VersionName = Version
-                Version = Version.Replace("neoforge-", "").Replace("-beta", "").Replace("1.20.1-", "")
-                DownloadInfo.VersionCode = Version
-                DownloadInfo.IsBeta = True
-            Else
-                DownloadInfo.VersionName = Version
-                Version = Version.Replace("neoforge-", "").Replace("1.20.1-", "")
-                DownloadInfo.VersionCode = Version
-                DownloadInfo.IsBeta = False
-            End If
-        Else
-            DownloadInfo = DownloadRawInfo
-            Version = DownloadInfo.VersionCode
-        End If
-        Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
-        Dim Id As String = DownloadInfo.VersionName
-        Dim InstallerAddress As String = PathTemp & "Cache\Code\NeoForgeInstall-" & Version & "_" & RandomInteger(0, 100000)
-        Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
-        Dim DisplayName As String = "NeoForge " & Inherit & " - " & Version
-        Dim Loaders As New List(Of LoaderBase)
-        Dim LibVersionFolder As String = PathMcFolder & "versions\" & Id & "\" '作为 Lib 文件目标的版本文件夹
-
-        '获取下载信息
-        If DownloadInfo Is Nothing Then
-            Loaders.Add(New LoaderTask(Of String, String)("获取 NeoForge 详细信息",
-            Sub(Task As LoaderTask(Of String, String))
-                '获取 NeoForge 版本列表
-                Dim NeoForgeLoader = New LoaderTask(Of String, List(Of DlNeoForgeVersionEntry))("McDownloadNeoForgeLoader " & Inherit, AddressOf DlNeoForgeVersionMain)
-                NeoForgeLoader.WaitForExit(Inherit)
-                Task.Progress = 0.8
-                '查找对应版本
-                For Each NeoForgeVersion In NeoForgeLoader.Output
-                    If NeoForgeVersion.VersionName = Version Then
-                        DownloadInfo = NeoForgeVersion
-                        Exit Sub
-                    End If
-                Next
-                Throw New Exception("未能找到 NeoForge " & Inherit & "-" & Version & " 的详细信息!")
-            End Sub) With {.ProgressWeight = 3})
-        End If
-        '下载 NeoForge 主文件
-        Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("准备下载 NeoForge",
-            Sub(Task As LoaderTask(Of String, List(Of NetFile)))
-                '启动依赖版本的下载
-                If ClientDownloadLoader Is Nothing Then
-                    If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
-                    ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, Inherit)
-                End If
-                Dim IsLegacyNeo As Boolean = DownloadInfo.VersionCode.StartsWith("47.")
-                Dim Files As New List(Of NetFile) From {New NetFile({
-                    $"https://bmclapi2.bangbang93.com/maven/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}",
-                    $"https://maven.neoforged.net/releases/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}"
-                }, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash))}
-                Task.Output = Files
-            End Sub) With {.ProgressWeight = 0.5, .Show = False})
-        Loaders.Add(New LoaderDownload("下载 NeoForge 主文件", New List(Of NetFile)) With {.ProgressWeight = 9})
-
-        '安装(需要原版 Jar)
-        Log("[Download] 检测到的 NeoForge 版本:" & Version)
-        Dim Libs As List(Of McLibToken) = Nothing
-        Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 NeoForge 支持库文件",
-            Sub(Task As LoaderTask(Of String, List(Of NetFile)))
-                Task.Output = New List(Of NetFile)
-                Dim Installer As ZipArchive = Nothing
-                Try
-                    '解压并获取、合并两个 Json 的信息
-                    Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
-                    Task.Progress = 0.2
-                    Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
-                    Dim Json2 As JObject = GetJson(ReadFile(Installer.GetEntry("version.json").Open))
-                    Json.Merge(Json2)
-                    '获取 Lib 下载信息
-                    Libs = McLibListGetWithJson(Json, True)
-                    '添加 Mappings 下载信息
-                    If Json("data") IsNot Nothing AndAlso Json("data")("MOJMAPS") IsNot Nothing Then
-                        '下载原版 Json 文件
-                        Task.Progress = 0.4
-                        Dim RawJson As JObject = GetJson(NetGetCodeByDownload(DlSourceLauncherOrMetaGet(DlClientListGet(Inherit)), IsJson:=True))
-                        '[net.minecraft:client:1.17.1-20210706.113038:mappings@txt] 或 @tsrg]
-                        Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Before("@")
-                        Dim Address = McLibGet(OriginalName).Replace(".jar", "-mappings." & Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(1))
-                        Libs.Add(New McLibToken With {.IsJumpLoader = False, .IsNatives = False, .LocalPath = Address, .OriginalName = OriginalName,
-                                                                                                            .Url = RawJson("downloads")("client_mappings")("url"), .Size = RawJson("downloads")("client_mappings")("size"), .SHA1 = RawJson("downloads")("client_mappings")("sha1")})
-                        Log("[Download] 需要下载 Mappings:" & Address)
-                    End If
-                    Task.Progress = 0.8
-                    '去除其中的原始 NeoForge 项
-                    For i = 0 To Libs.Count - 1
-                        If Libs(i).LocalPath.EndsWithF("neoforge-" & Inherit & "-" & Version & ".jar") OrElse
-                                                                                                      Libs(i).LocalPath.EndsWithF("forge-" & Inherit & "-" & Version & "-client.jar") Then
-                            Log("[Download] 已从待下载 NeoForge 支持库中移除:" & Libs(i).LocalPath, LogLevel.Debug)
-                            Libs.RemoveAt(i)
-                            Exit For
-                        End If
-                    Next
-                    Task.Output = McLibFixFromLibToken(Libs, PathMcFolder)
-                Catch ex As Exception
-                    Throw New Exception("获取 NeoForge 支持库列表失败", ex)
-                Finally
-                    '释放文件
-                    If Installer IsNot Nothing Then Installer.Dispose()
-                End Try
-            End Sub) With {.ProgressWeight = 2})
-        Loaders.Add(New LoaderDownload("下载 NeoForge 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 12})
-        Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("获取 NeoForge 支持库文件",
-            Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
-#Region "NeoForge 文件"
-                If IsCustomFolder Then
-                    For Each LibFile As McLibToken In Libs
-                        Dim RealPath As String = LibFile.LocalPath.Replace(PathMcFolder, McFolder)
-                        If Not File.Exists(RealPath) Then
-                            Directory.CreateDirectory(IO.Path.GetDirectoryName(RealPath))
-                            CopyFile(LibFile.LocalPath, RealPath)
-                        End If
-                        If ModeDebug Then Log("[Download] 复制的 NeoForge 支持库文件:" & LibFile.LocalPath)
-                    Next
-                End If
-#End Region
-#Region "原版文件"
-                '等待原版文件下载完成
-                If ClientDownloadLoader Is Nothing Then Exit Sub
-                Dim TargetLoaders As List(Of LoaderBase) =
-                                                                                ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
-                                                                                Where(Function(l) l.State <> LoadState.Finished).ToList
-                If TargetLoaders.Any Then Log("[Download] NeoForge 安装正在等待原版文件下载完成")
-                Do While TargetLoaders.Any AndAlso Not Task.IsAborted
-                    TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
-                    Thread.Sleep(50)
-                Loop
-                If Task.IsAborted Then Exit Sub
-                '拷贝原版文件
-                If Not IsCustomFolder Then Exit Sub
-                SyncLock VanillaSyncLock
-                    Dim ClientName As String = GetFolderNameFromPath(ClientFolder)
-                    Directory.CreateDirectory(McFolder & "versions\" & Inherit)
-                    If Not File.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".json") Then
-                        CopyFile(ClientFolder & ClientName & ".json", McFolder & "versions\" & Inherit & "\" & Inherit & ".json")
-                    End If
-                    If Not File.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".jar") Then
-                        CopyFile(ClientFolder & ClientName & ".jar", McFolder & "versions\" & Inherit & "\" & Inherit & ".jar")
-                    End If
-                End SyncLock
-#End Region
-            End Sub) With {.ProgressWeight = 0.1, .Show = False})
-        Loaders.Add(New LoaderTask(Of Boolean, Boolean)("安装 NeoForge",
-            Sub(Task As LoaderTask(Of Boolean, Boolean))
-                Dim Installer As ZipArchive = Nothing
-                Try
-                    Log("[Download] 开始进行 NeoForge 安装:" & InstallerAddress)
-                    '记录当前文件夹列表(在新建目标文件夹之前)
-                    Dim OldList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.
-                                                                        Select(Function(i) i.FullName).ToList()
-                    '解压并获取信息
-                    Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
-                    Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
-                    '新建目标版本文件夹
-                    Directory.CreateDirectory(VersionFolder)
-                    Task.Progress = 0.04
-                    '释放 launcher_installer.json
-                    McFolderLauncherProfilesJsonCreate(McFolder)
-                    Task.Progress = 0.05
-                    '运行 NeoForge 安装器
-                    Dim UseJavaWrapper As Boolean = True
-Retry:
-                    Try
-                        '释放 NeoForge 注入器
-                        WriteFile(PathTemp & "Cache\neoforge_installer.jar", GetResources("ForgeInstaller"))
-                        Task.Progress = 0.06
-                        '运行注入器
-                        NeoForgeInjector(InstallerAddress, Task, McFolder, UseJavaWrapper)
-                        Task.Progress = 0.97
-                    Catch ex As Exception
-                        If UseJavaWrapper Then
-                            Log(ex, "使用 JavaWrapper 安装 NeoForge 失败,将不使用 JavaWrapper 并重试")
-                            UseJavaWrapper = False
-                            GoTo Retry
-                        Else
-                            Throw New Exception("运行 NeoForge 安装器失败", ex)
-                        End If
-                    End Try
-                    '拷贝新增的版本 Json
-                    Dim DeltaList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.
-                        SkipWhile(Function(i) OldList.Contains(i.FullName)).ToList()
-                    If DeltaList.Count > 1 Then
-                        '它可能和 OptiFine 安装同时运行,导致增加的文件不止一个(这导致了 #151)
-                        '也可能是因为 NeoForge 安装器的 Bug,生成了一个名字错误的文件夹,所以需要检查文件夹是否为空
-                        DeltaList = DeltaList.Where(Function(l) l.Name.Contains("neoforge") AndAlso l.EnumerateFiles.Any).ToList
-                    End If
-                    If DeltaList.Count = 1 Then '如果没有新增文件夹,那么预测的文件夹名就是正确的
-                        Dim JsonFile As FileInfo = DeltaList(0).EnumerateFiles.First()
-                        WriteFile(VersionFolder & Id & ".json", ReadFile(JsonFile.FullName))
-                    End If
-                    '新建 mods 文件夹
-                    Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
-                Catch ex As Exception
-                    Throw New Exception("安装新 NeoForge 版本失败", ex)
-                Finally
-                    '清理文件
-                    Try
-                        If Installer IsNot Nothing Then Installer.Dispose()
-                        If File.Exists(InstallerAddress) Then File.Delete(InstallerAddress)
-                    Catch ex As Exception
-                        Log(ex, "安装 NeoForge 清理文件时出错")
-                    End Try
-                End Try
-            End Sub) With {.ProgressWeight = 10})
-
-        Return Loaders
-    End Function
-
-#End Region
-
 #Region "NeoForge 下载菜单"
 #Region "NeoForge 下载菜单"
 
 
     Public Sub NeoForgeDownloadListItemPreload(Stack As StackPanel, Entrys As List(Of DlNeoForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
     Public Sub NeoForgeDownloadListItemPreload(Stack As StackPanel, Entrys As List(Of DlNeoForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
@@ -2270,7 +1830,7 @@ Retry:
         Else
         Else
             Version = sender.Parent.Parent.Tag
             Version = sender.Parent.Parent.Tag
         End If
         End If
-        McDownloadNeoForgeSave(Version)
+        McDownloadForgeSave(True, , Version)
     End Sub
     End Sub
 
 
 #End Region
 #End Region
@@ -2642,11 +2202,11 @@ Retry:
         End If
         End If
         'Forge
         'Forge
         If Request.ForgeVersion IsNot Nothing Then
         If Request.ForgeVersion IsNot Nothing Then
-            LoaderList.Add(New LoaderCombo(Of String)("下载 Forge " & Request.ForgeVersion, McDownloadForgeLoader(Request.ForgeVersion, Request.MinecraftName, Request.ForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) With {.Show = False, .ProgressWeight = 25, .Block = Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing AndAlso Request.NeoForgeEntry Is Nothing})
+            LoaderList.Add(New LoaderCombo(Of String)("下载 Forge " & Request.ForgeVersion, McDownloadForgeLoader(False, Request.ForgeVersion, Request.MinecraftName, Request.ForgeEntry, , TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) With {.Show = False, .ProgressWeight = 25, .Block = Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing AndAlso Request.NeoForgeEntry Is Nothing})
         End If
         End If
         'NeoForge
         'NeoForge
         If Request.NeoForgeVersion IsNot Nothing Then
         If Request.NeoForgeVersion IsNot Nothing Then
-            LoaderList.Add(New LoaderCombo(Of String)("下载 NeoForge " & Request.NeoForgeVersion, McDownloadNeoForgeLoader(Request.NeoForgeVersion, Request.MinecraftName, Request.NeoForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) With {.Show = False, .ProgressWeight = 25, .Block = Request.ForgeEntry Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
+            LoaderList.Add(New LoaderCombo(Of String)("下载 NeoForge " & Request.NeoForgeVersion, McDownloadForgeLoader(True, Request.NeoForgeVersion, Request.MinecraftName, , Request.NeoForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) With {.Show = False, .ProgressWeight = 25, .Block = Request.ForgeEntry Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
         End If
         End If
         'LiteLoader
         'LiteLoader
         If Request.LiteLoaderEntry IsNot Nothing Then
         If Request.LiteLoaderEntry IsNot Nothing Then

+ 2 - 2
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml.vb

@@ -42,10 +42,10 @@
         End If
         End If
     End Sub
     End Sub
     Private Sub NeoForge_Selected(sender As MyListItem, e As EventArgs)
     Private Sub NeoForge_Selected(sender As MyListItem, e As EventArgs)
-        McDownloadNeoForgeSave(sender.Tag)
+        McDownloadForgeSave(True, sender.Tag)
     End Sub
     End Sub
     Public Sub DownloadStart(sender As MyListItem, e As Object)
     Public Sub DownloadStart(sender As MyListItem, e As Object)
-        McDownloadNeoForge(sender.Tag)
+        McDownloadForge(True, sender.Tag)
     End Sub
     End Sub
     Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
     Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
         OpenWebsite("https://neoforged.net/")
         OpenWebsite("https://neoforged.net/")